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

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