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