home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / PASCAL / MKMSG102.ZIP / MKMSGSQU.PAS < prev    next >
Pascal/Delphi Source File  |  1993-08-15  |  44KB  |  1,706 lines

  1. Unit MKMsgSqu;
  2.  
  3. {$I MKB.Def}
  4. {$A-}
  5. Interface
  6.  
  7. Uses MKGlobT, MKMsgAbs;
  8.  
  9.  
  10.  
  11. Const
  12.   SqHdrId = $AFAE4453;
  13.   SqLinkNext = 0;
  14.   SqLinkPrev = 1;
  15.   SqNullFrame = 0;
  16.   SqFrameMsg = 0;
  17.   SqFrameFree = 1;
  18.   SqFrameRLE = 2;
  19.   SqFrameLZW = 3;
  20.   SqFromSize = 36;
  21.   SqToSize = 36;
  22.   SqSubjSize = 72;
  23.   SqMaxReply = 10;
  24.  
  25.  
  26. Type SqBaseType = Record
  27.   Len: Word; {Length of this record}
  28.   Rsvd1: Word; {Future use}
  29.   NumMsg: LongInt; {Number of messages}
  30.   HighMsg: LongInt; {Highest msg}
  31.   SkipMsg: LongInt; {# of msgs to keep in beginning of area}
  32.   HighWater: LongInt; {High water UMsgId}
  33.   Uid: LongInt; {Next UMsgId}
  34.   Base: String[79]; {Base name of Squish file}
  35.   BeginFrame: LongInt; {Offset of first frame in file}
  36.   LastFrame: LongInt; {Offset of last frame in file}
  37.   FirstFree: LongInt; {Offset of first free frame in file}
  38.   LastFree: LongInt; {Offset of last free frame in file}
  39.   EndFrame: LongInt; {Pointer to end of file}
  40.   MaxMsg: LongInt; {Maximum number of messages}
  41.   KeepDays: Word; {Maximum age of messages}
  42.   SqHdrSize: Word; {Size of frame header}
  43.   Rsvd2: Array[1..124] of Byte; {Future use}
  44.   End;
  45.  
  46.  
  47. Type SqFrameHdrType = Record
  48.   Id: LongInt; {Must equal SqHdrId}
  49.   NextFrame: LongInt; {Next msg frame}
  50.   PrevFrame: LongInt; {Prior msg frame}
  51.   FrameLength: LongInt; {Length of this frame not counting header}
  52.   MsgLength: LongInt; {Length of message}
  53.   ControlLength: LongInt; {Length of control information}
  54.   FrameType: Word; {Type of message frame}
  55.   Rsvd: Word; {Future use}
  56.   End;
  57.  
  58.  
  59. Type SqMsgHdrType = Record
  60.   Attr: LongInt; {Msg attribute}
  61.   MsgFrom: String[SqFromSize - 1]; {Nul Term from name}
  62.   MsgTo: String[SqToSize - 1]; {Nul term to name}
  63.   Subj: String[SqSubjSize - 1]; {Nul term subject}
  64.   Orig: AddrType; {Origin address}
  65.   Dest: AddrType; {Destination address}
  66.   DateWritten: LongInt; {Date/Time msg written}
  67.   DateArrived: LongInt; {Date/Time msg arrived here}
  68.   UtcOffset: Word; {Minutes offset from UTC}
  69.   ReplyTo: LongInt; {Original msg}
  70.   Replies: Array[1..SqMaxReply] of LongInt; {Replies}
  71.   AzDate: String[19]; {AsciiZ "Fido" style date}
  72.   End;
  73.  
  74.  
  75. Type SqIdxType = Record
  76.   Ofs: LongInt; {Offset of frame header}
  77.   UMsgId: LongInt; {Unique message id}
  78.   Hash: LongInt; {Hash of MsgTo name}
  79.   End;
  80.  
  81.  
  82. Const
  83.   SqIdxArraySize = 5200;  {5200}
  84.  
  85. Type SqIdxArrayType = Array[1..SqIdxArraySize] of SqIdxType;
  86.  
  87. Type SqIdxPtrType = ^SqIdxArrayType;
  88.  
  89. Type FreeListType = Record
  90.   FreePos: LongInt;
  91.   FreeSize: LongInt;
  92.   End;
  93.  
  94. Const MaxFree = 500;
  95.  
  96. Type FreeArrayType = Array[1..MaxFree] of FreeListType;
  97.  
  98. Const
  99.   SqBSize: Word = SizeOf(SqBaseType);
  100.   SqFSize: Word = SizeOf(SqFrameHdrType);
  101.   SqMSize: Word = SizeOf(SqMsgHdrType);
  102.   SqISize: Word = SizeOf(SqIdxType);
  103.  
  104.  
  105. Const
  106.   SqTxtBufferSize = 34000;  {34000}
  107.  
  108. Type SqInfoType = Record
  109.   FN: String[80];
  110.   MsgChars: Array[1..SqTxtBufferSize] of Char;
  111.   Error: Word;
  112.   SqdFile: File;
  113.   SqIFile: File;
  114.   SqBase: SqBaseType;
  115.   SqBaseExtra: Array[1..100] of Char;
  116.   SqdOpened: Boolean;
  117.   SqiOpened: Boolean;
  118.   SqiAlloc: Word;
  119.   Locked: Boolean;
  120.   FreeLoaded: Boolean;
  121.   HighestFree: Word;
  122.   Frame: SqFrameHdrType;
  123.   MsgHdr: SqMsgHdrType;
  124.   Extra: Array[1..100] of Char;
  125.   TxtCtr: Word;
  126.   MsgDone: Boolean;
  127.   CurrIdx: Word;
  128.   StrDate: String[8];
  129.   StrTime: String[8];
  130.   CurrentFramePos: LongInt;
  131.   CurrentUID: LongInt;
  132.   SName: String[35];
  133.   SHandle: String[35];
  134.   HName: LongInt;
  135.   HHandle: LongInt;
  136.   End;
  137.  
  138.  
  139. Type SqMsgObj = Object(AbsMsgObj)
  140.   SqInfo: ^SqInfoType;
  141.   SqIdx: ^SqIdxArrayType;
  142.   FreeArray: ^FreeArrayType;
  143.   Constructor Init; {Initialize}
  144.   Destructor Done; Virtual; {Done cleanup and dispose}
  145.   Function  OpenMsgBase: Word; Virtual; {Open message base}
  146.   Function  CloseMsgBase: Word; Virtual; {Close message base}
  147.   Function  CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word; Virtual;
  148.   Function  MsgBaseExists: Boolean; Virtual;
  149.   Procedure SetMsgPath(FN: String); Virtual; {Set filepath and name - no extension}
  150.   Function  SqdOpen: Word; Virtual; {Open squish data file}
  151.   Function  SqiOpen: Word; Virtual; {Open squish index file}
  152.   Procedure SqdClose; Virtual; {Close squish data file}
  153.   Procedure SqiClose; Virtual; {Close squish index file}
  154.   Function  LockMsgBase: Boolean; Virtual; {Lock msg base}
  155.   Function  UnLockMsgBase: Boolean; Virtual; {Unlock msg base}
  156.   Procedure ReadBase; Virtual; {Read base data record}
  157.   Procedure WriteBase; Virtual; {Write base data record}
  158.   Function  GetBeginFrame: LongInt; Virtual; {Get beginning frame pos}
  159.   Function  GetHighWater: LongInt; Virtual; {Get high water umsgid}
  160.   Function  GetHighMsgNum: LongInt; Virtual; {Get highest msg number}
  161.   Procedure ReadFrame(FPos: LongInt); Virtual; {Read frame at FPos}
  162.   Procedure ReadVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); Virtual; {Read frame at FPos into Frame}
  163.   Procedure WriteFrame(FPos: LongInt); Virtual; {Write frame at FPos}
  164.   Procedure WriteVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); Virtual;
  165.   Procedure UnlinkFrame(Var Frame: SqFrameHdrType); Virtual; {Unlink frame from linked list}
  166.   Procedure LinkFrameNext(Var Frame: SqFrameHdrType; OtherFrame: LongInt;
  167.     FramePos: LongInt); Virtual; {Link frame after other frame}
  168.   Procedure KillMsg(MsgNum: LongInt); {Kill msg msgnum}
  169.   Procedure KillExcess; {Kill msg in excess of limit}
  170.   Procedure FindFrame(Var FL: LongInt; Var FramePos: LongInt); Virtual;
  171.   Function  GetNextFrame: LongInt; Virtual; {Get next frame pos}
  172.   Procedure ReadMsgHdr(FPos: LongInt); Virtual; {Read msg hdr for frame at FPos}
  173.   Procedure WriteMsgHdr(FPos: LongInt); Virtual; {Read msg hdr for frame at FPos}
  174.   Procedure WriteText(FPos: LongInt); Virtual; {Write text buffer for frame at Fpos}
  175.   Function  SqHashName(Name: String): LongInt; Virtual; {Convert name to hash value}
  176.   Procedure StartNewMsg; Virtual; {Initialize msg header}
  177.   Function  GetFrom: String; Virtual; {Get message from}
  178.   Function  GetTo: String; Virtual; {Get message to}
  179.   Function  GetSubj: String; Virtual; {Get message subject}
  180.   Procedure SetFrom(Str: String); Virtual; {Set message from}
  181.   Procedure SetTo(Str: String); Virtual; {Set message to}
  182.   Procedure SetSubj(Str: String); Virtual; {Set message subject}
  183.   Procedure SetDate(Str: String); Virtual; {Set message date}
  184.   Procedure SetTime(Str: String); Virtual; {Set message time}
  185.   Function  GetDate: String; Virtual; {Get message date mm-dd-yy}
  186.   Function  GetTime: String; Virtual; {Get message time hh:mm}
  187.   Function  GetRefer: LongInt; Virtual; {Get reply to of current msg}
  188.   Procedure SetRefer(Num: LongInt); Virtual; {Set reply to of current msg}
  189.   Function  GetSeeAlso: LongInt; Virtual; {Get see also msg}
  190.   Procedure SetSeeAlso(Num: LongInt); Virtual; {Set see also msg}
  191.   Procedure ReadText(FPos: LongInt); Virtual;
  192.   Function  GetChar: Char; Virtual;
  193.   Function  GetString(MaxLen: Word): String; Virtual;
  194.   Procedure GetOrig(Var Addr: AddrType); Virtual;
  195.   Procedure SetOrig(Var Addr: AddrType); Virtual;
  196.   Procedure GetDest(Var Addr: AddrType); Virtual;
  197.   Procedure SetDest(Var Addr: AddrType); Virtual;
  198.   Function  EOM: Boolean; Virtual;
  199.   Function  WasWrap: Boolean; Virtual;
  200.   Procedure InitText; Virtual;
  201.   Procedure DoString(Str: String); Virtual; {Add string to message text}
  202.   Procedure DoChar(Ch: Char); Virtual; {Add character to message text}
  203.   Procedure DoStringLn(Str: String); Virtual; {Add string and newline to msg text}
  204.   Function  WriteMsg: Word; Virtual; {Write msg to msg base}
  205.   Procedure ReadIdx; Virtual;
  206.   Procedure WriteIdx; Virtual;
  207.   Procedure SeekFirst(MsgNum: LongInt); Virtual; {Seeks to 1st msg >= MsgNum}
  208.   Function  GetMsgNum: LongInt; Virtual;
  209.   Procedure SeekNext; Virtual;
  210.   Procedure SeekPrior; Virtual;
  211.   Function  SeekFound: Boolean; Virtual;
  212.   Function  GetIdxFramePos: LongInt; Virtual;
  213.   Function  GetIdxHash: LongInt; Virtual;
  214.   Function  IsLocal: Boolean; Virtual; {Is current msg local}
  215.   Function  IsCrash: Boolean; Virtual; {Is current msg crash}
  216.   Function  IsKillSent: Boolean; Virtual; {Is current msg kill sent}
  217.   Function  IsSent: Boolean; Virtual; {Is current msg sent}
  218.   Function  IsFAttach: Boolean; Virtual; {Is current msg file attach}
  219.   Function  IsReqRct: Boolean; Virtual; {Is current msg request receipt}
  220.   Function  IsReqAud: Boolean; Virtual; {Is current msg request audit}
  221.   Function  IsRetRct: Boolean; Virtual; {Is current msg a return receipt}
  222.   Function  IsFileReq: Boolean; Virtual; {Is current msg a file request}
  223.   Function  IsRcvd: Boolean; Virtual; {Is current msg received}
  224.   Function  IsPriv: Boolean; Virtual; {Is current msg priviledged/private}
  225.   Function  IsDeleted: Boolean; Virtual; {Is current msg deleted}
  226.   Procedure SetAttr(St: Boolean; Mask: LongInt); Virtual; {Set attribute}
  227.   Procedure SetLocal(St: Boolean); Virtual; {Set local status}
  228.   Procedure SetRcvd(St: Boolean); Virtual; {Set received status}
  229.   Procedure SetPriv(St: Boolean); Virtual; {Set priveledge vs public status}
  230.   Procedure SetCrash(St: Boolean); Virtual; {Set crash netmail status}
  231.   Procedure SetKillSent(St: Boolean); Virtual; {Set kill/sent netmail status}
  232.   Procedure SetSent(St: Boolean); Virtual; {Set sent netmail status}
  233.   Procedure SetFAttach(St: Boolean); Virtual; {Set file attach status}
  234.   Procedure SetReqRct(St: Boolean); Virtual; {Set request receipt status}
  235.   Procedure SetReqAud(St: Boolean); Virtual; {Set request audit status}
  236.   Procedure SetRetRct(St: Boolean); Virtual; {Set return receipt status}
  237.   Procedure SetFileReq(St: Boolean); Virtual; {Set file request status}
  238.   Procedure MsgStartUp; Virtual; {Set up message}
  239.   Procedure MsgTxtStartUp; Virtual; {Set up for msg text}
  240.   Procedure SetMailType(MT: MsgMailType); Virtual; {Set message base type}
  241.   Function  GetSubArea: Word; Virtual; {Get sub area number}
  242.   Procedure ReWriteHdr; Virtual; {Rewrite msg header after changes}
  243.   Procedure DeleteMsg; Virtual; {Delete current message}
  244.   Procedure LoadFree; Virtual; {Load freelist into memory}
  245.   Function  NumberOfMsgs: LongInt; Virtual; {Number of messages}
  246.   Procedure SetEcho(ES: Boolean); Virtual; {Set echo status}
  247.   Function  IsEchoed: Boolean; Virtual; {Is current msg unmoved echomail msg}
  248.   Function  GetLastRead(UNum: LongInt): LongInt; Virtual; {Get last read for user num}
  249.   Procedure SetLastRead(UNum: LongInt; LR: LongInt); Virtual; {Set last read}
  250.   Function  GetMsgLoc: LongInt; Virtual; {To allow reseeking to message}
  251.   Procedure SetMsgLoc(ML: LongInt); Virtual; {Reseek to message}
  252.   Function  IdxHighest: LongInt; Virtual; { *** }
  253.   Procedure YoursFirst(Name: String; Handle: String); Virtual; {Seek your mail}
  254.   Procedure YoursNext; Virtual; {Seek next your mail}
  255.   Function  YoursFound: Boolean; Virtual; {Message found}
  256.   Function  GetMsgDisplayNum: LongInt; Virtual; {Get msg number to display}
  257.   Function  GetTxtPos: LongInt; Virtual; {Get indicator of msg text position}
  258.   Procedure SetTxtPos(TP: LongInt); Virtual; {Set text position}
  259.   End;
  260.  
  261. Type SqMsgPtr = ^SqMsgObj;
  262.  
  263. Implementation
  264.  
  265. Uses MKFile, MKString, MKDos
  266. {$IFDEF WINDOWS}
  267. ,WinDos;
  268. {$ELSE}
  269. ,Dos;
  270. {$ENDIF}
  271.  
  272.  
  273. Const
  274.   SqMsgPriv =   $00001;
  275.   SqMsgCrash =  $00002;
  276.   SqMsgRcvd =   $00004;
  277.   SqMsgSent =   $00008;
  278.   SqMsgFile =   $00010;
  279.   SqMsgFwd =    $00020;
  280.   SqMsgOrphan = $00040;
  281.   SqMsgKill =   $00080;
  282.   SqMsgLocal =  $00100;
  283.   SqMsgHold =   $00200;
  284.   SqMsgXX2 =    $00400;
  285.   SqMsgFreq =   $00800;
  286.   SqMsgRrq =    $01000;
  287.   SqMsgCpt =    $02000;
  288.   SqMsgArq =    $04000;
  289.   SqMsgUrg =    $08000;
  290.   SqMsgScanned= $10000;
  291.  
  292.  
  293. Constructor SqMsgObj.Init;
  294.   Begin
  295.   New(SqInfo);
  296.   New(FreeArray);
  297.   If ((SqInfo = nil) or (FreeArray = nil)) Then
  298.     Begin
  299.     If SqInfo <> Nil Then
  300.       Dispose(SqInfo);
  301.     If FreeArray <> Nil Then
  302.       Dispose(FreeArray);
  303.     Fail;
  304.     Exit;
  305.     End;
  306.   SqInfo^.SqdOpened := False;
  307.   SqInfo^.SqiOpened := False;
  308.   SqInfo^.FN := '';
  309.   SqInfo^.Error := 0;
  310.   SqInfo^.Locked := False;
  311.   SqInfo^.FreeLoaded := False;
  312.   SqInfo^.SqiAlloc := 0;
  313.   End;
  314.  
  315.  
  316. Destructor SqMsgObj.Done;
  317.   Begin
  318.   If SqInfo^.SqdOpened Then
  319.     SqdClose;
  320.   If SqInfo^.SqiOpened Then
  321.     SqiClose;
  322.   If SqInfo^.SqIAlloc > 0 Then
  323.     If SqIdx <> Nil Then
  324.       FreeMem(SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
  325.   Dispose(FreeArray);
  326.   Dispose(SqInfo);
  327.   End;
  328.  
  329.  
  330. Procedure SqMsgObj.SetMsgPath(FN: String);
  331.   Begin
  332.   SqInfo^.FN := FExpand(FN);
  333.   If Pos('.', SqInfo^.FN) > 0 Then
  334.     SqInfo^.FN := Copy(SqInfo^.FN,1,Pos('.', SqInfo^.FN) - 1);
  335.   End;
  336.  
  337.  
  338. Function SqMsgObj.OpenMsgBase: Word;
  339.   Begin
  340.   If SqiOpen = 0 Then
  341.     Begin
  342.     OpenMsgBase := SqdOpen;
  343.     ReadIdx;
  344.     End
  345.   Else
  346.     OpenMsgBase := 100;
  347.   End;
  348.  
  349.  
  350. Function SqMsgObj.SqdOpen: Word;
  351.   Var
  352.     NumRead: Word;
  353.  
  354.   Begin
  355.   If Not SqInfo^.SqdOpened Then
  356.     Begin
  357.     Assign(SqInfo^.SqdFile, SqInfo^.FN + '.SQD');
  358.     FileMode := fmReadWrite + fmDenyNone;
  359.     If Not shReset(SqInfo^.SqdFile, 1) Then
  360.       SqdOpen := FileError
  361.     Else
  362.       Begin
  363.       SqInfo^.SqdOpened := True;
  364.       SqdOpen := 0;
  365.       If Not shRead(SqInfo^.SqdFile, SqInfo^.SqBase, 2, NumRead) Then
  366.         SqdOpen := FileError
  367.       Else
  368.         Begin
  369.         If SqInfo^.SqBase.Len = 0 Then
  370.           SqInfo^.SqBase.Len := SqBSize;
  371.         If SqInfo^.SqBase.Len > (SizeOf(SqBaseType) + 100) Then
  372.           SqdOpen := 1001
  373.         Else
  374.           Begin
  375.           SqBSize := SqInfo^.SqBase.Len;
  376.           ReadBase;
  377.           End;
  378.         End;
  379.       End;
  380.     End
  381.   Else
  382.     SqdOpen := 0;
  383.   End;
  384.  
  385.  
  386. Function SqMsgObj.SqiOpen: Word;
  387.   Begin
  388.   If Not SqInfo^.SqiOpened Then
  389.     Begin
  390.     Assign(SqInfo^.SqiFile, SqInfo^.FN + '.SQI');
  391.     FileMode := fmReadWrite + fmDenyNone;
  392.     If Not shReset(SqInfo^.SqiFile, SizeOf(SqIdxType)) Then
  393.       SqiOpen := FileError
  394.     Else
  395.       Begin
  396.       SqInfo^.SqiOpened := True;
  397.       SqiOpen := 0;
  398.       End;
  399.     End
  400.   Else
  401.     SqiOpen := 0;
  402.   End;
  403.  
  404.  
  405. Function SqMsgObj.CloseMsgBase: Word;
  406.   Begin
  407.   SqdClose;
  408.   SqiClose;
  409.   CloseMsgBase := 0;
  410.   End;
  411.  
  412.  
  413. Function SqMsgObj.CreateMsgBase(MaxMsg: Word; MaxDays: Word): Word;
  414.   Begin
  415.   If Not SqInfo^.SqdOpened Then
  416.     Begin
  417.     FillChar(SqInfo^.SqBase, SizeOf(SqInfo^.SqBase), 0);
  418.     SqInfo^.SqBase.Len := 256;
  419.     SqInfo^.SqBase.SqHdrSize := SqFSize;
  420.     SqInfo^.SqBase.UID := 1;
  421.     SqInfo^.SqBase.NumMsg := 0;
  422.     SqInfo^.SqBase.Base := SqInfo^.FN;
  423.     Str2Az(SqInfo^.FN, 78, SqInfo^.SqBase.Base);
  424.     SqInfo^.SqBase.MaxMsg := MaxMsg;
  425.     SqInfo^.SqBase.KeepDays := MaxDays;
  426.     SqInfo^.SqBase.EndFrame := SqInfo^.SqBase.Len;
  427.     CreateMsgBase := SaveFile(SqInfo^.FN + '.SQD', SqInfo^.SqBase, SqInfo^.SqBase.Len);
  428.     If SaveFile(SqInfo^.FN + '.SQI', SqInfo^.SqBase, 0) = 0 Then;
  429.     If SaveFile(SqInfo^.FN + '.SQL', SqInfo^.SqBase, 0) = 0 Then;
  430.     End
  431.   Else
  432.     CreateMsgBase := 176;
  433.   End;
  434.  
  435.  
  436. Function SqMsgObj.MsgBaseExists: Boolean;
  437.   Begin
  438.   MsgBaseExists :=  FileExist(SqInfo^.FN + '.SQD');
  439.   End;
  440.  
  441.  
  442. Procedure SqMsgObj.SqdClose;
  443.   Begin
  444.   If SqInfo^.SqdOpened Then
  445.     Close(SqInfo^.SqdFile);
  446.   If IOResult <> 0 Then;
  447.   SqInfo^.SqdOpened := False;
  448.   End;
  449.  
  450.  
  451. Function SqMsgObj.LockMsgBase: Boolean; {Lock msg base}
  452.   Begin
  453.   If Not SqInfo^.Locked Then
  454.     Begin
  455.     SqInfo^.Locked := shLock(SqInfo^.SqdFile, 0, 1) = 0;
  456.     LockMsgBase := SqInfo^.Locked;
  457.     ReadBase;
  458.     ReadIdx;
  459.     SqInfo^.FreeLoaded := False;
  460.     End;
  461.   End;
  462.  
  463.  
  464. Function SqMsgObj.UnLockMsgBase: Boolean; {Unlock msg base}
  465.   Begin
  466.   If SqInfo^.Locked Then
  467.     Begin
  468.     WriteBase;
  469.     WriteIdx;
  470.     SqInfo^.Locked := Not UnLockFile(SqInfo^.SqdFile, 0, 1) < 2;
  471.     UnLockMsgBase := Not SqInfo^.Locked;
  472.     End;
  473.   End;
  474.  
  475.  
  476. Procedure SqMsgObj.SqiClose;
  477.   Begin
  478.   If SqInfo^.SqiOpened Then
  479.     Close(SqInfo^.SqiFile);
  480.   If IoResult <> 0 Then;
  481.   SqInfo^.SqiOpened := False;
  482.   End;
  483.  
  484.  
  485. Procedure SqMsgObj.ReadBase;
  486.   Var
  487.     NumRead: Word;
  488.  
  489.   Begin
  490.   Seek(SqInfo^.SqdFile, 0);
  491.   If Not shRead(SqInfo^.SqdFile, SqInfo^.SqBase, SqBSize, NumRead) Then
  492.     SqInfo^.Error := FileError;
  493.   If SqInfo^.SqBase.SqHdrSize = 0 Then
  494.     SQInfo^.SqBase.SqHdrSize := SqFSize;
  495.   SqFSize := SqInfo^.SqBase.SqHdrSize;
  496.   End;
  497.  
  498.  
  499. Procedure SqMsgObj.WriteBase;
  500.   Begin
  501.   Seek(SqInfo^.SqdFile, 0);
  502.   If Not shWrite(SqInfo^.SqdFile, SqInfo^.SqBase, SQBSize) Then
  503.     SqInfo^.Error := FileError;
  504.   End;
  505.  
  506.  
  507. Procedure SqMsgObj.StartNewMsg; {Initialize msg header}
  508.   Begin
  509.   FillChar(SqInfo^.MsgHdr, SizeOf(SqInfo^.MsgHdr), 0);
  510.   FillChar(SqInfo^.Frame, SizeOf(SqInfo^.Frame), 0);
  511.   SqInfo^.TxtCtr := 0;
  512.   SqInfo^.StrDate := '';
  513.   SqInfo^.StrTime := '';
  514.   End;
  515.  
  516.  
  517. Function SqMsgObj.GetFrom: String; {Get message from}
  518.   Begin
  519.   GetFrom := Az2Str(SqInfo^.MsgHdr.MsgFrom, 35);
  520.   End;
  521.  
  522.  
  523. Function SqMsgObj.GetTo: String; {Get message to}
  524.   Begin
  525.   GetTo := Az2Str(SqInfo^.MsgHdr.MsgTo, 35);
  526.   End;
  527.  
  528.  
  529. Function SqMsgObj.GetSubj: String; {Get message subject}
  530.   Begin
  531.   GetSubj := Az2Str(SqInfo^.MsgHdr.Subj, 72);
  532.   End;
  533.  
  534.  
  535. Procedure SqMsgObj.SetFrom(Str: String); {Set message from}
  536.   Begin
  537.   Str2Az(Str, 35, SqInfo^.MsgHdr.MsgFrom);
  538.   End;
  539.  
  540.  
  541. Procedure SqMsgObj.SetTo(Str: String); {Set message to}
  542.   Begin
  543.   Str2Az(Str,35, SqInfo^.MsgHdr.MsgTo);
  544.   End;
  545.  
  546.  
  547. Procedure SqMsgObj.SetSubj(Str: String); {Set message subject}
  548.   Begin
  549.   Str2Az(Str,72, SqInfo^.MSgHdr.Subj);
  550.   End;
  551.  
  552.  
  553. Function SqMsgObj.GetDate: String; {Get message date mm-dd-yy}
  554.   Var
  555.     TmpDate: LongInt;
  556.  
  557.   Begin
  558.   TmpDate := (SqInfo^.MsgHdr.DateWritten shr 16) +
  559.    ((SqInfo^.MsgHdr.DateWritten and $ffff) shl 16);
  560.   GetDate := DateStr(TmpDate);
  561.   End;
  562.  
  563.  
  564. Function SqMsgObj.GetTime: String; {Get message time hh:mm}
  565.   Var
  566.     TmpDate: LongInt;
  567.  
  568.   Begin
  569.   TmpDate := (SqInfo^.MsgHdr.DateWritten shr 16) +
  570.    ((SqInfo^.MsgHdr.DateWritten and $ffff) shl 16);
  571.   GetTime := TimeStr(TmpDate);
  572.   End;
  573.  
  574.  
  575. Procedure SqMsgObj.SetDate(Str: String);
  576.   Begin
  577.   SqInfo^.StrDate := Copy(Str,1,8);
  578.   End;
  579.  
  580.  
  581. Procedure SqMsgObj.SetTime(Str: String);
  582.   Begin
  583.   SqInfo^.StrTime := Copy(Str,1,8);
  584.   End;
  585.  
  586.  
  587. Procedure SqMsgObj.GetOrig(Var Addr: AddrType);
  588.   Begin
  589.   Addr := SqInfo^.MsgHdr.Orig;
  590.   End;
  591.  
  592.  
  593. Procedure SqMsgObj.SetOrig(Var Addr: AddrType);
  594.   Begin
  595.   SqInfo^.MsgHdr.Orig := Addr;
  596.   End;
  597.  
  598.  
  599. Procedure SqMsgObj.GetDest(Var Addr: AddrType);
  600.   Begin
  601.   Addr := SqInfo^.MsgHdr.Dest;
  602.   End;
  603.  
  604.  
  605. Procedure SqMsgObj.SetDest(Var Addr: AddrType);
  606.   Begin
  607.   SqInfo^.MsgHdr.Dest := Addr;
  608.   End;
  609.  
  610.  
  611. Function SqMsgObj.SqHashName(Name: String): LongInt;
  612.   Var
  613.     Hash: LongInt;
  614.     Tmp: LongInt;
  615.     Counter: Word;
  616.  
  617.   Begin
  618.   Hash := 0;
  619.   Counter := 1;
  620.   While Counter <= Length(Name) Do
  621.     Begin
  622.     Hash := (Hash shl 4) + Ord(LoCase(Name[Counter]));
  623.     Tmp := Hash and $F0000000;
  624.     If (Tmp <> 0) Then
  625.       Hash := (Hash or (Tmp shr 24)) or Tmp;
  626.     Inc(Counter);
  627.     End;
  628.   SqHashName := Hash and $7fffffff;
  629.   End;
  630.  
  631.  
  632. Procedure SqMsgObj.ReadFrame(FPos: LongInt); {Read frame at FPos}
  633.   Begin
  634.   ReadVarFrame(SqInfo^.Frame, FPos);
  635.   End;
  636.  
  637.  
  638. Procedure SqMsgObj.ReadVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); {Read frame at FPos}
  639.   Var
  640.     NumRead: Word;
  641.  
  642.   Begin
  643.   Seek(SqInfo^.SqdFile, FPos);
  644.   SqInfo^.Error := IoResult;
  645.   If SqInfo^.Error = 0 Then
  646.     Begin
  647.     If Not shRead(SqInfo^.SqdFile, Frame, SizeOf(SqFrameHdrType), NumRead) Then
  648.       SqInfo^.Error := FileError;
  649.     End;
  650.   End;
  651.  
  652.  
  653. Procedure SqMsgObj.WriteFrame(FPos: LongInt); {Read frame at FPos}
  654.   Begin
  655.   WriteVarFrame(SqInfo^.Frame, FPos);
  656.   End;
  657.  
  658.  
  659. Procedure SqMsgObj.WriteVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); {Write frame at FPos}
  660.   Begin
  661.   Seek(SqInfo^.SqdFile, FPos);
  662.   SqInfo^.Error := IoResult;
  663.   If SqInfo^.Error = 0 Then
  664.     Begin
  665.     If Not shWrite(SqInfo^.SqdFile, Frame, SizeOf(SqFrameHdrType)) Then
  666.       SqInfo^.Error := FileError;
  667.     End;
  668.   End;
  669.  
  670.  
  671.  
  672. Procedure SqMsgObj.UnlinkFrame(Var Frame: SqFrameHdrType);
  673.   Var
  674.     TmpFrame: SqFrameHdrType;
  675.  
  676.   Begin
  677.   If Frame.PrevFrame <> 0 Then
  678.     Begin
  679.     ReadVarFrame(TmpFrame, Frame.PrevFrame);
  680.     TmpFrame.NextFrame := Frame.NextFrame;
  681.     WriteVarFrame(TmpFrame, Frame.PrevFrame);
  682.     End;
  683.   If Frame.NextFrame <> 0 Then
  684.     Begin
  685.     ReadVarFrame(TmpFrame, Frame.NextFrame);
  686.     TmpFrame.PrevFrame := Frame.PrevFrame;
  687.     WriteVarFrame(TmpFrame, Frame.NextFrame);
  688.     End;
  689.   End;
  690.  
  691.  
  692. Procedure SqMsgObj.LoadFree;
  693.   Var
  694.     i: Word;
  695.     TmpFrame: SqFrameHdrType;
  696.     TmpPos: LongInt;
  697.  
  698.   Begin
  699.   For i := 1 to MaxFree Do
  700.     Begin
  701.     FreeArray^[i].FreePos := 0;
  702.     FreeArray^[i].FreeSize := 0;
  703.     End;
  704.   SqInfo^.FreeLoaded := True;
  705.   i := 0;
  706.   TmpPos := SqInfo^.SqBase.FirstFree;
  707.   While ((TmpPos <> 0) and (i < MaxFree)) Do
  708.     Begin
  709.     ReadVarFrame(TmpFrame, TmpPos);
  710.     Inc(i);
  711.     FreeArray^[i].FreeSize := TmpFrame.FrameLength;
  712.     FreeArray^[i].FreePos := TmpPos;
  713.     TmpPos := TmpFrame.NextFrame;
  714.     End;
  715.   SqInfo^.HighestFree := i;
  716.   End;
  717.  
  718.  
  719. Procedure SqMsgObj.FindFrame(Var FL: LongInt; Var FramePos: LongInt);
  720.   Var
  721.     TmpFrame: SqFrameHdrType;
  722.     BestFoundPos: LongInt;
  723.     BestFoundSize: LongInt;
  724.     BestIdx: Word;
  725.     i: Word;
  726.  
  727.   Begin
  728.   If Not SqInfo^.FreeLoaded Then
  729.     LoadFree;
  730.   BestFoundPos := 0;
  731.   BestFoundSize := 0;
  732.   For i := 1 to SqInfo^.HighestFree Do
  733.     Begin
  734.     If (FreeArray^[i].FreeSize > FL) Then
  735.       Begin
  736.       If ((BestFoundSize = 0) or (FreeArray^[i].FreeSize < BestFoundSize)) Then
  737.         Begin
  738.         BestFoundSize := FreeArray^[i].FreeSize;
  739.         BestFoundPos := FreeArray^[i].FreePos;
  740.         BestIdx := i;
  741.         End;
  742.       End
  743.     End;
  744.   FramePos := BestFoundPos;
  745.   If FramePos <> 0 Then
  746.     Begin
  747.     ReadVarFrame(TmpFrame, FramePos);
  748.     FreeArray^[BestIdx].FreePos := 0;
  749.     FreeArray^[BestIdx].FreeSize := 0;
  750.     End;
  751.   If FramePos = 0 Then
  752.     Begin
  753.     FL := 0;
  754.     FramePos := SqInfo^.SqBase.EndFrame;
  755.     End
  756.   Else
  757.     Begin
  758.     UnLinkFrame(TmpFrame);
  759.     If TmpFrame.PrevFrame = 0 Then
  760.       SqInfo^.SqBase.FirstFree := TmpFrame.NextFrame;
  761.     If TmpFrame.NextFrame = 0 Then
  762.       SqInfo^.SqBase.LastFree := TmpFrame.PrevFrame;
  763.     FL := TmpFrame.FrameLength;
  764.     End;
  765.   End;
  766.  
  767.  
  768. Procedure SqMsgObj.LinkFrameNext(Var Frame: SqFrameHdrType; OtherFrame: LongInt;
  769.   FramePos: LongInt);
  770.  
  771.   Var
  772.     TmpFrame: SqFrameHdrType;
  773.  
  774.   Begin
  775.   If OtherFrame <> 0 Then
  776.     Begin
  777.     ReadVarFrame(TmpFrame, OtherFrame);
  778.     TmpFrame.NextFrame := FramePos;
  779.     Frame.PrevFrame := OtherFrame;
  780.     WriteVarFrame(TmpFrame, OtherFrame);
  781.     End;
  782.   End;
  783.  
  784.  
  785. Procedure SqMsgObj.KillMsg(MsgNum: LongInt);
  786.   Var
  787.     i: Word;
  788.     KillPos: LongInt;
  789.     IndexPos: LongInt;
  790.     KillFrame: SqFrameHdrType;
  791.     TmpFrame: SqFrameHdrType;
  792.     CurrMove: LongInt;
  793.     AlreadyLocked: Boolean;
  794.     FreeCtr: Word;
  795.  
  796.   Begin
  797.   AlreadyLocked := SqInfo^.Locked;
  798.   If Not AlreadyLocked Then
  799.     If LockMsgBase Then;
  800.   If SqIdx = Nil Then
  801.     SqInfo^.Error := 999
  802.   Else
  803.     Begin
  804.     i := 1;
  805.     While ((i <= SqInfo^.SqBase.NumMsg) and (MsgNum <> SqIdx^[i].UMsgId)) Do
  806.       Inc(i);
  807.     If MsgNum = SqIdx^[i].UMsgId Then
  808.       Begin
  809.       IndexPos := i;
  810.       KillPos := SqIdx^[i].Ofs;
  811.       ReadVarFrame(KillFrame, KillPos);
  812.       If KillFrame.PrevFrame = 0 Then
  813.         SqInfo^.SqBase.BeginFrame := KillFrame.NextFrame;
  814.       If KillFrame.NextFrame = 0 Then
  815.         SqInfo^.SqBase.LastFrame := KillFrame.PrevFrame;
  816.       KillFrame.FrameType := sqFrameFree;
  817.       UnLinkFrame(KillFrame);
  818.       If ((SqInfo^.SqBase.FirstFree = 0) or (SqInfo^.SqBase.LastFree = 0)) Then
  819.         Begin
  820.         SqInfo^.SqBase.FirstFree := KillPos;
  821.         SqInfo^.SqBase.LastFree := KillPos;
  822.         KillFrame.PrevFrame := 0;
  823.         KillFrame.NextFrame := 0;
  824.         End
  825.       Else
  826.         Begin
  827.         KillFrame.NextFrame := 0;
  828.         KillFrame.PrevFrame := SqInfo^.SqBase.LastFree;
  829.         ReadVarFrame(TmpFrame, SqInfo^.SqBase.LastFree);
  830.         TmpFrame.NextFrame := KillPos;
  831.         WriteVarFrame(TmpFrame, SqInfo^.SqBase.LastFree);
  832.         SqInfo^.SqBase.LastFree := KillPos;
  833.         End;
  834.       WriteVarFrame(KillFrame, KillPos);
  835.       FreeCtr := 1;
  836.       While ((FreeCtr < MaxFree) and (FreeArray^[FreeCtr].FreePos <> 0)) Do
  837.         Inc(FreeCtr);
  838.       If FreeArray^[FreeCtr].FreePos = 0 Then
  839.         Begin
  840.         FreeArray^[FreeCtr].FreePos := KillPos;
  841.         FreeArray^[FreeCtr].FreeSize := KillFrame.FrameLength;
  842.         End;
  843.       If FreeCtr > SqInfo^.HighestFree Then
  844.         SqInfo^.HighestFree := FreeCtr;
  845.       Dec(SqInfo^.SqBase.NumMsg);
  846.       Dec(SqInfo^.SqBase.HighMsg);
  847.       CurrMove := IndexPos;
  848.       While CurrMove <= SqInfo^.SqBase.NumMsg Do
  849.         Begin
  850.         SqIdx^[CurrMove] := SqIdx^[CurrMove + 1];
  851.         Inc(CurrMove);
  852.         End;
  853.   {    NumMove := SqInfo^.SqBase.NumMsg + 1 - IndexPos;
  854.       NumMove := NumMove * SizeOf(SqIdxType);
  855.       Move(SqIdx^[IndexPos + 1], SqIdx^[IndexPos], NumMove);  }
  856.       End;
  857.     End;
  858.   If Not AlreadyLocked Then
  859.     If UnlockMsgBase Then;
  860.   End;
  861.  
  862.  
  863. Procedure SqMsgObj.ReadMsgHdr(FPos: LongInt); {Read msg hdr for frame at FPos}
  864.   Var
  865.     NumRead: Word;
  866.  
  867.   Begin
  868.   Seek(SqInfo^.SqdFile, FPos + SqFSize);
  869.   SqInfo^.Error := IoResult;
  870.   If SqInfo^.Error = 0 Then
  871.     Begin
  872.     If Not shRead(SqInfo^.SqdFile, SqInfo^.MsgHdr, SizeOf(SqMsgHdrType), NumRead) Then
  873.       SqInfo^.Error := FileError;
  874.     End;
  875.   End;
  876.  
  877.  
  878. Procedure SqMsgObj.WriteMsgHdr(FPos: LongInt); {Read msg hdr for frame at FPos}
  879.   Var
  880.     NumRead: Word;
  881.  
  882.   Begin
  883.   Seek(SqInfo^.SqdFile, FPos + SqFSize);
  884.   SqInfo^.Error := IoResult;
  885.   If SqInfo^.Error = 0 Then
  886.     Begin
  887.     If Not shWrite(SqInfo^.SqdFile, SqInfo^.MsgHdr, SizeOf(SqMsgHdrType)) Then
  888.       SqInfo^.Error := FileError;
  889.     End;
  890.   End;
  891.  
  892.  
  893. Procedure SqMsgObj.WriteText(FPos: LongInt); {Write text buffer for frame at Fpos}
  894.   Begin
  895.   Seek(SqInfo^.SqdFile, FPos + SqFSize + SqMSize);
  896.   SqInfo^.Error := IoResult;
  897.   If SqInfo^.Error = 0 Then
  898.     Begin
  899.     If Not shWrite(SqInfo^.SqdFile, SqInfo^.MsgChars, SqInfo^.TxtCtr) Then
  900.       SqInfo^.Error := FileError;
  901.     End;
  902.   End;
  903.  
  904.  
  905. Function SqMsgObj.GetBeginFrame: LongInt; {Get beginning frame pos}
  906.   Begin
  907.   GetBeginFrame := SqInfo^.SqBase.BeginFrame;
  908.   End;
  909.  
  910.  
  911. Function SqMsgObj.GetNextFrame: LongInt; {Get next frame pos}
  912.   Begin
  913.   GetNextFrame := SqInfo^.Frame.NextFrame;
  914.   End;
  915.  
  916.  
  917. Procedure SqMsgObj.ReadText(FPos: LongInt);
  918.   Begin
  919.   Seek(SqInfo^.SqdFile, FPos + SqFSize + SqMSize);
  920.   SqInfo^.Error := IoResult;
  921.   If SqInfo^.Error = 0 Then
  922.     Begin
  923.     If SqInfo^.Frame.MsgLength > SqTxtBufferSize Then
  924.       BlockRead(SqInfo^.SqdFile, SqInfo^.MsgChars, SqTxtBufferSize)
  925.     Else
  926.       BlockRead(SqInfo^.SqdFile, SqInfo^.MsgChars, SqInfo^.Frame.MsgLength);
  927.     SqInfo^.Error := IoResult;
  928.     End;
  929.   SqInfo^.TxtCtr := 1 + SqInfo^.Frame.ControlLength;
  930.   SqInfo^.MsgDone := False;
  931.   LastSoft := False;
  932.   End;
  933.  
  934.  
  935.  
  936. Procedure SqMsgObj.InitText;
  937.   Begin
  938.   SqInfo^.TxtCtr := 0;
  939.   End;
  940.  
  941.  
  942. Procedure SqMsgObj.DoString(Str: String); {Add string to message text}
  943.   Var
  944.     i: Word;
  945.  
  946.   Begin
  947.   i := 1;
  948.   While i <= Length(Str) Do
  949.     Begin
  950.     DoChar(Str[i]);
  951.     Inc(i);
  952.     End;
  953.   End;
  954.  
  955.  
  956. Procedure SqMsgObj.DoChar(Ch: Char); {Add character to message text}
  957.   Begin
  958.   If SqInfo^.TxtCtr < SqTxtBufferSize Then
  959.     Begin
  960.     Inc(SqInfo^.TxtCtr);
  961.     SqInfo^.MsgChars[SqInfo^.TxtCtr] := ch;
  962.     End;
  963.   End;
  964.  
  965.  
  966. Procedure SqMsgObj.DoStringLn(Str: String); {Add string and newline to msg text}
  967.   Begin
  968.   DoString(Str);
  969.   DoChar(#13);
  970.   End;
  971.  
  972.  
  973.  
  974. Procedure SqMsgObj.KillExcess;
  975.   Var
  976.     AlreadyLocked: Boolean;
  977.  
  978.   Begin
  979.   AlreadyLocked := SqInfo^.Locked;
  980.   If Not AlreadyLocked Then
  981.     If LockMsgBase Then;
  982.   If SqIdx = Nil Then
  983.     SqInfo^.error := 999
  984.   Else
  985.     Begin
  986.     If ((SqInfo^.SqBase.MaxMsg > 0) and
  987.     (SqInfo^.SqBase.MaxMsg > SqInfo^.SqBase.SkipMsg)) Then
  988.       Begin
  989.       While (SqInfo^.SqBase.NumMsg > SqInfo^.SqBase.MaxMsg) Do
  990.         KillMsg(SqIdx^[SqInfo^.SqBase.SkipMsg + 1].UMsgId);
  991.       End;
  992.     End;
  993.   If Not AlreadyLocked Then
  994.     If UnlockMsgBase Then;
  995.   End;
  996.  
  997.  
  998. Function SqMsgObj.WriteMsg: Word; {Write msg to msg base}
  999.   Var
  1000.     MsgSize: LongInt;
  1001.     FrameSize: LongInt;
  1002.     FramePos: LongInt;
  1003.     TmpFrame: SqFrameHdrType;
  1004.     TmpDate: LongInt;
  1005.     {$IFDEF WINDOWS}
  1006.     TmpDT: TDateTime;
  1007.     {$ELSE}
  1008.     TmpDT: DateTime;
  1009.     {$ENDIF}
  1010.     TmpStr: String;
  1011.     AlreadyLocked: Boolean;
  1012.  
  1013.   Begin
  1014.   DoChar(#0);
  1015.   TmpDT.Year := Str2Long(Copy(SqInfo^.StrDate,7,2));
  1016.   If TmpDT.Year > 79 Then
  1017.     Inc(TmpDT.Year, 1900)
  1018.   Else
  1019.     Inc(TmpDT.Year, 2000);
  1020.   TmpDT.Month := Str2Long(Copy(SqInfo^.StrDate,1,2));
  1021.   TmpDT.Day := Str2Long(Copy(SqInfo^.StrDate,4,2));
  1022.   TmpDt.Hour := Str2Long(Copy(SqInfo^.StrTime,1,2));
  1023.   TmpDt.Min := Str2Long(Copy(SqInfo^.StrTime, 4,2));
  1024.   TmpDt.Sec := 0;
  1025.   TmpStr := FormattedDate(TmpDT, 'DD NNN YY  ') + Copy(SqInfo^.StrTime,1,5) + ':00';
  1026.   PackTime(TmpDT, TmpDate);
  1027.   SqInfo^.MsgHdr.DateWritten :=  (TmpDate shr 16) + ((TmpDate and $ffff) shl 16);
  1028.   TmpDate := GetDosDate;
  1029.   SqInfo^.MsgHdr.DateArrived := (TmpDate shr 16) + ((TmpDate and $ffff) shl 16);
  1030.   Str2AZ(TmpStr, 20, SqInfo^.MsgHdr.AZDate);
  1031.   AlreadyLocked := SqInfo^.Locked;
  1032.   If Not AlreadyLocked Then
  1033.     If LockMsgBase Then;
  1034.   If SqInfo^.Locked Then
  1035.     Begin
  1036.     MsgSize := SqInfo^.TxtCtr + SqMSize;
  1037.     FrameSize := MsgSize;
  1038.     FindFrame(FrameSize, FramePos);
  1039.     If SqInfo^.SqBase.LastFrame <> 0 Then
  1040.       Begin
  1041.       ReadVarFrame(TmpFrame, SqInfo^.SqBase.LastFrame);
  1042.       TmpFrame.NextFrame := FramePos;
  1043.       WriteVarFrame(TmpFrame, SqInfo^.SqBase.LastFrame);
  1044.       TmpFrame.PrevFrame := SqInfo^.SqBase.LastFrame;
  1045.       End
  1046.     Else
  1047.       Begin
  1048.       SqInfo^.SqBase.BeginFrame := FramePos;
  1049.       TmpFrame.PrevFrame := 0;
  1050.       End;
  1051.     TmpFrame.Id := SqHdrId;
  1052.     TmpFrame.FrameType := SqFrameMsg;
  1053.     SqInfo^.SqBase.LastFrame := FramePos;
  1054.     TmpFrame.NextFrame := 0;
  1055.     TmpFrame.FrameLength := FrameSize;
  1056.     TmpFrame.MsgLength := MsgSize;
  1057.     TmpFrame.ControlLength := 0;
  1058.     If TmpFrame.FrameLength = 0 Then
  1059.       Begin
  1060.       TmpFrame.FrameLength := TmpFrame.MsgLength + 0; {slack to minimize free frames}
  1061.       SqInfo^.SqBase.EndFrame := FramePos + SqFSize + TmpFrame.FrameLength;
  1062.       End;
  1063.     If SqInfo^.SqBase.NumMsg >= SqInfo^.SqiAlloc Then
  1064.       Begin
  1065.       WriteIdx;
  1066.       ReadIdx;
  1067.       End;
  1068.     If SqIdx = Nil Then
  1069.       Begin
  1070.       SqInfo^.Error := 999;
  1071.       WriteMsg := 999;
  1072.       End
  1073.     Else
  1074.       Begin
  1075.       WriteVarFrame(TmpFrame, FramePos);
  1076.       WriteMsgHdr(FramePos);
  1077.       WriteText(FramePos);
  1078.       Inc(SqInfo^.SqBase.NumMsg);
  1079.       SqIdx^[SqInfo^.SqBase.NumMsg].Ofs := FramePos;
  1080.       SqIdx^[SqInfo^.SqBase.NumMsg].UMsgId := SqInfo^.SqBase.UID;
  1081.       SqIdx^[SqInfo^.SqBase.NumMsg].Hash := SqHashName(Az2Str(SqInfo^.MsgHdr.MsgTo, 35));
  1082.       Inc(SqInfo^.SqBase.UId);
  1083.       SqInfo^.SqBase.HighMsg := SqInfo^.SqBase.NumMsg;
  1084.       KillExcess;
  1085.       SqInfo^.CurrIdx := SqInfo^.SqBase.NumMsg;
  1086.       WriteMsg := 0;
  1087.       End;
  1088.     If Not AlreadyLocked Then
  1089.       If UnLockMsgBase Then;
  1090.     End
  1091.   Else
  1092.     WriteMsg := 5;
  1093.   End;
  1094.  
  1095.  
  1096.  
  1097. Function SqMsgObj.GetString(MaxLen: Word): String;
  1098.   Var
  1099.     WPos: Word;
  1100.     WLen: Byte;
  1101.     StrDone: Boolean;
  1102.     TxtOver: Boolean;
  1103.     StartSoft: Boolean;
  1104.     CurrLen: Word;
  1105.     PPos: Word;
  1106.     TmpCh: Char;
  1107.  
  1108.   Begin
  1109.   StrDone := False;
  1110.   CurrLen := 0;
  1111.   PPos := SqInfo^.TxtCtr;
  1112.   WPos := 0;
  1113.   WLen := 0;
  1114.   StartSoft := LastSoft;
  1115.   LastSoft := True;
  1116.   TmpCh := GetChar;
  1117.   While ((Not StrDone) And (CurrLen < MaxLen) And (Not SqInfo^.MsgDone)) Do
  1118.     Begin
  1119.     Case TmpCh of
  1120.       #$00:;
  1121.       #$0d: Begin
  1122.             StrDone := True;
  1123.             LastSoft := False;
  1124.             End;
  1125.       #$8d:;
  1126.       #$0a:;
  1127.       #$20: Begin
  1128.             If ((CurrLen <> 0) or (Not StartSoft)) Then
  1129.               Begin
  1130.               Inc(CurrLen);
  1131.               WLen := CurrLen;
  1132.               GetString[CurrLen] := TmpCh;
  1133.               WPos := SqInfo^.TxtCtr;
  1134.               End
  1135.             Else
  1136.               StartSoft := False;
  1137.             End;
  1138.       Else
  1139.         Begin
  1140.         Inc(CurrLen);
  1141.         GetString[CurrLen] := TmpCh;
  1142.         End;
  1143.       End;
  1144.     If Not StrDone Then
  1145.       TmpCh := GetChar;
  1146.     End;
  1147.   If StrDone Then
  1148.     Begin
  1149.     GetString[0] := Chr(CurrLen);
  1150.     End
  1151.   Else
  1152.     If SqInfo^.MsgDone Then
  1153.       Begin
  1154.       GetString[0] := Chr(CurrLen);
  1155.       End
  1156.     Else
  1157.       Begin
  1158.       If WLen = 0 Then
  1159.         Begin
  1160.         GetString[0] := Chr(CurrLen);
  1161.         Dec(SqInfo^.TxtCtr);
  1162.         End
  1163.       Else
  1164.         Begin
  1165.         GetString[0] := Chr(WLen);
  1166.         SqInfo^.TxtCtr := WPos;
  1167.         End;
  1168.       End;
  1169.   End;
  1170.  
  1171.  
  1172. Function SqMsgObj.EOM: Boolean;
  1173.   Begin
  1174.   EOM := SqInfo^.MsgDone;
  1175.   End;
  1176.  
  1177.  
  1178. Function SqMsgObj.WasWrap: Boolean;
  1179.   Begin
  1180.   WasWrap := LastSoft;
  1181.   End;
  1182.  
  1183.  
  1184. Function SqMsgObj.GetChar: Char;
  1185.   Begin
  1186.   If ((SqInfo^.TxtCtr >= SqInfo^.Frame.MsgLength) Or
  1187.   (SqInfo^.MsgChars[SqInfo^.TxtCtr] = #0)) Then
  1188.     Begin
  1189.     GetChar := #0;
  1190.     SqInfo^.MsgDone := True;
  1191.     End
  1192.   Else
  1193.     Begin
  1194.     GetChar := SqInfo^.MsgChars[SqInfo^.TxtCtr];
  1195.     Inc(SqInfo^.TxtCtr);
  1196.     End;
  1197.   End;
  1198.  
  1199.  
  1200. Function SqMsgObj.GetHighWater: LongInt; {Get high water umsgid}
  1201.   Begin
  1202.   GetHighWater := LongInt(SqInfo^.SqBase.HighWater);
  1203.   End;
  1204.  
  1205.  
  1206. Function SqMsgObj.GetHighMsgNum: LongInt; {Get highest msg number}
  1207.   Begin
  1208.   GetHighMsgNum := LongInt(SqInfo^.SqBase.Uid) - 1;
  1209.   End;
  1210.  
  1211.  
  1212. Procedure SqMsgObj.ReadIdx;
  1213.   Var
  1214.     NumRead: Word;
  1215.  
  1216.   Begin
  1217.   If SqInfo^.SqiAlloc > 0 Then
  1218.     If SqIdx <> Nil Then
  1219.       FreeMem(SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
  1220.   SqInfo^.SqiAlloc := FileSize(SqInfo^.SqiFile) + 100;
  1221.   If SqInfo^.SqiAlloc > SqIdxArraySize Then
  1222.     SqInfo^.SqiAlloc := SqIdxArraySize ;
  1223.   GetMem(SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
  1224.   If SqIdx = nil Then
  1225.     SqInfo^.Error := 999
  1226.   Else
  1227.     Begin
  1228.     Seek(SqInfo^.SqiFile, 0);
  1229.     If IoResult = 0 Then
  1230.       Begin
  1231.       If Not shRead(SqInfo^.SqiFile, SqIdx^, SqInfo^.SqiAlloc, NumRead) Then
  1232.         SqInfo^.Error := FileError;
  1233.       End
  1234.     Else
  1235.       SqInfo^.Error := 300;
  1236.     End;
  1237.   End;
  1238.  
  1239.  
  1240. Procedure SqMsgObj.WriteIdx;
  1241.   Begin
  1242.   If SqIdx = nil Then
  1243.     SqInfo^.Error := 999
  1244.   Else
  1245.     Begin
  1246.     Seek(SqInfo^.SqiFile, 0);
  1247.     Truncate(SqInfo^.SqiFile);
  1248.     If IoResult = 0 Then
  1249.       Begin
  1250.       If Not shWrite(SqInfo^.SqiFile, SqIdx^, SqInfo^.SqBase.NumMsg) Then
  1251.         SqInfo^.Error := FileError;
  1252.       End
  1253.     Else
  1254.       SqInfo^.Error := 300;
  1255.     End;
  1256.   End;
  1257.  
  1258.  
  1259. Procedure SqMsgObj.SeekFirst(MsgNum: LongInt);
  1260.   Begin
  1261.   SqInfo^.CurrIdx := 1;
  1262.   ReadIdx;
  1263.   While ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and
  1264.   (MsgNum > LongInt(SqIdx^[SqInfo^.CurrIdx].UMsgId))) Do
  1265.     SeekNext;
  1266.   End;
  1267.  
  1268.  
  1269. Function SqMsgObj.IdxHighest: LongInt;
  1270.   Var
  1271.     i: Word;
  1272.     Tmp: LongInt;
  1273.  
  1274.   Begin
  1275.   Tmp := 0;
  1276.   i := 1;
  1277.   While i <= SqInfo^.SqBase.NumMsg Do
  1278.     Begin
  1279.     If  SqIdx^[i].UMsgId > Tmp Then
  1280.       Tmp := SqIdx^[i].UMsgId;
  1281.     Inc(i);
  1282.     End;
  1283.   IdxHighest := Tmp;
  1284.   End;
  1285.  
  1286.  
  1287. Function SqMsgObj.GetMsgNum: LongInt;
  1288.   Begin
  1289.   If ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and
  1290.   (SqInfo^.CurrIdx > 0)) Then
  1291.     GetMsgNum := LongInt(SqIdx^[SqInfo^.CurrIdx].UMsgId)
  1292.   Else
  1293.     GetMsgNum := -1;
  1294.   End;
  1295.  
  1296.  
  1297. Procedure SqMsgObj.SeekNext;
  1298.   Begin
  1299.   Inc(SqInfo^.CurrIdx);
  1300.   End;
  1301.  
  1302.  
  1303. Procedure SqMsgObj.SeekPrior;
  1304.   Begin
  1305.   If SqInfo^.CurrIdx > 1 Then
  1306.     Dec(SqInfo^.CurrIdx)
  1307.   Else
  1308.     SqInfo^.CurrIdx := 0;
  1309.   End;
  1310.  
  1311.  
  1312. Function SqMsgObj.SeekFound: Boolean;
  1313.   Begin
  1314.   SeekFound := GetMsgNum >= 0;
  1315.   End;
  1316.  
  1317.  
  1318. Function SqMsgObj.GetIdxFramePos: LongInt;
  1319.   Begin
  1320.   If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
  1321.     GetIdxFramePos := SqIdx^[SqInfo^.CurrIdx].Ofs
  1322.   Else
  1323.     GetIdxFramePos := -1;
  1324.   End;
  1325.  
  1326.  
  1327. Function SqMsgObj.GetIdxHash: LongInt;
  1328.   Begin
  1329.   If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
  1330.     GetIdxHash := SqIdx^[SqInfo^.CurrIdx].Hash
  1331.   Else
  1332.     GetIdxHash := 0;
  1333.   End;
  1334.  
  1335.  
  1336. Function SqMsgObj.IsLocal: Boolean; {Is current msg local}
  1337.   Begin
  1338.   IsLocal := ((SqInfo^.MsgHdr.Attr and SqMsgLocal) <> 0);
  1339.   End;
  1340.  
  1341.  
  1342. Function SqMsgObj.IsCrash: Boolean; {Is current msg crash}
  1343.   Begin
  1344.   IsCrash := ((SqInfo^.MsgHdr.Attr and SqMsgCrash) <> 0);
  1345.   End;
  1346.  
  1347.  
  1348. Function SqMsgObj.IsKillSent: Boolean; {Is current msg kill sent}
  1349.   Begin
  1350.   IsKillSent := ((SqInfo^.MsgHdr.Attr and SqMsgKill) <> 0);
  1351.   End;
  1352.  
  1353.  
  1354. Function SqMsgObj.IsSent: Boolean; {Is current msg sent}
  1355.   Begin
  1356.   IsSent := ((SqInfo^.MsgHdr.Attr and SqMsgSent) <> 0);
  1357.   End;
  1358.  
  1359.  
  1360. Function SqMsgObj.IsFAttach: Boolean; {Is current msg file attach}
  1361.   Begin
  1362.   IsFAttach := ((SqInfo^.MsgHdr.Attr and SqMsgFile) <> 0);
  1363.   End;
  1364.  
  1365.  
  1366. Function SqMsgObj.IsReqRct: Boolean; {Is current msg request receipt}
  1367.   Begin
  1368.   IsReqRct := ((SqInfo^.MsgHdr.Attr and SqMsgRRQ) <> 0);
  1369.   End;
  1370.  
  1371.  
  1372. Function SqMsgObj.IsReqAud: Boolean; {Is current msg request audit}
  1373.   Begin
  1374.   IsReqAud := ((SqInfo^.MsgHdr.Attr and SqMsgArq) <> 0);
  1375.   End;
  1376.  
  1377.  
  1378. Function SqMsgObj.IsRetRct: Boolean; {Is current msg a return receipt}
  1379.   Begin
  1380.   IsRetRct := ((SqInfo^.MsgHdr.Attr and SqMsgCpt) <> 0);
  1381.   End;
  1382.  
  1383.  
  1384. Function SqMsgObj.IsFileReq: Boolean; {Is current msg a file request}
  1385.   Begin
  1386.   IsFileReq := ((SqInfo^.MsgHdr.Attr and SqMsgFreq) <> 0);
  1387.   End;
  1388.  
  1389.  
  1390. Function SqMsgObj.IsRcvd: Boolean; {Is current msg received}
  1391.   Begin
  1392.   IsRcvd := ((SqInfo^.MsgHdr.Attr and SqMsgRcvd) <> 0);
  1393.   End;
  1394.  
  1395.  
  1396. Function SqMsgObj.IsPriv: Boolean; {Is current msg priviledged/private}
  1397.   Begin
  1398.   IsPriv := ((SqInfo^.MsgHdr.Attr and SqMsgPriv) <> 0);
  1399.   End;
  1400.  
  1401.  
  1402. Function SqMsgObj.IsEchoed: Boolean;
  1403.   Begin
  1404.   IsEchoed := ((SqInfo^.MsgHdr.Attr and SqMsgScanned) = 0);
  1405.   End;
  1406.  
  1407.  
  1408. Function SqMsgObj.IsDeleted: Boolean; {Is current msg deleted}
  1409.   Begin
  1410.   IsDeleted := False;
  1411.   End;
  1412.  
  1413.  
  1414. Function SqMsgObj.GetRefer: LongInt; {Get reply to of current msg}
  1415.   Begin
  1416.   GetRefer := LongInt(SqInfo^.MsgHdr.ReplyTo);
  1417.   End;
  1418.  
  1419.  
  1420. Procedure SqMsgObj.SetRefer(Num: LongInt); {Set reply to of current msg}
  1421.   Begin
  1422.   SqInfo^.MsgHdr.ReplyTo := LongInt(Num);
  1423.   End;
  1424.  
  1425.  
  1426. Function SqMsgObj.GetSeeAlso: LongInt; {Get see also msg}
  1427.   Begin
  1428.   GetSeeAlso := LongInt(SqInfo^.MsgHdr.Replies[1]);
  1429.   End;
  1430.  
  1431.  
  1432. Procedure SqMsgObj.SetSeeAlso(Num: LongInt); {Set see also msg}
  1433.   Begin
  1434.   SqInfo^.MsgHdr.Replies[1] := LongInt(Num);
  1435.   End;
  1436.  
  1437.  
  1438. Procedure SqMsgObj.SetAttr(St: Boolean; Mask: LongInt); {Set attribute}
  1439.   Begin
  1440.   If St Then
  1441.     SqInfo^.MsgHdr.Attr := SqInfo^.MsgHdr.Attr or Mask
  1442.   Else
  1443.     SqInfo^.MsgHdr.Attr := SqInfo^.MsgHdr.Attr and (Not Mask);
  1444.   End;
  1445.  
  1446.  
  1447. Procedure SqMsgObj.SetLocal(St: Boolean); {Set local status}
  1448.   Begin
  1449.   SetAttr(St, SqMsgLocal);
  1450.   End;
  1451.  
  1452.  
  1453. Procedure SqMsgObj.SetRcvd(St: Boolean); {Set received status}
  1454.   Begin
  1455.   SetAttr(St, SqMsgRcvd);
  1456.   End;
  1457.  
  1458.  
  1459. Procedure SqMsgObj.SetPriv(St: Boolean); {Set priveledge vs public status}
  1460.   Begin
  1461.   SetAttr(St, SqMsgPriv);
  1462.   End;
  1463.  
  1464.  
  1465. Procedure SqMsgObj.SetEcho(ES: Boolean);
  1466.   Begin
  1467.   SetAttr(Not ES, SqMsgScanned);
  1468.   End;
  1469.  
  1470.  
  1471. Procedure SqMsgObj.SetCrash(St: Boolean); {Set crash netmail status}
  1472.   Begin
  1473.   SetAttr(St, SqMsgCrash);
  1474.   End;
  1475.  
  1476.  
  1477. Procedure SqMsgObj.SetKillSent(St: Boolean); {Set kill/sent netmail status}
  1478.   Begin
  1479.   SetAttr(St, SqMsgKill);
  1480.   End;
  1481.  
  1482.  
  1483. Procedure SqMsgObj.SetSent(St: Boolean); {Set sent netmail status}
  1484.   Begin
  1485.   SetAttr(St, SqMsgSent);
  1486.   End;
  1487.  
  1488.  
  1489. Procedure SqMsgObj.SetFAttach(St: Boolean); {Set file attach status}
  1490.   Begin
  1491.   SetAttr(St, SqMsgFile);
  1492.   End;
  1493.  
  1494.  
  1495. Procedure SqMsgObj.SetReqRct(St: Boolean); {Set request receipt status}
  1496.   Begin
  1497.   SetAttr(St, SqMsgRrq);
  1498.   End;
  1499.  
  1500.  
  1501. Procedure SqMsgObj.SetReqAud(St: Boolean); {Set request audit status}
  1502.   Begin
  1503.   SetAttr(St, SqMsgarq);
  1504.   End;
  1505.  
  1506.  
  1507. Procedure SqMsgObj.SetRetRct(St: Boolean); {Set return receipt status}
  1508.   Begin
  1509.   SetAttr(St, SqMsgCpt);
  1510.   End;
  1511.  
  1512.  
  1513. Procedure SqMsgObj.SetFileReq(St: Boolean); {Set file request status}
  1514.   Begin
  1515.   SetAttr(St, SqMsgFreq);
  1516.   End;
  1517.  
  1518.  
  1519. Procedure SqMsgObj.MsgStartUp;
  1520.   Begin
  1521.   SqInfo^.CurrentFramePos := GetIdxFramePos;
  1522.   SqInfo^.CurrentUID := SqIdx^[SqInfo^.CurrIdx].UMsgId;
  1523.   ReadFrame(SqInfo^.CurrentFramePos);
  1524.   ReadMsgHdr(SqInfo^.CurrentFramePos);
  1525.   End;
  1526.  
  1527.  
  1528. Procedure SqMsgObj.MsgTxtStartUp;
  1529.   Var
  1530.     CFrame: LongInt;
  1531.  
  1532.   Begin
  1533.   ReadText(SqInfo^.CurrentFramePos);
  1534.   End;
  1535.  
  1536.  
  1537. Procedure SqMsgObj.SetMailType(MT: MsgMailType);
  1538.   Begin
  1539.   End;
  1540.  
  1541.  
  1542. Function SqMsgObj.GetSubArea: Word;
  1543.   Begin
  1544.   GetSubArea := 0;
  1545.   End;
  1546.  
  1547.  
  1548. Procedure SqMsgObj.ReWriteHdr;
  1549.   Var
  1550.     AlreadyLocked: Boolean;
  1551.     i: LongInt;
  1552.  
  1553.  
  1554.   Begin
  1555.   AlreadyLocked := SqInfo^.Locked;
  1556.   If Not AlreadyLocked Then
  1557.     If LockMsgBase Then;
  1558.   WriteFrame(SqInfo^.CurrentFramePos);
  1559.   WriteMsgHdr(SqInfo^.CurrentFramePos);
  1560.   i := 1;
  1561.   While ((i <= SqInfo^.SqBase.NumMsg) and (SqInfo^.CurrentFramePos <> SqIdx^[i].Ofs)) Do
  1562.     Inc(i);
  1563.   If SqIdx^[i].Ofs = SqInfo^.CurrentFramePos Then
  1564.     Begin
  1565.     If IsRcvd Then
  1566.       SqIdx^[i].Hash := 0
  1567.     Else
  1568.       SqIdx^[i].Hash := SqHashName(SqInfo^.MsgHdr.MsgTo);
  1569.     End;
  1570.   If Not AlreadyLocked Then
  1571.     If UnLockMsgBase Then;
  1572.   End;
  1573.  
  1574.  
  1575. Procedure SqMsgObj.DeleteMsg;
  1576.   Begin
  1577.   KillMsg(SqInfo^.CurrentUID);
  1578.   End;
  1579.  
  1580.  
  1581. Function SqMsgObj.NumberOfMsgs: LongInt;
  1582.   Var
  1583.     TmpBase: SqBaseType;
  1584.  
  1585.   Begin
  1586.   If LoadFile(SqInfo^.FN + '.Sqd', TmpBase, SizeOf(TmpBase)) = 0 Then
  1587.     NumberOfMsgs := TmpBase.NumMsg
  1588.   Else
  1589.     NumberOfMsgs := 0;
  1590.   End;
  1591.  
  1592.  
  1593. Function SqMsgObj.GetLastRead(UNum: LongInt): LongInt;
  1594.   Var
  1595.     LRec: LongInt;
  1596.  
  1597.   Begin
  1598.   If ((UNum + 1) * SizeOf(LRec)) >
  1599.   SizeFile(SqInfo^.FN + '.Sql') Then
  1600.     GetLastRead := 0
  1601.   Else
  1602.     Begin
  1603.     If LoadFilePos(SqInfo^.FN + '.Sql', LRec, SizeOf(LRec),
  1604.     UNum * SizeOf(LRec)) = 0 Then
  1605.       GetLastRead := LRec
  1606.     Else
  1607.       GetLastRead := 0;
  1608.     End;
  1609.   End;
  1610.  
  1611.  
  1612. Procedure SqMsgObj.SetLastRead(UNum: LongInt; LR: LongInt);
  1613.   Var
  1614.     LRec: LongInt;
  1615.     Status: Word;
  1616.  
  1617.   Begin
  1618.   Status := 0;
  1619.   If ((UNum + 1) * SizeOf(LRec)) >
  1620.   SizeFile(SqInfo^.FN + '.Sql') Then
  1621.     Begin
  1622.     Status := ExtendFile(SqInfo^.FN + '.Sql', (UNum + 1) * SizeOf(LRec));
  1623.     End;
  1624.   LRec := LR;
  1625.   If Status = 0 Then
  1626.     Status := SaveFilePos(SqInfo^.FN + '.Sql', LRec, SizeOf(LRec),
  1627.       UNum * SizeOf(LRec));
  1628.   End;
  1629.  
  1630.  
  1631. Function SqMsgObj.GetMsgLoc: LongInt;
  1632.   Begin
  1633.   GetMsgLoc := GetMsgNum;
  1634.   End;
  1635.  
  1636.  
  1637. Procedure SqMsgObj.SetMsgLoc(ML: LongInt);
  1638.   Begin
  1639.   SeekFirst(ML);
  1640.   End;
  1641.  
  1642.  
  1643. Procedure SqMsgObj.YoursFirst(Name: String; Handle: String);
  1644.   Begin
  1645.   SqInfo^.CurrIdx := 0;
  1646.   ReadIdx;
  1647.   SqInfo^.SName := Upper(Name);
  1648.   SqInfo^.SHandle := Upper(Handle);
  1649.   SqInfo^.HName := SqHashName(Name);
  1650.   SqInfo^.HHandle := SqHashName(Handle);
  1651.   YoursNext;
  1652.   End;
  1653.  
  1654.  
  1655. Procedure SqMsgObj.YoursNext;
  1656.   Var
  1657.     WasFound: Boolean;
  1658.  
  1659.   Begin
  1660.   WasFound := False;
  1661.   Inc(SqInfo^.CurrIdx);
  1662.   While ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and (Not WasFound)) Do
  1663.     Begin
  1664.     While ((SqIdx^[SqInfo^.CurrIdx].Hash <> SqInfo^.HName) And
  1665.     (SqIdx^[SqInfo^.CurrIdx].Hash <> SqInfo^.HHandle) And
  1666.     (SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg)) Do
  1667.       Inc(SqInfo^.CurrIdx);
  1668.     If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
  1669.       Begin
  1670.       MsgStartUp;
  1671.       If ((Not IsRcvd) and
  1672.       ((Upper(GetTo) = SqInfo^.SName) or (Upper(GetTo) = SqInfo^.SHandle))) Then
  1673.         WasFound := True
  1674.       Else
  1675.         Inc(SqInfo^.CurrIdx);
  1676.       End;
  1677.     End;
  1678.   End;
  1679.  
  1680.  
  1681. Function SqMsgObj.YoursFound: Boolean;
  1682.   Begin
  1683.   YoursFound := SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg;
  1684.   End;
  1685.  
  1686.  
  1687. Function SqMsgObj.GetMsgDisplayNum: LongInt;
  1688.   Begin
  1689.   GetMsgDisplayNum := SqInfo^.CurrIdx;
  1690.   End;
  1691.  
  1692.  
  1693. Function SqMsgObj.GetTxtPos: LongInt;
  1694.   Begin
  1695.   GetTxtPos := SqInfo^.TxtCtr;
  1696.   End;
  1697.  
  1698.  
  1699. Procedure SqMsgObj.SetTxtPos(TP: LongInt);
  1700.   Begin
  1701.   SqInfo^.TxtCtr := TP;
  1702.   End;
  1703.  
  1704.  
  1705. End.
  1706.