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