Subject: Qwk Specs Format of Control.Dat file Control.Dat is a normal CR/LF style text file with the following lines in exactly the order shown. BBS name BBS City, BBS State BBS phone number {AAA-EEE-NNNN} Sysop name,Sysop {Sysop name in upper case followed by the literal ',Sysop'} Serial number ,BBS ID {Serial Number, UpperCase BBSID} Date of mail packet, time of packet {MM-DD-YYYY,HH:MM:SS} Caller's name {Uppercase} blank 0 0 Number of conferences (in additon to conference 0 which is main) (ie use number of conferences minus one) Conference number Name of Conference (should be limited to maximum length of 12 characters) ... ... ... ... ... Conference number Name of Conference name of BBS welcome file name of NEWS file name of BBS goodbye file Other optional data may occur after the Goodbye file line, but the trend is to omit this data. If included it is as follows: 0 {Unknown} Screen Length USER NAME {Upper case} FirstName {Proper case} CITY, ST {Upper case} Data Phone {AAA EEE-NNNN} Voice Phone {AAA EEE-NNNN} Security Level Expiration Date {MM-DD-YY} Last On Date {MM-DD-YY} Last On Time {HH:MM} Number of calls 0 {Unknown} DownLoaded Bytes DownLoaded Count Uploaded Bytes Uploaded Count Time Limit Per Day {Minutes} Time Remaining {Minutes} Time Used Today {Minutes} DownLoad Limit/Day {Kilobytes} DownLoad Bytes Remaining Today {Bytes} DownLoaded Today {Bytes} Current Time {HH:MM} Current Date {MM-DD-YY} System Tag Line Filenames used by the *.QWK format BBSID.QWK is an archive containing the files from the message door being sent to the caller. MESSAGES.DAT - a file containing the messages themselves in 128 byte records. CONTROL.DAT - a file with info on the system, caller, and conference names and numbers. 999.NDX - one file for each selected conference that contains pointers to the messages in MESSAGES.DAT There are usually several *.NDX files in each QWK file. (Right justified, padded with leading zeros to make the 3 characters). NEWFILES.DAT - an optional file that contains a list of new files from the Bbs. BLT-0.99 - optional files containing ascii or ansi bulletins. The 99 extension is replaced by the bulletin number (Left justified not padded). SESSION.TXT - an optional ascii/ansi file containing info on the activity occuring in the mail door. Optionally it may also contain ascii or ansi screens for Welcome, News, and Goodbye as named in the CONTROL.DAT file. BBSID.REP is an archive containing a single file of the messages sent from the caller to the Bbs. BBSID.MSG - a file containing the messages themselves in 128 byte records. The format is similar to MESSAGES.DAT. Format of the exported messages in Messages.Dat This file contains records with a length of 128 bytes. There are 3 types of these records: (1) Packet Header, (2) Message Header, and (3) Message Text. All unused fields in the records are normally filled with spaces, although you will sometimes find the final Message text record will be filled with nulls (#0) after the last text. Packet Header Packet Header - is always the first record in the file and only occurs once. It contains only normal ascii text (limitted to at most 128 characters) and should always start with "Produced by ". The remaining text normally includes a product name and copyright message. Message Header A message header immediately preceeds zero or more message text records. Each Message header has the following format: Start Pos Length Description ------ ------ ----------------------------------------- 1 1 Message status flag (see below) 2 7 Message number (ascii left justified) 9 8 Date (MM-DD-YY) 17 5 Time (HH:MM) 22 25 To (left justified space filled - uppercase) (Be sure to check the to field to spot configuration type messages) 47 25 From (left justified space filled - uppercase) 72 25 Subject (left justified space filled - uppercase) (a subject starting "NE:" should not be echoed into a network) 97 12 Password (not really used leave blank) 109 8 Message reference number (ascii left justified) 117 6 Number of blocks (ascii left justified - number of 128 byte blocks including 1 for the message header) 123 1 Message active (a or #225 = Active, b or #226 = Inactive) 124 1 Conference number (Binary byte) Message Status Flag has the following possibilities: '~' Private, unread ' ' Public, read '`' Private, read '-' Public, unread '*' Private, unread '+' Private, read Message Text Records The message text records immediately follow the the message header. They contain straight ascii text (lines are normally limitted to 72 chars/line although you may see longer lines). Each line is followed by a "c" or #227 character to mark the end of the line (in place of the normal CR/LF that would exist in a straight text file). The text continues consecutavly and text lines do continue across block boundaries. Some systems may have problems with messages longer than 99 lines, although more recently this no longer seems to be a limit. The last block should be padded with blanks to fill the block, although on input you may find it padded with nulls (#0). Format of Index files Index files are named XXX.NDX (where XXX is the conference number padded with leading zeros to make it three characters long. There is one *.NDX file for each conference chosen that contains messages in the MESSAGES.DAT file. The *.NDX file contain records five characters long that point to each message in that conference. NdxRecord = Record MsgPointer: BasicReal Conference: Byte; End; The BasicReal is a four byte number in BASIC MKS$ format. The following is a sample program unit for TurboPascal that converts between BasicReal format and LongInt format. -+--------------------------------------------------------------------------- Unit BasicConvert; Interface Function BasicReal2Long(InValue: LongInt): LongInt; {Convert Basic Short Reals to LongInts} Function Long2BasicReal(InValue: LongInt): LongInt; {Convert LongInts to Basic Short Reals} Implementation Function BasicReal2Long(InValue: LongInt): LongInt; Var Temp: LongInt; Negative: Boolean; Expon: Integer; Begin If InValue And $00800000 <> 0 Then Negative := True Else Negative := False; Expon := InValue shr 24; Expon := Expon and $ff; Temp := InValue and $007FFFFF; Temp := Temp or $00800000; Expon := Expon - 152; If Expon < 0 Then Temp := Temp shr Abs(Expon) Else Temp := Temp shl Expon; If Negative Then BasicReal2Long := -Temp Else BasicReal2Long := Temp; If Expon = 0 Then BasicReal2Long := 0; End; Function Long2BasicReal(InValue: LongInt): LongInt; Var Negative: Boolean; Expon: LongInt; Begin If InValue = 0 Then Long2BasicReal := 0 Else Begin If InValue < 0 Then Begin Negative := True; InValue := Abs(InValue); End Else Negative := False; Expon := 152; If InValue < $007FFFFF Then While ((InValue and $00800000) = 0) Do Begin InValue := InValue shl 1; Dec(Expon); End Else While ((InValue And $FF000000) <> 0) Do Begin InValue := InValue shr 1; Inc(Expon); End; InValue := InValue And $007FFFFF; If Negative Then InValue := InValue Or $00800000; Long2BasicReal := InValue + (Expon shl 24); End; End; End. -+--------------------------------------------------------------------------- A quick and dirty conversion (handles positive numbers only) is possible with the following expression: MKSToNum := ((x AND NOT $ff000000) OR $00800000) SHR (24 - ((x SHR 24) AND $7f)); -+--------------------------------------------------------------------------- The number contained in the MsgPointer is the record number (128 byte records - starting numbering from record 1 not 0) of the message header. Note that since the 1st record contains packet header, the lowest MsgPointer that can exist is 2. Some message readers will reformat the *.NDX files so that the MsgPointer becomes a LongInt fileseek position (using a record size of 1). To determine which type of index you are reading you should look at the size of the number. Any BasicReal will appear as a huge number that would unlikely ever be a byte seek positon. Starting July 1st, Sparkware is making minor changes to the "QWK" format we originated in 1987. The changes made to the format are minor but add information that is used by our new offline mail reader system, 1stReader. NOTE that 1stReader will also work with "conventional" QWK mail packets produced by Qmail Doors released before 06-01-92 or on other Qmail-compatible mail doors. However, 1stReader works *best* with these changes in place. These changes in the format take hold if the user turns on OPTION #21 inside Qmail Door. If this option turned off then Qmail Door continues to generate standard QWK formats. Two changes have been made to the format. The first change involves line #10 in the CONTROL.DAT file. Since 1987 this line has been reserved for the total number of messages contained inside the QWK mail packet. This change prevents 1stReader from having to scan MESSAGES.DAT to determine how many messages are in the packet. The second format change deals with individual message headers. The format has been changed to: Status AS STRING * 1 'Status of message Number AS STRING * 7 'Message number Date AS STRING * 8 'Date Time AS STRING * 5 'Time MsgTo AS STRING * 25 'To MsgFrom AS STRING * 25 'From Subject AS STRING * 25 'Subject Password AS STRING * 12 'Password Reference AS STRING * 8 'Reference number Blocks AS STRING * 6 'Number of blocks Delete AS STRING * 1 'Current status of message Conference AS INTEGER 'Conference ----> MsgCount AS INTEGER 'Logical msg number in packet Tag AS STRING * 1 'Message tagline Notice "MsgCount". This value now contains the logical message number for the message in the packet. In other words, this value will be "1" for the first message in the packet, "2" for the second message in the packet, etc. Again, these changes are now in effect for the 1,468 Qmail Door systems that were compiled on or after 06-01-92.