fsxNet Wiki

BBS Development & Resources

User Tools

Site Tools


probbs:qwk

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
probbs:qwk [2019/11/16 19:28]
ozz [CONTROL.DAT]
probbs:qwk [2019/11/18 07:16] (current)
ozz [MESSAGES.DAT]
Line 7: Line 7:
 Even though the files are zipped, the file extension is renamed to .QWK for the download from the BBS software, and .REP for the zip uploading messages to the BBS. Even though the files are zipped, the file extension is renamed to .QWK for the download from the BBS software, and .REP for the zip uploading messages to the BBS.
  
-  - Ordered List ItemCONTROL.DAT (a string list file)+  - CONTROL.DAT (a string list file)
   - MESSAGES.DAT (a 128 block ASCII file)   - MESSAGES.DAT (a 128 block ASCII file)
   - *.NDX (an array of binary bytes)   - *.NDX (an array of binary bytes)
Line 63: Line 63:
 ^BBS network tag-line |FSXNet BBS| ^BBS network tag-line |FSXNet BBS|
  
 +===== MESSAGES.DAT =====
  
 +Messages file starts with a 128 byte product information. Like:
  
 +  * Produced by Qmail...Copyright (c) 1987 by Sparkware. ​ All Rights Reserved. (padded with spaces)
 +  * QWK Packet Produced by PCBoard v15.0 (padded with spaces)
 +
 +That block is followed by messages using PCBoard 12.0 format.
 +
 +In Pascal:
 +<code pascal>
 +    type
 +       ​MsgHeaderRec=Packed Record
 +          TypeID:​String[1];​
 +          MsgID:​String[7];​
 +          DateStr:​String[8];​
 +          TimeStr:​String[5];​
 +          MsgTo:​String[25];​
 +          MsgFrom:​String[25];​
 +          MsgSubj:​String[25];​
 +          Reserved:​String[12];​
 +          MsgRefer:​String[8];​
 +          Chunks:​Longint;​
 +          Attributes:​String[6];​
 +       End;
 +</​code>​
 +
 +In C:
 +
 +<code C>
 +    struct QwkHeader {
 + unsigned char Msgstat; ​    /* Message status ​      */
 + unsigned char Msgnum[7]; ​  /* Message number ​      */
 + unsigned char Msgdate[8]; ​ /* Message date MM-DD-YY*/
 + unsigned char Msgtime[5]; ​ /* Message time HH:MM   */
 + unsigned char MsgTo[25]; ​  /* Message To:          */
 + unsigned char MsgFrom[25];​ /* Message From:        */
 + unsigned char MsgSubj[25];​ /* Message Subject: ​    */
 + unsigned char Msgpass[12];​ /* Message password ​    */
 + unsigned char Msgrply[8]; ​ /* Message reply to     */
 + unsigned char Msgrecs[6]; ​ /* Length in records ​   */
 + unsigned char Msglive; ​    /* Message active status*/
 + unsigned char Msgarealo; ​  /* Lo-byte message area */
 + unsigned char Msgareahi; ​  /* Hi-byte message area */
 + unsigned char Msgofflo;
 + unsigned char Msgoffhi;
 + unsigned char Msgtagp;
 +    } __attribute__((packed));​
 +</​code>​
 +
 +Of course to populate that structure you will BlockRead 128 bytes, them move from offset to length to each field.
 +
 +^Offset ​ |^Length ​ |^Description|
 +|1||1||Message status flag (unsigned character)|
 +^ |^ ||#32 = (space) public, unread|
 +^ |^ ||'​-'​ = public, read|
 +^ |^ ||'​+'​ = private, unread|
 +^ |^ ||'​*'​ = private, read|
 +^ |^ ||'​~'​ = comment to Sysop, unread|
 +^ |^ ||'​`'​ = comment to Sysop, read|
 +^ |^ ||'​%'​ = password protected, unread|
 +^ |^ ||#94 = (carrot) password protected, read|
 +^ |^ ||'​!'​ = group password, unread|
 +^ |^ ||'#'​ = group password, read|
 +^ |^ ||'​$'​ = group password to all|
 +|2||7||Message number (in ASCII)|
 +|9||8||Date (''​mm-dd-yy'',​ in ASCII)|
 +|17||5||Time (24 hour ''​hh:​mm'',​ in ASCII)|
 +|22||25||To (uppercase, left justified)|
 +|47||25||From (uppercase, left justified)|
 +|72||25||Subject of message (mixed case)|
 +|97||12||Password (space filled)|
 +|109||8||Reference message number (in ASCII)|
 +|117||6||Number of 128-bytes blocks in message ((including the header, in ASCII; the lowest value should be 2, header plus one block message; this number may not be left flushed within the field))|
 +|123||1||Flag ((ASCII 225 means message is active; ASCII 226 means this message is to be killed))|
 +|124||2||Conference number (unsigned word)|
 +|126||2||Logical message number in the current packet ((this number will be 1 for the first message, 2 for the second, and so on. unsigned word))|
 +|128||1||Indicates whether the message has a network tag-line or not. ((A value of '​*'​ indicates that a network tag-line is present; a value of ' ' (space) indicates there isn't one.  Messages sent to readers (non-net-status) generally leave this as a space. Only network software need this information.))|
 +
 +
 +==== MESSAGE BODY ====
 +
 +Instead of carriage return and line feed combination,​ each line in the message end with an ASCII 227 (pi character) symbol. If a message does not completely occupy the 128-bytes block, the remainder of the block is padded with space or null.
 +
 +===== Index files (*.NDX) =====
 +
 +The index files contain a list of pointers pointing to the beginning of messages in the MESSAGES.DAT file.  The pointer is in terms of the 128-bytes block logical record that the MESSAGES.DAT file is in. Each
 +conference has its own xxx.NDX file, where xxx is the conference number left padded with zeroes. Some mail programs offer the user the option to not generate index files. So the mail readers need to create the index files if they are missing.
 +
 +^Offset ​ |^Length ​ |^Description|
 +^1|^4|^Record number pointing to corresponding message in MESSAGES.DAT. [1]|
 +^5|^1|^Conference number of the message (same as filename, e.g. USELESS)|
 +
 +[1] = This number is in the Microsoft MKS$ BASIC format.
 +
 +In Pascal:
 +
 +    Type
 +       ​BSingle:​Array[0..3] of Byte;
 +    ​
 +    Procedure LONG2MSB(Index:​LongInt;​Var MS:​BSingle);​
 +    Var
 +       Exp : Byte;
 +    Begin
 +       If Index <> 0 Then Begin
 +          Exp := 0;
 +          While Index And $800000 = 0 Do Begin
 +             Inc (Exp);
 +             Index := Index SHL 1;
 +          End;
 +    ​
 +          Index := Index And $7FFFFF;
 +       End
 +       Else Exp := 152;
 +       MS[0] := Index AND $FF;
 +       MS[1] := (Index SHR 8) AND $FF;
 +       MS[2] := (Index SHR 16) AND $FF;
 +       MS[3] := 152 - Exp;
 +    End;
 +
 +In C:
 +
 +    int ieee_to_msbin(float *src4, float *dest4) {
 + unsigned char *ieee = (unsigned char *)src4;
 + unsigned char *msbin = (unsigned char *)dest4;
 + unsigned char sign = 0x00;
 + unsigned char msbin_exp = 0x00;
 + int i;
 + /* See _fmsbintoieee() for details of formats ​  */
 + sign = ieee[3] & 0x80;
 + msbin_exp |= ieee[3] << 1;
 + msbin_exp |= ieee[2] >> 7;
 + /* An ieee exponent of 0xfe overflows in MBF    */
 + if (msbin_exp == 0xfe) return 1;
 + msbin_exp += 2; /* actually, -127 + 128 + 1 */
 + for (i = 0; i < 4; i++) msbin[i] = 0;
 + msbin[3] = msbin_exp;
 + msbin[2] |= sign;
 + msbin[2] |= ieee[2] & 0x7f;
 + msbin[1] = ieee[1];
 + msbin[0] = ieee[0];
 + return 0;
 +    }
 +
 +==== Personal index (PERSONAL.NDX) ====
 +
 +There is a special index file named PERSONAL.NDX. This file contains pointers to messages which are addressed to the user, i.e. personal messages. Some mail door and utility programs also allow the selection of other messages to be flagged as personal messages.
 +
 +**NOTE** I have found that not all BBS software generate this file, for example PCBoard 15.x
  
probbs/qwk.1573932506.txt.gz ยท Last modified: 2019/11/16 19:28 by ozz