home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / mksmvp10.zip / MKMSGHUD.PAS < prev    next >
Pascal/Delphi Source File  |  1997-09-24  |  48KB  |  1,741 lines

  1. Unit MKMsgHud;        {Hudson/QuickBbs-style Message Base}
  2.  
  3. {$I MKB.Def}
  4.  
  5.  
  6.  
  7. {
  8.      MKMsgHud - Copyright 1993 by Mark May - MK Software
  9.      You are free to use this code in your programs, however
  10.      it may not be included in Source/TPU function libraries
  11.      without my permission.
  12.  
  13.      Mythical Kingom Tech BBS (513)237-7737 HST/v32
  14.      FidoNet: 1:110/290
  15.      Rime: ->MYTHKING
  16.      You may also reach me at maym@dmapub.dma.org
  17. }
  18.  
  19.  
  20. {$X+}
  21.  
  22.  
  23. Interface
  24.  
  25.  
  26. Uses MKMsgAbs, MKGlobT, MKString, MKFile, Use32;
  27.  
  28. {$I Struct.Hud}
  29.  
  30.  
  31. Const TxtSize = 64;
  32. Const SeekSize = 250;
  33. Const YourSize = 100;
  34.  
  35. Const HudsonFlushing: Boolean = True;
  36. Const HudsonLast: String = '';
  37. Const HudsonEcho: String = '';
  38.  
  39. Type TxtRecsType = Array[1..TxtSize] of MsgTxtType;
  40. Type SeekArrayType = Array[1..SeekSize] of MsgIdxType;
  41.  
  42. Type YourSearchType = Record
  43.   NumRead: Word;
  44.   SeekStart: Integer;
  45.   CurrPos: Integer;
  46.   MsgFound: Boolean;
  47.   Name: String[35];
  48.   Handle: String[35];
  49.   SearchArray: Array[1..YourSize] of String[35];
  50.   End;
  51.  
  52.  
  53. Type HudsonMsgType = Record
  54.   MsgPath: String[50];                 {Message base directory}
  55.   MsgInfoFile: File;
  56.   MsgTxtFile: File;
  57.   MsgHdrFile: File;
  58.   MsgToIdxFile: File;
  59.   MsgIdxFile: File;
  60.   Opened: Boolean;
  61.   Locked: Boolean;
  62.   Error: SmallWord; {0=no error}
  63.   MsgHdr: MsgHdrType;                  {Current message header}
  64.   MsgInfo: MsgInfoType;                {MsgInfo record}
  65.   MsgPos: SmallWord;                        {MsgHdr seek position of current rec}
  66.   SeekNumRead: Word;                   {Number of records in the array}
  67.   SeekPos: SmallInt;                    {Current position in array}
  68.   SeekStart: SmallWord;                     {File Pos of 1st record in Idx Array}
  69.   SeekOver: Boolean;                   {More idx records?}
  70.   CurrMsgNum: SmallWord;                    {Current Seek Msg number}
  71.   CurrTxtRec: SmallWord;                    {Current txtrec in current msg}
  72.   CurrTxtPos: SmallWord;                    {Current position in current txtrec}
  73.   EOM: Boolean;                        {end of message text}
  74.   OrigPoint: SmallWord;                     {Point Addr orig}
  75.   DestPoint: SmallWord;                     {Point Addr destination}
  76.   Echo: Boolean;                       {Should message be exported}
  77.   CRLast: Boolean;                     {Last char was CR #13}
  78.   Area: SmallWord;
  79.   MT: MsgMailType;
  80.   End;
  81.  
  82.  
  83. Type HudsonMsgObj = Object(AbsMsgObj)  {Message Export Object}
  84.   MsgRec: ^HudsonMsgType;
  85.   MsgChars: ^TxtRecsType;
  86.   SeekArray: ^SeekArrayType;
  87.   YourInfo: ^YourSearchType;
  88.   Constructor Init; {Initialize}
  89.   Destructor Done; Virtual; {Done}
  90.   Procedure MsgStartUp; Virtual; {Setup message/read header}
  91.   Procedure MsgTxtStartUp; Virtual; {Setup message text}
  92.   Function  EOM: Boolean; Virtual; {No more msg text}
  93.   Function  GetChar: Char; Virtual; {Get msg text character}
  94.   Function  NextChar(Var Rec: SmallWord; Var PPos: SmallWord): Boolean;
  95.                                        {internal to position for char}
  96.   Function  GetString(MaxLen: Word): String; Virtual; {Get SmallWordwrapped string}
  97.   Function  WasWrap: Boolean; Virtual; {Last line was soft wrapped no CR}
  98.   Procedure SeekFirst(MsgNum: LongInt); Virtual; {Seek msg number}
  99.   Procedure SeekNext; Virtual; {Find next matching msg}
  100.   Procedure SeekPrior; Virtual; {Find prior matching msg}
  101.   Procedure SeekRead(NumToRead: Word); {Refill seek array}
  102.   Function  GetFrom: String; Virtual; {Get from name on current msg}
  103.   Function  GetTo: String;Virtual; {Get to name on current msg}
  104.   Function  GetSubj: String; Virtual; {Get subject on current msg}
  105.   Function  GetCost: Word; Virtual; {Get cost of current msg}
  106.   Function  GetDate: String; Virtual; {Get date of current msg}
  107.   Function  GetTime: String; Virtual; {Get time of current msg}
  108.   Function  GetRefer: LongInt; Virtual; {Get reply to of current msg}
  109.   Function  GetSeeAlso: LongInt; Virtual; {Get see also of current msg}
  110.   Function  GetMsgNum: LongInt; Virtual; {Get message number}
  111.   Procedure GetOrig(Var Addr: AddrType); Virtual; {Get origin address}
  112.   Procedure GetDest(Var Addr: AddrType); Virtual; {Get destination address}
  113.   Function  IsLocal: Boolean; Virtual; {Is current msg local}
  114.   Function  IsCrash: Boolean; Virtual; {Is current msg crash}
  115.   Function  IsKillSent: Boolean; Virtual; {Is current msg kill sent}
  116.   Function  IsSent: Boolean; Virtual; {Is current msg sent}
  117.   Function  IsFAttach: Boolean; Virtual; {Is current msg file attach}
  118.   Function  IsReqRct: Boolean; Virtual; {Is current msg request receipt}
  119.   Function  IsReqAud: Boolean; Virtual; {Is current msg request audit}
  120.   Function  IsRetRct: Boolean; Virtual; {Is current msg a return receipt}
  121.   Function  IsFileReq: Boolean; Virtual; {Is current msg a file request}
  122.   Function  IsRcvd: Boolean; Virtual; {Is current msg received}
  123.   Function  IsPriv: Boolean; Virtual; {Is current msg priviledged/private}
  124.   Function  IsDeleted: Boolean; Virtual; {Is current msg deleted}
  125.   Function  IsEchoed: Boolean; Virtual; {Is current msg unmoved echomail msg}
  126.   Procedure YoursFirst(Name: String; Handle: String); Virtual; {Search for mail to caller}
  127.   Procedure YoursNext; Virtual; {Search for next message}
  128.   Function  YoursFound: Boolean; Virtual; {Found a message}
  129.   Procedure SetDest(Var Addr: AddrType); Virtual; {Set Zone/Net/Node/Point for Dest}
  130.   Procedure SetOrig(Var Addr: AddrType); Virtual; {Set Zone/Net/Node/Point for Orig}
  131.   Procedure SetFrom(Name: String); Virtual; {Set message from}
  132.   Procedure SetTo(Name: String); Virtual; {Set message to}
  133.   Procedure SetSubj(Str: String); Virtual; {Set message subject}
  134.   Procedure SetCost(SCost: Word); Virtual; {Set message cost}
  135.   Procedure SetRefer(SRefer: LongInt); Virtual; {Set message reference}
  136.   Procedure SetSeeAlso(SAlso: LongInt); Virtual; {Set message see also}
  137.   Procedure SetDate(SDate: String); Virtual; {Set message date}
  138.   Procedure SetTime(STime: String); Virtual; {Set message time}
  139.   Procedure SetEcho(ES: Boolean); Virtual; {Set echo status}
  140.   Procedure SetMsgAttr(Setting: Boolean; Mask: SmallWord);
  141.   Procedure SetNetAttr(Setting: Boolean; Mask: SmallWord);
  142.   Procedure SetLocal(LS: Boolean); Virtual; {Set local status}
  143.   Procedure SetRcvd(RS: Boolean); Virtual; {Set received status}
  144.   Procedure SetPriv(PS: Boolean); Virtual; {Set priveledge vs public status}
  145.   Procedure SetCrash(SS: Boolean); Virtual; {Set crash netmail status}
  146.   Procedure SetKillSent(SS: Boolean); Virtual; {Set kill/sent netmail status}
  147.   Procedure SetSent(SS: Boolean); Virtual; {Set sent netmail status}
  148.   Procedure SetFAttach(SS: Boolean); Virtual; {Set file attach status}
  149.   Procedure SetReqRct(SS: Boolean); Virtual; {Set request receipt status}
  150.   Procedure SetReqAud(SS: Boolean); Virtual; {Set request audit status}
  151.   Procedure SetRetRct(SS: Boolean); Virtual; {Set return receipt status}
  152.   Procedure SetFileReq(SS: Boolean); Virtual; {Set file request status}
  153.   Procedure DoString(Str: String); Virtual; {Add string to message text}
  154.   Procedure DoChar(Ch: Char); Virtual; {Add character to message text}
  155.   Procedure DoStringLn(Str: String); Virtual; {Add string and newline to msg text}
  156.   Function  WriteMsg: Word; Virtual; {Write msg to message base}
  157.   Function  OpenMsgBase: Word; Virtual; {Individual msg open}
  158.   Function  CloseMsgBase: Word; Virtual; {Individual msg close}
  159.   Function  SeekEnd: Word; Virtual; {Seek to eof for msg base files}
  160.   Function  SeekMsgBasePos(Position: Word): Word; Virtual; {Seek to pos of Msg Base File}
  161.   Function  Check: SmallWord; Virtual; {Check if msg base is ok}
  162.   Function  CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word; Virtual;{Create initial msg base files}
  163.   Function  LockMsgBase: Boolean; Virtual; {Lock msg base for updating}
  164.   Function  UnlockMsgBase: Boolean; Virtual; {Unlock msg base after updating}
  165.   Function  WriteMailIdx(FN: String; MsgPos: SmallWord): SmallWord; Virtual;
  166.     {Write Netmail or EchoMail.Bbs}
  167.   Function  MsgBaseSize: SmallWord; Virtual; {Number of msg base index records}
  168.   Function  GetNumActive: SmallWord; Virtual; {Get number of active messages}
  169.   Function  GetHighMsgNum: LongInt; Virtual; {Get highest msg number}
  170.   Function  GetLowMsgNum: LongInt; Virtual; {Get lowest msg number}
  171.   Procedure StartNewMsg; Virtual; {Initialize message}
  172.   Procedure SetMsgPath(MP: String); Virtual;
  173.   Function  SeekFound:Boolean; Virtual; {Seek msg found}
  174.   Procedure SetMailType(MT: MsgMailType); Virtual; {Set message base type}
  175.   Function  GetSubArea: Word; Virtual; {Get sub area number}
  176.   Procedure ReWriteHdr; Virtual; {Rewrite msg header after changes}
  177.   Procedure DeleteMsg; Virtual; {Delete current message}
  178.   Function  GetMsgLoc: LongInt; Virtual; {To allow reseeking to message}
  179.   Procedure SetMsgLoc(ML: LongInt); Virtual; {Reseek to message}
  180.   Function  NumberOfMsgs: LongInt; Virtual; {Number of messages}
  181.   Function  GetLastRead(UNum: LongInt): LongInt; Virtual; {Get last read for user num}
  182.   Procedure SetLastRead(UNum: LongInt; LR: LongInt); Virtual; {Set last read}
  183.   Procedure GetAllLastRead(UNum: LongInt; Var LR: LastReadType); Virtual; {all areas}
  184.   Procedure GetHighest(Var LR: LastReadType); Virtual; {Get highest all areas}
  185.   Function  GetTxtPos: LongInt; Virtual;
  186.   Procedure SetTxtPos(TP: LongInt); Virtual;
  187.   Function  MsgBaseExists: Boolean; Virtual;
  188.   End;
  189.  
  190. Type HudsonMsgPtr = ^HudsonMsgObj;
  191.  
  192. Implementation
  193.  
  194. Constructor HudsonMsgObj.Init;
  195.   Begin
  196.   New(MsgRec);
  197.   New(MsgChars);
  198.   New(SeekArray);
  199.   New(YourInfo);
  200.   If ((MsgRec = Nil) Or (MsgChars = Nil) or (SeekArray = Nil) or (YourInfo = Nil)) Then
  201.     Begin
  202.     If MsgRec <> Nil Then
  203.       Dispose(MsgRec);
  204.     If MsgChars <> Nil Then
  205.       Dispose(MsgChars);
  206.     If SeekArray <> Nil Then
  207.       Dispose(SeekArray);
  208.     If YourInfo <> Nil Then
  209.       Dispose(YourInfo);
  210.     Fail;
  211.     Exit;
  212.     End;
  213.   MsgRec^.MsgPath := '';
  214.   MsgRec^.Opened := False;
  215.   MsgRec^.Locked := False;
  216.   MsgRec^.Error := 0;
  217.   End;
  218.  
  219.  
  220. Procedure HudsonMsgObj.YoursFirst(Name: String; Handle: String);
  221.   Begin
  222.   YourInfo^.NumRead := 0;
  223.   YourInfo^.SeekStart := 0;
  224.   YourInfo^.CurrPos := 1;
  225.   YourInfo^.MsgFound := False;
  226.   YourInfo^.Name := Copy(StripBoth(Upper(Name), ' '),1, 35);
  227.   YourInfo^.Handle := Copy(StripBoth(Upper(Handle), ' '),1,35);
  228.   YoursNext;
  229.   End;
  230.  
  231.  
  232. Procedure HudsonMsgObj.YoursNext;
  233.   Var
  234.     SearchOver: Boolean;
  235.  
  236.   Begin
  237.   Inc(YourInfo^.CurrPos);
  238.   SearchOver := False;
  239.   YourInfo^.MsgFound := False;
  240.   While Not SearchOver Do
  241.     Begin
  242.     If YourInfo^.CurrPos > YourInfo^.NumRead Then
  243.       Begin
  244.       Inc(YourInfo^.SeekStart, YourInfo^.NumRead);
  245.       YourInfo^.CurrPos := 1;
  246.       Seek(MsgRec^.MsgToIdxFile, YourInfo^.SeekStart);
  247.       If IoResult <> 0 Then
  248.         YourInfo^.NumRead := 0;
  249.       If Not shRead(MsgRec^.MsgToIdxFile, YourInfo^.SearchArray,
  250.       YourSize, YourInfo^.NumRead) Then
  251.         Begin
  252.         MsgRec^.Error := 1000;
  253.         YourInfo^.NumRead := 0;
  254.         End;
  255.       End;
  256.     If YourInfo^.NumRead = 0 Then
  257.       SearchOver := True
  258.     Else
  259.       Begin
  260.       If (((Upper(YourInfo^.SearchArray[YourInfo^.CurrPos]) = YourInfo^.Name) Or
  261.       (Upper(YourInfo^.SearchArray[YourInfo^.CurrPos]) = YourInfo^.Handle)) And
  262.       ((YourInfo^.CurrPos > 0) And (YourInfo^.CurrPos <= YourInfo^.NumRead)))Then
  263.         Begin
  264.         MsgRec^.MsgPos := YourInfo^.SeekStart + YourInfo^.CurrPos - 1;
  265.         MsgStartUp;
  266.         If Not (IsRcvd)  Then
  267.           Begin
  268.           YourInfo^.MsgFound := True;
  269.           SearchOver := True;
  270.           End;
  271.         End;
  272.       End;
  273.     If Not YourInfo^.MsgFound Then
  274.       Inc(YourInfo^.CurrPos);
  275.     End;
  276.   End;
  277.  
  278.  
  279. Function  HudsonMsgObj.YoursFound: Boolean;
  280.   Begin
  281.   YoursFound := YourInfo^.MsgFound;
  282.   End;
  283.  
  284.  
  285. Function HudsonMsgObj.WasWrap: Boolean;
  286.   Begin
  287.   WasWrap := LastSoft;
  288.   End;
  289.  
  290.  
  291. Destructor HudsonMsgObj.Done;
  292.   Begin
  293.   Dispose(MsgRec);
  294.   Dispose(MsgChars);
  295.   Dispose(SeekArray);
  296.   Dispose(YourInfo);
  297.   End;
  298.  
  299.  
  300. Procedure HudsonMsgObj.MsgStartUp;
  301.   Var
  302.     NumRead: Word;
  303.  
  304.   Begin
  305.   MsgRec^.Error := SeekMsgBasePos(MsgRec^.MsgPos);
  306.   MsgRec^.OrigPoint := 0;
  307.   MsgRec^.DestPoint := 0;
  308.   If MsgRec^.Error = 0 Then
  309.     Begin
  310.     If not shRead(MsgRec^.MsgHdrFile, MsgRec^.MsgHdr,1, NumRead) Then
  311.       MsgRec^.Error := MKFileError;
  312.     End;
  313.   End;
  314.  
  315.  
  316. Procedure HudsonMsgObj.SetMsgAttr(Setting: Boolean; Mask: SmallWord);
  317.   Begin
  318.   If Setting Then
  319.     MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr or Mask
  320.   Else
  321.     MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr and (Not Mask);
  322.   End;
  323.  
  324.  
  325.  
  326. Procedure HudsonMsgObj.SetRcvd(RS: Boolean);
  327.   Begin
  328.   SetMsgAttr(RS, maRcvd);
  329.   End;
  330.  
  331.  
  332. Procedure HudsonMsgObj.SetPriv(PS: Boolean);
  333.   Begin
  334.   SetMsgAttr(PS, maPriv);
  335.   End;
  336.  
  337.  
  338. Procedure HudsonMsgObj.SetNetAttr(Setting: Boolean; Mask: SmallWord);
  339.   Begin
  340.   If Setting Then
  341.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr Or Mask
  342.   Else
  343.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr And (Not Mask);
  344.   End;
  345.  
  346.  
  347. Procedure HudsonMsgObj.SetSeeAlso(SAlso: LongInt);
  348.   Begin
  349.   MsgRec^.MsgHdr.SeeAlso := SAlso;
  350.   End;
  351.  
  352.  
  353. Procedure HudsonMsgObj.SetFrom(Name: String); {Set msg from}
  354.   Begin
  355.   MsgRec^.MsgHdr.MsgFrom := Name;
  356.   End;
  357.  
  358.  
  359. Procedure HudsonMsgObj.SetTo(Name: String); {Set msg to}
  360.   Begin
  361.   MsgRec^.MsgHdr.MsgTo := Name;
  362.   End;
  363.  
  364.  
  365. Procedure HudsonMsgObj.SetSubj(Str: String); {Set msg subject}
  366.   Begin
  367.   MsgRec^.MsgHdr.Subj := Str;
  368.   End;
  369.  
  370.  
  371. Function HudsonMsgObj.GetFrom: String;
  372.   Begin
  373.   GetFrom := MsgRec^.MsgHdr.MsgFrom;
  374.   End;
  375.  
  376.  
  377. Function HudsonMsgObj.GetTo: String;
  378.   Begin
  379.   GetTo := MsgRec^.MsgHdr.MsgTo;
  380.   End;
  381.  
  382.  
  383. Function HudsonMsgObj.GetSubj: String;
  384.   Begin
  385.   GetSubj := MsgRec^.MsgHdr.Subj;
  386.   End;
  387.  
  388.  
  389. Function HudsonMsgObj.GetCost: Word;
  390.   Begin
  391.   GetCost := MsgRec^.MsgHdr.Cost;
  392.   End;
  393.  
  394.  
  395. Function HudsonMsgObj.GetDate: String;            {Get date of current msg}
  396.   Begin
  397.   GetDate := MsgRec^.MsgHdr.Date;
  398.   End;
  399.  
  400.  
  401. Function HudsonMsgObj.GetTime: String;            {Get time of current msg}
  402.   Begin
  403.   GetTime := MsgRec^.MsgHdr.Time;
  404.   End;
  405.  
  406.  
  407. Function HudsonMsgObj.GetRefer: LongInt;
  408.   Begin
  409.   GetRefer := MsgRec^.MsgHdr.ReplyTo;
  410.   End;
  411.  
  412.  
  413. Function HudsonMsgObj.GetSeeAlso: LongInt;
  414.   Begin
  415.   GetSeeAlso := MsgRec^.MsgHdr.SeeAlso;
  416.   End;
  417.  
  418.  
  419. Function HudsonMsgObj.GetMsgNum: LongInt;
  420.   Begin
  421.   GetMsgNum := MsgRec^.MsgHdr.MsgNum;
  422.   End;
  423.  
  424.  
  425. Procedure HudsonMsgObj.GetOrig(Var Addr: AddrType);
  426.   Begin
  427.   Addr.Zone := MsgRec^.MsgHdr.OrigZone;
  428.   Addr.Net := MsgRec^.MsgHdr.OrigNet;
  429.   Addr.Node := MsgRec^.MsgHdr.OrigNode;
  430.   Addr.Point := MsgRec^.OrigPoint;
  431.   End;
  432.  
  433.  
  434. Procedure HudsonMsgObj.GetDest(Var Addr: AddrType);
  435.   Begin
  436.   Addr.Zone := MsgRec^.MsgHdr.DestZone;
  437.   Addr.Net := MsgRec^.MsgHdr.DestNet;
  438.   Addr.Node := MsgRec^.MsgHdr.DestNode;
  439.   Addr.Point := MsgRec^.DestPoint;
  440.   End;
  441.  
  442.  
  443. Function HudsonMsgObj.IsLocal: Boolean;
  444.   Begin
  445.   IsLocal := ((MsgRec^.MsgHdr.MsgAttr and maLocal) <> 0);
  446.   End;
  447.  
  448.  
  449. Function HudsonMsgObj.IsCrash: Boolean;
  450.   Begin
  451.   IsCrash := ((MsgRec^.MsgHdr.NetAttr and naCrash) <> 0);
  452.   End;
  453.  
  454.  
  455. Function HudsonMsgObj.IsKillSent: Boolean;
  456.   Begin
  457.   IsKillSent := ((MsgRec^.MsgHdr.NetAttr and naKillSent) <> 0);
  458.   End;
  459.  
  460.  
  461. Function HudsonMsgObj.IsSent: Boolean;
  462.   Begin
  463.   IsSent := ((MsgRec^.MsgHdr.NetAttr and naSent) <> 0);
  464.   End;
  465.  
  466.  
  467. Function HudsonMsgObj.IsFAttach: Boolean;
  468.   Begin
  469.   IsFAttach := ((MsgRec^.MsgHdr.NetAttr and naFAttach) <> 0);
  470.   End;
  471.  
  472.  
  473. Function HudsonMsgObj.IsReqRct: Boolean;
  474.   Begin
  475.   IsReqRct := ((MsgRec^.MsgHdr.NetAttr and naReqRcpt) <> 0);
  476.   End;
  477.  
  478.  
  479. Function HudsonMsgObj.IsReqAud: Boolean;
  480.   Begin
  481.   IsReqAud := ((MsgRec^.MsgHdr.NetAttr and naReqAudit) <> 0);
  482.   End;
  483.  
  484.  
  485. Function HudsonMsgObj.IsRetRct: Boolean;
  486.   Begin
  487.   IsRetRct := ((MsgRec^.MsgHdr.NetAttr and naRetRcpt) <> 0);
  488.   End;
  489.  
  490.  
  491. Function HudsonMsgObj.IsFileReq: Boolean;
  492.   Begin
  493.   IsFileReq := ((MsgRec^.MsgHdr.NetAttr and naFileReq) <> 0);
  494.   End;
  495.  
  496.  
  497. Function HudsonMsgObj.IsRcvd: Boolean;
  498.   Begin
  499.   IsRcvd := ((MsgRec^.MsgHdr.MsgAttr and maRcvd) <> 0);
  500.   End;
  501.  
  502.  
  503. Function HudsonMsgObj.IsPriv: Boolean;
  504.   Begin
  505.   IsPriv := ((MsgRec^.MsgHdr.MsgAttr and maPriv) <> 0);
  506.   End;
  507.  
  508.  
  509. Function HudsonMsgObj.IsDeleted: Boolean;
  510.   Begin
  511.   IsDeleted := ((MsgRec^.MsgHdr.MsgAttr and maDeleted) <> 0);
  512.   End;
  513.  
  514.  
  515. Function HudsonMsgObj.IsEchoed: Boolean;
  516.   Begin
  517.   IsEchoed := MsgRec^.Echo;
  518. {  IsEchoed := ((MsgRec^.MsgHdr.MsgAttr and maUnmovedEcho) <> 0); }
  519. {  IsUnmovedNet := ((MsgRec^.MsgHdr.MsgAttr and maUnmovedNet) <> 0);}
  520.   End;
  521.  
  522.  
  523. Procedure HudsonMsgObj.MsgTxtStartUp;
  524.   Var
  525.     NumRead: Word;
  526.     MaxTxt: SmallWord;
  527.  
  528.   Begin
  529.   LastSoft := False;
  530.   If MsgRec^.MsgHdr.NumRecs > TxtSize Then
  531.     MaxTxt := TxtSize
  532.   Else
  533.     MaxTxt := MsgRec^.MsgHdr.NumRecs;
  534.   Seek(MsgRec^.MsgTxtFile, MsgRec^.MsgHdr.StartRec);
  535.   If IoResult <> 0 Then
  536.     MsgRec^.Error := 2222;
  537.   If not shRead(MsgRec^.MsgTxtFile, MsgChars^, MaxTxt, NumRead) Then
  538.     MsgRec^.Error := MKFileError;
  539.   If NumRead <> MaxTxt Then
  540.     MsgRec^.Error := 1111;
  541.   MsgRec^.CurrTxtRec := 1;
  542.   MsgRec^.CurrTxtPos := 1;
  543.   MsgRec^.EOM := False;
  544.   End;
  545.  
  546.  
  547. Function HudsonMsgObj.NextChar(Var Rec: SmallWord; Var PPos: SmallWord): Boolean;
  548.   Var
  549.     MoreNext: Boolean;
  550.  
  551.   Begin
  552.   MoreNext := True;
  553.   NextChar := True;
  554.   While MoreNext Do
  555.     Begin
  556.     If ((Rec > MsgRec^.MsgHdr.NumRecs) or (Rec > TxtSize)) Then
  557.       MoreNext := False
  558.     Else
  559.       Begin
  560.       If (PPos > Length(MsgChars^[Rec])) Then
  561.         Begin
  562.         Inc(Rec);
  563.         PPos := 1;
  564.         End
  565.       Else
  566.         MoreNext := False;
  567.       End;
  568.     End;
  569.   If ((Rec > MsgRec^.MsgHdr.NumRecs) or (Rec > TxtSize)) Then
  570.     NextChar := False;
  571.   End;
  572.  
  573.  
  574. Function HudsonMsgObj.GetChar: Char;
  575.   Var
  576.     MoreNext: Boolean;
  577.  
  578.   Begin
  579.   MoreNext := True;
  580.   If ((MsgRec^.CurrTxtRec <= MsgRec^.MsgHdr.NumRecs) and
  581.   (MsgRec^.CurrTxtRec <= TxtSize)) Then
  582.     Begin
  583.     While MoreNext Do
  584.       Begin
  585.       If ((MsgRec^.CurrTxtRec > MsgRec^.MsgHdr.NumRecs) Or
  586.       (MsgRec^.CurrTxtRec > TxtSize)) Then
  587.         MoreNext := False
  588.       Else
  589.         Begin
  590.         If (MsgRec^.CurrTxtPos > Length(MsgChars^[MsgRec^.CurrTxtRec])) Then
  591.           Begin
  592.           Inc(MsgRec^.CurrTxtRec);
  593.           MsgRec^.CurrTxtPos := 1;
  594.           End
  595.         Else
  596.           MoreNext := False;
  597.         End;
  598.       End;
  599.     If ((MsgRec^.CurrTxtRec > MsgRec^.MsgHdr.NumRecs) Or
  600.     (MsgRec^.CurrTxtRec > TxtSize)) Then
  601.       MsgRec^.EOM := True;
  602.     End
  603.   Else
  604.     MsgRec^.EOM := True;
  605.   If MsgRec^.EOM Then
  606.     Begin
  607.     GetChar := #0;
  608.     End
  609.   Else
  610.     GetChar := MsgChars^[MsgRec^.CurrTxtRec][MsgRec^.CurrTxtPos];
  611.   Inc(MsgRec^.CurrTxtPos);
  612.   End;
  613.  
  614.  
  615. Function HudsonMsgObj.EOM: Boolean;
  616.   Begin
  617.   EOM := MsgRec^.EOM;
  618.   End;
  619.  
  620.  
  621. Procedure HudsonMsgObj.StartNewMsg;  {Initialize message}
  622.   Const
  623.     Blank = '* Blank *';
  624.  
  625.   Begin
  626.   MsgRec^.CurrTxtRec := 1;
  627.   MsgRec^.CurrTxtPos := 0;
  628.   FillChar(MsgRec^.MsgHdr, SizeOf(MsgRec^.MsgHdr), #0);
  629.   MsgRec^.Echo := False;
  630.   MsgRec^.MsgHdr.Time := '00:00';
  631.   MsgRec^.MsgHdr.Date := '00-00-00';
  632.   MsgRec^.MsgHdr.MsgTo := Blank;
  633.   MsgRec^.MsgHdr.MsgFrom := Blank;
  634.   MsgRec^.MsgHdr.Subj := Blank;
  635.   MsgRec^.CRLast := True;
  636.   End;
  637.  
  638.  
  639. Procedure HudsonMsgObj.SetEcho(ES: Boolean); {Set echo status}
  640.   Begin
  641.   MsgRec^.Echo := ES;
  642.   End;
  643.  
  644.  
  645. Procedure HudsonMsgObj.SetLocal(LS: Boolean); {Set local status}
  646.   Begin
  647.   If LS Then
  648.     MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr or maLocal
  649.   Else
  650.     MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.Msgattr and (Not maLocal);
  651.   End;
  652.  
  653.  
  654. Procedure HudsonMsgObj.SetCrash(SS: Boolean); {Set crash netmail status}
  655.   Begin
  656.   If SS Then
  657.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naCrash
  658.   Else
  659.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naCrash);
  660.   End;
  661.  
  662.  
  663. Procedure HudsonMsgObj.SetKillSent(SS: Boolean); {Set kill/sent netmail status}
  664.   Begin
  665.   If SS Then
  666.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naKillSent
  667.   Else
  668.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naKillSent);
  669.   End;
  670.  
  671.  
  672.  
  673. Procedure HudsonMsgObj.SetSent(SS: Boolean); {Set sent netmail status}
  674.   Begin
  675.   If SS Then
  676.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naSent
  677.   Else
  678.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naSent);
  679.   End;
  680.  
  681.  
  682.  
  683. Procedure HudsonMsgObj.SetFAttach(SS: Boolean); {Set file attach status}
  684.   Begin
  685.   If SS Then
  686.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naFAttach
  687.   Else
  688.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naFAttach);
  689.   End;
  690.  
  691.  
  692.  
  693. Procedure HudsonMsgObj.SetReqRct(SS: Boolean); {Set request receipt status}
  694.   Begin
  695.   If SS Then
  696.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naReqRcpt
  697.   Else
  698.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naReqRcpt);
  699.   End;
  700.  
  701.  
  702.  
  703. Procedure HudsonMsgObj.SetReqAud(SS: Boolean); {Set request audit status}
  704.   Begin
  705.   If SS Then
  706.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naReqAudit
  707.   Else
  708.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naReqAudit);
  709.   End;
  710.  
  711.  
  712.  
  713. Procedure HudsonMsgObj.SetRetRct(SS: Boolean); {Set return receipt status}
  714.   Begin
  715.   If SS Then
  716.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naRetRcpt
  717.   Else
  718.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naRetRcpt);
  719.   End;
  720.  
  721.  
  722.  
  723. Procedure HudsonMsgObj.SetFileReq(SS: Boolean); {Set file request status}
  724.   Begin
  725.   If SS Then
  726.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr or naFileReq
  727.   Else
  728.     MsgRec^.MsgHdr.NetAttr := MsgRec^.MsgHdr.NetAttr and (Not naFileReq);
  729.   End;
  730.  
  731.  
  732. Procedure HudsonMsgObj.SetCost(SCost: Word);      {Set message cost}
  733.   Begin
  734.   MsgRec^.MsgHdr.Cost := SCost;
  735.   End;
  736.  
  737.  
  738. Procedure HudsonMsgObj.SetRefer(SRefer: LongInt);    {Set message reference}
  739.   Begin
  740.   MsgRec^.MsgHdr.ReplyTo := SRefer;
  741.   End;
  742.  
  743.  
  744. Procedure HudsonMsgObj.SetDate(SDate: String);    {Set message date}
  745.   Begin
  746.   MsgRec^.MsgHdr.Date := Copy(PadLeft(SDate,'0',8),1,8);
  747.   MsgRec^.MsgHdr.Date[3] := '-';
  748.   MsgRec^.MsgHdr.Date[6] := '-';
  749.   End;
  750.  
  751.  
  752. Procedure HudsonMsgObj.SetTime(STime: String);    {Set message time}
  753.   Begin
  754.   MsgRec^.MsgHdr.Time := Copy(PadLeft(STime,'0',5),1,5);
  755.   MsgRec^.MsgHdr.Time[3] := ':';
  756.   End;
  757.  
  758.  
  759.  
  760. Procedure HudsonMsgObj.DoString(Str: String);     {Add string to message text}
  761.   Var
  762.     i: SmallWord;
  763.  
  764.   Begin
  765.   i := 1;
  766.   While i <= Length(Str) Do
  767.     Begin
  768.     DoChar(Str[i]);
  769.     Inc(i);
  770.     End;
  771.   End;
  772.  
  773.  
  774. Procedure HudsonMsgObj.DoChar(Ch: Char);          {Add character to message text}
  775.   Begin
  776.   If (MsgRec^.CurrTxtRec < TxtSize) or (MsgRec^.CurrTxtPos < 255) Then
  777.     Begin
  778.     If MsgRec^.CurrTxtPos = 255 Then
  779.       Begin
  780.       MsgChars^[MsgRec^.CurrTxtRec][0] := Chr(255);
  781.       Inc(MsgRec^.CurrTxtRec);
  782.       MsgRec^.CurrTxtPos := 0;
  783.       End;
  784.     Case CH of
  785.       #$0D: MsgRec^.CRLast := True;
  786.       #$0A:;
  787.       #$8D:;
  788.       Else
  789.         MsgRec^.CRLast := False;
  790.       End;
  791.     Inc(MsgRec^.CurrTxtPos);
  792.     MsgChars^[MsgRec^.CurrTxtRec][MsgRec^.CurrTxtPos] := Ch;
  793.     End;
  794.   End;
  795.  
  796.  
  797.  
  798. Procedure HudsonMsgObj.DoStringLn(Str: String);   {Add string and newline to msg text}
  799.   Begin
  800.   DoString(Str);
  801.   DoChar(#13);
  802.   End;
  803.  
  804.  
  805. Function HudsonMsgObj.WriteMsg: Word;
  806.   Var
  807.     WriteError: Word;
  808.     MsgPos: Word;
  809.     MsgIdx: MsgIdxType;
  810.     FN: String[13];
  811.     AlreadyLocked: Boolean;
  812.  
  813.   Begin
  814.   If FileSize(MsgRec^.MsgTxtFile) > $ff00 Then
  815.     WriteError := 99
  816.   Else
  817.     WriteError := 0;
  818.   If Not MsgRec^.CRLast Then
  819.     DoChar(#$0D);
  820.   MsgRec^.MsgHdr.NumRecs := MsgRec^.CurrTxtRec;
  821.   MsgChars^[MsgRec^.CurrTxtRec][0] := Chr(MsgRec^.CurrTxtPos);
  822.   Case MsgRec^.MT of
  823.     mmtNormal:  Begin
  824.              MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr and
  825.                Not(maNetMail + maUnmovedNet + maUnmovedEcho);
  826.              End;
  827.     mmtEchoMail: Begin
  828.              MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr and
  829.                Not(maNetMail + maUnmovedNet);
  830.              If MsgRec^.Echo Then
  831.                MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr or maUnmovedEcho;
  832.              End;
  833.     mmtNetMail: Begin
  834.              MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr and Not(maUnmovedEcho);
  835.              MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr or maNetMail;
  836.              If MsgRec^.Echo Then
  837.                MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr or maUnmovedNet;
  838.              End;
  839.     End;
  840.   MsgRec^.MsgHdr.Area := MsgRec^.Area;
  841.   AlreadyLocked := MsgRec^.Locked;
  842.   If Not AlreadyLocked Then
  843.     If Not LockMsgBase Then
  844.       WriteError := 5;
  845.   If WriteError = 0 Then
  846.     WriteError := SeekEnd;
  847.   If WriteError = 0 Then               {Write MsgHdr}
  848.     Begin
  849.     MsgRec^.MsgHdr.StartRec := FileSize(MsgRec^.MsgTxtFile);
  850.     MsgPos := FileSize(MsgRec^.MsgHdrFile);
  851.     Inc(MsgRec^.MsgInfo.HighMsg);
  852.     MsgRec^.MsgHdr.MsgNum := MsgRec^.MsgInfo.HighMsg;
  853.     Inc(MsgRec^.MsgInfo.Active);
  854.     Inc(MsgRec^.MsgInfo.AreaActive[MsgRec^.MsgHdr.Area]);
  855.     If Not shWrite(MsgRec^.MsgHdrFile, MsgRec^.MsgHdr, 1)
  856.       Then WriteError := MKFileError;
  857.     End;
  858.   If WriteError = 0 Then
  859.     If Not shWrite(MsgRec^.MsgToIdxFile, MsgRec^.MsgHdr.MsgTo, 1) Then
  860.       WriteError := MKFileError;
  861.   If WriteError = 0 Then               {Write MsgIdx}
  862.     Begin
  863.     MsgIdx.MsgNum := MsgRec^.MsgHdr.MsgNum;
  864.     MsgIdx.Area := MsgRec^.MsgHdr.Area;
  865.     If Not shWrite(MsgRec^.MsgIdxFile, MsgIdx, 1) Then
  866.       WriteError := MKFileError;
  867.     End;
  868.   If WriteError = 0 Then               {Write MsgTxt}
  869.     Begin
  870.     If Not shWrite(MsgRec^.MsgTxtFile, MsgChars^, MsgRec^.MsgHdr.NumRecs) Then
  871.       WriteError := MKFileError;
  872.     End;
  873.   If WriteError = 0 Then
  874.     Begin
  875.     Case MsgRec^.MT of
  876.       mmtEchoMail: FN := 'ECHOMAIL.BBS';
  877.       mmtNetMail: FN := 'NETMAIL.BBS';
  878.       Else
  879.         FN := '';
  880.       End; {Case MsgType}
  881.     If ((Length(FN) > 0) and MsgRec^.Echo) Then
  882.       WriteError := WriteMailIdx(FN, MsgPos);
  883.     End;
  884.   If WriteError = 0 Then
  885.     If Not AlreadyLocked Then
  886.       If Not UnlockMsgBase Then
  887.         WriteError := 5;
  888.   If ((WriteError = 0) and (HudsonFlushing)) Then
  889.     Begin
  890.     FlushFile(MsgRec^.MsgInfoFile);
  891.     FlushFile(MsgRec^.MsgTxtFile);
  892.     FlushFile(MsgRec^.MsgHdrFile);
  893.     FlushFile(MsgRec^.MsgInfoFile);
  894.     FlushFile(MsgRec^.MsgToIdxFile);
  895.     FlushFile(MsgRec^.MsgIdxFile);
  896.     End;
  897.   MsgRec^.MsgPos := MsgPos;;
  898.   WriteMsg := WriteError;
  899.   End;
  900.  
  901.  
  902. Procedure HudsonMsgObj.SetDest(Var Addr: AddrType);   {Set Zone/Net/Node/Point for Dest}
  903.   Begin
  904.   MsgRec^.MsgHdr.DestZone := Lo(Addr.Zone);
  905.   MsgRec^.MsgHdr.DestNet := Addr.Net;
  906.   MsgRec^.MsgHdr.DestNode := Addr.Node;
  907.   MsgRec^.DestPoint := Addr.Point;
  908.   If ((MsgRec^.DestPoint <> 0) and (MsgRec^.Mt = mmtNetMail)) Then
  909.     DoStringLn(#1 + 'TOPT ' + Long2Str(MsgRec^.DestPoint));
  910.   End;
  911.  
  912.  
  913. Procedure HudsonMsgObj.SetOrig(Var Addr: AddrType);   {Set Zone/Net/Node/Point for Orig}
  914.   Begin
  915.   MsgRec^.MsgHdr.OrigZone := Lo(Addr.Zone);
  916.   MsgRec^.MsgHdr.OrigNet := Addr.Net;
  917.   MsgRec^.MsgHdr.OrigNode := Addr.Node;
  918.   MsgRec^.OrigPoint := Addr.Point;
  919.   If ((MsgRec^.OrigPoint <> 0) and (MsgRec^.Mt = mmtNetmail)) Then
  920.     DoStringLn(#1 + 'FMPT ' + Long2Str(MsgRec^.OrigPoint));
  921.   End;
  922.  
  923.  
  924.  
  925. Procedure HudsonMsgObj.SetMsgPath(MP: String);
  926.   Begin
  927.   MsgRec^.Area := Str2Long(Copy(MP,1,3));
  928.   MsgRec^.MsgPath := Copy(MP,4,60);
  929.   AddBackSlash(MsgRec^.MsgPath);
  930.   shAssign(MsgRec^.MsgIdxFile, MsgRec^.MsgPath + 'MSGIDX.BBS');
  931.   shAssign(MsgRec^.MsgToIdxFile, MsgRec^.MsgPath + 'MSGTOIDX.BBS');
  932.   shAssign(MsgRec^.MsgHdrFile, MsgRec^.MsgPath + 'MSGHDR.BBS');
  933.   shAssign(MsgRec^.MsgTxtFile, MsgRec^.MsgPath + 'MSGTXT.BBS');
  934.   shAssign(MsgRec^.MsgInfoFile, MsgRec^.MsgPath + 'MSGINFO.BBS');
  935.   End;
  936.  
  937.  
  938. Function HudsonMsgObj.LockMsgBase: Boolean; {Lock msg base prior to adding message}
  939.   Var
  940.     LockError: SmallWord;
  941.     NumRead: Word;
  942.  
  943.   Begin
  944.   LockError := 0;
  945.   If Not MsgRec^.Locked Then
  946.     Begin
  947.     LockError := shLock(MsgRec^.MsgInfoFile,406,1);
  948.     If LockError = 1 Then
  949.       LockError := 0;                    {No Locking if share not loaded}
  950.     If LockError = 0 Then
  951.       Begin
  952.       Seek(MsgRec^.MsgInfoFile,0);
  953.       LockError := IoResult;
  954.       End;
  955.     If LockError = 0 Then
  956.       Begin
  957.       If Not shRead(MsgRec^.MsgInfoFile, MsgRec^.MsgInfo,1,NumRead) Then
  958.         LockError := MKFileError;
  959.       End;
  960.     End;
  961.   MsgRec^.Locked := (LockError = 0);
  962.   LockMsgBase := LockError = 0;
  963.   End;
  964.  
  965.  
  966. Function HudsonMsgObj.UnlockMsgBase: Boolean; {Unlock msg base after adding message}
  967.   Var
  968.     LockError: SmallWord;
  969.  
  970.   Begin
  971.   LockError := 0;
  972.   If MsgRec^.Locked Then
  973.     Begin
  974.     Seek(MsgRec^.MsgInfoFile,0);
  975.     LockError := IoResult;
  976.     shWrite(MsgRec^.MsgInfoFile, MsgRec^.MsgInfo,1);
  977.     If LockError = 0 Then
  978.       LockError := IoResult;
  979.     LockError := UnLockFile(MsgRec^.MsgInfoFile,406,1);
  980.     If LockError = 1 Then
  981.       LockError := 0;                    {No locking if share not loaded}
  982.     End;
  983.   MsgRec^.Locked := False;
  984.   UnlockMsgBase := LockError = 0;
  985.   End;
  986.  
  987.  
  988. Function HudsonMsgObj.GetNumActive: SmallWord;
  989.   Begin
  990.   GetNumActive := MsgRec^.MsgInfo.Active;
  991.   End;
  992.  
  993.  
  994. Function HudsonMsgObj.GetHighMsgNum: LongInt;
  995.   Begin
  996.   GetHighMsgNum := MsgRec^.MsgInfo.HighMsg;
  997.   End;
  998.  
  999.  
  1000. Function HudsonMsgObj.GetLowMsgNum: LongInt;
  1001.   Begin
  1002.   GetLowMsgNum := MsgRec^.MsgInfo.LowMsg;
  1003.   End;
  1004.  
  1005.  
  1006. Function HudsonMsgObj.CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word;
  1007.   Var
  1008.     CreateError: Word;
  1009.     i: Word;
  1010.  
  1011.   Begin
  1012.   CreateError := 0;
  1013.   If Not MakePath(MsgRec^.MsgPath) Then
  1014.     CreateError := 1;
  1015.   ReWrite(MsgRec^.MsgIdxFile, SizeOf(MsgIdxType));
  1016.   If CreateError = 0 Then
  1017.     CreateError := IoResult;
  1018.   ReWrite(MsgRec^.MsgToIdxFile, SizeOf(MsgToIdxType));
  1019.   If CreateError = 0 Then
  1020.     CreateError := IoResult;
  1021.   ReWrite(MsgRec^.MsgHdrFile, SizeOf(MsgHdrType));
  1022.   If CreateError = 0 Then
  1023.     CreateError := IoResult;
  1024.   ReWrite(MsgRec^.MsgTxtFile, SizeOf(MsgTxtType));
  1025.   If CreateError = 0 Then
  1026.     CreateError := IoResult;
  1027.   ReWrite(MsgRec^.MsgInfoFile, SizeOf(MsgInfoType));
  1028.   If CreateError = 0 Then
  1029.     CreateError := IoResult;
  1030.   MsgRec^.MsgInfo.LowMsg := 1;
  1031.   MsgRec^.MsgInfo.HighMsg := 0;
  1032.   MsgRec^.MsgInfo.Active := 0;
  1033.   For i := 1 to 200 Do
  1034.     MsgRec^.MsgInfo.AreaActive[i] := 0;
  1035.   If Not shWrite(MsgRec^.MsgInfoFile, MsgRec^.MsgInfo, 1) Then
  1036.     CreateError := MKFileError;
  1037.   Close(MsgRec^.MsgInfoFile);
  1038.   If CreateError = 0 Then
  1039.     CreateError := IoResult;
  1040.   Close(MsgRec^.MsgIdxFile);
  1041.   If CreateError = 0 Then
  1042.     CreateError := IoResult;
  1043.   Close(MsgRec^.MsgToIdxFile);
  1044.   If CreateError = 0 Then
  1045.     CreateError := IoResult;
  1046.   Close(MsgRec^.MsgTxtFile);
  1047.   If CreateError = 0 Then
  1048.     CreateError := IoResult;
  1049.   Close(MsgRec^.MsgHdrFile);
  1050.   If CreateError = 0 Then
  1051.     CreateError := IoResult;
  1052.   CreateMsgBase := CreateError;
  1053.   End;
  1054.  
  1055.  
  1056. Function  HudsonMsgObj.MsgBaseExists: Boolean;
  1057.   Begin
  1058.   MsgBaseExists := (Check <> 1);
  1059.   End;
  1060.  
  1061.  
  1062.  
  1063. Function HudsonMsgObj.Check: SmallWord;          {Check if msg base is Ok}
  1064.   { 0 = ok, 1 = not there (create), 2 = corrupted}
  1065.   Var
  1066.     BaseSize: LongInt;
  1067.     Status: SmallWord;
  1068.  
  1069.   Begin
  1070.   Status := 0;
  1071.   If (Not FileExist(MsgRec^.MsgPath + 'MSGINFO.BBS'))  Then
  1072.     Status := 1;
  1073.   If (Not FileExist(MsgRec^.MsgPath + 'MSGHDR.BBS'))  Then
  1074.     Begin
  1075.     If Status = 0 Then
  1076.       Status := 2;
  1077.     End
  1078.   Else
  1079.     Begin
  1080.     If Status = 1 Then
  1081.       Status := 2;
  1082.     End;
  1083.   If (Not FileExist(MsgRec^.MsgPath + 'MSGTXT.BBS'))  Then
  1084.     Begin
  1085.     If Status = 0 Then
  1086.       Status := 2;
  1087.     End
  1088.   Else
  1089.     Begin
  1090.     If Status = 1 Then
  1091.       Status := 2;
  1092.     End;
  1093.   If (Not FileExist(MsgRec^.MsgPath + 'MSGIDX.BBS')) Then
  1094.     Begin
  1095.     If Status = 0 Then
  1096.       Status := 2;
  1097.     End
  1098.   Else
  1099.     Begin
  1100.     If Status = 1 Then
  1101.       Status := 2;
  1102.     End;
  1103.   If (Not FileExist(MsgRec^.MsgPath + 'MSGTOIDX.BBS'))  Then
  1104.     Begin
  1105.     If Status = 0 Then
  1106.       Status := 2;
  1107.     End
  1108.   Else
  1109.     Begin
  1110.     If Status = 1 Then
  1111.       Status := 2;
  1112.     End;
  1113.   If Status = 0 Then
  1114.     Begin
  1115.     If SizeFile(MsgRec^.MsgPath + 'MSGINFO.BBS') <> SizeOf(MsgInfoType) Then
  1116.       Status := 2;
  1117.     End;
  1118.   If Status = 0 Then
  1119.     Begin
  1120.     BaseSize := SizeFile(MsgRec^.MsgPath + 'MSGHDR.BBS') Div SizeOf(MsgHdrType);
  1121.     If BaseSize <> (SizeFile(MsgRec^.MsgPath + 'MSGIDX.BBS') Div SizeOf(MsgIdxType)) Then
  1122.       Status := 2;
  1123.     If BaseSize <> (SizeFile(MsgRec^.MsgPath + 'MSGTOIDX.BBS') Div SizeOf(MsgToIdxType)) Then
  1124.       Status := 2;
  1125.     End;
  1126.   Check := Status;
  1127.   End;
  1128.  
  1129.  
  1130.  
  1131. Function HudsonMsgObj.MsgBaseSize:SmallWord;
  1132.   Begin
  1133.   If Length(MsgRec^.MsgPath) > 0 Then
  1134.     Begin
  1135.     MsgBaseSize := FileSize(MsgRec^.MsgIdxFile);
  1136.     End
  1137.   Else
  1138.     MsgBaseSize := 0;
  1139.   End;
  1140.  
  1141.  
  1142. Function HudsonMsgObj.SeekEnd: Word;        {Seek to end of Msg Base Files}
  1143.   Var
  1144.     SeekError: SmallWord;
  1145.  
  1146.   Begin
  1147.   SeekError := 0;
  1148.   Seek(MsgRec^.MsgIdxFile, FileSize(MsgRec^.MsgIdxFile));
  1149.   If SeekError = 0 Then
  1150.     SeekError := IoResult;
  1151.   Seek(MsgRec^.MsgToIdxFile, FileSize(MsgRec^.MsgToIdxFile));
  1152.   If SeekError = 0 Then
  1153.     SeekError := IoResult;
  1154.   Seek(MsgRec^.MsgTxtFile, FileSize(MsgRec^.MsgTxtFile));
  1155.   If SeekError = 0 Then
  1156.     SeekError := IoResult;
  1157.   Seek(MsgRec^.MsgHdrFile, FileSize(MsgRec^.MsgHdrFile));
  1158.   If SeekError = 0 Then
  1159.     SeekError := IoResult;
  1160.   SeekEnd := SeekError;
  1161.   End;
  1162.  
  1163.  
  1164. Function HudsonMsgObj.SeekMsgBasePos(Position: Word): Word; {Seek to pos of Msg Base File}
  1165.   Var
  1166.     SeekError: SmallWord;
  1167.   Begin
  1168.   Seek(MsgRec^.MsgIdxFile, Position);
  1169.   SeekError := IoResult;
  1170.   Seek(MsgRec^.MsgToIdxFile, Position);
  1171.   If SeekError = 0 Then
  1172.     SeekError := IoResult;
  1173.   Seek(MsgRec^.MsgHdrFile, Position);
  1174.   If SeekError = 0 Then
  1175.     SeekError := IoResult;
  1176.   SeekMsgBasePos := SeekError;
  1177.   End;
  1178.  
  1179.  
  1180. Function HudsonMsgObj.WriteMailIdx(FN: String; MsgPos: SmallWord): SmallWord; {Write Netmail or EchoMail.Bbs}
  1181.   Var
  1182.     IdxFile: File;
  1183.     WriteError: SmallWord;
  1184.     IdxName: String;
  1185.  
  1186.   Begin
  1187.   WriteError := 0;
  1188.   If Length(HudsonEcho) > 0 Then
  1189.     IdxName := WithBackSlash(HudsonEcho) + FN
  1190.   Else
  1191.     IdxName := MsgRec^.MsgPath + FN;
  1192.   shAssign(IdxFile, IdxName);
  1193.   FileMode := fmReadWrite + fmDenyNone;
  1194.   If FileExist(IdxName) Then
  1195.     Begin
  1196.     If Not shReset(IdxFile, SizeOf(MsgPos)) Then
  1197.       WriteError := MKFileError;
  1198.     End
  1199.   Else
  1200.     Begin
  1201.     ReWrite(IdxFile, SizeOf(MsgPos));
  1202.     WriteError := IoResult;
  1203.     End;
  1204.   If WriteError = 0 Then
  1205.     Begin
  1206.     Seek(IdxFile, FileSize(IdxFile));
  1207.     WriteError := IoResult;
  1208.     End;
  1209.   If WriteError = 0 Then
  1210.     Begin
  1211.     BlockWrite(IdxFile, MsgPos, 1);
  1212.     WriteError := IoResult;
  1213.     End;
  1214.   If WriteError = 0 Then
  1215.     Begin
  1216.     Close(IdxFile);
  1217.     WriteError := IoResult;
  1218.     End;
  1219.   WriteMailIdx := WriteError;
  1220.   End;
  1221.  
  1222.  
  1223. Function HudsonMsgObj.OpenMsgBase: Word; {Set path and initialize}
  1224.   Var
  1225.     OpenError: SmallWord;
  1226.     CheckMode: SmallWord;
  1227.     NumRead: Word;
  1228.  
  1229.   Begin
  1230.   OpenError := 0;
  1231.   If Not MsgRec^.Opened Then
  1232.     Begin
  1233.     CheckMode := Check;
  1234.     If CheckMode = 1 Then
  1235.       Begin
  1236.       OpenError := CreateMsgBase(100,100);
  1237.       If OpenError = 0 Then
  1238.         CheckMode := 0;
  1239.       End;
  1240.     If CheckMode = 2 Then
  1241.       OpenError := 5000;
  1242.     If CheckMode = 0 Then
  1243.       Begin
  1244.       FileMode := fmReadWrite + fmDenyNone;
  1245.       If Not ShReset(MsgRec^.MsgIdxFile, SizeOf(MsgIdxType)) Then
  1246.         OpenError := MKFileError;
  1247.       FileMode := fmReadWrite + fmDenyNone;
  1248.       If Not shReset(MsgRec^.MsgToIdxFile, SizeOf(MsgToIdxType)) Then
  1249.         OpenError := MKFileError;
  1250.       FileMode := fmReadWrite + fmDenyNone;
  1251.       If Not shReset(MsgRec^.MsgTxtFile, SizeOf(MsgTxtType)) Then
  1252.         OpenError := MKFileError;
  1253.       FileMode := fmReadWrite + fmDenyNone;
  1254.       If Not shReset(MsgRec^.MsgHdrFile, SizeOf(MsgHdrType)) Then
  1255.         OpenError := MKFileError;
  1256.       FileMode := fmReadWrite + fmDenyNone;
  1257.       If Not shReset(MsgRec^.MsgInfoFile, SizeOf(MsgInfoType)) Then
  1258.         OpenError := MKFileError;
  1259.       End;
  1260.     End;
  1261.   If OpenError = 0 Then
  1262.     Begin
  1263.     If Not shRead(MsgRec^.MsgInfoFile, MsgRec^.MsgInfo,1,NumRead) Then
  1264.       OpenError := 1;
  1265.     End;
  1266.   MsgRec^.Opened := (OpenError = 0);
  1267.   OpenMsgBase := OpenError;
  1268.   End;
  1269.  
  1270.  
  1271. Function HudsonMsgObj.CloseMsgBase: Word;         {Close Msg Base Files}
  1272.   Var
  1273.     CloseError: SmallWord;
  1274.  
  1275.   Begin
  1276.   CloseError := 0;
  1277.   If MsgRec^.Opened Then
  1278.     Begin
  1279.     Close(MsgRec^.MsgIdxFile);
  1280.     If CloseError = 0 Then
  1281.       CloseError := IoResult;
  1282.     Close(MsgRec^.MsgToIdxFile);
  1283.     If CloseError = 0 Then
  1284.       CloseError := IoResult;
  1285.     Close(MsgRec^.MsgTxtFile);
  1286.     If CloseError = 0 Then
  1287.       CloseError := IoResult;
  1288.     Close(MsgRec^.MsgHdrFile);
  1289.     If CloseError = 0 Then
  1290.       CloseError := IoResult;
  1291.     Close(MsgRec^.MsgInfoFile);
  1292.     If CloseError = 0 Then
  1293.       CloseError := IoResult;
  1294.     End;
  1295.   CloseMsgBase := CloseError;
  1296.   End;
  1297.  
  1298.  
  1299. Procedure HudsonMsgObj.SeekRead(NumToRead: Word);
  1300.   Begin
  1301.   If NumToRead > SeekSize Then
  1302.     NumToRead := SeekSize;
  1303.   Seek(MsgRec^.MsgIdxFile, MsgRec^.SeekStart);
  1304.   If IoResult <> 0 Then;
  1305.   If Not shRead(MsgRec^.MsgIdxFile, SeekArray^, NumToRead , MsgRec^.SeekNumRead) Then
  1306.     MsgRec^.Error := 1000;
  1307.   End;
  1308.  
  1309.  
  1310. Procedure HudsonMsgObj.SeekNext;
  1311.   Var
  1312.     SDone: Boolean;
  1313.  
  1314.   Begin
  1315.   SDone := False;
  1316.   While Not SDone Do
  1317.     Begin
  1318.     Inc(MsgRec^.SeekPos);
  1319.     If (MsgRec^.SeekPos > MsgRec^.SeekNumRead) Then
  1320.       Begin
  1321.       Inc(MsgRec^.SeekStart, MsgRec^.SeekNumRead);
  1322.       SeekRead(SeekSize);
  1323.       MsgRec^.SeekPos := 1;
  1324.       End;
  1325.     If MsgRec^.SeekNumRead = 0 Then
  1326.       Begin
  1327.       MsgRec^.SeekOver := True;
  1328.       SDone := True;
  1329.       End
  1330.     Else
  1331.       Begin
  1332.       If ((SeekArray^[MsgRec^.SeekPos].MsgNum > MsgRec^.CurrMsgNum) And
  1333.       (SeekArray^[MsgRec^.SeekPos].MsgNum <> $ffff) And
  1334.       (SeekArray^[MsgRec^.SeekPos].Area = MsgRec^.Area) And
  1335.       (MsgRec^.SeekPos > 0) And (MsgRec^.SeekPos <= MsgRec^.SeekNumRead)) Then
  1336.         Begin
  1337.         SDone := True;
  1338.         MsgRec^.CurrMsgNum := SeekArray^[MsgRec^.SeekPos].MsgNum;
  1339.         End;
  1340.       End;
  1341.     End;
  1342.   MsgRec^.MsgPos := MsgRec^.SeekStart + MsgRec^.SeekPos - 1;
  1343.   End;
  1344.  
  1345.  
  1346. Procedure HudsonMsgObj.SeekPrior;
  1347.   Var
  1348.     SDone: Boolean;
  1349.     SeekDec: SmallWord;
  1350.  
  1351.   Begin
  1352.   MsgRec^.SeekOver := False;
  1353.   SDone := False;
  1354.   While Not SDone Do
  1355.     Begin
  1356.     Dec(MsgRec^.SeekPos);
  1357.     If (MsgRec^.SeekPos < 1) Then
  1358.       Begin
  1359.       If MsgRec^.SeekStart = 0 Then
  1360.         Begin
  1361.         MsgRec^.SeekOver := True;
  1362.         SDone := True;
  1363.         End;
  1364.       If (MsgRec^.SeekStart < SeekSize) Then
  1365.         SeekDec := MsgRec^.SeekStart
  1366.       Else
  1367.         SeekDec := SeekSize;
  1368.       Dec(MsgRec^.SeekStart, SeekDec);
  1369.       If MsgRec^.SeekStart < 0 Then
  1370.         MsgRec^.SeekStart := 0;
  1371.       SeekRead(SeekDec);
  1372.       MsgRec^.SeekPos := MsgRec^.SeekNumRead;
  1373.       End;
  1374.     If Not MsgRec^.SeekOver Then
  1375.       Begin
  1376.       If ((SeekArray^[MsgRec^.SeekPos].MsgNum < MsgRec^.CurrMsgNum) And
  1377.       (SeekArray^[MsgRec^.SeekPos].MsgNum <> $ffff) And
  1378.       (SeekArray^[MsgRec^.SeekPos].Area = MsgRec^.Area) And
  1379.       (MsgRec^.SeekPos > 0) And (MsgRec^.SeekPos <= MsgRec^.SeekNumRead)) Then
  1380.         Begin
  1381.         SDone := True;
  1382.         MsgRec^.CurrMsgNum := SeekArray^[MsgRec^.SeekPos].MsgNum;
  1383.         End;
  1384.       End;
  1385.     End;
  1386.   MsgRec^.MsgPos := MsgRec^.SeekStart + MsgRec^.SeekPos - 1;
  1387.   End;
  1388.  
  1389.  
  1390. Function HudsonMsgObj.SeekFound:Boolean;   {Seek has been completed}
  1391.   Begin
  1392.   SeekFound := Not MsgRec^.SeekOver;
  1393.   End;
  1394.  
  1395.  
  1396. Procedure HudsonMsgObj.SeekFirst(MsgNum: LongInt);
  1397.   Begin
  1398.   MsgRec^.SeekStart := 0;
  1399.   MsgRec^.SeekNumRead := 0;
  1400.   MsgRec^.SeekPos := 0;
  1401.   MsgRec^.SeekOver := False;
  1402.   SeekRead(SeekSize);
  1403.   MsgRec^.CurrMsgNum := MsgNum - 1;
  1404.   SeekNext;
  1405.   End;
  1406.  
  1407.  
  1408. Procedure HudsonMsgObj.SetMailType(MT: MsgMailType);
  1409.   Begin
  1410.   MsgRec^.MT := MT;
  1411.   End;
  1412.  
  1413.  
  1414. Function HudsonMsgObj.GetSubArea: Word;
  1415.   Begin
  1416.   GetSubArea := MsgRec^.MsgHdr.Area;
  1417.   End;
  1418.  
  1419.  
  1420. Procedure HudsonMsgObj.ReWriteHdr;
  1421.   Var
  1422.     NumRead: SmallWord;
  1423.     RcvdName: String[35];
  1424.     MsgError: SmallWord;
  1425.     MsgIdx: MsgIdxType;
  1426.  
  1427.   Begin
  1428.   MsgError := SeekMsgBasePos(MsgRec^.MsgPos);
  1429.   If IsRcvd Then
  1430.     RcvdName := '* Received *'
  1431.   Else
  1432.     RcvdName := MsgRec^.MsgHdr.MsgTo;
  1433.   If IsDeleted Then
  1434.     Begin
  1435.     RcvdName := '* Deleted *';
  1436.     MsgIdx.MsgNum := $ffff;
  1437.     End
  1438.   Else
  1439.     MsgIdx.MsgNum := MsgRec^.MsgHdr.MsgNum;
  1440.   If MsgError = 0 Then
  1441.     Begin
  1442.     If not shWrite(MsgRec^.MsgHdrFile, MsgRec^.MsgHdr,1) Then
  1443.       MsgError := MKFileError;
  1444.     End;
  1445.   If MsgError = 0 Then
  1446.     Begin
  1447.     If Not shWrite(MsgRec^.MsgToIdxFile, RcvdName, 1) Then
  1448.       MsgError := MKFileError;
  1449.     End;
  1450.   MsgIdx.Area := MsgRec^.MsgHdr.Area;
  1451.   If MsgError = 0 Then
  1452.     Begin
  1453.     If not shWrite(MsgRec^.MsgIdxFile, MsgIdx,1) Then
  1454.       MsgError := MKFileError;
  1455.     End;
  1456.   End;
  1457.  
  1458.  
  1459. Procedure HudsonMsgObj.DeleteMsg;
  1460.   Var
  1461.     NumRead: Word;
  1462.     RcvdName: String[35];
  1463.     MsgIdx: MsgIdxType;
  1464.     MsgError: SmallWord;
  1465.  
  1466.   Begin
  1467.   MsgIdx.Area := MsgRec^.MsgHdr.Area;
  1468.   If LockMsgBase Then
  1469.     MsgError := 0
  1470.   Else
  1471.     MsgError := 5;
  1472.   If MsgError = 0 Then
  1473.     MsgError := SeekMsgBasePos(MsgRec^.MsgPos);
  1474.   If MsgError = 0 Then
  1475.     Begin
  1476.     If not shRead(MsgRec^.MsgHdrFile, MsgRec^.MsgHdr,1, NumRead) Then
  1477.       MsgError := MKFileError;
  1478.     End;
  1479.   If ((MsgRec^.MsgHdr.MsgAttr and maDeleted) = 0) Then
  1480.     Begin
  1481.     Dec(MsgRec^.MsgInfo.Active);
  1482.     Dec(MsgRec^.MsgInfo.AreaActive[MsgRec^.MsgHdr.Area]);
  1483.     End;
  1484.   MsgRec^.MsgHdr.MsgAttr := MsgRec^.MsgHdr.MsgAttr Or maDeleted;
  1485.   RcvdName := '* Deleted *';
  1486.   MsgIdx.MsgNum := $ffff;
  1487.   If MsgError = 0 Then
  1488.     MsgError := SeekMsgBasePos(MsgRec^.MsgPos);
  1489.   If MsgError = 0 Then
  1490.     Begin
  1491.     If not shWrite(MsgRec^.MsgHdrFile, MsgRec^.MsgHdr,1) Then
  1492.       MsgError := MKFileError;
  1493.     End;
  1494.   If MsgError = 0 Then
  1495.     If Not shWrite(MsgRec^.MsgToIdxFile, RcvdName, 1) Then
  1496.       MsgError := MKFileError;
  1497.   If MsgError = 0 Then
  1498.     If Not shWrite(MsgRec^.MsgIdxFile, MsgIdx, 1) Then
  1499.       MsgError := MKFileError;
  1500.   If MsgError = 0 Then
  1501.     If Not UnLockMsgBase Then
  1502.       MsgError := 5;
  1503.   End;
  1504.  
  1505.  
  1506. Function HudsonMsgObj.GetMsgLoc: LongInt;
  1507.   Begin
  1508.   GetMsgLoc := MsgRec^.MsgPos;
  1509.   End;
  1510.  
  1511.  
  1512. Procedure HudsonMsgObj.SetMsgLoc(ML: LongInt);
  1513.   Begin
  1514.   MsgRec^.MsgPos := ML;
  1515.   End;
  1516.  
  1517.  
  1518. Function HudsonMsgObj.NumberOfMsgs: LongInt;
  1519.   Var
  1520.     TmpInfo: MsgInfoType;
  1521.  
  1522.   Begin
  1523.   If LoadFile(MsgRec^.MsgPath + 'MsgInfo.Bbs', TmpInfo, SizeOf(TmpInfo)) = 0 Then
  1524.     NumberOfMsgs := TmpInfo.AreaActive[MsgRec^.Area]
  1525.   Else
  1526.     NumberOfMsgs := 0;
  1527.   End;
  1528.  
  1529.  
  1530. Procedure HudsonMsgObj.GetAllLastRead(UNum: LongInt; Var LR: LastReadType);
  1531.   Var
  1532.     LastName: String;
  1533.  
  1534.   Begin
  1535.   If Length(HudsonLast) > 0 Then
  1536.     LastName := WithBackSlash(HudsonLast) + 'LastRead.Bbs'
  1537.   Else
  1538.     LastName := MsgRec^.MsgPath + 'LastRead.Bbs';
  1539.   FillChar(LR, SizeOf(LR), 0);
  1540.   If ((UNum + 1) * SizeOf(LastReadType)) <=
  1541.   SizeFile(LastName) Then
  1542.     Begin
  1543.     If LoadFilePos(LastName, LR, SizeOf(LR),
  1544.     UNum * SizeOf(LastReadType)) = 0 Then;
  1545.     End;
  1546.   End;
  1547.  
  1548.  
  1549.  
  1550.  
  1551. Function HudsonMsgObj.GetLastRead(UNum: LongInt): LongInt;
  1552.   Var
  1553.     LRec: LastReadType;
  1554.     LastName: String;
  1555.  
  1556.   Begin
  1557.   If Length(HudsonLast) > 0 Then
  1558.     LastName := WithBackSlash(HudsonLast) + 'LastRead.Bbs'
  1559.   Else
  1560.     LastName := MsgRec^.MsgPath + 'LastRead.Bbs';
  1561.   If ((UNum + 1) * SizeOf(LastReadType)) >
  1562.   SizeFile(LastName) Then
  1563.     GetLastRead := 0
  1564.   Else
  1565.     Begin
  1566.     If LoadFilePos(LastName, LRec, SizeOf(LRec),
  1567.     UNum * SizeOf(LastReadType)) = 0 Then
  1568.       GetLastRead := LRec[MsgRec^.Area]
  1569.     Else
  1570.       GetLastRead := 0;
  1571.     End;
  1572.   End;
  1573.  
  1574.  
  1575. Procedure HudsonMsgObj.SetLastRead(UNum: LongInt; LR: LongInt);
  1576.   Var
  1577.     LRec: LastReadType;
  1578.     Status: SmallWord;
  1579.     LastName: String; {path\filename of lastread.bbs}
  1580.  
  1581.   Begin
  1582.   If Length(HudsonLast) > 0 Then
  1583.     LastName := WithBackSlash(HudsonLast) + 'LastRead.Bbs'
  1584.   Else
  1585.     LastName := MsgRec^.MsgPath + 'LastRead.Bbs';
  1586.   If ((UNum + 1) * SizeOf(LastReadType)) >  SizeFile(LastName) Then
  1587.     Begin
  1588.     Status := ExtendFile(LastName,(UNum + 1) * SizeOf(LastReadType));
  1589.     End;
  1590.   If LoadFilePos(LastName, LRec, SizeOf(LRec), UNum * SizeOf(LastReadType)) = 0 Then
  1591.     Begin
  1592.     LRec[MsgRec^.Area] := LR;
  1593.     Status := SaveFilePos(LastName, LRec, SizeOf(LRec),
  1594.     UNum * SizeOf(LastReadType));
  1595.     End;
  1596.   End;
  1597.  
  1598.  
  1599. Procedure HudsonMsgObj.GetHighest(Var LR: LastReadType);
  1600.   Var
  1601.     i: SmallWord;
  1602.     IdxFile: File;
  1603.     MIdx: ^SeekArrayType;
  1604.     NumRead: Word;
  1605.  
  1606.   Begin
  1607.   New(MIdx);
  1608.   For i := 1 to 200 Do
  1609.     LR[i] := 0;
  1610.   Assign(IdxFile, MsgRec^.MsgPath + 'MsgIdx.Bbs');
  1611.   FileMode := fmReadOnly + fmDenyNone;
  1612.   If shReset(IdxFile, SizeOf(MsgIdxType)) Then;
  1613.   While Not(Eof(IdxFile)) Do
  1614.     Begin
  1615.     If shRead(IdxFile, MIdx^, SeekSize, NumRead) Then;
  1616.     i := 1;
  1617.     While i <= NumRead Do
  1618.       Begin
  1619.       If MIdx^[i].MsgNum <> $ffff Then
  1620.         Begin
  1621.         If MIdx^[i].MsgNum > LR[MIdx^[i].Area] Then
  1622.           LR[MIdx^[i].Area] := MIdx^[i].MsgNum;
  1623.         End;
  1624.       Inc(i);
  1625.       End;
  1626.     End;
  1627.   Close(IdxFile);
  1628.   If IoResult <> 0 Then;
  1629.   Dispose(MIdx);
  1630.   End;
  1631.  
  1632.  
  1633. Function HudsonMsgObj.GetTxtPos: LongInt;
  1634.   Var
  1635.     Tmp: LongInt;
  1636.  
  1637.   Begin
  1638.   Tmp := MsgRec^.CurrTxtRec;
  1639.   GetTxtPos := MsgRec^.CurrTxtPos +  Tmp shl 16;
  1640.   End;
  1641.  
  1642.  
  1643. Procedure HudsonMsgObj.SetTxtPos(TP: LongInt);
  1644.   Begin
  1645.   MsgRec^.CurrTxtRec := TP shr 16;
  1646.   MsgRec^.CurrTxtPos := TP and $ffff;
  1647.   End;
  1648.  
  1649.  
  1650. Function HudsonMsgObj.GetString(MaxLen: Word): String;
  1651.   Var
  1652.     Rec: SmallWord;
  1653.     PPos: SmallWord;
  1654.     CurrLen: Byte;
  1655.     WRec: SmallWord;
  1656.     WPos: SmallWord;
  1657.     WLen: Byte;
  1658.     StrDone: Boolean;
  1659.     TxtOver: Boolean;
  1660.     StartSoft: Boolean;
  1661.  
  1662.   Begin
  1663.   StrDone := False;
  1664.   CurrLen := 0;
  1665.   Rec := MsgRec^.CurrTxtRec;
  1666.   PPos := MsgRec^.CurrTxtPos;
  1667.   TxtOver := Not NextChar(Rec, PPos);
  1668.   If TxtOver Then
  1669.     MsgRec^.EOM := True;
  1670.   WLen := 0;
  1671.   WRec := Rec;
  1672.   WPos := PPos;
  1673.   StartSoft := LastSoft;
  1674.   LastSoft := True;
  1675.   While ((Not StrDone) And (CurrLen < MaxLen) And (Not TxtOver)) Do
  1676.     Begin
  1677.     Case MsgChars^[Rec][PPos] of
  1678.       #$0d: Begin
  1679.             StrDone := True;
  1680.             LastSoft := False;
  1681.             End;
  1682.       #$8d:;
  1683.       #$0a:;
  1684.       #$20: Begin
  1685.             If ((CurrLen <> 0) or (Not StartSoft)) Then
  1686.               Begin
  1687.               Inc(CurrLen);
  1688.               GetString[CurrLen] := MsgChars^[Rec][PPos];
  1689.               WLen := CurrLen;
  1690.               WRec := Rec;
  1691.               WPos := PPos;
  1692.               End
  1693.             Else
  1694.               StartSoft := False;
  1695.             End;
  1696.       Else
  1697.         Begin
  1698.         Inc(CurrLen);
  1699.         GetString[CurrLen] := MsgChars^[Rec][PPos];
  1700.         End;
  1701.       End;
  1702.     Inc(PPos);
  1703.     TxtOver := Not NextChar(Rec, PPos);
  1704.     End;
  1705.   If StrDone Then
  1706.     Begin
  1707.     GetString[0] := Chr(CurrLen);
  1708.     MsgRec^.CurrTxtRec := Rec;
  1709.     MsgRec^.CurrTxtPos := PPos;
  1710.     End
  1711.   Else
  1712.     If TxtOver Then
  1713.       Begin
  1714.       GetString[0] := Chr(CurrLen);
  1715.       MsgRec^.CurrTxtRec := Rec;
  1716.       MsgRec^.CurrTxtPos := PPos;
  1717.       If CurrLen = 0 Then
  1718.         MsgRec^.EOM := True;
  1719.       End
  1720.     Else
  1721.       Begin
  1722.       If WLen = 0 Then
  1723.         Begin
  1724.         GetString[0] := Chr(CurrLen);
  1725.         MsgRec^.CurrTxtRec := Rec;
  1726.         MsgRec^.CurrTxtPos := PPos;
  1727.         End
  1728.       Else
  1729.         Begin
  1730.         GetString[0] := Chr(WLen);
  1731.         Inc(WPos);
  1732.         NextChar(WRec, WPos);
  1733.         MsgRec^.CurrTxtPos := WPos;
  1734.         MsgRec^.CurrTxtRec := WRec;
  1735.         End;
  1736.       End;
  1737.   End;
  1738.  
  1739.  
  1740. End.
  1741.