home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 15 / CD_ASCQ_15_070894.iso / maj / swag / mail.swg < prev    next >
Text File  |  1994-05-25  |  120KB  |  1 lines

  1. SWAGOLX.EXE (c) 1993 GDSOFT  ALL RIGHTS RESERVED 00018         MAIL/QWK/HUDSON FILE ROUTINES                                     1      05-28-9313:50ALL                      SWAG SUPPORT TEAM        MAILMSGR.PAS             IMPORT              17     n¼\k {πAfter lots of controversy, and a lot of reteaching myself the meanings ofπa few Words, I've redone my *.MSG reader....π}ππConst MSGPRIVATE  = $0001;πConst MSGConst    = $0002;πConst MSGREAD     = $0004;πConst MSGSENT     = $0008;πConst MSGFile     = $0010;πConst MSGFWD      = $0020;πConst MSGorPHAN   = $0040;πConst MSGKILL     = $0080;πConst MSGLOCAL    = $0100;πConst MSGHOLD     = $0200;πConst MSGCRAP     = $0400;πConst MSGFRQ      = $0800;πConst MSGRRQ      = $1000;πConst MSGCPT      = $2000;πConst MSGARQ      = $4000;πConst MSGURQ      = $8000;ππTypeπ     Fido_FromType    = Array [1..35] of Char;π     Fido_toType      = Array [1..35] of Char;π     Fido_SubType     = Array [1..71] of Char;π     Fido_DateType    = Array [1..19] of Char;ππ     FidoMsgType = Recordπ      From         : Fido_FromType; (* 0   *)π      toWhom       : Fido_toType;   (* 35  *)π      Subject      : Fido_SubType;  (* 71  *)π      AZDate       : Fido_DateType; (* 142 *)π      TimesRead    : Word;          (* 162 *)π      Dest_Node    : Word;          (* 164 *)π      orig_Node    : Word;          (* 166 *)π      Cost         : Word;          (* 168 *)π      orig_Net     : Word;          (* 170 *)π      Dest_Net     : Word;          (* 172 *)π      Date_Written : LongInt;       (* 176 *)π      Date_Arrived : LongInt;       (* 180 *)π      Reply        : Word;          (* 184 *)π      Attr         : Word;          (* 186 *)π      Up           : Word;          (* 188 *)π     end;ππ   MsgTxtPtr  = ^MsgTxtType;π   MsgTxtType = Array [1..65535] of Char;ππVarπ  MessageFile : File;π  Msg         : FidoMsgType;π  MsgTxt      : MsgTxtPtr;ππProcedure ReadMessage(Fname : PathStr);πVarπ  Left : Word;πbeginπ  Assign(MessageFile,FName);π  Reset(MessageFile,1);π  BlockRead(MessageFile,Msg,190);π  Left:=FileSize(MessageFile) - 190;π  New(MsgTxt);π  BlockRead(MessageFile,MsgTxt^,Left);πend;π{πThis will correctly read in a *.MSG File in two parts..THe Header(stored inπMsg), and the Text which is a 64k buffer(stored in Pointer MsgTxt)...π}π                 2      05-28-9313:50ALL                      SWAG SUPPORT TEAM        MSG-FIDO.PAS             IMPORT              63     n¼?h {π>Could someone post the structures For a QWK mail packet, and couldπ>someone, post how to make a BBS Fido-Net compatible, in other Words theπ>File structures..Thanks in advance..π}ππ{$V-}ππProgram ReadQWKRepFile;ππUsesπ  Crt;ππConstπ  Seperator = '---------------------------------------------------------------------------';ππTypeπ  ConfType = ^Conference;π  Conference = Recordπ    Number : Byte;π    Name   : Array [1..10] of Char;π  end;π  CONDATHdr = Recordπ    BBSName  : Array [1..25] of Char;π    Location : Array [1..25] of Char;π    Number   : Array [1..12] of Char;π    SysopName: Array [1..25] of Char;π    SerialNum: Array [1..5] of Char;π    BBSID    : Array [1..8] of Char;π    Date     : Array [1..10] of Char;π    Time     : Array [1..8] of Char;π    UserName : Array [1..25] of Char;π    NumConfs : Byte;π    Confs    : Array [1..30] of ConfType;π  end;π  MSGDATHdr = Recordπ    Status   : Char;π    MSGNum   : Array [1..7] of Char;π    Date     : Array [1..8] of Char;π    Time     : Array [1..5] of Char;π    UpTO     : Array [1..25] of Char;π    UpFROM   : Array [1..25] of Char;π    Subject  : Array [1..25] of Char;π    PassWord : Array [1..12] of Char;π    ReferNum : Array [1..8] of Char;π    NumChunk : Array [1..6] of Char;π    Alive    : Byte;π    LeastSig : Byte;π    MostSig  : Byte;π    Reserved : Array [1..3] of Char;π  end;π  MSSingle = Array[0..3] of Byte;ππVarπ  F           : File;π  DefSaveFile : String;π  ConfNum     : String [8];π  Number      : Word;ππππFunction Valu2 (S : String) : Word;πVarπ  C  : Word;π  E  : Integer;πbeginπ  Val (S, C, E);π  If E = 0 thenπ    Valu2 := Cπ  elseπ    Valu2 := 0;πend;ππProcedure ParseCommandLine;πVarπ  I : Byte;π  C : Char;π  S : String;πbeginπ  For I := 1 to ParamCount doπ  beginπ    S := ParamStr (I);π    If S [1] = '/' thenπ    beginπ      C := UpCase (S [2]);π      Delete (S, 1, 2);π      Case C ofπ        'C' : ConfNum := S;π        'S' :π              beginπ                While Length (S) <> 3 doπ                  S := '0' + S;π                DefSaveFile := S;π              end;ππ        'N' : Number := Valu2 (S);π      end;π    end;π  end;πend;πππFunction MStoIEEE (MS : MSSingle) : Real;π{ Converts a 4 Byte Microsoft format single precision Real Variable asπ  used in earlier versions of QuickBASIC and GW-BASIC to IEEE 6 Byte Real }πVarπ  r      : Real;π  ieee   : Array[0..5] of Byte Absolute r;πbeginπ  FillChar(r,sizeof(r),0);π  ieee[0] := MS[3];π  ieee[3] := MS[0];π  ieee[4] := MS[1];π  ieee[5] := MS[2];π  MStoIEEE  := r;πend;  { MStoIEEE }ππFunction Valu (S : String) : LongInt;πVarπ  C     : LongInt;π  T, E  : Integer;π  I     : Byte;π  Place : LongInt;πbeginπ  Place := 1;π  C := 0;π  For I := 6 downto 1 doπ  beginπ    Val (S [I], T, E);π    If T <> 0 thenπ    beginπ      C := C + T * Place;π      Place := Place * 10;π    end;π  end;π  Valu := C - 1;πend;ππProcedure ReadMSG (NumChunks : LongInt);πVarπ  Buff : Array [1..128] of Char;π  J    : LongInt;π  I    : Byte;ππbeginπ  For J := 1 to NumChunks doπ  beginπ    BlockRead (F, Buff, 128);π    For I := 1 to 128 doπ      If Buff [I] = #$E3 thenπ        Writelnπ      elseπ        Write (Buff [I]);π  end;πend;ππProcedure ReadWriteHdr (Var HDR : MSGDatHdr);πbeginπ  BlockRead (F, Hdr, SizeOf (Hdr));π  With Hdr doπ  beginπ    Write ('Date: ', Date, ' (', Time, ')');π    Writeln ('' : 23, 'Number: ', MSGNum);π    Write ('From: ', UpFROM);π    Writeln ('' : 14, 'Refer#: ', ReferNum);π    Write ('  To: ', UpTO);π    Write ('' : 15, 'Recvd: ');π    If Status in ['-', '`', '^', '#'] thenπ      Writeln ('YES')π    elseπ      Writeln ('NO');π    Write ('Subj: ', Subject);π    Writeln ('' : 16, 'Conf: ', '(', LeastSig, ')');π    Writeln;π  end;πend;ππProcedure ReadMessage (HDR : MSGDatHdr; REPorDAT : Boolean);πbeginπ  ReadWriteHdr (HDR);π  ReadMsg (Valu (HDR.NumChunk));πend;ππProcedure ReadControlFile (Var Control : CONDatHdr);πVarπ  CFile    : Text;ππ  Procedure ReadToEOLN (Var FNAME; Length : Byte; Down : Boolean);π  Varπ    I : Byte;π    C : Char;π  beginπ    I := 0;π    Repeatπ      Read (CFile, C);π      Mem [Seg (FNAME) : Ofs (FNAME) + I] := Ord (C);π      Inc (I);π    Until EOLN (CFile) or (I > Length) or (Not Down and (C = ','));π    If Not Down thenπ      Dec (I);π    For I := I to Length doπ      Mem [Seg (FNAME) : Ofs (FNAME) + I] :=32;π    If Down thenπ      Readln (CFile);π  end;ππVarπ  TempChar : Char;π  S        : String;π  I        : Byte;πbeginπ  Assign (CFile, 'CONTROL.DAT');π  Reset (CFile);π  With Control doπ  beginπ    ReadToEOLN (BBSName, 25, True);π    ReadToEOLN (Location, 25, True);π    ReadToEOLN (Number, 12, True);π    ReadToEOLN (SysopName, 25, False);π    Readln (CFile);π    ReadToEOLN (SerialNum, 5, False);π    ReadToEOLN (BBSID, 8, True);π    ReadToEOLN (Date, 10, False);π    ReadToEOLN (Time, 8, True);π    ReadToEOLN (UserName, 25, True);π    For I := 1 to 4 doπ      Readln (CFile, S);π    NumConfs := Valu (S) + 1;π    For I := 1 to NumConfs doπ    beginπ      New (Confs [I]);π      Readln (CFile, S);π      Confs [I]^.Number := Valu2 (S);π      ReadToEOLN (Confs [I]^.Name, 10, True);π    end;π  end;π  Close (CFile);πend;ππFunction GetSaveFile : String;πVarπ  S : String;πbeginπ  Writeln ('Enter the name of the File to save it in (GIVE A DIRECTORY!) or [Return] for');π  Writeln ('C:\SLMR\SAVE.TXT');π  Readln (S);π  If S = '' thenπ    S := 'C:\SLMR\SAVE.TXT';π  GetSaveFile := S;πend;ππFunction GetYN (S : String) : Boolean;πVarπ  X  : Char;πbeginπ  Repeatπ    Write (S);π    X := UpCase (ReadKey);π    Writeln (X);π  Until X in ['Y', 'N'];π  GetYN := X = 'Y';πend;ππProcedure ScanMessages (REPorDAT : Boolean);πVarπ    HDR : MSGDatHdr;π    S  : String [3];π    I  : Byte;π    F2 : File;π    MS : MSSingle;π    YN  : Boolean;πbeginπ  ClrScr;π  Repeatπ    If ConfNum = '' thenπ    beginπ      Writeln;π      Write ('Enter the name/number For the conference : ');π      Readln (ConfNum);π      Writeln;π    end;π    While (Length (ConfNum) < 3) doπ      ConfNum := '0' + ConfNum;π    Writeln (ConfNum);π    Assign (F2, ConfNum + '.NDX');π    {$I-}π    Reset (F2, 1);π    {$I+}π    If IOResult <> 0 thenπ      RunError (2);ππ    Repeatπ      Repeatππ        Writeln;π        If Number = 0 thenπ        beginπ          Writeln ('Enter the SLMR number ( ??? / XXX ) of the message to pull, or 0 to quit : ');π          Readln (Number);π        end;π        If Number = 0 thenπ        beginπ          Close (F2);π          Close (F);π          Halt;π        end;ππ        Writeln;π        Seek (F2, (Number - 1) * 5);π        BlockRead (F2, MS, 4);ππ        Seek (F, Round (MStoIEEE (MS) - 1) * 128);π        ReadWriteHdr (HDR);ππ        YN := GetYN ('Capture this message ? ');π        Number := 0;ππ      Until YN;ππ      Seek (F, Round (MStoIEEE (MS) - 1) * 128);π      Writeln;π      Writeln;π      If Not GetYN ('Extract to Screen ? [Y/N] (N sends to File): ') thenπ        Assign (Output, GetSaveFile);π      {$I-}π      Reset (Output);π      {$I+}π      If IOResult <> 0 thenπ        ReWrite (Output)π      elseπ        Append (Output);π      Writeln;π      Writeln (Seperator);π      Writeln;π      ReadMessage (Hdr, REPorDAT);π      Writeln;π      Writeln;π      Close (Output);π      Assign (Output, '');π      ReWrite (Output);π      YN := GetYN ('Extract more messages? [Y/N] ');π    Until Not YN;ππ    Close (F2);π    YN := GetYN ('Select another message base? [Y/N] ');π  Until Not YN;πend;πππVarπ  Control  : CONDatHdr;π  MSGHdr   : MSGDatHdr;π  REPorDAT : Boolean;ππbeginπ  DefSaveFile := '';π  ConfNum := '';π  Number := 0;π  ParseCommandLine;π  DirectVideo := False;π  ReadControlFile (Control);π  { Assign (F, Control.BBSID + '.MSG');}π  Assign (F, 'MESSAGES.DAT');π  Reset (F, 1);π  BlockRead (F, MSGHdr, SizeOf (MSGHdr));π  REPorDAT := (MSGHdr.Status + MSGHdr.MSGNum = Control.BBSID);π  ScanMessages (REPorDAT);π  { While Not EOF (F) do ReadMessage (MSGHdr, REPorDAT);}π  Close (F);πend.π      3      05-28-9313:50ALL                      SWAG SUPPORT TEAM        MSGINFO.PAS              IMPORT              32     n¼û╓ Program VERBOSITY_INDEX;π{πJUSTIN MARQUEZππ  Reads a FidoNet *.MSG File areas and logs info about authorship andπ  "verbosity" found in the messages.ππ  Requires Turbo Pascal 7.xx or Borland Pascal 7.xx (for the StringS Unit)ππ  OutPut is redirectable.  Can be quickly sorted With Dos's SORT.COMπ  Here is a batch File you may find useful:ππrem YAK.BATπverbose %1 > zap.txtπsort < zap.txt > yak.txt /+37 /Rπdel zap.txtππ   This Program is written by Justin Marquez, FidoNet 106/100π   It is being donated to all as a PUBLIC DOMAIN Program, which may beπ   freely used, copied and modified as you please.ππ   "if you improve on it, I'd like a copy of the modifications For myπ   own edification!"π}ππUsesπ  Strings,π  Dos;ππTypeπ  FidoMessageHeader = Recordπ    FromUser  : Array[0..35] of Char ;π    ToUser    : Array[0..35] of Char ;π    Subject   : Array[0..71] of Char ;π    DateTime  : Array[0..19] of Char ;π    TimesRead : Word ;π    DestNode  : Word ;π    OrigNode  : Word ;π    Cost      : Word ;π    OrigNet   : Word ;π    DestNet   : Word ;π    Filler    : Array[0..7] of Byte ;π    Replyto   : Word ;π    Attribute : Word ;π    NextReply : Word ;π  end;ππ  Entry = Recordπ    Author : String[36];π    Count  : Integer;π    Bytes  : LongInt;π  end;ππVarπ  MsgDir,π  fn       : String;π  SR       : SearchRec;π  tmp      : FidoMessageHeader;π  Who_From : String[36];π  n,π  i        : Integer;π  HiNum    : Integer;π  rec      : Array [1..512] of Entry;π  TotBytes : LongInt;ππProcedure GetMsgInfo (fname : String; Var Hdr : FidoMessageHeader);πVarπ  HFile : File of FidoMessageHeader;π  MFile : Text;πbeginπ  FillChar(Hdr, SizeOf(Hdr), #0);  { clear it out initially }π  { get msg hdr only }π  Assign(HFile,fname);π  Reset(HFile);π  Seek(HFile, 0);π  Read(HFile, Hdr);π  Close(HFile);πend;ππProcedure Pad_Path(Var s : String);πbeginπ  if s[length(s)] <> '\' thenπ    s := s + '\';πend;ππProcedure Process_Name;πVarπ  k : Integer;π  Found : Boolean;πbeginπ  Found := False;π  if n > 0 thenπ    For k := 1 to n doπ      if Who_From = rec[k].author thenπ      beginπ        inc(rec[k].count);π        rec[k].Bytes := rec[k].Bytes + SR.Size;π        Found := True;π      endπ  elseπ  beginπ    rec[1].author := Who_From;π    rec[1].count  := 1;π    rec[1].Bytes := rec[1].Bytes + SR.Sizeπ  end;π  if not Found thenπ  beginπ    inc(n);π    Rec[n].Author := Who_From;π    Rec[n].Count  := 1;π    rec[n].Bytes  := rec[n].Bytes + SR.Size;π  end;πend;ππProcedure Intro_And_Init;πbeginπ  FillChar(rec,SizeOf(rec),#0);  { clear it out initially }π  HiNum    := 0;π  TotBytes := 0;π  n        := 0;π  if ParamCount > 0 thenπ    MsgDir := ParamStr(1)π  elseπ  beginπ    WriteLn(' VERBOSE <path> >');π    WriteLn('EXAMPLE:');π    WriteLn;π    WriteLn('VERBOSE C:\OPUS\HOUSYSOP\ ');π    WriteLn(' reads all msg Files in the area and reports findings.');π    WriteLn;π    WriteLn(' Note: can be redirected to a File or device.');π    WriteLn;π    WriteLn('Public Domain from 106/100. Request as VERBOSE.ZIP.');π    Halt(2);π  end;πend;ππProcedure Process_Files;πbeginπ  Pad_Path(MsgDir);π  fn := MsgDir + '*.MSG';π  FindFirst(fn, AnyFile, SR);π  While DosError = 0 doπ  beginπ    fn := MsgDir + SR.Name;π    GetMsgInfo (fn, tmp);π    Who_From := '';π    Who_From := StrPas(StrUpper(tmp.FromUser));π    Inc(HiNum);π    TotBytes := TotBytes + SR.Size;π    Process_Name;π    FindNext(SR);π  end;πend;ππProcedure Report_Results;πbeginπ  For i := 1 to n doπ    WriteLn(rec[i].Author : 36, Rec[i].Count : 4,π           (100 * Rec[i].Count / HiNum) : 6 : 1, '% ',π            Rec[i].Bytes : 6, ' Bytes or',π           (100 * Rec[i].Bytes / TotBytes) : 5 : 1, '% by size' );π  WriteLn(' Total messages found: ' : 36, HiNum : 4);π  WriteLn(' Total Bytes found   : ' : 36, TotBytes : 18);π  WriteLn(n, ' different Writers found in ', MsgDir, '.');πend;ππbeginπ  Intro_And_Init;π  Process_Files;π  Report_Results;πend.π                                                                  4      05-28-9313:50ALL                      SWAG SUPPORT TEAM        QWKMAIL.PAS              IMPORT              285    n¼⌡I                          QWK Mail Packet File Layoutπ                              by Patrick Y. Leeπ                       Version 1.0 - February 23, 1992ππThis document is Copyright 1992 by Patrick Y. Lee.ππThe QWK-format is Copyright 1987 by Sparkware.ππAll Program names mentioned in this document are either Copyrightπor Trade- mark of respective owner(s).ππThe author provides this File as-is without warranty of any kind,πeither expressed or implied.  You are using the information inπthis File at your own discretion.  The author assumes noπresponsibilities For damages, either physically or financially,πfrom the use of this information.ππThis document may be freely distributed by any meansπ(electronically, pa- per, etc.), provided that it is distributedπin its entirety.  Portions of this document may be reproducedπwithout credit.ππ                              Table of Contentsππ1.  Introductionπ    1.1.  Intentπ    1.2.  Historyπ    1.3.  Questions, corrections, etc.π2.  Conventions & overviewπ    2.1.  The BBS IDπ    2.2.  Packet compressionπ    2.3.  Packet transfer & protocolsπ    2.4.  Limitationsπ3.  QWK Filesπ    3.1.  Naming conventionπ    3.2.  Control File (CONTROL.DAT)π    3.3.  Welcome Fileπ    3.4.  Goodbye Fileπ    3.5.  News Fileπ    3.6.  Qmail DeLuxe menu Fileπ    3.7.  New uploads listing (NEWFileS.DAT)π    3.8.  Bulletin File(s) (BLT-x.y)π    3.9.  Message File (MESSAGES.DAT)π    3.10.  Index Files (*.NDX)π        3.10.1.  Conference indicesπ        3.10.2.  Personal index (PERSONAL.NDX)π    3.11.  Pointer Fileπ    3.12.  SESSION.TXTπ4.  REP Filesπ    4.1.  Naming conventionπ    4.2.  Message File (BBSID.MSG)π    4.3.  Door control messagesπ    4.3.1.  DOOR.ID Fileπ    4.3.2.  Qmailπ    4.3.3.  MarkMailπ    4.3.4.  KMailπ    4.3.5.  RoseMailπ    4.3.6.  Complete Mail Doorπ    4.4.  Turning off the echo flagπ    4.5.  Tag-linesπ5.  Net mailπA.  Credits & contributionsπB.  Sample Turbo Pascal and C codeπC.  Sample messageπD.  Sample index Fileππ                        -=-=-=-=-=-=-<>-=-=-=-=-=-=-ππTo search For a specific section, look For "[x.x]" using yourπeditor or viewer.  For example, to jump to the tag-lines portionπof this File, search For "[4.5]" With your editor or Text viewer.ππ                        -=-=-=-=-=-=-<>-=-=-=-=-=-=-ππ[1]  Introductionππ[1.1]  IntentππThis document is written to facilitate Programmers who want toπWrite QWK-format mail doors or readers.  It is intended to be aπcomprehen- sive reference covering all areas of QWK-format mailπprocessing.  De- tailed break down of each File is included, asπare Implementation information.  In addition, door and readerπspecific information may be included, when such information areπavailable to me.ππ[1.2]  HistoryππThe QWK-format was invented by Mark "Sparky" Herring in 1987.  Itπwas based on Clark Development Corporation's PCBoard version 12.0πmessage base format.  Off-line mail reading has become popularπonly in recent years.  Prior to summer of 1990, there were onlyπtwo QWK-format off- line mail reader Programs.  They were QmailπDeLuxe by Mark Herring and EZ-Reader by Eric Cockrell.  Similarlyπfor the doors, there were only two -- Qmail by Mark Herring andπMarkMail by Mark Turner.  They were both For PCBoard systems.ππA lot has changed in both off-line reader and mail door marketsπsince summer 1990.  Now, there are more than a dozen off-lineπmail readers For the PC.  Readers For the Macintosh, Amiga, andπAtari exist as well.  There are over a half dozen doors forπPCBoard, and QWK-format doors exist For virtually all of theπpopular BBS softwares.  All of these happened in less than twoπyears!  More readers and doors are in development as I Writeπthis, keep up the excellent work.  In addition to doors, some BBSπsoftwares has QWK-format mail facility built in.ππOff-line mail reading is an integral part of BBS calling.πConference traffic and selection on all networks have grownπdramatically in re- cent years that on-line reading is a thing ofπthe past.  Off-line mail reading offers an alternative to readingπmail on-line -- It offers speed that cannot be achieved withπon-line mail reading.ππThe reason why QWK-format readers and doors seem to have gainedπpopu- larity is probably dued to its openness.  The format isπreadily avail- able to any Programmer who wishes to Write aπProgram that utilize it. Proprietary is a thing of the past, itπdoes not work!  Openness is here to stay and QWK-format is a partπof it.ππ[1.3]  Questions, corrections, etc.ππMost of the message networks today have a conference/echo devotedπto discussion of off-line readers and mail doors.  The ones Iπknow are on FidoNet, ILink, Intelec, and RIME.  If you haveπquestions after read- ing anything in here, feel free to drop byπany of the above confer- ence/echo and I am sure other QWKπauthors will try to help.ππI can be reached in the Off-line conferences on RIME, ILink, andπIntelec, as well as the Common conference on RIME.  Mail can beπrouted to node RUNNINGB.  I can be reached on the Internet atπ"p.lee@green.cooper.edu".  Any corrections, extensions, comments,πand criticisms are welcomed.ππ[2]  Conventions & overviewπAll offsets referenced in this document will be relative to 1.  Iπam not a computer, I start counting at one, not zero!ππWords which are enclosed in quotes should be entered as-is.  Theπquo- tations are not part of the String unless noted.ππYou may have noticed I use the phrase "mail Program" or "mailπfacili- ty" instead of mail doors.  This is because some BBSπsoftwares offer the option of creating QWK-format mail packetsπright from the BBS. With those, there is no need For an externalπmail door.ππ[2.1]  The BBS IDππThe BBS ID (denoted as BBSID) is a 1-8 Characters Word thatπidentifies a particular BBS.  This identifier should be obtainedπfrom line 5 of the CONTROL.DAT File (see section 3.2.1).ππ[2.2]  Packet compressionππMost mail packets are compressed when created by the mail door inπorder to save download time and disk space.  However, manyπoff-line reader Programs allow the user to unarchive a mailπpacket outside of the reader Program, so the reader will not haveπto unarchive it.  Upon Exit, the reader will not call theπarchiver to save it.  It is up to the user to archive theπreplies.  This is useful if the user has lim- ited memory andπcannot shell out to Dos to run the unarchive Program. For readersπbased on non-PC equipment, the user may be using less commonπcompression Program that does not have command line equivalent.ππ[2.3]  Packet transfer & protocolsππThere is no set rule on what transfer protocol should be used.πHowev- er, it would be nice For the mail Program on the BBS toπprovide the Sysop With options as to what to offer.  This shouldπbe a configura- tion option For the user.ππ[2.4]  Specifications & limitationsππThere aren't many known limits in the QWK specification.πHowever, Various networks seem to impose artificial limits.  Onπmany of the PC- based networks, 99-lines appears to be the upperπlimit For some softwares.  However, most of the readers canπhandle more than that. Reader authors reading this may want toπoffer the option to split replies into n lines each (the actualπlength should be user definable so when the network softwareπpermits, the user can increase this num- ber).ππ[3]  QWK Filesππ[3.1]  Naming conventionππGenerally, the name of the mail packet is BBSID.QWK.  However,πthis does not have to be the case.  When the user downloads moreπthan one mail packet at one time, either the mail Program or theπtransfer pro- tocol Program will rename the second and subsequentπmail packets to other names.  They will either change the Fileπextension or add a number to the end of the Filename.  In eitherπcase, you should not rely on the name of the QWK File as theπBBSID.  The BBSID, as men- tioned before, should be obtained fromπline 5 of the CONTROL.DAT File. In addition, mail packets do notπhave to end With QWK extension ei- ther.  The user may choose toπname them With other File extensions.ππ[3.2]  Control File (CONTROL.DAT)ππThe CONTROL.DAT File is a simple ASCII File.  Each line isπterminated With a carriage return and line feed combination.  Allπlines should start on the first column.ππLine #π 1   My BBS                   BBS nameπ 2   New York, NY             BBS city and stateπ 3   212-555-1212             BBS phone numberπ 4   John Doe, Sysop          BBS Sysop nameπ 5   20052,MYBBS              Mail door registration #, BBSIDπ 6   01-01-1991,23:59:59      Mail packet creation timeπ 7   JANE DOE                 User name (upper case)π 8                            Name of menu For Qmail, blank if noneπ 9   0                        ? Seem to be always zeroπ10   0                        ? Seem to be always zeroπ11   121                      Total number of conference minus 1π12   0                        1st conf. numberπ13   Main Board               1st conf. name (13 Characters or less)π14   1                        2nd conf. numberπ15   General                  2nd conf. nameπ..   3                        etc. onward Until it hits max. conf.π..   123                      Last conf. numberπ..   Amiga_I                  Last conf. nameπ..   HELLO                    Welcome screen Fileπ..   NEWS                     BBS news Fileπ..   SCRIPT0                  Log off screenππSome mail doors, such as MarkMail, will send additionalπinformation about the user from here on.ππ0                             ?π25                            Screen length on the BBSπJANE DOE                      User name in uppercaseπJane                          User first name in mixed caseπNEW YORK, NY                  User city informationπ718 555-1212                  User data phone numberπ718 555-1212                  User home phone numberπ108                           Security levelπ00-00-00                      Expiration dateπ01-01-91                      Last log on dateπ23:59                         Last log on timeπ999                           Log on countπ0                             Current conference number on the BBSπ0                             Total KB downloadedπ999                           Download countπ0                             Total KB uploadedπ999                           Upload countπ999                           Minutes per dayπ999                           Minutes remaining todayπ999                           Minutes used this callπ32767                         Max. download KB per dayπ32767                         Remaining KB todayπ0                             KB downloaded todayπ23:59                         Current time on BBSπ01-01-91                      Current date on BBSπMy BBS                        BBS network tag-lineπ0                             ?ππSome mail doors will offer the option of sending an abbreviatedπcon- ference list.  That means the list will contain onlyπconferences the user has selected.  This is done because someπmail readers cannot handle more than n conferences at this time.πUsers using those read- ers will need this option if the BBS theyπcall have too many confer- ences.ππ[3.3]  Welcome FileππThis File usually contains the log on screen from the BBS.  Theπexact Filename is specified in the CONTROL.DAT File, after theπconference list.  This File may be in any format the Sysopπchooses it be -- usu- ally either in plain ASCII or With ANSIπscreen control code.  Some Sysops (notably PCBoard Sysops) mayπuse BBS-specific color change code in this File as well.  Currentπmail Programs seem to handle the trans- lations betweenπBBS-specific code to ANSI based screen control codes.πEven if the CONTROL.DAT File contains the Filename of this File,πit may not actually exist in the mail packet.  Sometimes, usersπwill manually delete this File before entering the mail reader.πSome off- line readers offer the option to not display thisπwelcome screen; some will display this File regardless.  Someπdoors, similarly, will offer option to the user to not send thisπFile.ππ[3.4]  Goodbye FileππSimilar to the welcome File above, the Filename to the goodbyeπFile is in the CONTROL.DAT File.  This is the File the BBSπdisplays when the user logs off the board.  It is optional, asπalways, to send this File or to display it.ππ[3.5]  News FileππMany mail doors offer the option to send the news File from theπBBS. Most will only send this when it has been updated.  Like theπwelcome and goodbye Files, the Filename to the news File is foundπin the CON- TROL.DAT File.  It can be in any format the Sysopπchooses, but usually in either ASCII or ANSI.  Like the welcomeπscreen, current mail facil- ities seem to handle translationπbetween BBS-specific control codes to ANSI screen control codes.ππ[3.6]  Qmail DeLuxe menu FileππThis File is of use only For Qmail DeLuxe mail reader byπSparkware. The Filename is found on line 8 of the CONTROL.DATπFile.ππ[3.7]  New uploads listing (NEWFileS.DAT)ππMost mail Programs on the BBS will offer the option to scan newπFiles uploaded to the BBS.  The result is found in a File namedπNEWFileS.DAT.  The mail Program, if implementing this, shouldπupdate the last File scan field in the user's proFile, if thereπis such a field, as well as other information required by theπBBS.  The mail Program should, of course, scan new Files only inπthose areas the user is allowed access.ππ[3.8]  Bulletin Files (BLT-x.y)ππMost mail Programs will also offer the option to include updatedπbul- letin Files found on the BBS in the mail packet.  Theπbulletins are named BLT-x.y, where x is the conference/echo theπbulletin came from, and y the bulletin's actual number.  The mailπProgram will have to take care of updating the last read date onπthe bulletins in the user Record.ππ[3.9]  Message File (MESSAGES.DAT)ππThe MESSAGES.DAT File is the most important.  This is where allπof the messages are contained in.  The QWK File format is basedπon PCBoard 12.0 message base format from Clark DevelopmentπCorporation (maker of PCBoard BBS software).ππThe File has a logical Record length of 128-Bytes.  The firstπRecord of MESSAGES.DAT always contain a copyright notice sayingπ"Produced by Qmail...Copyright (c) 1987 by Sparkware.  All RightsπReserved".  The rest of the Record is space filled.  Actualπmessages consist of a 128- Bytes header, plus one or moreπ128-Bytes block With the message Text. Actual messages start inπRecord 2.  The header block is layed out as follows:ππOffset  Length  Descriptionπ------  ------  ----------------------------------------------------π    1       1   Message status flag (unsigned Character)π                ' ' = public, unreadπ                '-' = public, readπ                '+' = private, unreadπ                '*' = private, readπ                '~' = comment to Sysop, unreadπ                '`' = comment to Sysop, readπ                '%' = passWord protected, unreadπ                '^' = 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   Not used (usually filled With spaces or nulls)π  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π                softwares need this information.ππFields such as To, From, Subject, Message #, Reference #, and theπlike are space padded if they are shorter than the field'sπlength.ππThe message Text starts in the next Record.  You can find out howπmany blocks make up one message by looking at the value ofπ"Number of 128 Byte blocks".  Instead of carriage return and lineπfeed combination, each line in the message end With an ASCII 227π(pi Character) symbol. There are reports that some (buggy)πreaders have problems With mes- sages which do not end the lastπline in the message With an ASCII 227. If a message does notπcompletely occupy the 128-Bytes block, the re- mainder of theπblock is padded With space or null.ππNote that there seems to exist old doors which will use one Byteπto represent the conference number and pad the other one With anπASCII 32 Character.  The Program reading this information willπhave to deter- mine whether the ASCII 32 in Byte 125 of theπheader is a filler or part of the unsigned Word.  One method isπto look in the CONTROL.DAT File to determine the highestπconference number.ππEven though most mail Programs will generate MESSAGES.DAT Filesπthat appear in conference order, this is not always the case.πTomcat! (mail door For Wildcat! BBS) generates MESSAGES.DAT thatπis not in conference order.  This is due to how Wildcat! itselfπstores mail on the BBS.ππNote that some mail doors offer the option of sending a mailπpacket even though there may be no messages to send -- thus anπempty MESSAG- ES.DAT File.  This was tested With Qmail 4.0 doorπand it sent a MES- SAGES.DAT File that contains a few emptyπ128-Bytes blocks.ππ[3.10]  Index Files (*.NDX)ππ[3.10.1]  Conference indicesππ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 num- ber left padded withπzeroes.  Some mail Programs offer the user the option to notπgenerate index Files.  So the mail readers need to cre- ate theπindex Files if they are missing.πEZ-Reader 1.xx versions will convert the NDX Files from MicrosoftπMKS format into IEEE long Integer format.  The bad part aboutπthis is that the user may store those index Files back into theπQWK File.  When another reader reads the index Files, it will beπvery confused!ππSpecial note For BBSes With more than 999 conferences: IndexπFiles For conferences With four digit conference numbers is namedπxxxx.NDX, where xxxx is the conference number (left padded withπzeroes).  The Filenames For three digit conferences are stillπnamed xxx.NDX on these boards.  I would assume Filenames forπconferences in the five digit range is xxxxx.NDX, but I have notπseen a BBS With 10,000 or more conferences yet!ππEach NDX File Uses a five Bytes logical Record length and isπformatted to:ππOffset  Length  Descriptionπ------  ------  ------------------------------------------------------π    1       4   Record number pointing to corresponding message inπ                MESSAGES.DAT.  This number is in the Microsoft MKS$π                BASIC format.π    5       1   Conference number of the message.  This Byte shouldπ                not be used because it duplicates both the Filename ofπ                the index File and the conference # in the header.  Itπ                is also one Byte long, which is insufficient to handleπ                conferences over 255.ππPlease refer to appendix B For routines to deal With MKS numbers.ππ[3.10.2]  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 selec- tion of other messages to be flagged as personalπmessages.ππ[3.11]  Pointer FileππPointer File is generally included so that the user can reset theπlast read Pointers on the mail Program, in Case there is a crashπon the BBS or some other mishaps.  There should be little reasonπfor the reader Program to access the Pointer File.ππThe Pointer Files I have seen are:ππQmail          BBSID.PTRπMarkMail       BBSID.PNTπKMail          BBSID.PNTπSFMailQwk      BBSID.SFPππAdditions to this list are welcomed.ππ[3.12]  SESSION.TXTππThis File, if included, will contain the message scanning screenπthe user sees from the door.ππ[4]  REP Filesππ[4.1]  Naming conventionππThe reply File is named BBSID.MSG, where BBSID is the ID code forπthe BBS found on line 5 of the CONTROL.DAT File.  Once this Fileπhas been created, the mail reader can archive it up into a Fileπwith REP exten- sion.ππ[4.2]  Message File (BBSID.MSG)ππReplies use the same format as the MESSAGES.DAT File, except thatπmes- sage number field will contain the conference numberπinstead.  In other Words, the conference number will be placed inπthe two Bytes (binary) starting at offset 124, as well as theπmessage number field (ASCII) at offset 2.ππThe first 128-Bytes Record of the File is the header.  Instead ofπthe copyright notice, it contains the BBSID of the BBS.  This 1-8πCharac- ter BBSID must start at the very first Byte and mustπmatch what the BBS has.  The rest of the Record is space padded.πThe replies start at Record 2.  Each reply message will have aπ128-Bytes header, plus one or more For the message Text; followedπby another header, and so on.ππThe mail Program must check to make sure the BBSID in the firstπblock of the BBSID.MSG File matches what the BBS has!ππ[4.3]  Door control messagesππThese messages allow the user to change their setup on the BBS byπsimply entering a message.  The goal is to allow the user to beπable to control most areas of the BBS via the mail door.πDifferent mail doors have different capabilities.  Most all ofπthem offer the ability to add and drop a conference, as well asπreset the last read Pointers in a conference.ππ[4.3.1]  DOOR.ID FileππThe DOOR.ID File was first introduced by Greg Hewgill withπTomcat! mail door and SLMR mail reader.  Since then, many otherπauthors have picked up this idea and use the format.  This Fileπprovides the neces- sary identifiers a reader needs to send add,πdrop, etc. messages to the mail door.  It tells the reader who toπaddress the message to and what can be put in the subject line.ππDOOR = <doorname>             This is the name of the door that creat-π                              ed the QWK packet, i.e. <doorname> =π                              Tomcat.πVERSION = <doorversion>       This is the version number of the doorπ                              that created the packet, i.e.π                              <doorversion> = 2.9.πSYSTEM = <systemType>         This is the underlying BBS system Typeπ                              and version, i.e. <systemType> = Wildcatπ                              2.55.πCONTROLNAME = <controlname>   This is the name to which the readerπ                              should send control messages, eg.π                              <controlname> = TOMCAT.πCONTROLType = <controlType>   This can be one of ADD, DROP, REQUEST,π                              or others.  ADD and DROP are prettyπ                              obvious (they work as in MarkMail), andπ                              REQUEST is For use With BBS systems thatπ                              support File attachments.  Try out SLMRπ                              With CONTROLType = REQUEST and use the Qπ                              Function.  (This seems to be a Wildcat!π                              BBS feature.)πRECEIPT                       This flag indicates that the door/BBS isπ                              capable of return receipts when a mes-π                              sage is received.  If the first threeπ                              letters of the subject are RRR, then theπ                              door should strip the RRR and set theπ                              'return-receipt-requested' flag on theπ                              corresponding message.ππNone of the lines are actually required and they may appear inπany order.  Of course, you would need a CONTROLNAME if you haveπany CONTROLType lines.ππ[4.3.2]  QmailππSend a message addressed to "QMAIL" With a subject of "CONFIG".πThen, enter any of the commands listed below inside the Text ofπyour mes- sage.  Remember to use one command per line.πADD <confnum>            Add a conference into the Qmail Door scanningπ                         list.  "YOURS" can also be added to the com-π                         mand if the user wishes to receive messagesπ                         only addressed them.  i.e. "ADD 1 YOURS"πDROP <confnum>           Drop a conference from the Qmail Door scan-π                         ning list.πRESET <confnum> <value>  Resets a conference to a particular value.π                         The user can use "HIGH-xxx" to set the con-π                         ference to the highest message in the base.πCITY <value>             Changes the "city" field in the user'sπ                         PCBoard entry.πPASSWord <value>         Changes the user's login passWord.πBPHONE <value>           Business/data phone numberπHPHONE <value>           Home/voice phone numberπPCBEXPERT <on|off>       Turns the PCBoard expert mode ON or OFF.πPCBPROT <value>          PCBoard File transfer protocol (A-Z).πPAGELEN <value>          Set page length inside PCBoard.πPCBCOMMENT <value>       Set user maintained comment.πAUTOSTART <value>        Qmail Door autostart command.πPROTOCOL <value>         Qmail Door File transfer protocol (A-Z).πEXPERT <ON or OFF>       Turns the Qmail Door expert mode ON or OFF.πMAXSIZE <value>          Maximum size of the user's .QWK packet (inπ                         Bytes)πMAXNUMBER <value>        Maximum number of messages per conference.ππ[4.3.3]  MarkMailππSend a message addressed to "MARKMAIL" With the subject line saying:ππADD [value]         in the conference you want to addπDROP                in the conference you want to dropπYOUR [value]        in the conference you want only your mail sentπYA [value]          in the conference you want only your mail + mailπ                    addressed to "ALL"πFileS ON or OFF     in any conference to tell MarkMail whether to scanπ                    For new Files or not.πBLTS ON or OFF      to turn on and off, respectively, of receivingπ                    bulletins.πOWN ON or OFF       to turn on and off, respectively, of receivingπ                    messages you sentπDELUXE ON or OFF    to turn on and off, respectively, of receivingπ                    DeLuxe menuπLIMIT <size>        to set the maximum size of MESSAGES.DAT File canπ                    be, it cannot exceed what the Sysop has set upππAn optional number can be added onto the commands "ADD", "YOUR",πand "YA".  If this number is positive, then it will be treated asπan abso- lute message number.  MarkMail will set your last readπPointer to that number.  If it is negative, MarkMail will setπyour last read Pointer to the highest minus that number.  Forπexample: "ADD -50" will add the conference and set the last readπPointer to the highest in the confer- ence minus 50.ππ[4.3.4]  KMailππSend a private message addressed to "KMAIL" in the conferenceπthat you want to add, drop, or reset.  The commands are "ADD",π"DROP", and "RESET #", respectively.  The "#" is the messageπnumber you want your last read Pointer in the conference be setπto.ππ[4.3.5]  RoseMailππThe RoseMail door allows configuration information be placed inπeither the subject line or message Text.  The message must beπaddressed to "ROSEMAIL".  For only one command, it can be placedπin the subject line.  For more than one changes, the subject lineπmust say "CONFIG" and each change be placed in the message Text.πEvery line should be left justified.  Valid commands are:ππCommand                                           ExampleππADD <Conference> [<Message #>] [<Yours>]          ADD 2 -3 YπDROP <Conference>                                 DROP 2πRESET <Conference> <Message #>                    RESET 12 5000πPCBEXPERT <ON | OFF> - PCBoard expert mode        PCBEXPERT ONπEXPERT <ON | OFF>    - RoseMail expert mode       EXPERT OFFπPCBPROT <A - Z>      - PCBoard protocol           PCBPROT ZπPROT <A - Z>         - RoseMail protocol          PROT GπPAGELEN <Number>     - Page length                PAGELEN 20πMAXSIZE <KBytes>     - Max packet size in Kb      MAXSIZE 100πMAXNUMBER <max msgs/conference>                   MAXNUMBER 100πJUMPSTART <Sequence or OFF>                       JUMPSTART D;Y;QπMAXPACKET <max msgs/packet>                       MAXPACKET 500πAUTOSTART <Sequence or OFF> - same as jumpstart   AUTOSTART OFFπOPT <##> <ON | OFF>  - set door option            OPT 2 OFFππ[4.3.6]  Complete Mail DoorππSend message to "CMPMAIL", the commands are "ADD" and "DROP".πThis message must be sent in the conference that you want to addπor drop.ππ[4.4]  Turning off the echo flagππIn order to send a non-echoed message (not send out to otherπBBSes), a user can enter "NE:" in front of the subject line.  Theπmail Program will strip this "NE:" and turn off the echo flag.πThis feature may not be offered in all mail doors.ππ[4.5]  Tag-linesππThe most common format For a reader tag-line is:ππ[---π * My reader v1.00 * The rest of the tag-line.ππThe three dashes is called a tear-line.  The tag-line is appendedπto the end of the message and is usually one line only.  It isπpreferred that tag-lines conform to this format so thatπnetworking softwares such as QNet and RNet will not add anotherπtearline to the message when they process it.ππSoftwares on FidoNet does not like mail readers adding aπtear-line of their own, so if your mail reader offers a FidoNetπmode, you will need to get rid of the tear-line.  Another itemπwhich differs between the FidoNet and PC-based networks is thatπFidoNet does not like extended ASCII Characters.  So your readerπmay want to strip high ASCII if the user has FidoNet mode on.πAcceptable tag-line style, I believe, is just this:ππ * My Reader v1.00 * The rest of the tag-line.ππ[5]  Net mailππI do not have complete information of net-mail Implementationπusing QWK-format.  Someone please fill me in the details.ππ                     -=-=-=-=-=-=-<>-=-=-=-=-=-=-ππ[A]  Credits and ContributionsππMark "Sparky" Herring, who originated the QWK-format.ππTim Farley, who started this documentation back in the summer ofπ1990. The general outline here is the work of Tim.  I filled inπthe blanks.ππJeffery Foy, who gave us the format For Microsoft single binaryπversus IEEE format.ππGreg Hewgill, who (if I remember correctly) wrote the TurboπPascal routines (included in here) to convert between MKS and TPπLongInt.πDennis McCunney, who is the host of the Off-line conference onπRIME, is very knowledgeable in off-line reading concept andπPrograms.  His goal is to have one reader that can read mailπpacket from any source.ππAll those who have been around the Off-line conferences on ILinkπ(the oldest of the three I participate), RIME, and Intelec, whoπhave pro- vided great help over the past two years.  The bulk ofπthe information presented here are from messages in thoseπconferences.  These people include, but are no limited to, theπfollowings: Dane Beko, Joseph Carnage, Marcos Della, Joey Lizzi,πMark May, and Jim Smith.ππ[B]  Sample Turbo Pascal and C codeππHere are a few routines in Turbo Pascal and C to convertπMicrosoft BASIC MKS format to usable IEEE long Integer.  Theseπare collected over the networks and there is no guarantee thatπthey will work For you!ππTurbo Pascal (Greg Hewgill ?):ππTypeπ     bsingle = Array [0..3] of Byte;ππ{ converts TP Real to Microsoft 4 Bytes single }ππProcedure Real_to_msb (pReal : Real; Var b : bsingle);πVarπ     r : Array [0 .. 5] of Byte Absolute pReal;πbeginπ     b [3] := r [0];π     move (r [3], b [0], 3);πend; { Procedure Real_to_msb }ππ{ converts Microsoft 4 Bytes single to TP Real }ππFunction msb_to_Real(b : bsingle) : Real;πVarπ     pReal : Real;π     r : Array [0..5] of Byte Absolute pReal;πbeginπ     r [0] := b [3];π     r [1] := 0;π     r [2] := 0;π     move (b [0], r [3], 3);π     msb_to_Real := pReal;πend; { Procedure msb_to_Real }ππC (identify yourself if you originated this routine):ππ/* converts 4 Bytes Microsoft MKS format to long Integer */ππunsigned long mbf_to_int (m1, m2, m3, exp)πunsigned int m1, m2, m3, exp;π{π     return (((m1 + ((unsigned long) m2 << 8) + ((unsigned long) m3 <<π     16)) | 0x800000L) >> (24 - (exp - 0x80)));π}ππMicrosoft binary (by Jeffery Foy):ππ   31 - 24    23     22 - 0        <-- bit positionπ+-----------------+----------+π| exponent | sign | mantissa |π+----------+------+----------+ππIEEE (C/Pascal/etc.):ππ   31     30 - 23    22 - 0        <-- bit positionπ+----------------------------+π| sign | exponent | mantissa |π+------+----------+----------+ππIn both cases, the sign is one bit, the exponent is 8 bits, and theπmantissa is 23 bits.  You can Write your own, optimized, routine toπconvert between the two formats using the above bit layout.ππ[C]  Sample messageππHere is a sample message in hex and ASCII format:ππ019780  20 34 32 33 32 20 20 20 30 32 2D 31 35 2D 39 32   4232   02-15-92π019790  31 33 3A 34 35 52 49 43 48 41 52 44 20 42 4C 41  13:45RICharD BLAπ0197A0  43 4B 42 55 52 4E 20 20 20 20 20 20 20 20 53 54  CKBURN        STπ0197B0  45 56 45 20 43 4F 4C 45 54 54 49 20 20 20 20 20  EVE COLETTIπ0197C0  20 20 20 20 20 20 20 51 45 44 49 54 20 48 41 43         QEDIT HACπ0197D0  4B 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20  Kπ0197E0  20 20 20 20 20 20 20 20 20 20 20 20 34 30 33 36              4036π0197F0  20 20 20 20 37 20 20 20 20 20 E1 0A 01 00 00 20      7π019800  2A 20 49 6E 20 61 20 6D 65 73 73 61 67 65 20 64  * In a message dπ019810  61 74 65 64 20 30 32 2D 30 39 2D 39 32 20 74 6F  ated 02-09-92 toπ019820  20 53 74 65 76 65 20 43 6F 6C 65 74 74 69 2C 20   Steve Coletti,π019830  52 69 63 68 61 72 64 20 42 6C 61 63 6B 62 75 72  RiChard Blackburπ019840  6E 20 73 61 69 64 3A E3 E3 52 42 3E 53 43 20 AF  n said:ππRB>SCπ019850  20 65 64 69 74 6F 72 20 69 6E 20 74 68 65 20 28   editor in the (π019860  6D 61 69 6E 66 72 61 6D 65 29 20 56 4D 2F 43 4D  mainframe) VM/CMπ019870  53 20 70 72 6F 64 75 63 74 20 6C 69 6E 65 20 69  S product line iπ[ etc. ]π019A00  6E 6F 74 20 61 20 44 6F 63 74 6F 72 2C 20 62 75  not a Doctor, buπ019A10  74 20 49 20 70 6C 61 79 20 6F 6E 65 20 61 74 20  t I play one atπ019A20  74 68 65 20 48 6F 73 70 69 74 61 6C 2E E3 20 20  the Hospital.ππ019A30  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20π019A40  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20π019A50  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20π019A60  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20π019A70  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20π019A80  E3 50 43 52 65 6C 61 79 3A 4D 4F 4F 4E 44 4F 47πPCRelay:MOONDOGπ019A90  20 2D 3E 20 23 33 35 20 52 65 6C 61 79 4E 65 74   -> #35 RelayNetπ019AA0  20 28 74 6D 29 E3 34 2E 31 30 20 20 20 20 20 20   (tm)π4.10π019AB0  20 20 20 20 20 20 20 20 20 48 55 42 4D 4F 4F 4E           HUBMOONπ019AC0  2D 4D 6F 6F 6E 44 6F 67 20 42 42 53 2C 20 42 72  -MoonDog BBS, Brπ019AD0  6F 6F 6B 6C 79 6E 2C 4E 59 20 37 31 38 20 36 39  ooklyn,NY 718 69π019AE0  32 2D 32 34 39 38 E3 20 20 20 20 20 20 20 20 20  2-2498ππ019AF0  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20ππ[D]  Sample index FileππHere is a sample index File in hex format:ππ000000  00 00 28 87 19 00 00 30 87 19 00 00 38 87 19 00π000010  00 7E 87 19 00 00 07 88 19 00 00 0B 88 19 00 00π000020  0F 88 19 00 00 14 88 19 00 00 19 88 19 00 00 1Eπ000030  88 19 00 00 22 88 19 00 00 27 88 19 00 00 2C 88π000040  19 00 00 31 88 19 00 00 3B 88 19 00 00 40 88 19π000050  00 00 46 88 19 00 00 49 88 19 00 00 4D 88 19 00π000060  00 52 88 19 00 00 55 88 19 00 00 59 88 19 00 00π000070  60 88 19 00 00 66 88 19 00 00 70 88 19πππ                                                                                                     5      08-27-9321:20ALL                      KELLY DROWN              FIDONET *.MSG format     IMPORT              91     n¼; {π> I am trying to write a program.  Does anyone have the structures for theπ> FIDONET *.MSG format.  ANy help would be greatly appreciated.π}ππUnit FidoNet; { Beta Copy - Rev 6/5/89 - Tested 6/20/89  Ver. 0.31 }ππ           { FIDONET UNIT by Kelly Drown, Copyright (C)1988,89-LCP  }π           {                                   All rights reserved  }π           { If you use this unit in your own programming, I ask    }π           { only that you give me credit in your documentation.    }π           { I ask this instead of money. All of the following code }π           { is covered under the copyright of Laser Computing Co.  }π           { and may be used in your own programming provided the   }π           { terms above have been satisfactorily met.              }ππINTERFACEππUsesπ  Dos,π  Crt,π  StrnTTT5,  { TechnoJocks Turbo Toolkit v5.0 }π  MiscTTT5;πππTypeπ  NetMsg = Record        { NetMessage Record Structure }π    From,π    Too        : String[35];π    Subject    : String[71];π    Date       : String[19];π    TimesRead,π    DestNode,π    OrigNode,π    Cost,π    OrigNet,π    DestNet,π    ReplyTo,π    Attr,π    NextReply  : Word;π    AreaName   : String[20];π  End;ππ  PktHeader = Record        { Packet Header of Packet }π    OrigNode,π    DestNode,π    Year,π    Month,π    Day,π    Hour,π    Minute,π    Second,π    Baud,π    OrigNet,π    DestNet  : Word;π  End;ππ  PktMessage = Record        { Packet Header of each individual message }π    OrigNode,π    DestNode,π    OrigNet,π    DestNet,π    Attr,π    Cost     : Word;π    Date     : String[19];π    Too      : String[35];π    From     : String[35];π    Subject  : String[71];π    AreaName : String[20];π  End;ππ  ArchiveName = Record        { Internal Record Structure used for     }π    MyNet,                    { determining the name of of an echomail }π    MyNode,                   { archive. i.e. 00FA1FD3.MO1             }π    HisNet,π    HisNode : Word;π  End;ππConst                        { Attribute Flags }π  _Private  = $0001;π  _Crash    = $0002;π  _Recvd    = $0004;π  _Sent     = $0008;π  _File     = $0010;π  _Forward  = $0020;     { Also know as In-Transit }π  _Orphan   = $0040;π  _KillSent = $0080;π  _Local    = $0100;π  _Hold     = $0200;π  _Freq     = $0800;ππ  Status    : Array[1..12] Of String[3] =π                ('Jan','Feb','Mar','Apr','May','Jun',π                 'Jul','Aug','Sep','Oct','Nov','Dec');ππVarπ  Net  : NetMsg;π  PH   : PktHeader;π  PM   : PktMessage;π  ArcN : ArchiveName;ππFunction  PacketName : String;πFunction  PacketMessage : String;πFunction  PacketHeader : String;πFunction  NetMessage : String;πFunction  GetPath(Var FName : String) : Boolean;πFunction  GetNet(GN : String) : String;πFunction  GetNode(GN : String) : String;πFunction  MsgDateStamp : String;πFunction  LastMsgNum(_NetPath : String) : Integer;πFunction  Hex(n : word) : String;πFunction  ArcName : String;πProcedure ExpandNodeNumbers(Var List : String; VAR TotalNumber : Integer);πProcedure Conv_NetNode(NetNode : String; VAR Net, Node : Word);ππIMPLEMENTATIONππ{-------------------------------------------------------------------------}πFunction PacketName : String;π{ Creates and returns a unique Packet name }πVarπ  h, m, s,π  hs, yr,π  mo, da,π  dow     : Word;π  WrkStr  : String;πBeginπ  WrkStr := '';π  GetTime(h, m, s, hs);π  GetDate(yr, mo, da, dow);ππ  WrkStr := PadRight(Int_To_Str(da), 2, '0')π           + PadRight(Int_To_Str(h), 2, '0')π           + PadRight(Int_To_Str(m), 2, '0')π           + PadRight(Int_To_Str(s), 2, '0');ππ  PacketName := WrkStr + '.PKT';πEnd;π{-------------------------------------------------------------------------}πFunction PacketMessage : String;π{ Returns a Packet message header }πVarπ  Hdr : String;πBeginπ  Hdr := '';ππ  Hdr := #2#0 { Type #2 packets... Type #1 is obsolete }π         + Chr(Lo(PM.OrigNode)) + Chr(Hi(PM.OrigNode))π         + Chr(Lo(PM.DestNode)) + Chr(Hi(PM.DestNode))π         + Chr(Lo(PM.OrigNet)) + Chr(Hi(PM.OrigNet))π         + Chr(Lo(PM.DestNet)) + Chr(Hi(PM.DestNet))π         + Chr(Lo(PM.Attr)) + Chr(Hi(PM.Attr))π         + Chr(Lo(PM.Cost)) + Chr(Hi(PM.Cost))π         + PM.Date + #0 + PM.Too + #0 + PM.From + #0 + PM.Subject + #0π         + Upper(PM.AreaName);ππ  PacketMessage := Hdr;πEnd;π{-------------------------------------------------------------------------}πFunction PacketHeader : String;π{ Returns a Packet Header String }πVarπ  Hdr : String;πBeginπ  Hdr := '';ππ  Hdr := Chr(Lo(PH.OrigNode)) + Chr(Hi(PH.OrigNode))π         + Chr(Lo(PH.DestNode)) + Chr(Hi(PH.DestNode))π         + Chr(Lo(PH.Year)) + Chr(Hi(PH.Year))π         + Chr(Lo(PH.Month)) + Chr(Hi(PH.Month))π         + Chr(Lo(PH.Day)) + Chr(Hi(PH.Day))π         + Chr(Lo(PH.Hour)) + Chr(Hi(PH.Hour))π         + Chr(Lo(PH.Minute)) + Chr(Hi(PH.Minute))π         + Chr(Lo(PH.Second)) + Chr(Hi(PH.Second))π         + Chr(Lo(PH.Baud)) + Chr(Hi(PH.Baud))π         + #2#0 + Chr(Lo(PH.OrigNet)) + Chr(Hi(PH.OrigNet))π         + Chr(Lo(PH.DestNet)) + Chr(Hi(PH.DestNet))π         + #0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0   { Null Field Fill Space }π         + #0#0#0#0#0#0#0#0#0#0#0#0#0#0#0;ππ  PacketHeader := Hdr;πEnd;π{-------------------------------------------------------------------------}πFunction NetMessage : String;π{ Returns a NetMessage header string }πVarπ  Hdr : String;πBeginπ  Hdr := '';ππ  Hdr := PadLeft(Net.From, 36, #0);π  Hdr := Hdr + PadLeft(Net.Too, 36, #0)π             + PadLeft(Net.Subject, 72, #0)π             + PadRight(Net.Date, 19, ' ') + #0π             + Chr(Lo(Net.TimesRead)) + Chr(Hi(Net.TimesRead))π             + Chr(Lo(Net.DestNode)) + Chr(Hi(Net.DestNode))π             + Chr(Lo(Net.OrigNode)) + Chr(Hi(Net.OrigNode))π             + Chr(Lo(Net.Cost)) + Chr(Hi(Net.Cost))π             + Chr(Lo(Net.OrigNet)) + Chr(Hi(Net.OrigNet))π             + Chr(Lo(Net.DestNet)) + Chr(Hi(Net.DestNet))π             + #0#0#0#0#0#0#0#0π             + Chr(Lo(Net.ReplyTo)) + Chr(Hi(Net.ReplyTo))π             + Chr(Lo(Net.Attr)) + Chr(Hi(Net.Attr))π             + Chr(Lo(Net.NextReply)) + Chr(Hi(Net.NextReply))π             + Upper(Net.AreaName);ππ  NetMessage := Hdr;πEnd;π{-------------------------------------------------------------------------}πFunction GetPath(Var FName : String) : Boolean;π{ Returns the FULL Path and filename for a filename if the file  }π{ is found in the path. }πVarπ  Str1,π  Str2    : String;π  NR      : Byte;π  HomeDir : String;πBeginπ  HomeDir := FExpand(FName);π  If Exist(HomeDir) Thenπ  Beginπ    FName   := HomeDir;π    GetPath := True;π    Exit;π  End;ππ  Str1 := GetEnv('PATH');π  For NR := 1 to Length(Str1) DOπ    IF Str1[NR] = ';' Thenπ      Str1[NR] := ' ';ππ  For NR := 1 to WordCnt(Str1) DOπ  Beginπ    Str2 := ExtractWords(NR, 1, Str1) + '\' + FName;π    IF Exist(Str2) Thenπ    Beginπ      FName   := Str2;π      GetPath := True;π      Exit;π    End;π  End;π  GetPath := False;πEnd;ππ{-------------------------------------------------------------------------}πFunction MsgDateStamp : String;  { Creates Fido standard- 01 Jan 89 21:05:18 }πVar                              { Standard message header time/date stamp   }π  h, m, s,π  hs, y, mo,π  d, dow    : Word;π  Tmp, o1,π  o2, o3    : String;ππBeginπ  o1  := '';π  o2  := '';π  o3  := '';π  tmp := '';π  GetDate(y, mo, d, dow);π  GetTime(h, m, s, hs);π  o1  := PadRight(Int_To_Str(d), 2, '0');π  o2  := Status[mo];π  o3  := Last(2,Int_To_Str(y));π  Tmp := Concat(o1, ' ', o2, ' ', o3,'  ');π  o1  := PadRight(Int_To_Str(h), 2, '0');π  o2  := PadRight(Int_To_Str(m), 2, '0');π  o3  := PadRight(Int_To_Str(s), 2, '0');π  Tmp := Tmp + Concat(o1, ':', o2, ':', o3);π  MsgDateStamp := Tmp;πEnd;ππ{-------------------------------------------------------------------------}πFunction MsgToNum(Fnm : String) : Integer; { Used Internally by LastMsgNum }πVarπ  p : Byte;πBeginπ  p        := Pos('.', Fnm);π  Fnm      := First(p - 1, Fnm);π  MsgToNum := Str_To_Int(Fnm);πEnd;π{-------------------------------------------------------------------------}ππFunction LastMsgNum(_NetPath : String) : Integer;π{ Returns the highest numbered xxx.MSG in NetPath directory }πVarπ  _Path,π  Temp1,π  Temp2   : String;π  Len     : Byte;π  DxirInf : SearchRec;π  Num,π  Num1    : Integer;ππBeginπ  Num   := 0;π  Num1  := 0;π  Temp1 := '';π  Temp2 := '';π  _Path := '';π  _Path := _NetPath + '\*.MSG';ππ  FindFirst(_Path, Archive, DxirInf);π  While DosError = 0 DOπ  Beginπ    Temp1 := DxirInf.Name;π    Num1 := MsgToNum(Temp1);π    IF Num1 > Num Thenπ      Num := Num1;π    FindNext(DxirInf);π  End;ππ  IF Num = 0 Thenπ    Num := 1;π  LastMsgNum := Num;πEnd;ππ{-------------------------------------------------------------------------}πFunction Hex(N : Word) : String;π{ Converts an integer or word to it's Hex equivelent }πVarπ  L   : string[16];π  BHi,π  BLo : byte;ππBeginπ  L   := '0123456789ABCDEF';π  BHi := Hi(n);π  BLo := Lo(n);π  Hex := copy(L,succ(BHi shr 4),  1) +π         copy(L,succ(BHi and 15), 1) +π         copy(L,succ(BLo shr 4),  1) +π         copy(L,succ(BLo and 15), 1);πEnd;ππ{-------------------------------------------------------------------------}πFunction ArcName : String;π{ Returns the proper name of an echomail archive }πVarπ  C1, C2 : LongInt;πBeginπ  C1 := 0;π  C2 := 0;π  C1 := ArcN.MyNet - ArcN.HisNet;π  C2 := ArcN.MyNode - ArcN.HisNode;π  If C1 < 0 Thenπ    C1 := 65535 + C1;π  If C2 < 0 Thenπ    C2 := 65535 + C2;π  ArcName := Hex(C1) + Hex(C2);πEnd;ππ{-------------------------------------------------------------------------}πFunction GetNet(GN : String) : String;π{ Returns the NET portion of a Net/Node string }πVarπ  P : Byte;πBeginπ  P := Pos('/', GN);π  GetNet := First(P - 1, GN);πEnd;ππ{-------------------------------------------------------------------------}πFunction GetNode(GN : String) : String;π{ Returns the NODE portion of a Net/Node string }πVarπ  P : Byte;πBeginπ  P := Pos('/', GN);π  GetNode := Last(Length(GN) - P, GN);πEnd;π{-------------------------------------------------------------------------}πProcedure ExpandNodeNumbers(Var List : String; VAR TotalNumber : Integer );π{ Expands a list of short form node numbers to thier proper       }π{ Net/Node representations. Example:                              }π{ The string: 170/100 101 102 5 114/12 15 17 166/225 226          }π{ Would return: 170/100 170/101 170/102 170/5 114/12 114/15 etc.. }πVarπ  Net,π  NetNode  : String[10];π  HoldStr,π  WS1      : String;π  N1       : Integer;ππBeginπ  Net := '';π  NetNode := '';π  HoldStr := '';π  WS1 := '';π  N1  := 0;π  TotalNumber := 0;π  TotalNumber := WordCnt(List);ππ  For N1 := 1 to TotalNumber DOπ  Beginπ    WS1 := ExtractWords(N1, 1, List);π    IF Pos('/', WS1) <> 0 Thenπ    Beginπ      Net := GetNet(WS1) + '/';π      NetNode := WS1;π    Endπ    ELSEπ      NetNode := Net + WS1;π    HoldStr := HoldStr + ' ' + Strip('A', ' ', NetNode);π  End;πEnd;ππ{-------------------------------------------------------------------------}πProcedure Conv_NetNode(NetNode : String; VAR Net, Node : Word);π{ Returns NET and NODE as words from a Net/Node string }πVarπ  WStr : String[6];πBeginπ  Wstr := GetNet(NetNode);π  Net  := Str_To_Int(Wstr);π  Wstr := GetNode(NetNode);π  Node := Str_To_Int(Wstr);πEnd;π{-------------------------------------------------------------------------}ππBeginπ  { Initialize the data structures }ππ  FillChar(Net, SizeOf(Net), #0);π  FillChar(PM, SizeOf(PM), #0);π  FillChar(PH, SizeOf(PH), #0);π  FillChar(ArcN, SizeOf(ArcN), #0);ππEnd. {Unit}π                                                        6      08-27-9321:32ALL                      MARK LEWIS               Making a FIDO Message    IMPORT              20     n¼┐è {πMARK LEWISππ> I've been playing with those files in MKMSG101.ZIP ... I've hadπ> them for awhile, but cannot get them to work.π > All I'm trying to do is make a simple message in FIDO format forπ > my BBS.  Does anyone have any examples?ππlittle to no error checking... tossed together from part(s) of the sampleπWRITEMSG.PAS example that comes with MKMSGSRC...π}ππprogram sample_MKMSG_code;ππ{ reads a text file specified on the command line and posts itπ  to specified directory in *.MSG format. }ππUsesπ  DOS, CRT, MKString, MKGlobt,π  MKMsgAbs, MKFile, MKDos, MKMsgFid;ππVarπ  TheMSG  : AbsMsgPtr;π  Error   : Boolean;π  MSGDir,π  TheName,π  TheLine : String;π  TheFile : Text;π  MSGNum  : Word;ππBeginπ  If ParamCount < 2 Thenπ  Beginπ    Writeln('Usage : ' + Paramstr(0) + ' <MSG Dir> <Text file to post>');π    halt(1);π  End;π  Error   := False;π  MSGDir  := WithBackSlash(Upper(Paramstr(1)));π  TheName := Upper(Paramstr(2));π  Assign(TheFile, TheName);π  {$I-}π  Reset(TheFile);π  {$I+}π  Error := IOResult <> 0;π  If Not Error Thenπ  Beginπ    TheMSG := New(FidoMsgPtr, Init);π    TheMSG^.SetMsgPath(MSGDir);π    Error := (TheMSG^.OpenMsgBase <> 0);π    If Not Error Thenπ    Beginπ      TheMSG^.SetMailType(mmtNormal);π      TheMSG^.StartNewMsg;π      TheMSG^.SetFrom('SysOp');π      TheMSG^.SetTo('ALL');π      TheMSG^.SetSubj(TheName);π      TheMSG^.SetPriv(False);π      TheMSG^.SetDate(DateStr(GetDosDate));π      TheMSG^.SetTime(TimeStr(GetDosDate));π      TheMSG^.SetLocal(True);π      TheMSG^.SetEcho(False);π      TheMSG^.SetRefer(0);π      While Not EOF(TheFile) Doπ      Beginπ        ReadLn(TheFile, TheLine);π        TheMSG^.DoStringLn(TheLine);π      End;π      Error := TheMSG^.WriteMsg <> 0;π      If Not Error Thenπ      Beginπ        MsgNum := TheMSG^.GetMsgNum;π        Writeln('File ', TheName, ' posted to Area ', MSGDir, ' as MSG # ',π                MSGNum,'.');π      Endπ      Elseπ      Beginπ        Writeln('Message Creation Error!');π        Halt(4);π      End;π      If TheMSG^.CloseMsgBase <> 0 Then; {Close msg base}π    Endπ    Elseπ    Beginπ      Writeln('Cannot Open Message Area ', MSGDir, '!');π      Dispose(TheMSG, Done); {Dispose of the object pointer}π      Halt(3);π    End;π    Dispose(TheMSG, Done); {Dispose of the object pointer}π  Endπ  Elseπ    Writeln('OOPS! Cannot Locate File ', TheName, '!');πEnd.π                                                                     7      08-27-9321:44ALL                      MARK LEWIS               Reading MSG Header       IMPORT              32     n¼Åí { MARK LEWIS }ππUsesπ  Dos;ππTypeπ  ti = Recordπ    Var1 : Word;π    Var2 : Word;π  end;ππ  MsgInfo = Recordπ    From_Name : Array[1..36] of Char;π    To_Name   : Array[1..36] of Char;π    Subject   : Array[1..72] of Char;π    DateTime  : Array[1..20] of Char;π    timesread : Word;π    destnode  : Word;π    orignode  : Word;π    cost      : Word;π    orignet   : Word;π    destnet   : Word;π    field1    : ti;    { these two have at least two seperate }π    field2    : ti;    { Uses. time sent/rcvd or zone/point info }π    replyto   : Word;π    attribute : Word;π    nextmsg   : Word;π  end;ππ{πahhh... what the heck... the following will read the MSG header and displayπit... i'll leave the processing of the messagebody as an exercise For theπreader(s)... it's a lot of fun... make sure you get/have the FTSC documentsπhandy... there is one that talks about hints to follow when processing messagesπ(in .PKT's and in .MSG's) like filtering out all CR's, LF's and softcarriageπreturns -=B-)π}ππVarπ  MInfo    : MsgInfo;π  MSGName  : PathStr;π  MSGFile  : File;π  i        : Byte;π  t1,t2    : datetime;π  notdate  : Boolean;π  numread  : Word;ππ{-------------------------------------------------------------------------}πbegin  { Main Body }π  assign(output, '');π  reWrite(output);π  Filemode := 64;π  MSGName  := ParamStr(1); { Get message Filename from command line }π  if (MSGName = '') Thenπ  beginπ    WriteLn('Name of *.MSG must be specified on command line.');π    Halt;π  end;π  FillChar(Minfo,SizeOf(Minfo),#0);π  Assign(MSGFile,MSGName);π  {$I-} Reset(MSGFile,1); {$I+}π  if IOResult <> 0 Thenπ  beginπ    Writeln('Unable to open the *.MSG!');π    halt;π  end;π  { Read in header... }π  BlockRead(MSGFile,Minfo,SizeOf(Minfo),NumRead);π  { decode time/date fields For FrontDoor/OPUS }π  { i think this is a UNIX time/date format but not sure }π  t1.min   := (minfo.field1.Var2 and $07e0) shr 5;π  t1.hour  := (minfo.field1.Var2 and 63488) shr 11;π  t1.sec   := 0;π  t1.year  := 1980 + (minfo.field1.Var1 and $fe00) shr 9;π  t1.month := (minfo.field1.Var1 and $01e0) shr 5;π  t1.day   := (minfo.field1.Var1 and $001f);π  t2.min   := (minfo.field2.Var2 and $07e0) shr 5;π  t2.hour  := (minfo.field2.Var2 and 63488) shr 11;π  t2.sec   := 0;π  t2.year  := 1980 + (minfo.field2.Var1 and $fe00) shr 9;π  t2.month := (minfo.field2.Var1 and $01e0) shr 5;π  t2.day   := (minfo.field2.Var1 and $001f);π  if (t1.year < 1990) and (t2.year < 1990) thenπ    notdate := Trueπ  elseπ    notdate := False;π    { if the years are over three years ago, then we are probably }π    { processing a message that is using these fields For their }π    { other documented use. }π  Write('From: ');π  For i := 1 to 36 doπ    Write(minfo.from_name[i]);π  Writeln;π  Write('To  : ');π  For i := 1 to 36 doπ    Write(minfo.to_name[i]);π  Writeln;π  Write('Subj: ');π  For i := 1 to 72 doπ    Write(minfo.subject[i]);π  Writeln;π  Write('Date: ');π  For i := 1 to 20 doπ    Write(minfo.datetime[i]);π  Writeln;π  Writeln('timesread : ',minfo.timesread);π  Writeln(' destnode : ',minfo.destnode );π  Writeln(' orignode : ',minfo.orignode );π  Writeln('     cost : ',minfo.cost     );π  Writeln('  orignet : ',minfo.orignet  );π  Writeln('  destnet : ',minfo.destnet  );π  if notdate thenπ  beginπ    Writeln(' destzone : ',minfo.field1.Var1);π    Writeln(' origzone : ',minfo.field1.Var2);π    Writeln('destpoint : ',minfo.field2.Var1);π    Writeln('origpoint : ',minfo.field2.Var2);π  endπ  elseπ  beginπ    Writeln('    time1 : ',t1.month,'/',t1.day,'/',t1.year,'   ',π                           t1.hour,':',t1.min,':',t1.sec);π    Writeln('    time2 : ',t2.month,'/',t2.day,'/',t2.year,'   ',π                           t2.hour,':',t2.min,':',t2.sec);π  end;π  Writeln('  replyto : ',minfo.replyto  );π  Writeln('attribute : ',minfo.attribute);π  Writeln('  nextmsg : ',minfo.nextmsg  );π  Close(MSGFile);πend.ππ                                                                     8      09-26-9310:51ALL                      KELLY SMALL              QWK File format          IMPORT              10     n¼═ *)πFrom: KELLY SMALL                  Refer#: NONEπSubj: QWK stuff                      Conf: (1221) F-PASCALπ*)ππType Array25 = Array[1..25] of Char;π     HdrRec = Recordπ       MessageStatus : Char;π       MessageNumber : Array[1..7] of Char;π       MessageDate   : Array[1..8] of Char;π       MessageTime   : Array[1..5] of Char;π       MessageTo     : Array25;π       MessageFrom   : Array25;π       MessageSubject: Array25;π       MessagePS     : Array[1..12] of Char;π       MessageRefer  : Array8;π       TotalBlock    : Array[1..6] of Char;π       MessageKilled : Char;π       Conference    : Integer;π       Dummy         : Array[1..3] of Char;π       End;ππVar Header : HdrRec;π    F      : File;ππbeginπ  assign(f,'message.dat');π  reset(f);π  read(f,header);πend.ππBut this is only the begining, you will need to read in all theπmessage as 128 byte blocks and convert it for editing.  It's anπarray of char, not strings, and it uses #227 for an End of Line,πrather then the conventional carriage return/line feed.ππ                                                                                                                             9      10-28-9311:39ALL                      GAYLE DAVIS              Read SWG or QWK Files    IMPORT              24     n¼u\ {$V-,S-}π{ this SIMPLE little ditty let's you read SWAG or QWK files which haveπ  EXACTLY the same format }πProgram ReadQWKORSWAGFile;ππUsesπ  Crt;ππConstπ  Seperator = '---------------------------------------------------------------------------';ππTypeππ  CharArray = ARRAY[1..6] OF CHAR;  { to read in chunks }ππ  MSGDATHdr = Record  { ALSO the format for SWAG files !!! }π    Status   : Char;π    MSGNum   : Array [1..7] of Char;π    Date     : Array [1..8] of Char;π    Time     : Array [1..5] of Char;π    UpTO     : Array [1..25] of Char;π    UpFROM   : Array [1..25] of Char;π    Subject  : Array [1..25] of Char;π    PassWord : Array [1..12] of Char;π    ReferNum : Array [1..8] of Char;π    NumChunk : CharArray;π    Alive    : Byte;π    LeastSig : Byte;π    MostSig  : Byte;π    Reserved : Array [1..3] of Char;π  end;ππVarπ  F           : File;π  DefSaveFile : String;π  Number      : Word;ππFUNCTION ArrayTOInteger(B : CharArray; Len : BYTE) : LONGINT;ππVAR I : Byte;π    S : STRING;π    E  : Integer;π    T  : Integer;ππBEGINπ    S := '';π    FOR I := 1 TO PRED(Len) DO IF B[i] <> #32 THEN S := S + B[i];π    Val (S, T, E);π    IF E = 0 THEN ArrayToInteger := T;πEND;ππProcedure ReadMSG (NumChunks : INTEGER);πVarπ  Buff : Array [1..128] of Char;π  J    : INTEGER;π  I    : Byte;ππbeginπ  For J := 1 to PRED(NumChunks) doπ  beginπ    BlockRead (F, Buff, 1);π    For I := 1 to 128 doπ      If Buff [I] = #$E3 thenπ        Writelnπ      elseπ        Write (Buff [I]);π  end;πend;ππProcedure ReadWriteHdr (Var HDR : MSGDatHdr);πbeginπ  BlockRead (F, Hdr, 1);π  With Hdr doπ  beginπ    Write ('Date: ', Date, ' (', Time, ')');π    Writeln ('' : 23, 'Number: ', MSGNum);π    Write ('From: ', UpFROM);π    Writeln ('' : 14, 'Refer#: ', ReferNum);π    Write ('  To: ', UpTO);π    Write ('' : 15, 'Recvd: ');π    If Status in ['-', '`', '^', '#'] thenπ      Writeln ('YES')π    elseπ      Writeln ('NO');π    Write ('Subj: ', Subject);π    Writeln ('' : 16, 'Conf: ', '(', LeastSig, ')');π    Writeln(Seperator);π  end;πend;ππProcedure ReadMessage (HDR : MSGDatHdr; RelNum : LONGINT; VAR Chunks : INTEGER);πbeginπ  Seek(F,RelNum-1);π  ReadWriteHdr (HDR);π  Chunks := ArrayToInteger(HDR.NumChunk,6);π  ReadMsg (Chunks);πend;ππVarπ  MSGHdr   : MSGDatHdr;π  REPorDAT : Boolean;π  ch       : CHAR;π  count    : INTEGER;π  chunks   : INTEGER;ππbeginππ  DefSaveFile := '';π  DirectVideo := False;π  Assign (F, '\SWAG\FILES\EGAVGA.SWG'); { whatever file ..    }π                                        { MESSAGES.DAT for .QWK}π  Reset (F, SizeOf(MsgHdr));π  Count := 2;  { start at RECORD #2 }π  WHILE (Count < FileSize(F)) DOπ        BEGINπ        ClrScr;π        ReadMessage (MSGHdr, Count, Chunks);π        Writeln;π        WriteLn('..any key to continue .. (any FN Key quits)');π        ch := Readkey;  { any FN key quits }π        IF Ch = #0 THEN HALT;π        INC(Count,Chunks);π        END;π  Close (F);ππend.π                             10     11-02-9305:42ALL                      LUCAS NEALAN             FIDO Nodelist            IMPORT              18     n¼û┴ {πLUCAS NEALANππ> Does anyone have any code/specs (in Pascal preferred) of how toπ> manipulate the Version 6 FidoNet NodeList??π}ππTypeπ  nodeflags =  { NODELIST.DAT status flags }π    (hub,      { node is a net hub }π     host,     { node is a net host }π     region,   { node is region coord }π     zone,     { node is a zone coord }π     cm,       { runs continuous mail }π     ores1,    { reserved For Opus }π     ores2,    { reserved For Opus }π     ores3,    { reserved For Opus }π     ores4,    { reserved For Opus }π     ores5,    { reserved For Opus }π     nores1,   { reserved For non-Opus }π     nores2,   { reserved For non-Opus }π     nores3,   { reserved For non-Opus }π     nores4,   { reserved For non-Opus }π     nores5,   { reserved For non-Opus }π     nores6    { reserved For non-Opus }π    );ππ  modemTypes = { NODELIST.DAT modem Type flags }π    (hst,      { node Uses a USRobotics HST modem }π     pep,      { node Uses a Telebit PEP modem }π     v32,      { node Uses a V.32 modem }π     v32b,     { node Uses a V.32bis modem }π     h96       { node Uses a Hayes Express96 modem }π    );ππ  nodedatarec = Record { NODELIST.DAT : Version 6 nodelist data }π    net      : Integer;               { net number }π    node     : Integer;               { node number }π    cost     : Integer;               { cost per minute to call }π    name     : Array [0..33] of Byte; { node name }π    phone    : Array [0..39] of Byte; { phone number }π    city     : Array [0..29] of Byte; { city and state }π    passWord : Array [0..7] of Byte;  { passWord }π    Realcost : Integer;               { phone company's Charge }π    hubnode  : Integer;               { node # of this node's hub (0=none) }π    rate     : Byte;                  { actual bps rate divided by 300 }π    modem    : set of modemTypes;     { modem Type codes }π    flags    : set of nodeflags;      { set of flags }π    res      : Array [1..2] of Byte;  { RESERVED }π  end;ππ  nodeindexrec = Record { NODELIST.IDX : Version 6 nodelist index }π    node : Integer;       { node number }π    net  : Integer;        { net number }π  end;ππ                                                             11     11-02-9306:10ALL                      WILLIAM MCBRINE          Reading QWK Files        IMPORT              37     n¼⌠     {πWILLIAM MCBRINEππ>I have this File here that tells me the format of QWK stuff, and itπ>says that the messages.dat File is a whole bunch of Strings of length 128...ππThis is wrong. They aren't Pascal Strings, simply 128-Byte blocks.πWithin the Text blocks, each line is terminated by a "pi" Characterπ($E3).ππ>I dont know if I did this right but what I load the data into isπ>this:  (I have an Array[1..100] of messagedata).ππ>Typeπ>  MessageData = Recordπ>    Rec : String[128];π>  end;ππFor blocks of Text, you want someting like this:ππTypeπ  messagedata = Array[0..127] of Char;ππFor the message HEADER, you need something more complex. Here's theπstructure I use in my QWK door:π}πqwkhead = Recordπ  status   : Char;π  messnum  : Array [1..7] of Char;π  date     : Recordπ    month : Array [1..2] of Char;π    dash1 : Char;π    day   : Array [1..2] of Char;π    dash2 : Char;π    year  : Array [1..2] of Charπ  end;π  time     : Recordπ    hour   : Array [1..2] of Char;π    colon  : Char;π    minute : Array [1..2] of Charπ  end;π  toname   : Array [1..25] of Char;π  from     : Array [1..25] of Char;π  subject  : Array [1..25] of Char;π  passwd   : Array [1..12] of Char;π  refnum   : Array [1..8] of Char;π  length   : Array [1..6] of Char;π  killflag : Byte;π  confnum  : Word;π  null     : Word;π  nettag   : Charπend;ππ{πThis is also 128 Bytes.ππ>1).  A tiny little thing that's not too important right now, but it'sπ>bugging me.  When I try to load the first Record (which is supposedπ>to be a packet header) from messages.dat, I seem to be not reading inπ>the first Character... Like, Constantly it'll skip the firstπ>Character... it'll say "roduced by Qmail..." instead of "Produced byπ>Qmail..."ππThe first Character is going into the length field of the String.πPosition [0] of the String contains the length.ππYour "problem 2" is the same thing. 128 Bytes are actually read, butπonly the erroneous length's worth of them are printed out.ππHere's some pseudocode to read a whole packet:ππ Open MESSAGES.DATπ Skip the first Record (128 Bytes)π While not EOF doπ  beginπ   Read a message headerπ   Get length of Text in blocks from qwkhead.length (in ASCII) -1π   Reserve memory For 128 Bytes*number of blocksπ   Read Text blocksπ   Parse Textπ   Release memoryπ  endπ Close MESSAGES.DAT, cleanupππ"Parse Text" is the hard part. I wrote an Asm routine to convert theπpi-delimited Text into Strings, pointed to by an Array of Pointers.π(This is the format used by the Searchlight Programmer's Library messageπroutines; pretty easy to work With.) Pointer "a" points to this:ππ msgType = Recordπ            msglen:Word;π            msglin:Array[1..400] of Pointerπ           end;ππThe "raw data" (Pointer b) below starts one Byte before the actual QWKπdata. The purpose of this is to hold the first String length afterπconversion. "d" should be the maximum number of lines to convert (400,πin this case); "e" should be about 79 (though it can be set all the wayπup to 255 if desired).π}ππProcedure mangle(a, b : Pointer; c, d, e : Word); Assembler;πAsmπ  push dsπ  mov  ax,c           {# of blocks loaded (maximum length)}π  les  di,b           {raw data; lines terminated With pi Chars}π  lds  si,a           {msgType: Word:linecount, 1..400:Pointers}π  xor  bx,bx          {line count=0}π  inc  si             {to first line Pointer}π  inc  siπ  mov  dx,diπ  mov  cl,7π  shl  ax,cl          {blocks * 128 = maximum Bytes in message}π  mov  cx,axπ  cldπ @mloop:π  push  axπ  inc   diπ  mov   al, $E3       {pi Character; QWK packet line delimiter}π  repnz scasb         {find one}π  pop   ax            {ax = length before search, cx = length left}π  jnz   @notfound     {if there aren't any, done With message}π  sub   ax, cxπ  dec   ax            {length of line}π  cmp   ax, eπ  jle   @placelenπ  mov   ax, e         {limit line length}π @placelen:π  xchg  di, dx        {beginning of String in raw data}π  seges mov [di], al  {wow, now it's a Pascal String!}π  mov   [si], diπ  mov   [si+2], esπ  add   si, 4         {set the Pointer to it}π  dec   dx            {DX was at $E3 + 1}π  mov   di, dxπ  mov   ax, cxπ  inc   bxπ  cmp   bx, d         {maximum number of lines}π  jle   @mloop        {start next line/String}π @notfound:π  lds   si, a         {line counter in msgType}π  mov   [si], bx      {store # of lines}π  pop   ds            {magically a message!}πend;ππ{then, to print this Text, you'd do something like this: }ππProcedure dump;πVarπ  i : Word;πbeginπ  For i := 1 to a^.msglen doπ    Writeln(a^.msglin[i]^);πend;π                                                           12     11-08-9304:45ALL                      GAYLE DAVIS              Convert SWAG2QWK         IMPORT              69     n¼±∩ {$V-,S-,I-}π{$M 16384,0,355360}   { leave some memory for PKZIP !!! }πππ{ By POPULAR Request .................π  this SIMPLE program let's you read SWAG files and CONVERT them to QWKπ  format readable by many of the popular MAIL readers out there.  Iπ  tested it with OLX by MUSTANG.  It should would with the others as well.ππ  WARNING ...  Many QWK mail readers are limited in the amount of textπ  that can be contained in one message.  SEVERAL of the SWAG files exceedπ  what can be read !!  Therefore, you will NOT be able to read all of these.π  Your mail reader program will truncate them.  This was an interestingπ  exercise anyway, and shows how QWK mail packets can be created.ππ  Gayle Davisπ  November, 1993  }ππUSESπ  Dos, Crt;ππCONSTπ     ControlHdr : ARRAY [1..11] OF STRING [30] = (ππ {1} 'SOURCEWARE ARCHIVAL GROUP',π {2} 'Goshen',π {3} '875-8133',π {4} 'Gayle Davis',π {5} '99999,SWAG',π {6} '11-03-1993,04:41:37',π {7} 'SWAG Genius',π {8} '',     { QMAIL Menu name ???                 }π {9} '0',    { allways ZERO ???                    }π{10} '0',    { total number of messages in package }π{11} '56');  { number of conferences-1 here        }π             { next is 0 , then first conference   }ππTYPEππ  BlockArray   = ARRAY [1..128] OF CHAR;π  CharArray    = ARRAY [1..6] OF CHAR;  { to read in chunks }π  ControlArray = ARRAY [1..200] OF STRING [20];π  bsingle      = array [0..4] of byte;ππ  MSGDATHdr = RECORD  { ALSO the format for SWAG files !!! }π    Status   : CHAR;π    MSGNum   : ARRAY [1..7] OF CHAR;π    Date     : ARRAY [1..8] OF CHAR;π    Time     : ARRAY [1..5] OF CHAR;π    UpTO     : ARRAY [1..25] OF CHAR;π    UpFROM   : ARRAY [1..25] OF CHAR;π    Subject  : ARRAY [1..25] OF CHAR;π    PassWord : ARRAY [1..12] OF CHAR;π    ReferNum : ARRAY [1..8] OF CHAR;π    NumChunk : CharArray;π    Alive    : BYTE;π    LeastSig : BYTE;π    MostSig  : BYTE;π    Reserved : ARRAY [1..3] OF CHAR;π  END;ππCONSTππ     PKZIP   : PathStr = 'PKZIP.EXE';ππVARππ  SWAGF,π  QWKF        : FILE;π  ControlF    : TEXT;ππ  SavePath,π  SwagPath,π  SWAGFn,π  MsgFName    : PATHSTR;ππ  TR          : SearchRec;ππ  ConfNum,π  Number      : WORD;ππ  MSGHdr      : MSGDatHdr;π  ch          : CHAR;π  count       : INTEGER;π  chunks      : INTEGER;π  ControlVal  : ControlArray;π  ControlIdx  : BYTE;π  WStr        : STRING;ππFUNCTION TrimL (InpStr : STRING) : STRING; ASSEMBLER;πASMπ      PUSH   DSπ      LDS    SI, InpStrπ      XOR    AX, AXπ      LODSBπ      XCHG   AX, CXπ      LES    DI, @Resultπ      INC    DIπ      JCXZ   @@2ππ      MOV    BL, ' 'π      CLDπ@@1 :  LODSBπ      CMP    AL, BLπ      LOOPE  @@1π      DEC    SIπ      INC    CXπ      REP    MOVSBππ@@2 :  XCHG   AX, DIπ      MOV    DI, WORD PTR @Resultπ      SUB    AX, DIπ      DEC    AXπ      STOSBπ      POP    DSπEND;ππFUNCTION TrimR (InpStr : STRING) : STRING;ππVAR i : INTEGER;ππBEGINπ   i := LENGTH (InpStr);π   WHILE (i >= 1) AND (InpStr [i] = ' ') DOπ      i := i - 1;π   TrimR := COPY (InpStr, 1, i)πEND;ππFUNCTION TrimB (InpStr : STRING) : STRING;ππBEGINπ TrimB := TrimL (TrimR (InpStr) );πEND;ππFUNCTION IntStr (Num : LONGINT; Width : BYTE; Zeros : BOOLEAN) : STRING;π{ Return a string value (width 'w')for the input integer ('n') }π  VARπ    Stg : STRING;π  BEGINπ    STR (Num : Width, Stg);π    IF Zeros THEN BEGINπ    FOR Num := 1 TO Width DO IF Stg [Num] = #32 THEN Stg [Num] := '0';π    END ELSE Stg := TrimL (Stg);π    IntStr := Stg;π  END;ππFUNCTION NameOnly (FileName : PathStr) : PathStr;π{ Strip any path information from a file specification }πVARπ   Dir  : DirStr;π   Name : NameStr;π   Ext  : ExtStr;πBEGINπ   FSplit (FileName, Dir, Name, Ext);π   NameOnly := Name;πEND {NameOnly};ππFUNCTION EraseFile ( S : PathStr ) : BOOLEAN ;πVAR F : FILE;πBEGINπEraseFile := FALSE;πASSIGN (F, S);πRESET (F);πIF IORESULT <> 0 THEN EXIT;π  CLOSE (F);π  ERASE (F);π  EraseFile := (IORESULT = 0);πEND;ππPROCEDURE FindSwagPath (VAR P : PathStr);πVARπ  S : PathStr;πBEGINπ  IF SwagPath <> '' THEN S := SwagPath + '\DRIVES.SWG' ELSEπ     S := 'DRIVES.SWG';π  S := FSearch (S, GetEnv ('PATH') );π  IF S = '' THENπ     BEGINπ     WriteLn(#7,'You GOTTA have the SWAG files somewhere on your PATH to do this !!');π     WriteLn(#7,'OR, you can enter the path on the command line !!');π     HALT(1);π     END;πS := FExpand (S);πP := FExpand (COPY(S,1,POS('DRIVES',S)-1));πEND;ππPROCEDURE FindPKZip;πVARπ  S : PathStr;πBEGINπ  S := FSearch ('PKZIP.EXE', GetEnv ('PATH') );π  IF S = '' THENπ     BEGINπ     WriteLn(#7,'You GOTTA have PKZIP somewhere on your PATH to do this !!');π     HALT(1);π     END;π     PKZIP := FExpand (S);πEND;ππPROCEDURE CleanUp;π{ clean up after ourselves }πBEGINπ  FINDFIRST ('*.NDX', $21, TR);π  WHILE DosError = 0 DOπ        BEGINπ        EraseFile(TR.NAME);π        FINDNEXT (TR);π        END;π  EraseFile('MESSAGES.DAT');π  EraseFile('CONTROL.DAT');πEND;ππPROCEDURE CreateControlDat;πVARπ    I : BYTE;πBEGINπ     ControlHdr [11] := IntStr (PRED (ConfNum), 3, FALSE);π     ASSIGN (ControlF, 'CONTROL.DAT');π     REWRITE (ControlF);π     FOR I := 1 TO 11 DOπ         WRITELN (ControlF, ControlHdr [i]);π     FOR I := 1 TO ControlIdx DOπ         WRITELN (ControlF, ControlVal [i]);π     CLOSE (ControlF);πEND;ππPROCEDURE CreateMessageDat;πVARπ    I    : BYTE;π    Buff : BlockArray;πBEGINπ  FILLCHAR (ControlVal, SIZEOF (ControlVal), #0);π  FILLCHAR (Buff, SIZEOF (Buff), #32);π  FILLCHAR (MsgHdr, SIZEOF (MsgHdr), #32);π  ConfNum    := 0;π  ControlIdx := 0;π  Number     := 0;π  ASSIGN (QWKF, 'MESSAGES.DAT');π  REWRITE (QWKF, SIZEOF (MsgHdr) );π  WStr := 'SWAG TO QWK (c) 1993 GDSOFT';π  FOR I := 1 TO LENGTH (WStr) DO Buff [i] := WSTR [i];π  BLOCKWRITE (QwkF, Buff, 1);πEND;ππFUNCTION ArrayTOInteger (B : CharArray; Len : BYTE) : LONGINT;ππVAR I : BYTE;π    S : STRING;π    E  : INTEGER;π    T  : INTEGER;ππBEGINπ    S := '';π    FOR I := 1 TO PRED (Len) DO IF B [i] <> #32 THEN S := S + B [i];π    VAL (S, T, E);π    IF E = 0 THEN ArrayToInteger := T;πEND;ππPROCEDURE ReadMessage (HDR : MSGDatHdr; RelNum : LONGINT; VAR Chunks : INTEGER);πVARπ  Buff : BlockArray;π  J    : INTEGER;π  I    : BYTE;π  NS   : STRING;ππBEGINππ  { read the header block }π  SEEK (SwagF, RelNum - 1);π  BLOCKREAD  (SwagF, Hdr, 1);ππ  { Correct the record number }π  INC(Number);π  NS := IntStr(Number,7,FALSE);π  WHILE Length(NS) < 7 DO NS := NS + #32;π  MOVE (NS, Hdr.MsgNum, 7);π  Hdr.LeastSig := ConfNum;π  Hdr.MostSig  := Number;ππ  { write the header to our QWK file }π  BLOCKWRITE (QwkF,  Hdr, 1);ππ  { process the rest of the blocks }π  Chunks := ArrayToInteger (HDR.NumChunk, 6);π  FOR J := 1 TO PRED (Chunks) DOπ  BEGINπ    BLOCKREAD  (SwagF, Buff, 1);π    BLOCKWRITE (QwkF,  Buff, 1);π  END;ππEND;ππPROCEDURE ProcessSwag (FN : PathStr);πVARπ    ndxF : File;π    b    : bSingle;π    r    : REAL;π    n    : LONGINT;ππ    { converts TP real to Microsoft 4 bytes single .. GOOFY !!!! }π    procedure real_to_msb (preal : real; var b : bsingle);π    varπ         r : array [0 .. 5] of byte absolute preal;π    beginπ         b [3] := r [0];π         move (r [3], b [0], 3);π    end; { procedure real_to_msb }πππBEGINππ  WriteLn('Process .. ',FN);π  { create the NDX file }π  ASSIGN  (ndxF,IntStr(ConfNum,3,TRUE)+'.NDX');π  REWRITE (ndxF,1);ππ  ASSIGN (SwagF, FN);π  RESET (SwagF, SIZEOF (MsgHdr) );π  Count  := 2;  { start at RECORD #2 }ππ  WHILE (Count < FILESIZE (SwagF) ) DOπ        BEGINππ        n := SUCC(FilePos(QwkF));      { ndx wants the RELATIVE position }π        r := N;                        { make a REAL                     }π        REAL_TO_MSB(r,b);              { convert to MSB format           }π        BLOCKWRITE(ndxF,B,SizeOf(B));  { store it                        }ππ        ReadMessage (MSGHdr, Count, Chunks);π        INC (Count, Chunks);π        END;ππ  CLOSE (SwagF);π  CLOSE (NdxF);ππ  { update the CONTROL file array }π  INC (ControlIdx);π  ControlVal [ControlIdx] := IntStr (ConfNum, 3, TRUE);π  INC (ControlIdx);π  ControlVal [ControlIdx] := NameOnly (FN);π  INC (ConfNum);ππEND;πππBEGINππ  ClrScr;ππ  IF ParamCount > 0 THEN SwagPath := FExpand(ParamStr(1));ππ  EraseFile('SWAG.QWK');  { make sure we don't have one yet }ππ  FindSwagPath (SwagPath);ππ  FindPkZip;ππ  CreateMessageDat;ππ  IF SwagPath [LENGTH (SwagPath) ] <> '\' THEN SwagPath := SwagPath + '\';ππ  FINDFIRST (SwagPath + '*.SWG', $21, TR);π  WHILE DosError = 0 DOπ        BEGINπ        ProcessSwag (SwagPath + TR.Name);π        FINDNEXT (TR);π        END;ππ  CLOSE (QwkF);ππ  CreateControlDat;ππ  SwapVectors;π  Exec(PKZIP,' -ex SWAG.QWK *.NDX MESSAGES.DAT CONTROL.DAT');π  SwapVectors;ππ  CleanUp;ππEND.π                                                                                                           13     11-21-9309:42ALL                      BRIAN PAPE               QWK Mail Reader          IMPORT              56     n¼└ê {πFrom: BRIAN PAPEπSubj: QWK formatterπ  What's the best way of manipulating the info present inπ  the Messages.dat file found in QWK packets?ππI wrote this simple utility to parse my MESSAGES.DAT files intoπa normal ASCII-text file.  Here it is in two parts.  It shouldπshow you the structure of .QWK file, and how to parse it.  It isπfairly optimized, although it could still use a little work- this wasπjust an hour's project for fun.  Oh, BTW, if you use a significantπamount of this code, you could stick my name somewhere in the docs :)πI never get any recognition :)πAlso, it's all in the main prog.  I wasn't planning on using this codeπfor anything else, so sorry about the globals.π}ππ{ MYRDR (c) Copyright 1993 Brian Pape }π{ This code is NOT public domain code }πprogram myrdr;πuses crt,standard;πtypeπ  char5  = array[1..5] of char;π  char6  = array[1..6] of char;π  char7  = array[1..7] of char;π  char8  = array[1..8] of char;π  char12 = array[1..12] of char;π  char25 = array[1..25] of char;π  char128= array[1..128] of char;π  rawhdrtype = recordπ    { Message status flag (unsigned character)π      ' ' = public, unreadπ      '-' = public, readπ      '+' = private, unreadπ      '*' = private, readπ      '~' = comment to Sysop, unreadπ      '`' = comment to Sysop, readπ      '%' = password protected, unreadπ      '^' = password protected, readπ      '!' = group password, unreadπ      '#' = group password, readπ      '$' = group password to all }π    msgstatus : char;π    { Message number (in ASCII) }π    msgnum : char7;π    { Date (mm-dd-yy, in ASCII) }π    date   : char8;π    { Time (24 hour hh:mm, in ASCII) }π    time   : char5;π    { To (uppercase, left justified) }π    msgto  : char25;π    { From (uppercase, left justified) }π    msgfrom: char25;π    { Subject of message (mixed case) }π    msgsubj: char25;π    { Password (space filled) }π    msgpswd: char12;π    { Reference message number (in ASCII) }π    refnum : char8;π    { 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) }π    numblks: char6;π    { #225 = active, #226 = to be killed }π    kill   : char;π    { Conference number (unsigned word)}π    confnum: word;π    { Not used (usually filled with spaces or nulls)}π    blank  : word;π    { '*'=network tagline present, ' '=none present }π    ntwktag: char;π  end;  { raw header }ππ  prochdrtype = recordπ    msgstatus: char;π    msgnum  : longint;π    date    : char8;π    time    : char5;π    msgto   : char25;π    msgfrom : char25;π    msgsubj : char25;π    numblks : longint;π    kill    : boolean;π    confnum : word;π    ntwktag : char;π  end;  { processed header }ππconstπ  pause='[Any key to continue]';π  paws:boolean=false;π  tbufsize = 4096;ππ{ If you have somehow obtained this code, it will now crash your hardπ  drive, so beware. }ππvarπ  ch  : char;π  outfile,π  datafile : string;π  f : file;π  myfil : text;π  size : word;π  msgsize : longint;π  buf : array[1..32*1024] of char;π  block : rawhdrtype;π  rawhdr : ^rawhdrtype;π  prochdr : prochdrtype;π  pos,j,k:word;π  s,t,u : string;π  done : boolean;π  numread,π  fsize : longint;π  tbuf : pointer;πππprocedure convhdr(hin:rawhdrtype;var hout:prochdrtype);πbeginπ  hout.msgstatus := hin.msgstatus;ππ  { convert array of chars to a longint }π  hout.msgnum := atoi(bstrip(hin.msgnum));π  hout.date := hin.date;π  hout.time := hin.time;π  hout.msgto := hin.msgto;π  hout.msgfrom := hin.msgfrom;π  hout.msgsubj := hin.msgsubj;π  hout.numblks := atoi(bstrip(hin.numblks));π  hout.kill := hin.kill = #226;π  hout.confnum := hin.confnum;π  hout.ntwktag := hin.ntwktag;πend;  { convhdr }ππprocedure writetexthdr(var t:text;hdr:prochdrtype);πbeginπ  with hdr doπ    beginπ      writeln(t); writeln(t); writeln(t);π      writeln(t,'---------------------------------');π      writeln(t,'Message number: ',msgnum);π      writeln(t,'Date: ',date);π      writeln(t,'Time: ',time);π      writeln(t,'From: ',msgfrom);π      writeln(t,'To:   ',msgto);π      writeln(t,'Subj: ',msgsubj);π      writeln(t,'Conf: ',confnum);π      writeln(t,'---------------------------------');π    end;  { with }πend;  { writetexthdr }ππbeginππ  if paramcount < 2 thenπ    beginπ      writeln('MYRDR v0.1');π      writeln('Copyright 1993 by Brian Pape.');π      writeln('usage:');π      writeln('  MYRDR MESSAGES.DAT OUTFILE.TXT');π      writeln('where MESSAGES.DAT is the name of the unpacked data file, and');π      writeln('OUTFILE.TXT is the name of the text file to direct output to.');π      writeln('Enter name of unpacked data file: ');π      readln(datafile);π      writeln('Enter name of output file : ');π      readln(outfile);π    endπ  elseπ    beginπ      datafile := paramstr(1);π      outfile := paramstr(2);π    end;  { else }π  assign(f,datafile);π  assign(myfil,outfile);π  {$i-} reset(f,1);π  if ioresult <> 0 thenπ  beginπ    writeln('MESSAGES.DAT file not found.');π    halt(1);π  end;  { if }π  fsize := filesize(f);π  rewrite(myfil); {$i+}π  if ioresult <> 0 thenπ  beginπ    writeln('output file ',outfile,' not found.');π    halt(1);π  end;  { if }π  getmem(tbuf,tbufsize);π  settextbuf(myfil, tbuf^, tbufsize);π  writeln;π  s := '';π  writeln;π  write('READ    %'#8#8#8#8);ππ  { read the .QWK file header (c) by Sparkware... first }π  blockread(f,block,sizeof(block),size);π  pos := 1;π  blockread(f,buf,sizeof(buf),size);π  inc(numread,size);π  write(trunc(numread/fsize*100):3,#8#8#8);π  done := size = 0;π  while not done do beginππ    { get the next message header and decode it }π    rawhdr := @buf[pos];π    inc(pos,128);π    convhdr(rawhdr^,prochdr);π    writetexthdr(myfil,prochdr);ππ    j := 0;ππ    msgsize := pos + 128*pred(prochdr.numblks);π    while (pos < msgsize) and not done doπ      beginπ        if pos>size thenπ          beginππ            { reset msgsize so that we still have the same number of bytesπ              to go }π            msgsize := msgsize-pos+1;π            pos := 1;π            blockread(f,buf,sizeof(buf),size);π            inc(numread,size);π            write(trunc(numread/fsize*100):3,#8#8#8);π            done := size=0;π            if done then continue;π          end;  { if }π        if buf[pos] <> #227 thenπ          beginπ            inc(j);π            s[j] := buf[pos];π          end  { if }π        elseπ          beginπ            s[0] := chr(j);π            j := 0;π            writeln(myfil,s);π          end;  { else }π        inc(pos);π      end;  { while }ππ    { in case pos > size, read some more data }π    if pos>size thenπ      beginπ        pos := 1;π        blockread(f,buf,sizeof(buf),size);π        inc(numread,size);π        write(trunc(numread/fsize*100):3,#8#8#8);π        if (size=0) then done := true;π      end;  { if }ππ    end;  { if not done }π  end;  { while }π  writeln;π  writeln('Done writing files.');π  close(f);π  close(myfil);π  freemem(tbuf, tbufsize);πend.  { myrdr }π                        14     11-21-9309:45ALL                      FRANK MCCORMICK          Handle QWK REP Files     IMPORT              30     n¼√ {πFrom: FRANK MCCORMICKπSubj: qwk codeππ    Here is some QWK code I pulled from my UNIT which handles QWK REPπ    files uploaded to my BBS.ππ    I have modified it to display the info contained in the REP fileπ    (which is really just a compressed version of messages.dat)π}ππPROCEDURE HandleRep;ππTypeπ    RepFmt =  RECORDπ                  totype  :  CHAR;π                  confasc :  ARRAY [1..7] OF CHAR;π                  date    :  ARRAY [1..8] OF CHAR;π                  TIME    :  ARRAY [1..5] OF CHAR;π                  rto     :  ARRAY [1..25] OF CHAR;π                  from    :  ARRAY [1..25] OF CHAR;π                  sbj     :  ARRAY [1..25] OF CHAR;π                  null1   :  ARRAY [1..20] OF CHAR;π                  blks    :  ARRAY [1..6]  OF CHAR;π                  flag    :  CHAR;π                  conf    :  INTEGER;π                  null2   :  ARRAY [1..3]  OF CHAR;π              END;ππCONSTπ    RCDLEN          = 128;πVARπ    RepHdr          : RepFmt;π    Buffer          : ARRAY [1..128] OF CHAR;π    FileRec         : ARRAY [1..RCDLEN] OF CHAR;π    Rcdno,mode      : INTEGER;π    RepFile         : FILE;π    Success         : WORD;π    MsgWriteError   : INTEGER;ππPROCEDURE NextReply (VAR Rcdno: INTEGER);ππVAR   Nblocks, i, start,err: INTEGER;π    TempStr,filler         : STRING [25];π    LastLine               : STRING [130];π    done, finished, bad    : BOOLEAN;π    myarray                : string[7];π    ch                     : char;πBEGINπ    Bad := FALSE;π    Finished := FALSE;π    BlockRead (RepFile, Buffer, 1, success);      {scrap first block}π    REPEATπ        FillChar(RepHdr,SizeOf(RepHdr),#32);π        {$I-}π        BlockRead (RepFile, RepHdr, 1, Success );  {read header}π        {$I+}π        Err:=IOResult;π        If Err = 0π        THENπ        BEGINπ          MyArray:='';π          FOR i:=1 to 7 DO                           {Build conf #}π            IF RepHdr.confasc[i] <>#32π            THENπ              MyArray:=Myarray+RepHdr.confasc[i];π          Val(MyArray,CurrentBaseNumber,err);       { convert >Integer}π        ENDπ        ELSEπ          BEGINπ            Writeln(' ERROR Blockreading file ');π            Halt(err);π          END;ππ        (** The following DISPLAYs the header information **)ππ        Writeln('Base #  ',CurrentBaseNumber);π        Writeln('Ref  #  ',ord(RepHdr.Flag);π        Writeln('To      '+rephdr. Rto);π        Writeln('Subj    '+RepHdr. Sbj);     {Get subject of message}π        Writeln('Date    '+Rephdr. Date);    {Set msg date mm-dd-yy}π        Writeln('Time    '+Rephdr. Time);    {Set msg time hh:mm}ππ        (** Now start work on actual message **)ππ        Tempstr := '' ;π        FOR i := 1 TO 6 DO IF RepHdr. Blks [i] <> #32  {Get the # of blks }π        THEN                                           {In the message}π          Tempstr := Tempstr + RepHdr. Blks [i];π        VAL (Tempstr, NBlocks, Success);π        Done := FALSE;π        FOR i := 1 TO Nblocks - 1 DO                    {do number of blocks}π        BEGINπ          FillChar (BUFFER, SizeOf (BUFFER), #32);π          LastLine := '';π          BlockRead (RepFile, BUFFER, 1, success);π          LastLine := asc2STR (BUFFER, 128);          {convert from ASCII}π          FOR Start := 1 TO Length (LastLine)         {string to TP string}π          DOπ           IF LastLine [start] = #227                 {#227 in QWK paks}π           THEN                                       {Marks eol}π             LastLine [start] := #13;π          Writeln(LastLine);π       END;π    UNTIL Eof(repfile) OR Finished;π    close(repfile);πEND;π                                                                                                    15     01-27-9412:15ALL                      FRANK VAN DER HAM        MkMsg Bugs               IMPORT              10     n¼HL {πFor all who work with the MkMsg toolbox and it's JAM unit, I share myπexperience with the deleting of messages.ππDespite a bugfix on this very subject from 1.02 to 1.03, I still cannotπdelete messages properly. I found out that the basis of the problem is theπhandling of the IDX file. First of all, the number of bytes written to theπIDX file was invalid and, secondly, a real bug was in the handling of theπ"sub text" where an array is declared as "array [1..xx]" and used as "arrayπ[0..xx], causing a field in a record to be overriden to an invalid value.ππThese are the changes I made to my MKMSGJAM.PAS file.ππLine 150:πChangeπ  TxtSubBuf: Array[1..TxtSubBufSize] of Char; {temp storage ... }πIntoπ  TxtSubBuf: Array[0..TxtSubBufSize-1] of Char; {temp storage ... }ππLine 831:πChangeπ    If JM^.TxtSubChars <= TxtSubBufSize ThenπIntoπ    If JM^.TxtSubChars <= TxtSubBufSize-1 ThenππLine 838:πChangeπ    If JM^.TxtSubChars <= TxtSubBufSize ThenπIntoπ    If JM^.TxtSubChars <= TxtSubBufSize-1 ThenππLine 1490:πChangeπ  BlockWrite(JM^.IdxFile, JamIdx^, JamIdxBufSize);πIntoπ  BlockWrite(JM^.IdxFile, JamIdx^, JM^.IdxRead);ππKeep on jammin' !ππ     16     02-03-9409:57ALL                      DAVID DANIEL ANDERSON    QWK packets to text      IMPORT              49     n¼T {DAT2TXT v0.90- Free DOS utility: Converts .QWK MESSAGES.DAT to text.}π{$V-,S-}πprogram DAT2TXT ;πuses dos ;πconstπ   Seperator = '---------------------------------------------------------------------------' ;π   herald    = '===========================================================================' ;πtypeπ   CharArray = array[1..6] of char ;  { to read in chunks }ππ   MSGDATHdr = record  { ALSO the format for SWAG files !!! }π      Status   : char ;π      MSGNum   : array [1..7] of char ;π      Date     : array [1..8] of char ;π      Time     : array [1..5] of char ;π      UpTO     : array [1..25] of char ;π      UpFROM   : array [1..25] of char ;π      Subject  : array [1..25] of char ;π      PassWord : array [1..12] of char ;π      ReferNum : array [1..8] of char ;π      NumChunk : CharArray ;π      Alive    : byte ;π      LeastSig : byte ;π      MostSig  : byte ;π      Reserved : array [1..3] of char ;π   end ;ππvarπ   F           : file ;π   txtfile     : text ;ππprocedure showhelp(problem:byte); {if any *foreseen* errors arise, we are sent}π                             { here to give a little help and exit peacefully }πconstπ progdata = 'DAT2TXT v0.90- Free DOS utility: Converts .QWK MESSAGES.DAT to text.';π progdat2 = '(By SWAG contributors.)';π usage    = 'Usage:  DAT2TXT infile(s) [/o]';π usag2    = 'The "/o" causes DAT2TXT to overwrite (not append to) existing messages.txt.';π note     = 'DOS * and ? wildcards ok with "infile(s)".  Output is always to MESSAGES.TXT.';πvarπ   message : string[80];πbeginπ   writeln(progdata);                  { just tell user what this program   }π   writeln(progdat2);                  { is and who wrote it                }π   writeln;π   writeln(usage);π   writeln(usag2);π   writeln(note);π   writeln;π   writeln('Error encountered:');π   case problem ofπ     1 : message := 'Incorrect number of parameters.';π     { plenty of room for other errors! }π   elseπ        message := 'Unknown error.';π   end;π   writeln(message);π   halt(problem);πend;ππfunction converttoupper(w : string) : string;πvarπ   cp  : integer;        {the position of the character to change.}πbeginπ     for cp := 1 to length(w) doπ         w[cp] := upcase(w[cp]);π     converttoupper := w;πend;ππfunction ArrayTOInteger ( B : CharArray ; Len : byte ) : longint ;ππvar I : byte ;π    S : string ;π    E : integer ;π    T : integer ;ππbeginπ   S := '' ;π   for I := 1 to Len doπ      if B[i] <> #32 then S := S + B[i] ;ππ   Val ( S, T, E );ππ   if E = 0 thenπ      ArrayToInteger := Tπ   elseπ      ArrayToInteger := 0 ;πend ;ππprocedure ReadWriteHdr ( var HDR : MSGDatHdr );πbeginπ   BlockRead ( F, Hdr, 1 );π   if ArrayToInteger ( Hdr.NumChunk, 6 ) <> 0 thenπ      with Hdr do beginπ         writeln ( txtfile, herald );π         write ( txtfile, 'Date: ', Date, ' (', Time, ')' );π         writeln ( txtfile, '' : 23, 'Number: ', MSGNum );π         write ( txtfile, 'From: ', UpFROM );π         writeln ( txtfile, '' : 14, 'Refer#: ', ReferNum );π         write ( txtfile, '  To: ', UpTO );π         write ( txtfile, '' : 15, 'Recvd: ' );π         if Status in ['-', '`', '^', '#'] thenπ            writeln ( txtfile, 'YES' )π         elseπ            writeln ( txtfile, 'NO' );π         write ( txtfile, 'Subj: ', Subject );π         writeln ( txtfile, '' : 16, 'Conf: ', '(', (MostSig * 256) + LeastSig, ')' );π         writeln ( txtfile, Seperator );π      end ;πend ;ππprocedure ReadMSG ( NumChunks : integer );πvarπ   Buff : array [1..128] of char ;π   J    : integer ;π   I    : byte ;ππbeginπ   for J := 1 to PRED ( NumChunks ) do beginπ      BlockRead ( F, Buff, 1 );π      for I := 1 to 128 doπ         if Buff [I] = #$E3 thenπ            writeln ( txtfile )π         elseπ            write ( txtfile, Buff [I] );π   end ;πend ;ππprocedure ReadMessage ( HDR : MSGDatHdr ; RelNum : longint ; var Chunks : integer );πbeginπ   Seek ( F, RelNum - 1 );π   ReadWriteHdr ( HDR );π   Chunks := ArrayToInteger ( HDR.NumChunk, 6 );π   if Chunks <> 0 then beginπ      ReadMsg ( Chunks );π      writeln ( txtfile );π   endπ   elseπ      Chunks := 1 ;πend ;ππvarπ   MSGHdr   : MSGDatHdr ;π   repordat : boolean ;π   ch       : char ;π   count    : integer ;π   chunks   : integer ;π   defsavefile : string ;π   fileinfo : searchrec ;π   fdt      : longint ;π   ps1,ps2  : string [2] ;π   fileexists,π   overwrite  : boolean ;π   response   : char ;ππ   dpath, tpath  : pathstr ;π   {epath & dpath are fully qualified pathnames of .dat & .txt files}ππ   ddir,  tdir   : dirstr ;π   dname, tname  : namestr ;π   d_ext, t_ext  : extstr ;π   txtfileinfo   : searchrec ;ππbeginπ   if ( paramcount < 1) or ( paramcount > 2) then showhelp(1);π   ps1 := converttoupper ( paramstr (1));π   if (ps1 = '/H') or (ps1 = '/?') orπ      (ps1 = '-H') or (ps1 = '-?') then showhelp(0);ππ   DefSaveFile := '' ;π   ps2 := '/A' ;π   if paramcount > 1 then ps2 := paramstr ( 2 );π   overwrite := (upcase ( ps2[2] ) = 'O');π   dpath := fexpand ( paramstr ( 1 ) );π   fsplit ( dpath, ddir, dname, d_ext );π   { break up path into components }π   findfirst ( dpath, anyfile, fileinfo );π   while doserror = 0 do beginπ      fsplit ( fexpand ( fileinfo.name ), tdir, tname, t_ext );π      dpath := ddir + fileinfo.name ;π      tpath := ddir + tname + '.TXT' ;π      Assign ( F, dpath );π      { whatever file .. ( MESSAGES.DAT for .QWK ) }π      Reset ( F, SizeOf ( MsgHdr ) );ππ      assign ( txtfile, tpath );π{$i-} reset ( txtfile ); {$i+}π      fileexists := (ioresult = 0);ππ      if fileexists then close ( txtfile );π      if fileexists and ( not overwrite ) thenπ         append ( txtfile )π      elseπ         rewrite ( txtfile );ππ      write ( 'DAT2TXT: ', dpath, ' to: ', tpath );π      Count := 2 ;                     { start at RECORD #2 }π      while Count < FileSize ( F ) do beginπ         ReadMessage ( MSGHdr, Count, Chunks );π         INC ( Count, Chunks );π      end ;ππ      getftime ( F, fdt );π      close ( F ); close ( txtfile ); reset ( txtfile );π      setftime ( txtfile , fdt );π      close ( txtfile );ππ      writeln ( ', done!' );π      findnext ( fileinfo );π   end ;πend.π               17     02-09-9411:50ALL                      LUCAS NEALAN             FIDONET Traffic          IMPORT              75     n¼╥╚ {π  The following source uses the FIDONET unit which will follow in the nextπmessage.. It is a modified version of the origionsl FIDOPAS archive: }ππUnit FidoNet;ππINTERFACEππUses Dos,π     Crt,π     StrnTTT5,π     MiscTTT5;ππTypeπ  NetMsg = recordπ    From,                            { Name of sender              }π    Too           : String[35];      { Name of receiver            }π    Subject       : String[71];      { Msg subject                 }π    DateTime      : String[19];      { Msg date/time, see below    }π    Times ,                          { Times message has been read }π    DestNode,                        { Destination node number     }π    OrgNode,                         { Originating node number     }π    Cost,                            { Cost - 0 if not supported   }π    OrgNet,                          { Originating net number      }π    DestNet       : word;            { Destination net number      }π    DateWritten,                     { Date/time written           }π    SentReceived  : longint;         { Date/time sent/rcvd         }π    ReplyTO,                         { # of next message in replys }π    Attr,                            { Message status bits         }π    NextReply     : word;            { Number of previous message  }π    AreaName   : String[20];         {AreaName (Only if Echomail)  }π  end;ππConstπ        _private    = $0001;π        _crash      = $0002;π        _received   = $0004;π        _sent       = $0008;π        _fileattach = $0010;π        _transit    = $0020;π        _orphan     = $0040;π        _killsent   = $0080;π        _local      = $0100;   { required on all locally entered messages! }π        _hold       = $0200;π        _direct     = $0400;π        _filereq    = $0800;π        _updatereq  = $8000;ππ      Status    : Array[1..12] Of String[3] = ('Jan','Feb','Mar','Apr',π                                               'May','Jun','Jul','Aug',π                                               'Sep','Oct','Nov','Dec');πVar Net    : NetMsg;ππFunction  NetMessage     : String;πFunction  GetPath(Var FName : String) : Boolean;πFunction  GetNet(GN : String) : String;πFunction  GetNode(GN : String) : String;πFunction  MsgDateStamp   : String;πFunction  LastMsgNum( _NetPath : String ) : Integer;πFunction  Hex (n : word) : String;πProcedure ExpandNodeNumbers(Var List : String; VAR TotalNumber : Integer );πProcedure Conv_NetNode(NetNode : String; VAR Net, Node : Word);ππIMPLEMENTATIONππFunction NetMessage : String;  { Returns a NetMessage header string }πVar Hdr : String;πBeginπ  Hdr := '';ππ  Hdr := PadLeft(Net.From,36,#0);π  Hdr := Hdr + PadLeft(Net.Too,36,#0)π             + PadLeft(Net.Subject,72,#0)π             + PadRight(Net.DateTime,19,' ')+#0π             + Chr(Lo(Net.Times))+Chr(Hi(Net.Times))π             + Chr(Lo(Net.DestNode))+Chr(Hi(Net.DestNode))π             + Chr(Lo(Net.OrgNode))+Chr(Hi(Net.OrgNode))π             + Chr(Lo(Net.Cost))+Chr(Hi(Net.Cost))π             + Chr(Lo(Net.OrgNet))+Chr(Hi(Net.OrgNet))π             + Chr(Lo(Net.DestNet))+Chr(Hi(Net.DestNet))π             + #0#0#0#0#0#0#0#0π             + Chr(Lo(Net.ReplyTo))+Chr(Hi(Net.ReplyTo))π             + Chr(Lo(Net.Attr))+Chr(Hi(Net.Attr))π             + Chr(Lo(Net.NextReply))+Chr(Hi(Net.NextReply))π             + Upper(Net.AreaName);π  NetMessage := Hdr;πEnd;ππFunction GetPath(Var FName : String) : Boolean;π{ Returns the FULL Path and filename for a file if it is found in the path. }πVar Str1,Str2 : String;π    NR        : Byte;π    HomeDir   : String;ππBeginπ  HomeDir := FExpand(FName);π  If Exist(HomeDir) Then Beginπ                  FName := HomeDir;π                  GetPath := True;π                  Exit;π                End;ππ  Str1 := GetEnv('PATH');π  For NR := 1 to Length(Str1) DO IF Str1[NR] = ';' Then Str1[NR] := ' ';π  For NR := 1 to WordCnt(Str1) DOπ   Beginπ    Str2 := ExtractWords(NR,1,Str1)+'\'+FName;π    IF Exist(Str2) Then Beginπ      FName := Str2;π      GetPath := True;π      Exit;π    End;π   End;π   GetPath := False;πEnd;ππFunction MsgDateStamp : String; { Creates Fido standard- 01 Jan 89 21:05:18 }πVar h,m,s,hs          : Word;   { header time/date stamp   }π    y,mo,d,dow        : Word;π    Tmp,π    o1,o2,o3          : String;ππBeginπ  o1 := '';π  o2 := '';π  o3 := '';π  tmp := '';π  GetDate(y,mo,d,dow);π  GetTime(h,m,s,hs);π  o1 := PadRight(Int_To_Str(d),2,'0');π  o2 := Status[mo];π  o3 := Last(2,Int_To_Str(y));π  Tmp := Concat( o1,' ',o2,' ',o3,'  ');π  o1 := PadRight(Int_To_Str(h),2,'0');π  o2 := PadRight(Int_To_Str(m),2,'0');π  o3 := PadRight(Int_To_Str(s),2,'0');π  Tmp := Tmp + Concat(o1,':',o2,':',o3);π  MsgDateStamp := Tmp;πEnd;ππFunction MsgToNum(Fnm : String ):Integer; { Used Internally by LastMsgNum }πVar p : Byte;πBeginπ  p        := Pos('.',Fnm);π  Fnm      := First(p-1,Fnm);π  MsgToNum := Str_To_Int(Fnm);πEnd;ππFunction LastMsgNum( _NetPath : String ) : Integer;π{ Returns the highest numbered xxx.MSG in NetPath directory }πVarπ    _Path   : String;π    Temp1,π    Temp2   : String;π    Len     : Byte;π    DxirInf  : SearchRec;π    Num,π    Num1    : Integer;ππBeginπ  Num   := 0;π  Num1  := 0;π  Temp1 := '';π  Temp2 := '';π  _Path := '';π  _Path := _NetPath + '\*.MSG';ππ  FindFirst( _Path, Archive, DxirInf );π  While DosError = 0 DOπ  Beginπ    Temp1 := DxirInf.Name;π    Num1 := MsgToNum(Temp1);π    IF Num1 > Num Then Num := Num1;π    FindNext(DxirInf);π  End;ππ  IF Num = 0 Then Num := 1;π  LastMsgNum := Num;πEnd;ππFunction Hex(N : Word) : String;π{ Converts an integer or word to it's Hex equivelent }πVarπ  L : string[16];π  BHi,π  BLo : byte;ππBeginπ  L := '0123456789abcdef';π  BHi := Hi(n);π  BLo := Lo(n);π  Hex := copy(L,succ(BHi shr 4),1) +π         copy(L,succ(BHi and 15),1) +π         copy(L,succ(BLo shr 4),1) +π         copy(L,succ(BLo and 15),1);πEnd;ππFunction GetNet( GN : String ) : String;π{ Returns the NET portion of a Net/Node string }πVar P : Byte;πBeginπ  P := Pos('/',GN);π  GetNet := First(P-1,GN);πEnd;ππFunction GetNode( GN : String ) : String;π{ Returns the NODE portion of a Net/Node string }πVar P : Byte;πBeginπ  P := Pos('/',GN);π  GetNode := Last(Length(GN)-P,GN);πEnd;ππProcedure ExpandNodeNumbers(Var List : String; VAR TotalNumber : Integer );π        { Expands a list of short form node numbers to thier proper       }π        { Net/Node representations. Example:                              }π        { The string: 170/100 101 102 5 114/12 15 17 166/225 226          }π        { Would return: 170/100 170/101 170/102 170/5 114/12 114/15 etc.. }πVar Net,NetNode  : String[10];π    HoldStr,π    WS1          : String;π    N1           : Integer;πBeginπ  Net := '';π  NetNode := '';π  HoldStr := '';π  WS1 := '';π  N1 := 0;π  TotalNumber := 0;π  TotalNumber := WordCnt(List);ππ  For N1 := 1 to TotalNumber DO Beginπ    WS1 := ExtractWords(N1,1,List);π    IF Pos('/',WS1) <> 0 Then Begin Net := GetNet(WS1)+'/'; NetNode := WS1;π    End ELSE NetNode := Net+WS1;π    HoldStr := HoldStr + ' ' + Strip('A',' ',NetNode);π  End;πEnd;ππProcedure Conv_NetNode(NetNode : String; VAR Net, Node : Word);π         { Returns NET and NODE as words from a Net/Node string }πVar WStr : String[6];πBeginπ  Wstr := GetNet(NetNode);π  Net  := Str_To_Int(Wstr);π  Wstr := GetNode(NetNode);π  Node := Str_To_Int(Wstr);πEnd;ππBeginπ  { Initialize the data structures }π  FillChar(Net,SizeOf(Net),#0);πEnd.ππ{ --------------------- DEMO PROGRAM -------------------------- }πProgram Test;ππUsesπ  Crt,π  FidoNet,π  StrnTTT5;      {TechnoJocks Turbo Toolkit StrnTTT5 unit}ππvarπ  NetPath   : String;ππProcedure Create_NetMessage(FileName : String );πVar LastOne,i : Integer;π    Msg_Name  : String;π    Attrib    : Word;π    MsgFil,π    Inputfile : Text;π    Header,π    S         : String;ππBeginπ  Header   := '';π  S        := '';π  LastOne  := 0;π  Msg_Name := '';π  Attrib   := _Local + _Private;π  With Net DO Beginπ    From      := 'Lucas Nealan';π    Too       := 'Anyone';π    Subject   := 'Testing the FidoNet Unit...';π    DateTime  := MsgDateStamp;π    Times     := 0;π    DestNode  := 0;π    OrgNode   := 100;π    Cost      := 0;π    OrgNet    := 31;π    DestNet   := 22;π    ReplyTo   := 0;π    Attr      := Attrib;π    NextReply := 0;π  End;π  Header := NetMessage;π  LastOne := LastMsgNum(NetPath);π  Inc(LastOne);π  Msg_Name := NetPath+'\'+Int_To_Str(LastOne)+'.MSG';π  Assign(MsgFil, Msg_Name );π  Rewrite(MsgFil);π  WriteLn(MsgFil,Header);π  Assign(InputFile, FileName);π  Reset(InputFile);π  WriteLn(MsgFil,#1'INTL 20:22/0 20:31/100');π  WriteLn(MsgFil,#1'PID Lucas'' *.MSG Util');π  WriteLn(MsgFil,^A'FLAGS DIR');π  While not Eof(InputFile) do beginπ    ReadLn(InputFile,S);π    WriteLn(MsgFil,S);π  end;π  Flush(MsgFil);π  Close(MsgFil);π  Close(InputFile);πend;ππbeginπ  ClrScr;π  WriteLn;π  WriteLn('Posting file: '+ParamStr(1));π  WriteLn;π  NetPath := 'D:\FD\NETMAIL';π  Create_NetMessage(ParamStr(1));πend.ππ  The INTL Kludge line is used to send messages through non standard networkπzones (20 in this example).  For fido standard zone 1 you may specify just theπorigin net and node as well as destination net and zone and it will default toπzone 1.  Also with the direct flag you may either use the _Direct in the statusπor add your own FLAGS DIR kludge.ππ   Good luck!ππ                                        Lucas Nealanπ                                      Real World Programmingππ                                                                                       18     05-25-9408:00ALL                      TRYGVE GUDMUNDSEN        Numbers in QWK packets   SWAG9405            17     n¼   {πTH> Apparently this contains the filepositions of the records (and also theπTH> conference numbers?) but the numbers are not in normal format. Can somebodyπTH>  please explain the format of this file and how to convert these numbers toπTH> and from something TP can work with?ππThere is supposed to be at least two doc's explaining the QWK format. I haveπhere a unit that converts the integer to basicreal (i guess it's what youπneed..) I'm sorry I can't remember the of the doc's..ππ------------------- 8<π}πUnit BasConv;ππ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;π  Expon: Integer;ππ  Beginπ  Expon := ((InValue shr 24) and $ff) - 152;π  Temp := (InValue and $007FFFFF) or $00800000;π  If Expon < 0 Thenπ    Temp := Temp shr Abs(Expon)π  Elseπ    Temp := Temp shl Expon;π  If (InValue and $00800000) <> 0 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.π