home *** CD-ROM | disk | FTP | other *** search
/ C!T ROM 2 / ctrom_ii_b.zip / ctrom_ii_b / PROGRAM / PASCAL / MKMSG104 / MKMSGSQU.PAS < prev    next >
Pascal/Delphi Source File  |  1994-01-09  |  45KB  |  1,720 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;
  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: Word; {Length of this record}
  42.   Rsvd1: Word; {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: Word; {Maximum age of messages}
  56.   SqHdrSize: Word; {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: Word; {Type of message frame}
  69.   Rsvd: Word; {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 := FileError
  375.     Else
  376.       Begin
  377.       SqInfo^.SqdOpened := True;
  378.       SqdOpen := 0;
  379.       If Not shRead(SqInfo^.SqdFile, SqInfo^.SqBase, 2, NumRead) Then
  380.         SqdOpen := FileError
  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 := FileError
  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.   Begin
  429.   If Not SqInfo^.SqdOpened Then
  430.     Begin
  431.     FillChar(SqInfo^.SqBase, SizeOf(SqInfo^.SqBase), 0);
  432.     SqInfo^.SqBase.Len := 256;
  433.     SqInfo^.SqBase.SqHdrSize := SqFSize;
  434.     SqInfo^.SqBase.UID := 1;
  435.     SqInfo^.SqBase.NumMsg := 0;
  436.     SqInfo^.SqBase.Base := SqInfo^.FN;
  437.     Str2Az(SqInfo^.FN, 78, SqInfo^.SqBase.Base);
  438.     SqInfo^.SqBase.MaxMsg := MaxMsg;
  439.     SqInfo^.SqBase.KeepDays := MaxDays;
  440.     SqInfo^.SqBase.EndFrame := SqInfo^.SqBase.Len;
  441.     CreateMsgBase := SaveFile(SqInfo^.FN + '.SQD', SqInfo^.SqBase, SqInfo^.SqBase.Len);
  442.     If SaveFile(SqInfo^.FN + '.SQI', SqInfo^.SqBase, 0) = 0 Then;
  443.     If SaveFile(SqInfo^.FN + '.SQL', SqInfo^.SqBase, 0) = 0 Then;
  444.     End
  445.   Else
  446.     CreateMsgBase := 176;
  447.   End;
  448.  
  449.  
  450. Function SqMsgObj.MsgBaseExists: Boolean;
  451.   Begin
  452.   MsgBaseExists :=  FileExist(SqInfo^.FN + '.SQD');
  453.   End;
  454.  
  455.  
  456. Procedure SqMsgObj.SqdClose;
  457.   Begin
  458.   If SqInfo^.SqdOpened Then
  459.     Close(SqInfo^.SqdFile);
  460.   If IOResult <> 0 Then;
  461.   SqInfo^.SqdOpened := False;
  462.   End;
  463.  
  464.  
  465. Function SqMsgObj.LockMsgBase: Boolean; {Lock msg base}
  466.   Begin
  467.   If Not SqInfo^.Locked Then
  468.     Begin
  469.     SqInfo^.Locked := shLock(SqInfo^.SqdFile, 0, 1) = 0;
  470.     LockMsgBase := SqInfo^.Locked;
  471.     ReadBase;
  472.     ReadIdx;
  473.     SqInfo^.FreeLoaded := False;
  474.     End;
  475.   End;
  476.  
  477.  
  478. Function SqMsgObj.UnLockMsgBase: Boolean; {Unlock msg base}
  479.   Begin
  480.   If SqInfo^.Locked Then
  481.     Begin
  482.     WriteBase;
  483.     WriteIdx;
  484.     SqInfo^.Locked := Not UnLockFile(SqInfo^.SqdFile, 0, 1) < 2;
  485.     UnLockMsgBase := Not SqInfo^.Locked;
  486.     End;
  487.   End;
  488.  
  489.  
  490. Procedure SqMsgObj.SqiClose;
  491.   Begin
  492.   If SqInfo^.SqiOpened Then
  493.     Close(SqInfo^.SqiFile);
  494.   If IoResult <> 0 Then;
  495.   SqInfo^.SqiOpened := False;
  496.   End;
  497.  
  498.  
  499. Procedure SqMsgObj.ReadBase;
  500.   Var
  501.     NumRead: Word;
  502.  
  503.   Begin
  504.   Seek(SqInfo^.SqdFile, 0);
  505.   If Not shRead(SqInfo^.SqdFile, SqInfo^.SqBase, SqBSize, NumRead) Then
  506.     SqInfo^.Error := FileError;
  507.   If SqInfo^.SqBase.SqHdrSize = 0 Then
  508.     SQInfo^.SqBase.SqHdrSize := SqFSize;
  509.   SqFSize := SqInfo^.SqBase.SqHdrSize;
  510.   End;
  511.  
  512.  
  513. Procedure SqMsgObj.WriteBase;
  514.   Begin
  515.   Seek(SqInfo^.SqdFile, 0);
  516.   If Not shWrite(SqInfo^.SqdFile, SqInfo^.SqBase, SQBSize) Then
  517.     SqInfo^.Error := FileError;
  518.   End;
  519.  
  520.  
  521. Procedure SqMsgObj.StartNewMsg; {Initialize msg header}
  522.   Begin
  523.   FillChar(SqInfo^.MsgHdr, SizeOf(SqInfo^.MsgHdr), 0);
  524.   FillChar(SqInfo^.Frame, SizeOf(SqInfo^.Frame), 0);
  525.   SqInfo^.TxtCtr := 0;
  526.   SqInfo^.StrDate := '';
  527.   SqInfo^.StrTime := '';
  528.   End;
  529.  
  530.  
  531. Function SqMsgObj.GetFrom: String; {Get message from}
  532.   Begin
  533.   GetFrom := Az2Str(SqInfo^.MsgHdr.MsgFrom, 35);
  534.   End;
  535.  
  536.  
  537. Function SqMsgObj.GetTo: String; {Get message to}
  538.   Begin
  539.   GetTo := Az2Str(SqInfo^.MsgHdr.MsgTo, 35);
  540.   End;
  541.  
  542.  
  543. Function SqMsgObj.GetSubj: String; {Get message subject}
  544.   Begin
  545.   GetSubj := Az2Str(SqInfo^.MsgHdr.Subj, 72);
  546.   End;
  547.  
  548.  
  549. Procedure SqMsgObj.SetFrom(Str: String); {Set message from}
  550.   Begin
  551.   Str2Az(Str, 35, SqInfo^.MsgHdr.MsgFrom);
  552.   End;
  553.  
  554.  
  555. Procedure SqMsgObj.SetTo(Str: String); {Set message to}
  556.   Begin
  557.   Str2Az(Str,35, SqInfo^.MsgHdr.MsgTo);
  558.   End;
  559.  
  560.  
  561. Procedure SqMsgObj.SetSubj(Str: String); {Set message subject}
  562.   Begin
  563.   Str2Az(Str,72, SqInfo^.MSgHdr.Subj);
  564.   End;
  565.  
  566.  
  567. Function SqMsgObj.GetDate: String; {Get message date mm-dd-yy}
  568.   Var
  569.     TmpDate: LongInt;
  570.  
  571.   Begin
  572.   TmpDate := (SqInfo^.MsgHdr.DateWritten shr 16) +
  573.    ((SqInfo^.MsgHdr.DateWritten and $ffff) shl 16);
  574.   GetDate := DateStr(TmpDate);
  575.   End;
  576.  
  577.  
  578. Function SqMsgObj.GetTime: String; {Get message time hh:mm}
  579.   Var
  580.     TmpDate: LongInt;
  581.  
  582.   Begin
  583.   TmpDate := (SqInfo^.MsgHdr.DateWritten shr 16) +
  584.    ((SqInfo^.MsgHdr.DateWritten and $ffff) shl 16);
  585.   GetTime := TimeStr(TmpDate);
  586.   End;
  587.  
  588.  
  589. Procedure SqMsgObj.SetDate(Str: String);
  590.   Begin
  591.   SqInfo^.StrDate := Copy(Str,1,8);
  592.   End;
  593.  
  594.  
  595. Procedure SqMsgObj.SetTime(Str: String);
  596.   Begin
  597.   SqInfo^.StrTime := Copy(Str,1,8);
  598.   End;
  599.  
  600.  
  601. Procedure SqMsgObj.GetOrig(Var Addr: AddrType);
  602.   Begin
  603.   Addr := SqInfo^.MsgHdr.Orig;
  604.   End;
  605.  
  606.  
  607. Procedure SqMsgObj.SetOrig(Var Addr: AddrType);
  608.   Begin
  609.   SqInfo^.MsgHdr.Orig := Addr;
  610.   End;
  611.  
  612.  
  613. Procedure SqMsgObj.GetDest(Var Addr: AddrType);
  614.   Begin
  615.   Addr := SqInfo^.MsgHdr.Dest;
  616.   End;
  617.  
  618.  
  619. Procedure SqMsgObj.SetDest(Var Addr: AddrType);
  620.   Begin
  621.   SqInfo^.MsgHdr.Dest := Addr;
  622.   End;
  623.  
  624.  
  625. Function SqMsgObj.SqHashName(Name: String): LongInt;
  626.   Var
  627.     Hash: LongInt;
  628.     Tmp: LongInt;
  629.     Counter: Word;
  630.  
  631.   Begin
  632.   Hash := 0;
  633.   Counter := 1;
  634.   While Counter <= Length(Name) Do
  635.     Begin
  636.     Hash := (Hash shl 4) + Ord(LoCase(Name[Counter]));
  637.     Tmp := Hash and $F0000000;
  638.     If (Tmp <> 0) Then
  639.       Hash := (Hash or (Tmp shr 24)) or Tmp;
  640.     Inc(Counter);
  641.     End;
  642.   SqHashName := Hash and $7fffffff;
  643.   End;
  644.  
  645.  
  646. Procedure SqMsgObj.ReadFrame(FPos: LongInt); {Read frame at FPos}
  647.   Begin
  648.   ReadVarFrame(SqInfo^.Frame, FPos);
  649.   End;
  650.  
  651.  
  652. Procedure SqMsgObj.ReadVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); {Read frame at FPos}
  653.   Var
  654.     NumRead: Word;
  655.  
  656.   Begin
  657.   Seek(SqInfo^.SqdFile, FPos);
  658.   SqInfo^.Error := IoResult;
  659.   If SqInfo^.Error = 0 Then
  660.     Begin
  661.     If Not shRead(SqInfo^.SqdFile, Frame, SizeOf(SqFrameHdrType), NumRead) Then
  662.       SqInfo^.Error := FileError;
  663.     End;
  664.   End;
  665.  
  666.  
  667. Procedure SqMsgObj.WriteFrame(FPos: LongInt); {Read frame at FPos}
  668.   Begin
  669.   WriteVarFrame(SqInfo^.Frame, FPos);
  670.   End;
  671.  
  672.  
  673. Procedure SqMsgObj.WriteVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); {Write frame at FPos}
  674.   Begin
  675.   Seek(SqInfo^.SqdFile, FPos);
  676.   SqInfo^.Error := IoResult;
  677.   If SqInfo^.Error = 0 Then
  678.     Begin
  679.     If Not shWrite(SqInfo^.SqdFile, Frame, SizeOf(SqFrameHdrType)) Then
  680.       SqInfo^.Error := FileError;
  681.     End;
  682.   End;
  683.  
  684.  
  685.  
  686. Procedure SqMsgObj.UnlinkFrame(Var Frame: SqFrameHdrType);
  687.   Var
  688.     TmpFrame: SqFrameHdrType;
  689.  
  690.   Begin
  691.   If Frame.PrevFrame <> 0 Then
  692.     Begin
  693.     ReadVarFrame(TmpFrame, Frame.PrevFrame);
  694.     TmpFrame.NextFrame := Frame.NextFrame;
  695.     WriteVarFrame(TmpFrame, Frame.PrevFrame);
  696.     End;
  697.   If Frame.NextFrame <> 0 Then
  698.     Begin
  699.     ReadVarFrame(TmpFrame, Frame.NextFrame);
  700.     TmpFrame.PrevFrame := Frame.PrevFrame;
  701.     WriteVarFrame(TmpFrame, Frame.NextFrame);
  702.     End;
  703.   End;
  704.  
  705.  
  706. Procedure SqMsgObj.LoadFree;
  707.   Var
  708.     i: Word;
  709.     TmpFrame: SqFrameHdrType;
  710.     TmpPos: LongInt;
  711.  
  712.   Begin
  713.   For i := 1 to MaxFree Do
  714.     Begin
  715.     FreeArray^[i].FreePos := 0;
  716.     FreeArray^[i].FreeSize := 0;
  717.     End;
  718.   SqInfo^.FreeLoaded := True;
  719.   i := 0;
  720.   TmpPos := SqInfo^.SqBase.FirstFree;
  721.   While ((TmpPos <> 0) and (i < MaxFree)) Do
  722.     Begin
  723.     ReadVarFrame(TmpFrame, TmpPos);
  724.     Inc(i);
  725.     FreeArray^[i].FreeSize := TmpFrame.FrameLength;
  726.     FreeArray^[i].FreePos := TmpPos;
  727.     TmpPos := TmpFrame.NextFrame;
  728.     End;
  729.   SqInfo^.HighestFree := i;
  730.   End;
  731.  
  732.  
  733. Procedure SqMsgObj.FindFrame(Var FL: LongInt; Var FramePos: LongInt);
  734.   Var
  735.     TmpFrame: SqFrameHdrType;
  736.     BestFoundPos: LongInt;
  737.     BestFoundSize: LongInt;
  738.     BestIdx: Word;
  739.     i: Word;
  740.  
  741.   Begin
  742.   If Not SqInfo^.FreeLoaded Then
  743.     LoadFree;
  744.   BestFoundPos := 0;
  745.   BestFoundSize := 0;
  746.   For i := 1 to SqInfo^.HighestFree Do
  747.     Begin
  748.     If (FreeArray^[i].FreeSize > FL) Then
  749.       Begin
  750.       If ((BestFoundSize = 0) or (FreeArray^[i].FreeSize < BestFoundSize)) Then
  751.         Begin
  752.         BestFoundSize := FreeArray^[i].FreeSize;
  753.         BestFoundPos := FreeArray^[i].FreePos;
  754.         BestIdx := i;
  755.         End;
  756.       End
  757.     End;
  758.   FramePos := BestFoundPos;
  759.   If FramePos <> 0 Then
  760.     Begin
  761.     ReadVarFrame(TmpFrame, FramePos);
  762.     FreeArray^[BestIdx].FreePos := 0;
  763.     FreeArray^[BestIdx].FreeSize := 0;
  764.     End;
  765.   If FramePos = 0 Then
  766.     Begin
  767.     FL := 0;
  768.     FramePos := SqInfo^.SqBase.EndFrame;
  769.     End
  770.   Else
  771.     Begin
  772.     UnLinkFrame(TmpFrame);
  773.     If TmpFrame.PrevFrame = 0 Then
  774.       SqInfo^.SqBase.FirstFree := TmpFrame.NextFrame;
  775.     If TmpFrame.NextFrame = 0 Then
  776.       SqInfo^.SqBase.LastFree := TmpFrame.PrevFrame;
  777.     FL := TmpFrame.FrameLength;
  778.     End;
  779.   End;
  780.  
  781.  
  782. Procedure SqMsgObj.LinkFrameNext(Var Frame: SqFrameHdrType; OtherFrame: LongInt;
  783.   FramePos: LongInt);
  784.  
  785.   Var
  786.     TmpFrame: SqFrameHdrType;
  787.  
  788.   Begin
  789.   If OtherFrame <> 0 Then
  790.     Begin
  791.     ReadVarFrame(TmpFrame, OtherFrame);
  792.     TmpFrame.NextFrame := FramePos;
  793.     Frame.PrevFrame := OtherFrame;
  794.     WriteVarFrame(TmpFrame, OtherFrame);
  795.     End;
  796.   End;
  797.  
  798.  
  799. Procedure SqMsgObj.KillMsg(MsgNum: LongInt);
  800.   Var
  801.     i: Word;
  802.     KillPos: LongInt;
  803.     IndexPos: LongInt;
  804.     KillFrame: SqFrameHdrType;
  805.     TmpFrame: SqFrameHdrType;
  806.     CurrMove: LongInt;
  807.     AlreadyLocked: Boolean;
  808.     FreeCtr: Word;
  809.  
  810.   Begin
  811.   AlreadyLocked := SqInfo^.Locked;
  812.   If Not AlreadyLocked Then
  813.     If LockMsgBase Then;
  814.   If SqIdx = Nil Then
  815.     SqInfo^.Error := 999
  816.   Else
  817.     Begin
  818.     i := 1;
  819.     While ((i <= SqInfo^.SqBase.NumMsg) and (MsgNum <> SqIdx^[i].UMsgId)) Do
  820.       Inc(i);
  821.     If MsgNum = SqIdx^[i].UMsgId Then
  822.       Begin
  823.       IndexPos := i;
  824.       KillPos := SqIdx^[i].Ofs;
  825.       ReadVarFrame(KillFrame, KillPos);
  826.       If KillFrame.PrevFrame = 0 Then
  827.         SqInfo^.SqBase.BeginFrame := KillFrame.NextFrame;
  828.       If KillFrame.NextFrame = 0 Then
  829.         SqInfo^.SqBase.LastFrame := KillFrame.PrevFrame;
  830.       KillFrame.FrameType := sqFrameFree;
  831.       UnLinkFrame(KillFrame);
  832.       If ((SqInfo^.SqBase.FirstFree = 0) or (SqInfo^.SqBase.LastFree = 0)) Then
  833.         Begin
  834.         SqInfo^.SqBase.FirstFree := KillPos;
  835.         SqInfo^.SqBase.LastFree := KillPos;
  836.         KillFrame.PrevFrame := 0;
  837.         KillFrame.NextFrame := 0;
  838.         End
  839.       Else
  840.         Begin
  841.         KillFrame.NextFrame := 0;
  842.         KillFrame.PrevFrame := SqInfo^.SqBase.LastFree;
  843.         ReadVarFrame(TmpFrame, SqInfo^.SqBase.LastFree);
  844.         TmpFrame.NextFrame := KillPos;
  845.         WriteVarFrame(TmpFrame, SqInfo^.SqBase.LastFree);
  846.         SqInfo^.SqBase.LastFree := KillPos;
  847.         End;
  848.       WriteVarFrame(KillFrame, KillPos);
  849.       FreeCtr := 1;
  850.       While ((FreeCtr < MaxFree) and (FreeArray^[FreeCtr].FreePos <> 0)) Do
  851.         Inc(FreeCtr);
  852.       If FreeArray^[FreeCtr].FreePos = 0 Then
  853.         Begin
  854.         FreeArray^[FreeCtr].FreePos := KillPos;
  855.         FreeArray^[FreeCtr].FreeSize := KillFrame.FrameLength;
  856.         End;
  857.       If FreeCtr > SqInfo^.HighestFree Then
  858.         SqInfo^.HighestFree := FreeCtr;
  859.       Dec(SqInfo^.SqBase.NumMsg);
  860.       Dec(SqInfo^.SqBase.HighMsg);
  861.       CurrMove := IndexPos;
  862.       While CurrMove <= SqInfo^.SqBase.NumMsg Do
  863.         Begin
  864.         SqIdx^[CurrMove] := SqIdx^[CurrMove + 1];
  865.         Inc(CurrMove);
  866.         End;
  867.   {    NumMove := SqInfo^.SqBase.NumMsg + 1 - IndexPos;
  868.       NumMove := NumMove * SizeOf(SqIdxType);
  869.       Move(SqIdx^[IndexPos + 1], SqIdx^[IndexPos], NumMove);  }
  870.       End;
  871.     End;
  872.   If Not AlreadyLocked Then
  873.     If UnlockMsgBase Then;
  874.   End;
  875.  
  876.  
  877. Procedure SqMsgObj.ReadMsgHdr(FPos: LongInt); {Read msg hdr for frame at FPos}
  878.   Var
  879.     NumRead: Word;
  880.  
  881.   Begin
  882.   Seek(SqInfo^.SqdFile, FPos + SqFSize);
  883.   SqInfo^.Error := IoResult;
  884.   If SqInfo^.Error = 0 Then
  885.     Begin
  886.     If Not shRead(SqInfo^.SqdFile, SqInfo^.MsgHdr, SizeOf(SqMsgHdrType), NumRead) Then
  887.       SqInfo^.Error := FileError;
  888.     End;
  889.   End;
  890.  
  891.  
  892. Procedure SqMsgObj.WriteMsgHdr(FPos: LongInt); {Read msg hdr for frame at FPos}
  893.   Var
  894.     NumRead: Word;
  895.  
  896.   Begin
  897.   Seek(SqInfo^.SqdFile, FPos + SqFSize);
  898.   SqInfo^.Error := IoResult;
  899.   If SqInfo^.Error = 0 Then
  900.     Begin
  901.     If Not shWrite(SqInfo^.SqdFile, SqInfo^.MsgHdr, SizeOf(SqMsgHdrType)) Then
  902.       SqInfo^.Error := FileError;
  903.     End;
  904.   End;
  905.  
  906.  
  907. Procedure SqMsgObj.WriteText(FPos: LongInt); {Write text buffer for frame at Fpos}
  908.   Begin
  909.   Seek(SqInfo^.SqdFile, FPos + SqFSize + SqMSize);
  910.   SqInfo^.Error := IoResult;
  911.   If SqInfo^.Error = 0 Then
  912.     Begin
  913.     If Not shWrite(SqInfo^.SqdFile, SqInfo^.MsgChars, SqInfo^.TxtCtr) Then
  914.       SqInfo^.Error := FileError;
  915.     End;
  916.   End;
  917.  
  918.  
  919. Function SqMsgObj.GetBeginFrame: LongInt; {Get beginning frame pos}
  920.   Begin
  921.   GetBeginFrame := SqInfo^.SqBase.BeginFrame;
  922.   End;
  923.  
  924.  
  925. Function SqMsgObj.GetNextFrame: LongInt; {Get next frame pos}
  926.   Begin
  927.   GetNextFrame := SqInfo^.Frame.NextFrame;
  928.   End;
  929.  
  930.  
  931. Procedure SqMsgObj.ReadText(FPos: LongInt);
  932.   Begin
  933.   Seek(SqInfo^.SqdFile, FPos + SqFSize + SqMSize);
  934.   SqInfo^.Error := IoResult;
  935.   If SqInfo^.Error = 0 Then
  936.     Begin
  937.     If SqInfo^.Frame.MsgLength > SqTxtBufferSize Then
  938.       BlockRead(SqInfo^.SqdFile, SqInfo^.MsgChars, SqTxtBufferSize)
  939.     Else
  940.       BlockRead(SqInfo^.SqdFile, SqInfo^.MsgChars, SqInfo^.Frame.MsgLength);
  941.     SqInfo^.Error := IoResult;
  942.     End;
  943.   SqInfo^.TxtCtr := 1 + SqInfo^.Frame.ControlLength;
  944.   SqInfo^.MsgDone := False;
  945.   LastSoft := False;
  946.   End;
  947.  
  948.  
  949.  
  950. Procedure SqMsgObj.InitText;
  951.   Begin
  952.   SqInfo^.TxtCtr := 0;
  953.   End;
  954.  
  955.  
  956. Procedure SqMsgObj.DoString(Str: String); {Add string to message text}
  957.   Var
  958.     i: Word;
  959.  
  960.   Begin
  961.   i := 1;
  962.   While i <= Length(Str) Do
  963.     Begin
  964.     DoChar(Str[i]);
  965.     Inc(i);
  966.     End;
  967.   End;
  968.  
  969.  
  970. Procedure SqMsgObj.DoChar(Ch: Char); {Add character to message text}
  971.   Begin
  972.   If SqInfo^.TxtCtr < SqTxtBufferSize Then
  973.     Begin
  974.     Inc(SqInfo^.TxtCtr);
  975.     SqInfo^.MsgChars[SqInfo^.TxtCtr] := ch;
  976.     End;
  977.   End;
  978.  
  979.  
  980. Procedure SqMsgObj.DoStringLn(Str: String); {Add string and newline to msg text}
  981.   Begin
  982.   DoString(Str);
  983.   DoChar(#13);
  984.   End;
  985.  
  986.  
  987.  
  988. Procedure SqMsgObj.KillExcess;
  989.   Var
  990.     AlreadyLocked: Boolean;
  991.  
  992.   Begin
  993.   AlreadyLocked := SqInfo^.Locked;
  994.   If Not AlreadyLocked Then
  995.     If LockMsgBase Then;
  996.   If SqIdx = Nil Then
  997.     SqInfo^.error := 999
  998.   Else
  999.     Begin
  1000.     If ((SqInfo^.SqBase.MaxMsg > 0) and
  1001.     (SqInfo^.SqBase.MaxMsg > SqInfo^.SqBase.SkipMsg)) Then
  1002.       Begin
  1003.       While (SqInfo^.SqBase.NumMsg > SqInfo^.SqBase.MaxMsg) Do
  1004.         KillMsg(SqIdx^[SqInfo^.SqBase.SkipMsg + 1].UMsgId);
  1005.       End;
  1006.     End;
  1007.   If Not AlreadyLocked Then
  1008.     If UnlockMsgBase Then;
  1009.   End;
  1010.  
  1011.  
  1012. Function SqMsgObj.WriteMsg: Word; {Write msg to msg base}
  1013.   Var
  1014.     MsgSize: LongInt;
  1015.     FrameSize: LongInt;
  1016.     FramePos: LongInt;
  1017.     TmpFrame: SqFrameHdrType;
  1018.     TmpDate: LongInt;
  1019.     {$IFDEF WINDOWS}
  1020.     TmpDT: TDateTime;
  1021.     {$ELSE}
  1022.     TmpDT: DateTime;
  1023.     {$ENDIF}
  1024.     TmpStr: String;
  1025.     AlreadyLocked: Boolean;
  1026.  
  1027.   Begin
  1028.   DoChar(#0);
  1029.   TmpDT.Year := Str2Long(Copy(SqInfo^.StrDate,7,2));
  1030.   If TmpDT.Year > 79 Then
  1031.     Inc(TmpDT.Year, 1900)
  1032.   Else
  1033.     Inc(TmpDT.Year, 2000);
  1034.   TmpDT.Month := Str2Long(Copy(SqInfo^.StrDate,1,2));
  1035.   TmpDT.Day := Str2Long(Copy(SqInfo^.StrDate,4,2));
  1036.   TmpDt.Hour := Str2Long(Copy(SqInfo^.StrTime,1,2));
  1037.   TmpDt.Min := Str2Long(Copy(SqInfo^.StrTime, 4,2));
  1038.   TmpDt.Sec := 0;
  1039.   TmpStr := FormattedDate(TmpDT, 'DD NNN YY  ') + Copy(SqInfo^.StrTime,1,5) + ':00';
  1040.   PackTime(TmpDT, TmpDate);
  1041.   SqInfo^.MsgHdr.DateWritten :=  (TmpDate shr 16) + ((TmpDate and $ffff) shl 16);
  1042.   TmpDate := GetDosDate;
  1043.   SqInfo^.MsgHdr.DateArrived := (TmpDate shr 16) + ((TmpDate and $ffff) shl 16);
  1044.   Str2AZ(TmpStr, 20, SqInfo^.MsgHdr.AZDate);
  1045.   AlreadyLocked := SqInfo^.Locked;
  1046.   If Not AlreadyLocked Then
  1047.     If LockMsgBase Then;
  1048.   If SqInfo^.Locked Then
  1049.     Begin
  1050.     MsgSize := SqInfo^.TxtCtr + SqMSize;
  1051.     FrameSize := MsgSize;
  1052.     FindFrame(FrameSize, FramePos);
  1053.     If SqInfo^.SqBase.LastFrame <> 0 Then
  1054.       Begin
  1055.       ReadVarFrame(TmpFrame, SqInfo^.SqBase.LastFrame);
  1056.       TmpFrame.NextFrame := FramePos;
  1057.       WriteVarFrame(TmpFrame, SqInfo^.SqBase.LastFrame);
  1058.       TmpFrame.PrevFrame := SqInfo^.SqBase.LastFrame;
  1059.       End
  1060.     Else
  1061.       Begin
  1062.       SqInfo^.SqBase.BeginFrame := FramePos;
  1063.       TmpFrame.PrevFrame := 0;
  1064.       End;
  1065.     TmpFrame.Id := SqHdrId;
  1066.     TmpFrame.FrameType := SqFrameMsg;
  1067.     SqInfo^.SqBase.LastFrame := FramePos;
  1068.     TmpFrame.NextFrame := 0;
  1069.     TmpFrame.FrameLength := FrameSize;
  1070.     TmpFrame.MsgLength := MsgSize;
  1071.     TmpFrame.ControlLength := 0;
  1072.     If TmpFrame.FrameLength = 0 Then
  1073.       Begin
  1074.       TmpFrame.FrameLength := TmpFrame.MsgLength + 0; {slack to minimize free frames}
  1075.       SqInfo^.SqBase.EndFrame := FramePos + SqFSize + TmpFrame.FrameLength;
  1076.       End;
  1077.     If SqInfo^.SqBase.NumMsg >= SqInfo^.SqiAlloc Then
  1078.       Begin
  1079.       WriteIdx;
  1080.       ReadIdx;
  1081.       End;
  1082.     If SqIdx = Nil Then
  1083.       Begin
  1084.       SqInfo^.Error := 999;
  1085.       WriteMsg := 999;
  1086.       End
  1087.     Else
  1088.       Begin
  1089.       WriteVarFrame(TmpFrame, FramePos);
  1090.       WriteMsgHdr(FramePos);
  1091.       WriteText(FramePos);
  1092.       Inc(SqInfo^.SqBase.NumMsg);
  1093.       SqIdx^[SqInfo^.SqBase.NumMsg].Ofs := FramePos;
  1094.       SqIdx^[SqInfo^.SqBase.NumMsg].UMsgId := SqInfo^.SqBase.UID;
  1095.       SqIdx^[SqInfo^.SqBase.NumMsg].Hash := SqHashName(Az2Str(SqInfo^.MsgHdr.MsgTo, 35));
  1096.       Inc(SqInfo^.SqBase.UId);
  1097.       SqInfo^.SqBase.HighMsg := SqInfo^.SqBase.NumMsg;
  1098.       KillExcess;
  1099.       SqInfo^.CurrIdx := SqInfo^.SqBase.NumMsg;
  1100.       WriteMsg := 0;
  1101.       End;
  1102.     If Not AlreadyLocked Then
  1103.       If UnLockMsgBase Then;
  1104.     End
  1105.   Else
  1106.     WriteMsg := 5;
  1107.   End;
  1108.  
  1109.  
  1110.  
  1111. Function SqMsgObj.GetString(MaxLen: Word): String;
  1112.   Var
  1113.     WPos: Word;
  1114.     WLen: Byte;
  1115.     StrDone: Boolean;
  1116.     TxtOver: Boolean;
  1117.     StartSoft: Boolean;
  1118.     CurrLen: Word;
  1119.     PPos: Word;
  1120.     TmpCh: Char;
  1121.  
  1122.   Begin
  1123.   StrDone := False;
  1124.   CurrLen := 0;
  1125.   PPos := SqInfo^.TxtCtr;
  1126.   WPos := 0;
  1127.   WLen := 0;
  1128.   StartSoft := LastSoft;
  1129.   LastSoft := True;
  1130.   TmpCh := GetChar;
  1131.   While ((Not StrDone) And (CurrLen < MaxLen) And (Not SqInfo^.MsgDone)) Do
  1132.     Begin
  1133.     Case TmpCh of
  1134.       #$00:;
  1135.       #$0d: Begin
  1136.             StrDone := True;
  1137.             LastSoft := False;
  1138.             End;
  1139.       #$8d:;
  1140.       #$0a:;
  1141.       #$20: Begin
  1142.             If ((CurrLen <> 0) or (Not StartSoft)) Then
  1143.               Begin
  1144.               Inc(CurrLen);
  1145.               WLen := CurrLen;
  1146.               GetString[CurrLen] := TmpCh;
  1147.               WPos := SqInfo^.TxtCtr;
  1148.               End
  1149.             Else
  1150.               StartSoft := False;
  1151.             End;
  1152.       Else
  1153.         Begin
  1154.         Inc(CurrLen);
  1155.         GetString[CurrLen] := TmpCh;
  1156.         End;
  1157.       End;
  1158.     If Not StrDone Then
  1159.       TmpCh := GetChar;
  1160.     End;
  1161.   If StrDone Then
  1162.     Begin
  1163.     GetString[0] := Chr(CurrLen);
  1164.     End
  1165.   Else
  1166.     If SqInfo^.MsgDone Then
  1167.       Begin
  1168.       GetString[0] := Chr(CurrLen);
  1169.       End
  1170.     Else
  1171.       Begin
  1172.       If WLen = 0 Then
  1173.         Begin
  1174.         GetString[0] := Chr(CurrLen);
  1175.         Dec(SqInfo^.TxtCtr);
  1176.         End
  1177.       Else
  1178.         Begin
  1179.         GetString[0] := Chr(WLen);
  1180.         SqInfo^.TxtCtr := WPos;
  1181.         End;
  1182.       End;
  1183.   End;
  1184.  
  1185.  
  1186. Function SqMsgObj.EOM: Boolean;
  1187.   Begin
  1188.   EOM := SqInfo^.MsgDone;
  1189.   End;
  1190.  
  1191.  
  1192. Function SqMsgObj.WasWrap: Boolean;
  1193.   Begin
  1194.   WasWrap := LastSoft;
  1195.   End;
  1196.  
  1197.  
  1198. Function SqMsgObj.GetChar: Char;
  1199.   Begin
  1200.   If ((SqInfo^.TxtCtr >= SqInfo^.Frame.MsgLength) Or
  1201.   (SqInfo^.MsgChars[SqInfo^.TxtCtr] = #0)) Then
  1202.     Begin
  1203.     GetChar := #0;
  1204.     SqInfo^.MsgDone := True;
  1205.     End
  1206.   Else
  1207.     Begin
  1208.     GetChar := SqInfo^.MsgChars[SqInfo^.TxtCtr];
  1209.     Inc(SqInfo^.TxtCtr);
  1210.     End;
  1211.   End;
  1212.  
  1213.  
  1214. Function SqMsgObj.GetHighWater: LongInt; {Get high water umsgid}
  1215.   Begin
  1216.   GetHighWater := LongInt(SqInfo^.SqBase.HighWater);
  1217.   End;
  1218.  
  1219.  
  1220. Function SqMsgObj.GetHighMsgNum: LongInt; {Get highest msg number}
  1221.   Begin
  1222.   GetHighMsgNum := LongInt(SqInfo^.SqBase.Uid) - 1;
  1223.   End;
  1224.  
  1225.  
  1226. Procedure SqMsgObj.ReadIdx;
  1227.   Var
  1228.     NumRead: Word;
  1229.  
  1230.   Begin
  1231.   If SqInfo^.SqiAlloc > 0 Then
  1232.     If SqIdx <> Nil Then
  1233.       FreeMem(SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
  1234.   SqInfo^.SqiAlloc := FileSize(SqInfo^.SqiFile) + 100;
  1235.   If SqInfo^.SqiAlloc > SqIdxArraySize Then
  1236.     SqInfo^.SqiAlloc := SqIdxArraySize ;
  1237.   GetMem(SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
  1238.   If SqIdx = nil Then
  1239.     SqInfo^.Error := 999
  1240.   Else
  1241.     Begin
  1242.     Seek(SqInfo^.SqiFile, 0);
  1243.     If IoResult = 0 Then
  1244.       Begin
  1245.       If Not shRead(SqInfo^.SqiFile, SqIdx^, SqInfo^.SqiAlloc, NumRead) Then
  1246.         SqInfo^.Error := FileError;
  1247.       End
  1248.     Else
  1249.       SqInfo^.Error := 300;
  1250.     End;
  1251.   End;
  1252.  
  1253.  
  1254. Procedure SqMsgObj.WriteIdx;
  1255.   Begin
  1256.   If SqIdx = nil Then
  1257.     SqInfo^.Error := 999
  1258.   Else
  1259.     Begin
  1260.     Seek(SqInfo^.SqiFile, 0);
  1261.     Truncate(SqInfo^.SqiFile);
  1262.     If IoResult = 0 Then
  1263.       Begin
  1264.       If Not shWrite(SqInfo^.SqiFile, SqIdx^, SqInfo^.SqBase.NumMsg) Then
  1265.         SqInfo^.Error := FileError;
  1266.       End
  1267.     Else
  1268.       SqInfo^.Error := 300;
  1269.     End;
  1270.   End;
  1271.  
  1272.  
  1273. Procedure SqMsgObj.SeekFirst(MsgNum: LongInt);
  1274.   Begin
  1275.   SqInfo^.CurrIdx := 1;
  1276.   ReadIdx;
  1277.   While ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and
  1278.   (MsgNum > LongInt(SqIdx^[SqInfo^.CurrIdx].UMsgId))) Do
  1279.     SeekNext;
  1280.   End;
  1281.  
  1282.  
  1283. Function SqMsgObj.IdxHighest: LongInt;
  1284.   Var
  1285.     i: Word;
  1286.     Tmp: LongInt;
  1287.  
  1288.   Begin
  1289.   Tmp := 0;
  1290.   i := 1;
  1291.   While i <= SqInfo^.SqBase.NumMsg Do
  1292.     Begin
  1293.     If  SqIdx^[i].UMsgId > Tmp Then
  1294.       Tmp := SqIdx^[i].UMsgId;
  1295.     Inc(i);
  1296.     End;
  1297.   IdxHighest := Tmp;
  1298.   End;
  1299.  
  1300.  
  1301. Function SqMsgObj.GetMsgNum: LongInt;
  1302.   Begin
  1303.   If ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and
  1304.   (SqInfo^.CurrIdx > 0)) Then
  1305.     GetMsgNum := LongInt(SqIdx^[SqInfo^.CurrIdx].UMsgId)
  1306.   Else
  1307.     GetMsgNum := -1;
  1308.   End;
  1309.  
  1310.  
  1311. Procedure SqMsgObj.SeekNext;
  1312.   Begin
  1313.   Inc(SqInfo^.CurrIdx);
  1314.   End;
  1315.  
  1316.  
  1317. Procedure SqMsgObj.SeekPrior;
  1318.   Begin
  1319.   If SqInfo^.CurrIdx > 1 Then
  1320.     Dec(SqInfo^.CurrIdx)
  1321.   Else
  1322.     SqInfo^.CurrIdx := 0;
  1323.   End;
  1324.  
  1325.  
  1326. Function SqMsgObj.SeekFound: Boolean;
  1327.   Begin
  1328.   SeekFound := GetMsgNum >= 0;
  1329.   End;
  1330.  
  1331.  
  1332. Function SqMsgObj.GetIdxFramePos: LongInt;
  1333.   Begin
  1334.   If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
  1335.     GetIdxFramePos := SqIdx^[SqInfo^.CurrIdx].Ofs
  1336.   Else
  1337.     GetIdxFramePos := -1;
  1338.   End;
  1339.  
  1340.  
  1341. Function SqMsgObj.GetIdxHash: LongInt;
  1342.   Begin
  1343.   If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
  1344.     GetIdxHash := SqIdx^[SqInfo^.CurrIdx].Hash
  1345.   Else
  1346.     GetIdxHash := 0;
  1347.   End;
  1348.  
  1349.  
  1350. Function SqMsgObj.IsLocal: Boolean; {Is current msg local}
  1351.   Begin
  1352.   IsLocal := ((SqInfo^.MsgHdr.Attr and SqMsgLocal) <> 0);
  1353.   End;
  1354.  
  1355.  
  1356. Function SqMsgObj.IsCrash: Boolean; {Is current msg crash}
  1357.   Begin
  1358.   IsCrash := ((SqInfo^.MsgHdr.Attr and SqMsgCrash) <> 0);
  1359.   End;
  1360.  
  1361.  
  1362. Function SqMsgObj.IsKillSent: Boolean; {Is current msg kill sent}
  1363.   Begin
  1364.   IsKillSent := ((SqInfo^.MsgHdr.Attr and SqMsgKill) <> 0);
  1365.   End;
  1366.  
  1367.  
  1368. Function SqMsgObj.IsSent: Boolean; {Is current msg sent}
  1369.   Begin
  1370.   IsSent := ((SqInfo^.MsgHdr.Attr and SqMsgSent) <> 0);
  1371.   End;
  1372.  
  1373.  
  1374. Function SqMsgObj.IsFAttach: Boolean; {Is current msg file attach}
  1375.   Begin
  1376.   IsFAttach := ((SqInfo^.MsgHdr.Attr and SqMsgFile) <> 0);
  1377.   End;
  1378.  
  1379.  
  1380. Function SqMsgObj.IsReqRct: Boolean; {Is current msg request receipt}
  1381.   Begin
  1382.   IsReqRct := ((SqInfo^.MsgHdr.Attr and SqMsgRRQ) <> 0);
  1383.   End;
  1384.  
  1385.  
  1386. Function SqMsgObj.IsReqAud: Boolean; {Is current msg request audit}
  1387.   Begin
  1388.   IsReqAud := ((SqInfo^.MsgHdr.Attr and SqMsgArq) <> 0);
  1389.   End;
  1390.  
  1391.  
  1392. Function SqMsgObj.IsRetRct: Boolean; {Is current msg a return receipt}
  1393.   Begin
  1394.   IsRetRct := ((SqInfo^.MsgHdr.Attr and SqMsgCpt) <> 0);
  1395.   End;
  1396.  
  1397.  
  1398. Function SqMsgObj.IsFileReq: Boolean; {Is current msg a file request}
  1399.   Begin
  1400.   IsFileReq := ((SqInfo^.MsgHdr.Attr and SqMsgFreq) <> 0);
  1401.   End;
  1402.  
  1403.  
  1404. Function SqMsgObj.IsRcvd: Boolean; {Is current msg received}
  1405.   Begin
  1406.   IsRcvd := ((SqInfo^.MsgHdr.Attr and SqMsgRcvd) <> 0);
  1407.   End;
  1408.  
  1409.  
  1410. Function SqMsgObj.IsPriv: Boolean; {Is current msg priviledged/private}
  1411.   Begin
  1412.   IsPriv := ((SqInfo^.MsgHdr.Attr and SqMsgPriv) <> 0);
  1413.   End;
  1414.  
  1415.  
  1416. Function SqMsgObj.IsEchoed: Boolean;
  1417.   Begin
  1418.   IsEchoed := ((SqInfo^.MsgHdr.Attr and SqMsgScanned) = 0);
  1419.   End;
  1420.  
  1421.  
  1422. Function SqMsgObj.IsDeleted: Boolean; {Is current msg deleted}
  1423.   Begin
  1424.   IsDeleted := False;
  1425.   End;
  1426.  
  1427.  
  1428. Function SqMsgObj.GetRefer: LongInt; {Get reply to of current msg}
  1429.   Begin
  1430.   GetRefer := LongInt(SqInfo^.MsgHdr.ReplyTo);
  1431.   End;
  1432.  
  1433.  
  1434. Procedure SqMsgObj.SetRefer(Num: LongInt); {Set reply to of current msg}
  1435.   Begin
  1436.   SqInfo^.MsgHdr.ReplyTo := LongInt(Num);
  1437.   End;
  1438.  
  1439.  
  1440. Function SqMsgObj.GetSeeAlso: LongInt; {Get see also msg}
  1441.   Begin
  1442.   GetSeeAlso := LongInt(SqInfo^.MsgHdr.Replies[1]);
  1443.   End;
  1444.  
  1445.  
  1446. Procedure SqMsgObj.SetSeeAlso(Num: LongInt); {Set see also msg}
  1447.   Begin
  1448.   SqInfo^.MsgHdr.Replies[1] := LongInt(Num);
  1449.   End;
  1450.  
  1451.  
  1452. Procedure SqMsgObj.SetAttr(St: Boolean; Mask: LongInt); {Set attribute}
  1453.   Begin
  1454.   If St Then
  1455.     SqInfo^.MsgHdr.Attr := SqInfo^.MsgHdr.Attr or Mask
  1456.   Else
  1457.     SqInfo^.MsgHdr.Attr := SqInfo^.MsgHdr.Attr and (Not Mask);
  1458.   End;
  1459.  
  1460.  
  1461. Procedure SqMsgObj.SetLocal(St: Boolean); {Set local status}
  1462.   Begin
  1463.   SetAttr(St, SqMsgLocal);
  1464.   End;
  1465.  
  1466.  
  1467. Procedure SqMsgObj.SetRcvd(St: Boolean); {Set received status}
  1468.   Begin
  1469.   SetAttr(St, SqMsgRcvd);
  1470.   End;
  1471.  
  1472.  
  1473. Procedure SqMsgObj.SetPriv(St: Boolean); {Set priveledge vs public status}
  1474.   Begin
  1475.   SetAttr(St, SqMsgPriv);
  1476.   End;
  1477.  
  1478.  
  1479. Procedure SqMsgObj.SetEcho(ES: Boolean);
  1480.   Begin
  1481.   SetAttr(Not ES, SqMsgScanned);
  1482.   End;
  1483.  
  1484.  
  1485. Procedure SqMsgObj.SetCrash(St: Boolean); {Set crash netmail status}
  1486.   Begin
  1487.   SetAttr(St, SqMsgCrash);
  1488.   End;
  1489.  
  1490.  
  1491. Procedure SqMsgObj.SetKillSent(St: Boolean); {Set kill/sent netmail status}
  1492.   Begin
  1493.   SetAttr(St, SqMsgKill);
  1494.   End;
  1495.  
  1496.  
  1497. Procedure SqMsgObj.SetSent(St: Boolean); {Set sent netmail status}
  1498.   Begin
  1499.   SetAttr(St, SqMsgSent);
  1500.   End;
  1501.  
  1502.  
  1503. Procedure SqMsgObj.SetFAttach(St: Boolean); {Set file attach status}
  1504.   Begin
  1505.   SetAttr(St, SqMsgFile);
  1506.   End;
  1507.  
  1508.  
  1509. Procedure SqMsgObj.SetReqRct(St: Boolean); {Set request receipt status}
  1510.   Begin
  1511.   SetAttr(St, SqMsgRrq);
  1512.   End;
  1513.  
  1514.  
  1515. Procedure SqMsgObj.SetReqAud(St: Boolean); {Set request audit status}
  1516.   Begin
  1517.   SetAttr(St, SqMsgarq);
  1518.   End;
  1519.  
  1520.  
  1521. Procedure SqMsgObj.SetRetRct(St: Boolean); {Set return receipt status}
  1522.   Begin
  1523.   SetAttr(St, SqMsgCpt);
  1524.   End;
  1525.  
  1526.  
  1527. Procedure SqMsgObj.SetFileReq(St: Boolean); {Set file request status}
  1528.   Begin
  1529.   SetAttr(St, SqMsgFreq);
  1530.   End;
  1531.  
  1532.  
  1533. Procedure SqMsgObj.MsgStartUp;
  1534.   Begin
  1535.   SqInfo^.CurrentFramePos := GetIdxFramePos;
  1536.   SqInfo^.CurrentUID := SqIdx^[SqInfo^.CurrIdx].UMsgId;
  1537.   ReadFrame(SqInfo^.CurrentFramePos);
  1538.   ReadMsgHdr(SqInfo^.CurrentFramePos);
  1539.   End;
  1540.  
  1541.  
  1542. Procedure SqMsgObj.MsgTxtStartUp;
  1543.   Var
  1544.     CFrame: LongInt;
  1545.  
  1546.   Begin
  1547.   ReadText(SqInfo^.CurrentFramePos);
  1548.   End;
  1549.  
  1550.  
  1551. Procedure SqMsgObj.SetMailType(MT: MsgMailType);
  1552.   Begin
  1553.   End;
  1554.  
  1555.  
  1556. Function SqMsgObj.GetSubArea: Word;
  1557.   Begin
  1558.   GetSubArea := 0;
  1559.   End;
  1560.  
  1561.  
  1562. Procedure SqMsgObj.ReWriteHdr;
  1563.   Var
  1564.     AlreadyLocked: Boolean;
  1565.     i: LongInt;
  1566.  
  1567.  
  1568.   Begin
  1569.   AlreadyLocked := SqInfo^.Locked;
  1570.   If Not AlreadyLocked Then
  1571.     If LockMsgBase Then;
  1572.   WriteFrame(SqInfo^.CurrentFramePos);
  1573.   WriteMsgHdr(SqInfo^.CurrentFramePos);
  1574.   i := 1;
  1575.   While ((i <= SqInfo^.SqBase.NumMsg) and (SqInfo^.CurrentFramePos <> SqIdx^[i].Ofs)) Do
  1576.     Inc(i);
  1577.   If SqIdx^[i].Ofs = SqInfo^.CurrentFramePos Then
  1578.     Begin
  1579.     If IsRcvd Then
  1580.       SqIdx^[i].Hash := 0
  1581.     Else
  1582.       SqIdx^[i].Hash := SqHashName(SqInfo^.MsgHdr.MsgTo);
  1583.     End;
  1584.   If Not AlreadyLocked Then
  1585.     If UnLockMsgBase Then;
  1586.   End;
  1587.  
  1588.  
  1589. Procedure SqMsgObj.DeleteMsg;
  1590.   Begin
  1591.   KillMsg(SqInfo^.CurrentUID);
  1592.   End;
  1593.  
  1594.  
  1595. Function SqMsgObj.NumberOfMsgs: LongInt;
  1596.   Var
  1597.     TmpBase: SqBaseType;
  1598.  
  1599.   Begin
  1600.   If LoadFile(SqInfo^.FN + '.Sqd', TmpBase, SizeOf(TmpBase)) = 0 Then
  1601.     NumberOfMsgs := TmpBase.NumMsg
  1602.   Else
  1603.     NumberOfMsgs := 0;
  1604.   End;
  1605.  
  1606.  
  1607. Function SqMsgObj.GetLastRead(UNum: LongInt): LongInt;
  1608.   Var
  1609.     LRec: LongInt;
  1610.  
  1611.   Begin
  1612.   If ((UNum + 1) * SizeOf(LRec)) >
  1613.   SizeFile(SqInfo^.FN + '.Sql') Then
  1614.     GetLastRead := 0
  1615.   Else
  1616.     Begin
  1617.     If LoadFilePos(SqInfo^.FN + '.Sql', LRec, SizeOf(LRec),
  1618.     UNum * SizeOf(LRec)) = 0 Then
  1619.       GetLastRead := LRec
  1620.     Else
  1621.       GetLastRead := 0;
  1622.     End;
  1623.   End;
  1624.  
  1625.  
  1626. Procedure SqMsgObj.SetLastRead(UNum: LongInt; LR: LongInt);
  1627.   Var
  1628.     LRec: LongInt;
  1629.     Status: Word;
  1630.  
  1631.   Begin
  1632.   Status := 0;
  1633.   If ((UNum + 1) * SizeOf(LRec)) >
  1634.   SizeFile(SqInfo^.FN + '.Sql') Then
  1635.     Begin
  1636.     Status := ExtendFile(SqInfo^.FN + '.Sql', (UNum + 1) * SizeOf(LRec));
  1637.     End;
  1638.   LRec := LR;
  1639.   If Status = 0 Then
  1640.     Status := SaveFilePos(SqInfo^.FN + '.Sql', LRec, SizeOf(LRec),
  1641.       UNum * SizeOf(LRec));
  1642.   End;
  1643.  
  1644.  
  1645. Function SqMsgObj.GetMsgLoc: LongInt;
  1646.   Begin
  1647.   GetMsgLoc := GetMsgNum;
  1648.   End;
  1649.  
  1650.  
  1651. Procedure SqMsgObj.SetMsgLoc(ML: LongInt);
  1652.   Begin
  1653.   SeekFirst(ML);
  1654.   End;
  1655.  
  1656.  
  1657. Procedure SqMsgObj.YoursFirst(Name: String; Handle: String);
  1658.   Begin
  1659.   SqInfo^.CurrIdx := 0;
  1660.   ReadIdx;
  1661.   SqInfo^.SName := Upper(Name);
  1662.   SqInfo^.SHandle := Upper(Handle);
  1663.   SqInfo^.HName := SqHashName(Name);
  1664.   SqInfo^.HHandle := SqHashName(Handle);
  1665.   YoursNext;
  1666.   End;
  1667.  
  1668.  
  1669. Procedure SqMsgObj.YoursNext;
  1670.   Var
  1671.     WasFound: Boolean;
  1672.  
  1673.   Begin
  1674.   WasFound := False;
  1675.   Inc(SqInfo^.CurrIdx);
  1676.   While ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and (Not WasFound)) Do
  1677.     Begin
  1678.     While ((SqIdx^[SqInfo^.CurrIdx].Hash <> SqInfo^.HName) And
  1679.     (SqIdx^[SqInfo^.CurrIdx].Hash <> SqInfo^.HHandle) And
  1680.     (SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg)) Do
  1681.       Inc(SqInfo^.CurrIdx);
  1682.     If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
  1683.       Begin
  1684.       MsgStartUp;
  1685.       If ((Not IsRcvd) and
  1686.       ((Upper(GetTo) = SqInfo^.SName) or (Upper(GetTo) = SqInfo^.SHandle))) Then
  1687.         WasFound := True
  1688.       Else
  1689.         Inc(SqInfo^.CurrIdx);
  1690.       End;
  1691.     End;
  1692.   End;
  1693.  
  1694.  
  1695. Function SqMsgObj.YoursFound: Boolean;
  1696.   Begin
  1697.   YoursFound := SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg;
  1698.   End;
  1699.  
  1700.  
  1701. Function SqMsgObj.GetMsgDisplayNum: LongInt;
  1702.   Begin
  1703.   GetMsgDisplayNum := SqInfo^.CurrIdx;
  1704.   End;
  1705.  
  1706.  
  1707. Function SqMsgObj.GetTxtPos: LongInt;
  1708.   Begin
  1709.   GetTxtPos := SqInfo^.TxtCtr;
  1710.   End;
  1711.  
  1712.  
  1713. Procedure SqMsgObj.SetTxtPos(TP: LongInt);
  1714.   Begin
  1715.   SqInfo^.TxtCtr := TP;
  1716.   End;
  1717.  
  1718.  
  1719. End.
  1720.