home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / MKMSG104 / MKMSGHUD.PAS < prev    next >
Pascal/Delphi Source File  |  1994-01-09  |  48KB  |  1,730 lines

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