home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / OFFLINE / QWKINFO.ZIP / QWKINFO1.TXT < prev    next >
Text File  |  1991-08-09  |  18KB  |  384 lines

  1.                       ■■ THE MYSTERIOUS QWK-FILE FORMAT ■■
  2.                                       by
  3.                                   Jeffery Foy
  4.  
  5.  
  6.          It would be safe  to  assume  that  if  you're  reading  this
  7.          article,  you  use or have used a QWK-compatible offline mail
  8.          reader. The QWK format has emerged as the  format  of  choice
  9.          due  to  the  relatively  small  size  of QWK mail packets as
  10.          compared to an equivalent ASCII text file.
  11.  
  12.          As most users of offline mail readers know,  the  QWK  format
  13.          was designed by Mark Herring (Sparky) of Sparkware. While Mr.
  14.          Herring  did  design  the  format,  he only gave very sketchy
  15.          details as to the specifics of  the  format.  This  is  quite
  16.          understandable  as  he  is  a  very  busy person. That is the
  17.          reason why I'm writing this article.
  18.  
  19.          In it's most basic form, a QWK file is  simply  a  compressed
  20.          file.  In  almost all cases, the QWK file has been compressed
  21.          with PKZIP from PKWARE. With most mail doors, you can usually
  22.          choose your favorite archiver so your QWK file may not be  in
  23.          PKZIP format.
  24.  
  25.          Within  the  compressed  QWK file are quite a number of other
  26.          component files. We'll start with the one called  CONTROL.DAT
  27.          since it is the easiest to describe. It is an ASCII text file
  28.          so if you have one handy, you can follow along.
  29.  
  30.          Generic BBS            ; Line # 1
  31.          Seattle, WA            ; Line # 2
  32.          206-555-1212           ; Line # 3
  33.          Joe Sysop, Sysop       ; Line # 4
  34.          00000,GENBBS           ; Line # 5
  35.          01-01-1991,00:00:00    ; Line # 6
  36.          MARY USER              ; Line # 7
  37.          MENU                   ; Line # 8
  38.          0                      ; Line # 9
  39.          0                      ; Line #10
  40.          254                    ; Line #11
  41.          0                      ; Line #12
  42.          Main Conf              ; Line #13
  43.          ...                    ; Line # x
  44.          254                    ; Line # x
  45.          Last Conf              ; Line # x
  46.          HELLO
  47.          NEWS
  48.          GOODBYE
  49.  
  50.          Line # 1 - This is the BBS name where you got your mail
  51.                     packet.
  52.          Line # 2 - This is the city and state where the BBS is
  53.                     located.
  54.          Line # 3 - This is the BBS phone number.
  55.          Line # 4 - This is the sysop's name.
  56.          Line # 5 - This line contains first the serial number of the
  57.                     mail door followed by the BBS ID. Note the BBS ID
  58.                     as it will be used later in this article.
  59.          Line # 6 - This is the time and date of the packet.
  60.          Line # 7 - This is the uppercase name of the user for which
  61.                     this packet was prepared.
  62.          Line # 8 - This line contains the name of the menu file for
  63.                     those who use the Qmail reader/door. Almost all
  64.                     other mail doors leave this line blank.
  65.          Line # 9 - No one seems to know what this line is meant for.
  66.          Line #10 - No one seems to know what this line is meant for.
  67.                     (Note: Both of these ALWAYS seem to be 0)
  68.          Line #11 - This line is the maximum number of conferences
  69.                     MINUS 1.
  70.          Line #12 - This line is the first conference's number. It is
  71.                     usually 0 but not always.
  72.          Line #13 - This line is the name of the first conference. It
  73.                     is 10 characters or less.
  74.  
  75.          Lines  12  and  13  are  repeated  for as many conferences as
  76.          listed in line 11.
  77.  
  78.          Anything you see  after  the  last  conference  name  can  be
  79.          ignored  as  that  information isn't usually provided by mail
  80.          doors. One exception to this is the Markmail door.
  81.  
  82.          Now we'll talk about the message file itself. If you  haven't
  83.          guess  by  now,  it  is the MESSAGES.DAT file. This is, quite
  84.          obviously, the largest file in the .QWK packet.
  85.  
  86.          MESSAGES.DAT is organized  very  specifically  into  128-byte
  87.          records.  The first record is the Sparkware copyright notice.
  88.          The rest of the record after the copyright notice  is  filled
  89.          with blanks (spaces). To maintain compatibility with Sparky's
  90.          Qmail  Door,  all  mail  doors reproduce the copyright notice
  91.          exactly.
  92.  
  93.          Following the first record begins the "meat" of  the  message
  94.          file.  Each message included in the file consists of a header
  95.          followed directly by the message text itself. First  we  will
  96.          describe the header:
  97.  
  98.          Header    Field
  99.          Position   Length   Description
  100.          --------   ------   ----------------------------------------
  101.          1          1        Message status byte
  102.                                 ' ' = public message which hasn't been
  103.                                       read
  104.                                 '-' = public and already read
  105.                                 '*' = private message
  106.                                 '~' = comment  to  sysop  which hasn't
  107.                                       been read by the sysop
  108.                                 '`' = comment to sysop which HAS  been
  109.                                       read by the sysop
  110.                                 '%' = password  protected message that
  111.                                       hasn't been read  (protected  by
  112.                                       sender of message)
  113.                                 '^' = password  protected message that
  114.                                       HAS   been  read  (protected  by
  115.                                       sender of message)
  116.                                 '!' = password  protected message that
  117.                                       hasn't been read  (protected  by
  118.                                       group password)
  119.                                 '#' = password  protected message that
  120.                                       HAS   been  read  (protected  by
  121.                                       group password)
  122.                                 '$' = password protected message  that
  123.                                       is  addressed  to ALL (protected
  124.                                       by group password)
  125.          2         7         Message number coded in ASCII
  126.          9         8         Date coded in ASCII (MM-DD-YY)
  127.          17        5         Time  coded  in  ASCII  (HH:MM)  24  hour
  128.                              format
  129.          22        25        Uppercase name of person message is TO
  130.          47        25        Uppercase name of person message is FROM
  131.          72        25        Subject of message
  132.          97        12        Message password. Usually  not  anything
  133.                              but spaces (to denote no password)
  134.          109       8         Message  # this message refers to (coded
  135.                              in ASCII)
  136.          117       6         Number of 128-byte chunks in  the  actual
  137.                              message  (includes header and is coded in
  138.                              ASCII)
  139.          123       1         Determines whethere  a  message  is  live
  140.                              (active)  or  killed. 90% of the time you
  141.                              won't see a killed message in a packet.
  142.                                  'a' = Message is active/alive (0xE1)
  143.                                  'b' = Message is killed/dead  (0xE2)
  144.          124       1         Least  significant  byte  of  conference
  145.                              number.
  146.          125       1         Most  significant  byte   of   conference
  147.                              number.  NOTE: This isn't in the original
  148.                              .QWK format but has become  the  standard
  149.                              due  to  conference  numbers greater than
  150.                              255. In the original  format,  this  byte
  151.                              was space-filled.
  152.          126       3         Filler bytes for future expansion.
  153.                              Space-filled and usually ignored.
  154.  
  155.          Following the header record comes the  message  text  itself.
  156.          The  message  text is simply the body of the message. To save
  157.          space, the return/linefeed combination is translated  to  the
  158.          pi  character  'c'  (0xE3).  Note  that  the last line of the
  159.          message is padded  with  spaces  to  fill  out  the  128-byte
  160.          record.
  161.  
  162.          Now we'll talk about the *.NDX files that are included in the
  163.          packet.  Each  .NDX file is formatted into records of 5-bytes
  164.          each. The bytes in each record are formatted thusly:
  165.  
  166.          Start  Field
  167.          Byte   Length   Description
  168.          ----   ------   --------------------------------------------
  169.          1      4        This is a floating point number in the MSBIN
  170.                          format. This number is the record  number  of
  171.                          the   message  header  in  MESSAGES.DAT  that
  172.                          corresponds to this message.
  173.  
  174.          5      1        This  byte  is  the  conferece number of this
  175.                          message.  This  byte  can  (and  should)   be
  176.                          ignored  as  it  is duplicated in the message
  177.                          header in MESSAGES.DAT.  This  is  especially
  178.                          important  for  conferences  numbered  higher
  179.                          than 255.
  180.  
  181.          Let's stray just a moment to talk about  the  MSBIN  floating
  182.          point  format. This is the format used by the older Microsoft
  183.          Basic compilers and interpreters. Most compiler manufacturers
  184.          have switched to  the  more  efficient  IEEE  floating  point
  185.          format. Therefore, we must have a method of converting to and
  186.          from  MSBIN  format.  Included at the end of this article are
  187.          two routines in C that accomplish this quite easily.
  188.  
  189.          Ok, let's talk about the format of the .REP  (reply)  packet.
  190.          Like  the  .QWK  packet  it is usually compressed. Inside the
  191.          compressed archive is a file whose  extension  is  .MSG.  The
  192.          filename  itself  is the same as line #5 of CONTROL.DAT. This
  193.          is the BBSID. So, for example, if the BBSID is  GENERIC,  the
  194.          complete filename in the .REP packet would be GENERIC.MSG.
  195.  
  196.          The format of the .MSG file is almost exactly the same as the
  197.          MESSAGES.DAT file with three differences:
  198.  
  199.          1). In the first record, rather than a copyright notice, the
  200.              first  eight  bytes are the BBSID as described above. The
  201.              rest of the record is filled with spaces.
  202.  
  203.          2). In the message header, rather than the ASCII-coded
  204.              message number, we have the ASCII-coded conference number
  205.  
  206.          3). Also in the message header, the conference number field
  207.              (byte offset 124 & 125) may be filled  with  spaces  *OR*
  208.              the conference number.
  209.  
  210.          In  recent  months a new file, DOOR.ID, has been added to the
  211.          .QWK packet. I know very little about it but will attempt  to
  212.          explain it as best as I can.
  213.  
  214.          DOOR.ID  seems to be a method for individual doors to let the
  215.          mail reader know how to add and drop  conferences.  It  is  a
  216.          good  idea  and  I hope more doors and readers can be made to
  217.          cooperate with it.
  218.  
  219.          Usually there are only five lines in this  file.  Here  is  a
  220.          sample from one of my recent .QWK packets:
  221.  
  222.          DOOR = TomCat!                       Line #1
  223.          VERSION = 2.9                        Line #2
  224.          SYSTEM = Wildcat! 2.x                Line #3
  225.          CONTROLNAME = TOMCAT                 Line #4
  226.          CONTROLTYPE = ADD                    Line #5
  227.          CONTROLTYPE = DROP                   Line #6
  228.  
  229.          Line #1 - This is the mail door's name.
  230.          Line #2 - This is the mail door's version number.
  231.          Line #3 - This is the BBS software used and version number.
  232.          Line #4 - This is the control name (TO:) where to send
  233.                    requests for conference changes.
  234.          Line #5 - This is the command the door expects to see to add
  235.                    a conference to the user's current list.
  236.          Line #6 - This is the command the door expects to see to drop
  237.                    a conference from the user's current list.
  238.  
  239.          Here  are the routines I use to convert to and from the MSBIN
  240.          format. You  may  use  them  as  you  see  fit  -  they  are  not
  241.          copyrighted by me.
  242.  
  243.          /***  MSBIN conversion routines ***/
  244.  
  245.          union Converter
  246.                {
  247.                 unsigned char uc[10];
  248.                 unsigned int  ui[5];
  249.                 unsigned long ul[2];
  250.                 float          f[2];
  251.                 double         d[1];
  252.                }
  253.  
  254.          /* MSBINToIEEE - Converts an MSBIN floating point number */
  255.          /*               to IEEE floating point format           */
  256.          /*                                                       */
  257.          /*  Input: f - floating point number in MSBIN format     */
  258.          /* Output: Same number in IEEE format                    */
  259.  
  260.          float MSBINToIEEE(float f)
  261.          {
  262.             union Converter t;
  263.             int sign, exp;       /* sign and exponent */
  264.  
  265.             t.f[0] = f;
  266.  
  267.          /* extract the sign & move exponent bias from 0x81 to 0x7f */
  268.  
  269.             sign = t.uc[2] / 0x80;
  270.             exp  = (t.uc[3] - 0x81 + 0x7f) & 0xff;
  271.  
  272.          /* reassemble them in IEEE 4 byte real number format */
  273.  
  274.             t.ui[1] = (t.ui[1] & 0x7f) | (exp << 7) | (sign << 15);
  275.  
  276.          /* IEEEToMSBIN - Converts an IEEE floating point number  */
  277.          /*               to MSBIN floating point format          */
  278.          /*                                                       */
  279.          /*  Input: f - floating point number in IEEE format      */
  280.          /* Output: Same number in MSBIN format                   */
  281.  
  282.          float IEEEToMSBIN(float f)
  283.          {
  284.             union Converter t;
  285.             int sign, exp;       /* sign and exponent */
  286.  
  287.             t.f[0] = f;
  288.  
  289.          /* extract sign & change exponent bias from 0x7f to 0x81 */
  290.  
  291.             sign = t.uc[3] / 0x80;
  292.             exp  = ((t.ui[1] >> 7) - 0x7f + 0x81) & 0xff;
  293.  
  294.          /* reassemble them in MSBIN format */
  295.  
  296.             t.ui[1] = (t.ui[1] & 0x7f) | (sign << 7) | (exp << 8);
  297.             return t.f[0];
  298.          } /* End of IEEEToMSBIN */
  299.  
  300. More QWK stuff
  301.  
  302.     typedef struct QWKHeader
  303.       {
  304.         unsigned char sts;
  305.         char messagenumber[7];
  306.         char messagedate[8];
  307.         char messagetime[5];
  308.         char to[25];
  309.         char from[25];
  310.         char subject[25];
  311.         char password[12];
  312.         char referencenumber[8];
  313.         char numberblocks[6];
  314.         unsigned char action;
  315.         unsigned char conference;
  316.         char reserved[2];
  317.         unsigned char echoflag;
  318.         char reserv2;
  319.       } QWKHeader;
  320.  
  321.     union ut
  322.       {
  323.         float fl;
  324.         unsigned int b[4];
  325.         unsigned int u[2];
  326.         unsigned long ul;
  327.       };
  328.  
  329.     #pragma pack(1)
  330.     struct
  331.       {
  332.         union ut u;
  333.         unsigned int conference;
  334.       } ndxRec;
  335.     #pragma pack()
  336.  
  337.     float msToFloat(float f)
  338.       {
  339.         union ut u;
  340.         unsigned int sign;
  341.         unsigned int exp;
  342.  
  343.         u.fl = f;
  344.         sign = (u.b[2] & 0x80) ? 0x8000 : 0x0000;
  345.         exp  = ((u.u[1] & 0xff00) - 0x0200) >> 1;
  346.         u.u[1] = (u.u[1] & 0x007f) | sign | exp;
  347.  
  348.         return(u.fl);
  349.       }
  350.  
  351.     Sample header block within the QWK file.
  352.                                                            0123456789ABCDEF
  353.     0000  20 39 38 34 30 20 20 20-30 32 2D 31 36 2D 39 30   9840   02-16-90
  354.     0010  30 35 3A 35 33 54 49 4D-20 52 4F 53 53 49 54 45  05:53TIM ROSSITE
  355.     0020  52 20 20 20 20 20 20 20-20 20 20 20 20 20 44 4F  R             DO
  356.     0030  55 47 20 4D 41 43 4C 45-41 4E 20 20 20 20 20 20  UG MACLEAN
  357.     0040  20 20 20 20 20 20 20 41-42 55 53 49 56 45 20 55         ABUSIVE U
  358.     0050  53 45 52 20 20 20 20 20-20 20 20 20 20 20 20 20  SER
  359.     0060  20 20 20 20 20 20 20 20-20 20 20 20 39 37 32 35              9725
  360.     0070  20 20 20 20 20 35 20 20-20 20 E1 01 20 20 20 20       5    ß
  361.                                                            0123456789ABCDEF
  362.         Offset  Length  Purpose
  363.         --------------------------------------------------------------------
  364.         00      01      Private/Read/Not read
  365.                             space means the mail has been read
  366.                             - means not read
  367.                             + means R/O
  368.         01      07      Message number (character)
  369.         08      08      Date (mm-dd-yy)
  370.         10      05      Time (hh:mm)
  371.         15      25      To (character)
  372.         2E      25      From (character)
  373.         47      25      Subject (character)
  374.         60      12      Password (?)
  375.         6C      08      Refer to number (character)
  376.         73      06      Number of 128 byte blocks in message (including
  377.                             the header block, i.e. the shortest message
  378.                             has 2 blocks in it.)
  379.         7A      01      Killed message?  225 is active, 226 is killed
  380.         7B      01      Conference number (0-255) - This may have been
  381.                             changed because Eric is using two bytes for
  382.                             it, check with him first.
  383.         7C      04      Reserved (?)
  384.