home *** CD-ROM | disk | FTP | other *** search
/ Beijing Paradise BBS Backup / PARADISE.ISO / software / BBSDOORW / MKMSG102.ARJ / MKMSGHUD.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1993-08-15  |  46.1 KB  |  1,717 lines

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