mysticbbs/mystic/bbs_msgbase_squish.pas

1614 lines
49 KiB
ObjectPascal

Unit BBS_MsgBase_Squish;
// ====================================================================
// Mystic BBS Software Copyright 1997-2013 By James Coyle
// ====================================================================
//
// This file is part of Mystic BBS.
//
// Mystic BBS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mystic BBS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mystic BBS. If not, see <http://www.gnu.org/licenses/>.
//
// ====================================================================
{$I M_OPS.PAS}
Interface
Uses
BBS_Records,
BBS_MsgBase_ABS,
DOS;
Const
SqHdrId = $AFAE4453;
SqLinkNext = 0;
SqLinkPrev = 1;
SqNullFrame = 0;
SqFrameMsg = 0;
SqFrameFree = 1;
// SqFrameRLE = 2;
// SqFrameLZW = 3;
SqFromSize = 36;
SqToSize = 36;
SqSubjSize = 72;
SqMaxReply = 10;
Type
SqBaseType = Record
Len : Word; { Length of this record }
Rsvd1 : Word; { Future use }
NumMsg : LongInt; { Number of messages }
HighMsg : LongInt; { Highest msg }
SkipMsg : LongInt; { # of msgs to keep in beginning of area }
HighWater : LongInt; { High water UMsgId }
Uid : LongInt; { Next UMsgId }
Base : String[79]; { Base name of Squish file }
BeginFrame : LongInt; { Offset of first frame in file }
LastFrame : LongInt; { Offset of last frame in file }
FirstFree : LongInt; { Offset of first free frame in file }
LastFree : LongInt; { Offset of last free frame in file }
EndFrame : LongInt; { Pointer to end of file }
MaxMsg : LongInt; { Maximum number of messages }
KeepDays : Word; { Maximum age of messages }
SqHdrSize : Word; { Size of frame header }
Rsvd2 : Array[1..124] of Byte;
End;
SqFrameHdrType = Record
Id : Cardinal; { Must equal SqHdrId }
NextFrame : LongInt; { Next msg frame }
PrevFrame : LongInt; { Prior msg frame }
FrameLength : LongInt; { Length of this frame not counting header }
MsgLength : LongInt; { Length of message }
ControlLength : LongInt; { Length of control information }
FrameType : Word; { Type of message frame }
Rsvd : Word; { Future use }
End;
SqMsgHdrType = Record
Attr : LongInt; { Msg attribute }
MsgFrom : String[SqFromSize - 1]; { Nul Term from name }
MsgTo : String[SqToSize - 1]; { Nul term to name }
Subj : String[SqSubjSize - 1]; { Nul term subject }
Orig : RecEchoMailAddr; { Origin address }
Dest : RecEchoMailAddr; { Destination address }
DateWritten : LongInt; { Date msg written }
DateArrived : LongInt; { Date msg arrived here }
UtcOffset : Word; { Minutes offset from UTC }
ReplyTo : LongInt; { Original msg }
Replies : Array[1..SqMaxReply] of LongInt; { Replies }
AzDate : String[19]; { AsciiZ "Fido" style date }
End;
SqIdxType = Record
Ofs : LongInt; { Offset of frame header }
UMsgId : LongInt; { Unique message id }
Hash : LongInt; { Hash of MsgTo name }
End;
Const
SqIdxArraySize = 5200; {5200}
Type
SqIdxArrayType = Array[1..SqIdxArraySize] of SqIdxType;
SqIdxPtrType = ^SqIdxArrayType;
FreeListType = Record
FreePos : LongInt;
FreeSize : LongInt;
End;
Const
MaxFree = 500;
Type
FreeArrayType = Array[1..MaxFree] of FreeListType;
Const
SqBSize : Word = SizeOf(SqBaseType);
SqFSize : Word = SizeOf(SqFrameHdrType);
SqMSize : Word = SizeOf(SqMsgHdrType);
SqISize : Word = SizeOf(SqIdxType);
Const
SqTxtBufferSize = 16000;
{handle 200 lines x 80 chars EASILY }
Type
SqInfoType = Record
FN : String[80];
MsgChars : Array[1..SqTxtBufferSize] of Char;
Error : Word;
SqdFile : File;
SqIFile : File;
SqBase : SqBaseType;
SqBaseExtra : Array[1..100] of Char;
SqdOpened : Boolean;
SqiOpened : Boolean;
SqiAlloc : Word;
Locked : Boolean;
FreeLoaded : Boolean;
HighestFree : Word;
Frame : SqFrameHdrType;
MsgHdr : SqMsgHdrType;
Extra : Array[1..100] of Char;
TxtCtr : Word;
MsgDone : Boolean;
CurrIdx : Word;
StrDate : String[8];
StrTime : String[8];
CurrentFramePos : LongInt;
CurrentUID : LongInt;
SName : String[35];
SHandle : String[35];
HName : LongInt;
HHandle : LongInt;
End;
Type
PMsgBaseSquish = ^TMsgBaseSquish;
TMsgBaseSquish = Object(TMsgBaseAbs)
SqInfo : ^SqInfoType;
SqIdx : ^SqIdxArrayType;
FreeArray : ^FreeArrayType;
Procedure EditMsgInit; Virtual;
Procedure EditMsgSave; Virtual;
Constructor Init; {Initialize}
Destructor Done; Virtual; {Done cleanup and dispose}
Function OpenMsgBase: Boolean; Virtual; {Open message base}
Procedure CloseMsgBase; Virtual; {Close message base}
Function CreateMsgBase(MaxMsg: Word; MaxDays: Word): Boolean; Virtual;
// Function MsgBaseExists: Boolean; Virtual;
Procedure SetMsgPath(FN: String); Virtual; {Set filepath and name - no extension}
Function SqdOpen: Boolean; Virtual; {Open squish data file}
Function SqiOpen: Boolean; Virtual; {Open squish index file}
Procedure SqdClose; Virtual; {Close squish data file}
Procedure SqiClose; Virtual; {Close squish index file}
Function LockMsgBase: Boolean; Virtual; {Lock msg base}
Function UnLockMsgBase: Boolean; Virtual; {Unlock msg base}
Procedure ReadBase; Virtual; {Read base data record}
Procedure WriteBase; Virtual; {Write base data record}
Function GetBeginFrame: LongInt; Virtual; {Get beginning frame pos}
Function GetHighWater: LongInt; Virtual; {Get high water umsgid}
Function GetHighMsgNum: LongInt; Virtual; {Get highest msg number}
Procedure ReadFrame(FPos: LongInt); Virtual; {Read frame at FPos}
Procedure ReadVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); Virtual; {Read frame at FPos into Frame}
Procedure WriteFrame(FPos: LongInt); Virtual; {Write frame at FPos}
Procedure WriteVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); Virtual;
Procedure UnlinkFrame(Var Frame: SqFrameHdrType); Virtual; {Unlink frame from linked list}
Procedure LinkFrameNext(Var Frame: SqFrameHdrType; OtherFrame: LongInt;
FramePos: LongInt); Virtual; {Link frame after other frame}
Procedure KillMsg(MsgNum: LongInt); {Kill msg msgnum}
Procedure KillExcess; {Kill msg in excess of limit}
Procedure FindFrame(Var FL: LongInt; Var FramePos: LongInt); Virtual;
Function GetNextFrame: LongInt; Virtual; {Get next frame pos}
Procedure ReadMsgHdr(FPos: LongInt); Virtual; {Read msg hdr for frame at FPos}
Procedure WriteMsgHdr(FPos: LongInt); Virtual; {Read msg hdr for frame at FPos}
Procedure WriteText(FPos: LongInt); Virtual; {Write text buffer for frame at Fpos}
Function SqHashName(Name: String): LongInt; Virtual; {Convert name to hash value}
Procedure StartNewMsg; Virtual; {Initialize msg header}
Function GetFrom: String; Virtual; {Get message from}
Function GetTo: String; Virtual; {Get message to}
Function GetSubj: String; Virtual; {Get message subject}
Function GetTextLen: LongInt; Virtual; {Get text length}
Procedure SetFrom(Str: String); Virtual; {Set message from}
Procedure SetTo(Str: String); Virtual; {Set message to}
Procedure SetSubj(Str: String); Virtual; {Set message subject}
Procedure SetDate(Str: String); Virtual; {Set message date}
Procedure SetTime(Str: String); Virtual; {Set message time}
Function GetDate: String; Virtual; {Get message date mm-dd-yy}
Function GetTime: String; Virtual; {Get message time hh:mm}
Function GetRefer: LongInt; Virtual; {Get reply to of current msg}
Procedure SetRefer(Num: LongInt); Virtual; {Set reply to of current msg}
Function GetSeeAlso: LongInt; Virtual; {Get see also msg}
Procedure SetSeeAlso(Num: LongInt); Virtual; {Set see also msg}
Procedure ReadText(FPos: LongInt); Virtual;
Function GetChar: Char; Virtual;
Function GetString(MaxLen: Word): String; Virtual;
Procedure GetOrig(Var Addr: RecEchoMailAddr); Virtual;
Procedure SetOrig(Addr: RecEchoMailAddr); Virtual;
Procedure GetDest(Var Addr: RecEchoMailAddr); Virtual;
Procedure SetDest (Addr: RecEchoMailAddr); Virtual;
Function GetOrigAddr : RecEchoMailAddr; Virtual;
Function GetDestAddr : RecEchoMailAddr; Virtual;
Function EOM: Boolean; Virtual;
(*
Function WasWrap: Boolean; Virtual;
*)
Procedure InitText; Virtual;
Procedure DoString(Str: String); Virtual; {Add string to message text}
Procedure DoChar(Ch: Char); Virtual; {Add character to message text}
Procedure DoStringLn(Str: String); Virtual; {Add string and newline to msg text}
Function WriteMsg: Word; Virtual; {Write msg to msg base}
Procedure ReadIdx; Virtual;
Procedure WriteIdx; Virtual;
Procedure SeekFirst(MsgNum: LongInt); Virtual; {Seeks to 1st msg >= MsgNum}
Function GetMsgNum: LongInt; Virtual;
Procedure SeekNext; Virtual;
Procedure SeekPrior; Virtual;
Function SeekFound: Boolean; Virtual;
Function GetIdxFramePos: LongInt; Virtual;
Function GetIdxHash: LongInt; Virtual;
Function IsLocal: Boolean; Virtual; {Is current msg local}
Function IsCrash: Boolean; Virtual; {Is current msg crash}
Function IsKillSent: Boolean; Virtual; {Is current msg kill sent}
Function IsSent: Boolean; Virtual; {Is current msg sent}
Function IsFAttach: Boolean; Virtual; {Is current msg file attach}
// Function IsReqRct: Boolean; Virtual; {Is current msg request receipt}
// Function IsReqAud: Boolean; Virtual; {Is current msg request audit}
// Function IsRetRct: Boolean; Virtual; {Is current msg a return receipt}
Function IsFileReq: Boolean; Virtual; {Is current msg a file request}
Function IsRcvd: Boolean; Virtual; {Is current msg received}
Function IsPriv: Boolean; Virtual; {Is current msg priviledged/private}
Function IsDeleted: Boolean; Virtual; {Is current msg deleted}
Procedure SetAttr(St: Boolean; Mask: LongInt); Virtual; {Set attribute}
Procedure SetLocal(St: Boolean); Virtual; {Set local status}
Procedure SetRcvd(St: Boolean); Virtual; {Set received status}
Procedure SetPriv(St: Boolean); Virtual; {Set priveledge vs public status}
Procedure SetCrash(St: Boolean); Virtual; {Set crash netmail status}
Procedure SetHold (ST: Boolean); Virtual;
Procedure SetKillSent(St: Boolean); Virtual; {Set kill/sent netmail status}
Procedure SetSent(St: Boolean); Virtual; {Set sent netmail status}
Procedure SetFAttach(St: Boolean); Virtual; {Set file attach status}
Procedure SetReqRct(St: Boolean); Virtual; {Set request receipt status}
Procedure SetReqAud(St: Boolean); Virtual; {Set request audit status}
Procedure SetRetRct(St: Boolean); Virtual; {Set return receipt status}
Procedure SetFileReq(St: Boolean); Virtual; {Set file request status}
Procedure MsgStartUp; Virtual; {Set up message}
Procedure MsgTxtStartUp; Virtual; {Set up for msg text}
Procedure SetMailType(MT: MsgMailType); Virtual; {Set message base type}
// Function GetSubArea: Word; Virtual; {Get sub area number}
Procedure ReWriteHdr; Virtual; {Rewrite msg header after changes}
Procedure DeleteMsg; Virtual; {Delete current message}
Procedure LoadFree; Virtual; {Load freelist into memory}
Function NumberOfMsgs: LongInt; Virtual; {Number of messages}
Procedure SetEcho(ES: Boolean); Virtual; {Set echo status}
Function IsEchoed: Boolean; Virtual; {Is current msg unmoved echomail msg}
Function GetLastRead(UNum: LongInt): LongInt; Virtual; {Get last read for user num}
Procedure SetLastRead(UNum: LongInt; LR: LongInt); Virtual; {Set last read}
Function GetMsgLoc: LongInt; Virtual; {To allow reseeking to message}
Procedure SetMsgLoc(ML: LongInt); Virtual; {Reseek to message}
Function IdxHighest: LongInt; Virtual; { *** }
// Procedure YoursFirst(Name: String; Handle: String); Virtual; {Seek your mail}
// Procedure YoursNext; Virtual; {Seek next your mail}
// Function YoursFound: Boolean; Virtual; {Message found}
Function GetMsgDisplayNum: LongInt; Virtual; {Get msg number to display}
Function GetTxtPos: LongInt; Virtual; {Get indicator of msg text position}
Procedure SetTxtPos(TP: LongInt); Virtual; {Set text position}
End;
Implementation
Uses
mkcrap,
m_Strings,
m_DateTime,
m_FileIO;
Const
SqMsgPriv = $00001;
SqMsgCrash = $00002;
SqMsgRcvd = $00004;
SqMsgSent = $00008;
SqMsgFile = $00010;
SqMsgFwd = $00020;
SqMsgOrphan = $00040;
SqMsgKill = $00080;
SqMsgLocal = $00100;
SqMsgHold = $00200;
SqMsgXX2 = $00400;
SqMsgFreq = $00800;
SqMsgRrq = $01000;
SqMsgCpt = $02000;
SqMsgArq = $04000;
SqMsgUrg = $08000;
SqMsgScanned = $10000;
Constructor TMsgBaseSquish.Init;
Begin
New (SqInfo);
New (FreeArray);
If ((SqInfo = nil) or (FreeArray = nil)) Then Begin
If SqInfo <> Nil Then Dispose(SqInfo);
If FreeArray <> Nil Then Dispose(FreeArray);
Fail;
Exit;
End;
SqInfo^.SqdOpened := False;
SqInfo^.SqiOpened := False;
SqInfo^.FN := '';
SqInfo^.Error := 0;
SqInfo^.Locked := False;
SqInfo^.FreeLoaded := False;
SqInfo^.SqiAlloc := 0;
End;
Destructor TMsgBaseSquish.Done;
Begin
If SqInfo^.SqdOpened Then SqdClose;
If SqInfo^.SqiOpened Then SqiClose;
If SqInfo^.SqIAlloc > 0 Then
If SqIdx <> Nil Then
FreeMem (SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
Dispose (FreeArray);
Dispose (SqInfo);
End;
Procedure TMsgBaseSquish.SetMsgPath (FN: String);
Begin
SqInfo^.FN := FExpand(FN);
If Pos('.', SqInfo^.FN) > 0 Then
SqInfo^.FN := Copy(SqInfo^.FN,1,Pos('.', SqInfo^.FN) - 1);
End;
Function TMsgBaseSquish.OpenMsgBase: Boolean;
Begin
If SqiOpen Then Begin
OpenMsgBase := SqdOpen;
ReadIdx;
End Else
OpenMsgBase := False;
End;
Function TMsgBaseSquish.SqdOpen: Boolean;
Var
NumRead: LongInt;
Begin
If Not SqInfo^.SqdOpened Then Begin
Assign(SqInfo^.SqdFile, SqInfo^.FN + '.sqd');
FileMode := 66; {ReadWrite + DenyNone}
If Not ioReset(SqInfo^.SqdFile, 1, fmreadwrite + fmdenynone) Then
SqdOpen := False
Else Begin
SqInfo^.SqdOpened := True;
SqdOpen := True;
If Not ioBlockRead(SqInfo^.SqdFile, SqInfo^.SqBase, 2, NumRead) Then
SqdOpen := False
Else Begin
If SqInfo^.SqBase.Len = 0 Then
SqInfo^.SqBase.Len := SqBSize;
If SqInfo^.SqBase.Len > (SizeOf(SqBaseType) + 100) Then
SqdOpen := False
Else Begin
SqBSize := SqInfo^.SqBase.Len;
ReadBase;
End;
End;
End;
End Else
SqdOpen := True;
End;
Function TMsgBaseSquish.SqiOpen: Boolean;
Begin
If Not SqInfo^.SqiOpened Then Begin
Assign (SqInfo^.SqiFile, SqInfo^.FN + '.sqi');
If Not ioReset(SqInfo^.SqiFile, SizeOf(SqIdxType), fmReadWrite + fmDenyNone) Then
SqiOpen := False
Else Begin
SqInfo^.SqiOpened := True;
SqiOpen := True;
End;
End Else
SqiOpen := True;
End;
Procedure TMsgBaseSquish.CloseMsgBase;
Begin
SqdClose;
SqiClose;
FileMode := fmRWDN; { shouldn't be needed... }
End;
Function TMsgBaseSquish.CreateMsgBase (MaxMsg: Word; MaxDays: Word): Boolean;
Begin
If Not SqInfo^.SqdOpened Then Begin
FillChar(SqInfo^.SqBase, SizeOf(SqInfo^.SqBase), 0);
SqInfo^.SqBase.Len := 256;
SqInfo^.SqBase.SqHdrSize := SqFSize;
SqInfo^.SqBase.UID := 1;
SqInfo^.SqBase.NumMsg := 0;
SqInfo^.SqBase.Base := SqInfo^.FN;
Str2Az(SqInfo^.FN, 78, SqInfo^.SqBase.Base);
SqInfo^.SqBase.MaxMsg := MaxMsg;
SqInfo^.SqBase.KeepDays := MaxDays;
SqInfo^.SqBase.EndFrame := SqInfo^.SqBase.Len;
CreateMsgBase := (SaveFilePos(SqInfo^.FN + '.sqd', SqInfo^.SqBase, SqInfo^.SqBase.Len, 0) = 0);
SaveFilePos (SqInfo^.FN + '.sqi', SqInfo^.SqBase, 0, 0);
SaveFilePos (SqInfo^.FN + '.sql', SqInfo^.SqBase, 0, 0);
End Else
CreateMsgBase := False;
End;
//Function TMsgBaseSquish.MsgBaseExists: Boolean;
//Begin
// MsgBaseExists := FileExist(SqInfo^.FN + '.sqd');
//End;
Procedure TMsgBaseSquish.SqdClose;
Begin
If SqInfo^.SqdOpened Then Close(SqInfo^.SqdFile);
If IOResult <> 0 Then;
SqInfo^.SqdOpened := False;
End;
Function TMsgBaseSquish.LockMsgBase: Boolean; {Lock msg base}
Begin
If Not SqInfo^.Locked Then Begin
sqinfo^.locked := true;
{ SqInfo^.Locked := shLock(SqInfo^.SqdFile, 0, 1) = 0;}
LockMsgBase := SqInfo^.Locked;
ReadBase;
ReadIdx;
SqInfo^.FreeLoaded := False;
End;
End;
Function TMsgBaseSquish.UnLockMsgBase: Boolean; {Unlock msg base}
Begin
If SqInfo^.Locked Then Begin
WriteBase;
WriteIdx;
sqinfo^.locked := false;
// SqInfo^.Locked := Not UnLockFile(SqInfo^.SqdFile, 0, 1) < 2;
UnLockMsgBase := Not SqInfo^.Locked;
End;
End;
Procedure TMsgBaseSquish.SqiClose;
Begin
If SqInfo^.SqiOpened Then Close(SqInfo^.SqiFile);
If IoResult <> 0 Then;
SqInfo^.SqiOpened := False;
End;
Procedure TMsgBaseSquish.ReadBase;
Var
NumRead: LongInt;
Begin
Seek (SqInfo^.SqdFile, 0);
If Not ioBlockRead(SqInfo^.SqdFile, SqInfo^.SqBase, SqBSize, NumRead) Then
SqInfo^.Error := ioCode;
If SqInfo^.SqBase.SqHdrSize = 0 Then
SQInfo^.SqBase.SqHdrSize := SqFSize;
SqFSize := SqInfo^.SqBase.SqHdrSize;
End;
Procedure TMsgBaseSquish.WriteBase;
Var
Res : LongInt;
Begin
Seek (SqInfo^.SqdFile, 0);
If Not ioBlockWrite(SqInfo^.SqdFile, SqInfo^.SqBase, SQBSize, Res) Then
SqInfo^.Error := ioCode;
End;
Procedure TMsgBaseSquish.StartNewMsg; {Initialize msg header}
Begin
FillChar (SqInfo^.MsgHdr, SizeOf(SqInfo^.MsgHdr), 0);
FillChar (SqInfo^.Frame, SizeOf(SqInfo^.Frame), 0);
SqInfo^.TxtCtr := 0;
SqInfo^.StrDate := '';
SqInfo^.StrTime := '';
End;
Function TMsgBaseSquish.GetFrom: String; {Get message from}
Begin
GetFrom := strWide2Str(SqInfo^.MsgHdr.MsgFrom, 35);
End;
Function TMsgBaseSquish.GetTo: String; {Get message to}
Begin
GetTo := strWide2Str(SqInfo^.MsgHdr.MsgTo, 35);
End;
Function TMsgBaseSquish.GetSubj: String; {Get message subject}
Begin
GetSubj := strWide2Str(SqInfo^.MsgHdr.Subj, 72);
End;
Function TMsgBaseSquish.GetTextLen: LongInt; {Get text length}
Begin
{ GetTextLen := SqInfo^.TxtCtr;}
GetTextLen := SqInfo^.Frame.MsgLength - 320;
End;
Procedure TMsgBaseSquish.SetFrom(Str: String); {Set message from}
Begin
Str2Az(Str, 35, SqInfo^.MsgHdr.MsgFrom);
End;
Procedure TMsgBaseSquish.SetTo(Str: String); {Set message to}
Begin
Str2Az(Str,35, SqInfo^.MsgHdr.MsgTo);
End;
Procedure TMsgBaseSquish.SetSubj(Str: String); {Set message subject}
Begin
Str2Az(Str,72, SqInfo^.MSgHdr.Subj);
End;
Function TMsgBaseSquish.GetDate: String; {Get message date mm-dd-yy}
Var
TmpDate: LongInt;
Begin
TmpDate := (SqInfo^.MsgHdr.DateWritten shr 16) + ((SqInfo^.MsgHdr.DateWritten and $ffff) shl 16);
GetDate := DateDos2Str(TmpDate, 1);
End;
Function TMsgBaseSquish.GetTime: String; {Get message time hh:mm}
Var
TmpDate: LongInt;
Begin
TmpDate := (SqInfo^.MsgHdr.DateWritten shr 16) + ((SqInfo^.MsgHdr.DateWritten and $ffff) shl 16);
GetTime := TimeDos2Str(TmpDate, 0);
End;
Procedure TMsgBaseSquish.SetDate(Str: String);
Begin
SqInfo^.StrDate := Copy(Str,1,8);
End;
Procedure TMsgBaseSquish.SetTime(Str: String);
Begin
SqInfo^.StrTime := Copy(Str,1,8);
End;
Procedure TMsgBaseSquish.GetOrig(Var Addr: RecEchoMailAddr);
Begin
Addr := SqInfo^.MsgHdr.Orig;
End;
Function TMsgBaseSquish.GetOrigAddr : RecEchoMailAddr;
Begin
Result := SqInfo^.MsgHdr.Orig;
End;
Procedure TMsgBaseSquish.SetOrig(Addr: RecEchoMailAddr);
Begin
SqInfo^.MsgHdr.Orig := Addr;
End;
Procedure TMsgBaseSquish.GetDest(Var Addr: RecEchoMailAddr);
Begin
Addr := SqInfo^.MsgHdr.Dest;
End;
Function TMsgBaseSquish.GetDestAddr : RecEchoMailAddr;
Begin
Result := SqInfo^.MsgHdr.Dest;
End;
Procedure TMsgBaseSquish.SetDest (Addr: RecEchoMailAddr);
Begin
SqInfo^.MsgHdr.Dest := Addr;
End;
Function TMsgBaseSquish.SqHashName(Name: String): LongInt;
Var
Hash : LongInt;
Tmp : LongInt;
Counter : Word;
Begin
Hash := 0;
Counter := 1;
While Counter <= Length(Name) Do Begin
Hash := (Hash shl 4) + Ord(LoCase(Name[Counter]));
Tmp := Hash and $F0000000;
If (Tmp <> 0) Then Hash := (Hash or (Tmp shr 24)) or Tmp;
Inc (Counter);
End;
SqHashName := Hash and $7fffffff;
End;
Procedure TMsgBaseSquish.ReadFrame(FPos: LongInt); {Read frame at FPos}
Begin
ReadVarFrame (SqInfo^.Frame, FPos);
End;
Procedure TMsgBaseSquish.ReadVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); {Read frame at FPos}
Var
NumRead : LongInt;
Begin
Seek (SqInfo^.SqdFile, FPos);
SqInfo^.Error := IoResult;
If SqInfo^.Error = 0 Then Begin
If Not ioBlockRead (SqInfo^.SqdFile, Frame, SizeOf(SqFrameHdrType), NumRead) Then
SqInfo^.Error := ioCode;
End;
End;
Procedure TMsgBaseSquish.WriteFrame(FPos: LongInt); {Read frame at FPos}
Begin
WriteVarFrame(SqInfo^.Frame, FPos);
End;
Procedure TMsgBaseSquish.WriteVarFrame(Var Frame: SqFrameHdrType; FPos: LongInt); {Write frame at FPos}
Var
Res : LongInt;
Begin
Seek (SqInfo^.SqdFile, FPos);
SqInfo^.Error := IoResult;
If SqInfo^.Error = 0 Then Begin
If Not ioBlockWrite(SqInfo^.SqdFile, Frame, SizeOf(SqFrameHdrType), Res) Then
SqInfo^.Error := ioCode;
End;
End;
Procedure TMsgBaseSquish.UnlinkFrame(Var Frame: SqFrameHdrType);
Var
TmpFrame: SqFrameHdrType;
Begin
If Frame.PrevFrame <> 0 Then Begin
ReadVarFrame(TmpFrame, Frame.PrevFrame);
TmpFrame.NextFrame := Frame.NextFrame;
WriteVarFrame(TmpFrame, Frame.PrevFrame);
End;
If Frame.NextFrame <> 0 Then Begin
ReadVarFrame(TmpFrame, Frame.NextFrame);
TmpFrame.PrevFrame := Frame.PrevFrame;
WriteVarFrame(TmpFrame, Frame.NextFrame);
End;
End;
Procedure TMsgBaseSquish.LoadFree;
Var
Count : Word;
TmpFrame : SqFrameHdrType;
TmpPos : LongInt;
Begin
For Count := 1 to MaxFree Do Begin
FreeArray^[Count].FreePos := 0;
FreeArray^[Count].FreeSize := 0;
End;
SqInfo^.FreeLoaded := True;
Count := 0;
TmpPos := SqInfo^.SqBase.FirstFree;
While ((TmpPos <> 0) and (Count < MaxFree)) Do Begin
ReadVarFrame (TmpFrame, TmpPos);
Inc (Count);
FreeArray^[Count].FreeSize := TmpFrame.FrameLength;
FreeArray^[Count].FreePos := TmpPos;
TmpPos := TmpFrame.NextFrame;
End;
SqInfo^.HighestFree := Count;
End;
Procedure TMsgBaseSquish.FindFrame (Var FL: LongInt; Var FramePos: LongInt);
Var
TmpFrame : SqFrameHdrType;
BestFoundPos : LongInt;
BestFoundSize : LongInt;
BestIdx : Word;
i : Word;
Begin
If Not SqInfo^.FreeLoaded Then LoadFree;
BestFoundPos := 0;
BestFoundSize := 0;
For i := 1 to SqInfo^.HighestFree Do Begin
If (FreeArray^[i].FreeSize > FL) Then Begin
If ((BestFoundSize = 0) or (FreeArray^[i].FreeSize < BestFoundSize)) Then Begin
BestFoundSize := FreeArray^[i].FreeSize;
BestFoundPos := FreeArray^[i].FreePos;
BestIdx := i;
End;
End
End;
FramePos := BestFoundPos;
If FramePos <> 0 Then Begin
ReadVarFrame(TmpFrame, FramePos);
FreeArray^[BestIdx].FreePos := 0;
FreeArray^[BestIdx].FreeSize := 0;
End;
If FramePos = 0 Then Begin
FL := 0;
FramePos := SqInfo^.SqBase.EndFrame;
End Else Begin
UnLinkFrame(TmpFrame);
If TmpFrame.PrevFrame = 0 Then SqInfo^.SqBase.FirstFree := TmpFrame.NextFrame;
If TmpFrame.NextFrame = 0 Then SqInfo^.SqBase.LastFree := TmpFrame.PrevFrame;
FL := TmpFrame.FrameLength;
End;
End;
Procedure TMsgBaseSquish.LinkFrameNext(Var Frame: SqFrameHdrType; OtherFrame: LongInt; FramePos: LongInt);
Var
TmpFrame: SqFrameHdrType;
Begin
If OtherFrame <> 0 Then Begin
ReadVarFrame (TmpFrame, OtherFrame);
TmpFrame.NextFrame := FramePos;
Frame.PrevFrame := OtherFrame;
WriteVarFrame (TmpFrame, OtherFrame);
End;
End;
Procedure TMsgBaseSquish.KillMsg (MsgNum: LongInt);
Var
i : Word;
KillPos : LongInt;
IndexPos : LongInt;
KillFrame : SqFrameHdrType;
TmpFrame : SqFrameHdrType;
CurrMove : LongInt;
AlreadyLocked : Boolean;
FreeCtr : Word;
Begin
AlreadyLocked := SqInfo^.Locked;
If Not AlreadyLocked Then
If LockMsgBase Then;
If SqIdx = Nil Then
SqInfo^.Error := 999
Else Begin
i := 1;
While ((i <= SqInfo^.SqBase.NumMsg) and (MsgNum <> SqIdx^[i].UMsgId)) Do
Inc(i);
If MsgNum = SqIdx^[i].UMsgId Then Begin
IndexPos := i;
KillPos := SqIdx^[i].Ofs;
ReadVarFrame (KillFrame, KillPos);
If KillFrame.PrevFrame = 0 Then
SqInfo^.SqBase.BeginFrame := KillFrame.NextFrame;
If KillFrame.NextFrame = 0 Then
SqInfo^.SqBase.LastFrame := KillFrame.PrevFrame;
KillFrame.FrameType := sqFrameFree;
UnLinkFrame (KillFrame);
If ((SqInfo^.SqBase.FirstFree = 0) or (SqInfo^.SqBase.LastFree = 0)) Then Begin
SqInfo^.SqBase.FirstFree := KillPos;
SqInfo^.SqBase.LastFree := KillPos;
KillFrame.PrevFrame := 0;
KillFrame.NextFrame := 0;
End Else Begin
KillFrame.NextFrame := 0;
KillFrame.PrevFrame := SqInfo^.SqBase.LastFree;
ReadVarFrame (TmpFrame, SqInfo^.SqBase.LastFree);
TmpFrame.NextFrame := KillPos;
WriteVarFrame(TmpFrame, SqInfo^.SqBase.LastFree);
SqInfo^.SqBase.LastFree := KillPos;
End;
WriteVarFrame(KillFrame, KillPos);
FreeCtr := 1;
While ((FreeCtr < MaxFree) and (FreeArray^[FreeCtr].FreePos <> 0)) Do
Inc(FreeCtr);
If FreeArray^[FreeCtr].FreePos = 0 Then Begin
FreeArray^[FreeCtr].FreePos := KillPos;
FreeArray^[FreeCtr].FreeSize := KillFrame.FrameLength;
End;
If FreeCtr > SqInfo^.HighestFree Then
SqInfo^.HighestFree := FreeCtr;
Dec (SqInfo^.SqBase.NumMsg);
Dec (SqInfo^.SqBase.HighMsg);
CurrMove := IndexPos;
While CurrMove <= SqInfo^.SqBase.NumMsg Do Begin
SqIdx^[CurrMove] := SqIdx^[CurrMove + 1];
Inc (CurrMove);
End;
End;
End;
If Not AlreadyLocked Then
If UnlockMsgBase Then;
End;
Procedure TMsgBaseSquish.ReadMsgHdr(FPos: LongInt); {Read msg hdr for frame at FPos}
Var
NumRead: LongInt;
Begin
Seek (SqInfo^.SqdFile, FPos + SqFSize);
SqInfo^.Error := IoResult;
If SqInfo^.Error = 0 Then Begin
If Not ioBlockRead(SqInfo^.SqdFile, SqInfo^.MsgHdr, SizeOf(SqMsgHdrType), NumRead) Then
SqInfo^.Error := ioCode;
End;
End;
Procedure TMsgBaseSquish.WriteMsgHdr(FPos: LongInt); {Read msg hdr for frame at FPos}
Var
Res : LongInt;
Begin
Seek (SqInfo^.SqdFile, FPos + SqFSize);
SqInfo^.Error := IoResult;
If SqInfo^.Error = 0 Then Begin
If Not ioBlockWrite(SqInfo^.SqdFile, SqInfo^.MsgHdr, SizeOf(SqMsgHdrType), Res) Then
SqInfo^.Error := ioCode;
End;
End;
Procedure TMsgBaseSquish.WriteText(FPos: LongInt); {Write text buffer for frame at Fpos}
Var
Res : LongInt;
Begin
Seek (SqInfo^.SqdFile, FPos + SqFSize + SqMSize);
SqInfo^.Error := IoResult;
If SqInfo^.Error = 0 Then Begin
If Not ioBlockWrite(SqInfo^.SqdFile, SqInfo^.MsgChars, SqInfo^.TxtCtr, Res) Then
SqInfo^.Error := ioCode;
End;
End;
Function TMsgBaseSquish.GetBeginFrame: LongInt; {Get beginning frame pos}
Begin
GetBeginFrame := SqInfo^.SqBase.BeginFrame;
End;
Function TMsgBaseSquish.GetNextFrame: LongInt; {Get next frame pos}
Begin
GetNextFrame := SqInfo^.Frame.NextFrame;
End;
Procedure TMsgBaseSquish.ReadText(FPos: LongInt);
Begin
Seek(SqInfo^.SqdFile, FPos + SqFSize + SqMSize);
SqInfo^.Error := IoResult;
If SqInfo^.Error = 0 Then Begin
If SqInfo^.Frame.MsgLength > SqTxtBufferSize Then
BlockRead(SqInfo^.SqdFile, SqInfo^.MsgChars, SqTxtBufferSize)
Else
BlockRead(SqInfo^.SqdFile, SqInfo^.MsgChars, SqInfo^.Frame.MsgLength);
SqInfo^.Error := IoResult;
End;
SqInfo^.TxtCtr := 1 + SqInfo^.Frame.ControlLength;
SqInfo^.MsgDone := False;
LastSoft := False;
End;
Procedure TMsgBaseSquish.InitText;
Begin
SqInfo^.TxtCtr := 0;
End;
Procedure TMsgBaseSquish.DoString (Str: String);
Var
Count : Word;
Begin
For Count := 1 to Length(Str) Do
DoChar(Str[Count]);
End;
Procedure TMsgBaseSquish.DoChar (Ch: Char); {Add character to message text}
Begin
If SqInfo^.TxtCtr < SqTxtBufferSize Then Begin
Inc (SqInfo^.TxtCtr);
SqInfo^.MsgChars[SqInfo^.TxtCtr] := Ch;
End;
End;
Procedure TMsgBaseSquish.DoStringLn(Str: String); {Add string and newline to msg text}
Begin
DoString (Str);
DoChar (#13);
End;
Procedure TMsgBaseSquish.KillExcess;
Var
AlreadyLocked: Boolean;
Begin
AlreadyLocked := SqInfo^.Locked;
If Not AlreadyLocked Then
If LockMsgBase Then;
If SqIdx = Nil Then
SqInfo^.error := 999
Else Begin
If ((SqInfo^.SqBase.MaxMsg > 0) and
(SqInfo^.SqBase.MaxMsg > SqInfo^.SqBase.SkipMsg)) Then Begin
While (SqInfo^.SqBase.NumMsg > SqInfo^.SqBase.MaxMsg) Do
KillMsg(SqIdx^[SqInfo^.SqBase.SkipMsg + 1].UMsgId);
End;
End;
If Not AlreadyLocked Then
If UnlockMsgBase Then;
End;
Function TMsgBaseSquish.WriteMsg: Word; {Write msg to msg base}
Var
MsgSize : LongInt;
FrameSize : LongInt;
FramePos : LongInt;
TmpFrame : SqFrameHdrType;
TmpDate : LongInt;
TmpDT : DateTime;
TmpStr : String;
AlreadyLocked : Boolean;
Begin
DoChar(#0);
TmpDT.Year := strS2I(Copy(SqInfo^.StrDate,7,2));
If TmpDT.Year > 79 Then
Inc (TmpDT.Year, 1900)
Else
Inc (TmpDT.Year, 2000);
TmpDT.Month := strS2I(Copy(SqInfo^.StrDate,1,2));
TmpDT.Day := strS2I(Copy(SqInfo^.StrDate,4,2));
TmpDt.Hour := strS2I(Copy(SqInfo^.StrTime,1,2));
TmpDt.Min := strS2I(Copy(SqInfo^.StrTime, 4,2));
TmpDt.Sec := 0;
TmpStr := FormatDate(TmpDT, 'DD NNN YY ') + Copy(SqInfo^.StrTime, 1, 5) + ':00';
PackTime (TmpDT, TmpDate);
SqInfo^.MsgHdr.DateWritten := (TmpDate shr 16) + ((TmpDate and $ffff) shl 16);
TmpDate := CurDateDos;
SqInfo^.MsgHdr.DateArrived := (TmpDate shr 16) + ((TmpDate and $ffff) shl 16);
Str2AZ(TmpStr, 20, SqInfo^.MsgHdr.AZDate);
AlreadyLocked := SqInfo^.Locked;
If Not AlreadyLocked Then
If LockMsgBase Then;
If SqInfo^.Locked Then Begin
MsgSize := SqInfo^.TxtCtr + SqMSize;
FrameSize := MsgSize;
FindFrame (FrameSize, FramePos);
If SqInfo^.SqBase.LastFrame <> 0 Then Begin
ReadVarFrame (TmpFrame, SqInfo^.SqBase.LastFrame);
TmpFrame.NextFrame := FramePos;
WriteVarFrame(TmpFrame, SqInfo^.SqBase.LastFrame);
TmpFrame.PrevFrame := SqInfo^.SqBase.LastFrame;
End Else Begin
SqInfo^.SqBase.BeginFrame := FramePos;
TmpFrame.PrevFrame := 0;
End;
TmpFrame.Id := SqHdrId;
TmpFrame.FrameType := SqFrameMsg;
SqInfo^.SqBase.LastFrame := FramePos;
TmpFrame.NextFrame := 0;
TmpFrame.FrameLength := FrameSize;
TmpFrame.MsgLength := MsgSize;
TmpFrame.ControlLength := 0;
If TmpFrame.FrameLength = 0 Then Begin
TmpFrame.FrameLength := TmpFrame.MsgLength + 0; {slack to minimize free frames}
SqInfo^.SqBase.EndFrame := FramePos + SqFSize + TmpFrame.FrameLength;
End;
If SqInfo^.SqBase.NumMsg >= SqInfo^.SqiAlloc Then Begin
WriteIdx;
ReadIdx;
End;
If SqIdx = Nil Then Begin
SqInfo^.Error := 999;
WriteMsg := 999;
End Else Begin
WriteVarFrame (TmpFrame, FramePos);
WriteMsgHdr (FramePos);
WriteText (FramePos);
Inc (SqInfo^.SqBase.NumMsg);
SqIdx^[SqInfo^.SqBase.NumMsg].Ofs := FramePos;
SqIdx^[SqInfo^.SqBase.NumMsg].UMsgId := SqInfo^.SqBase.UID;
SqIdx^[SqInfo^.SqBase.NumMsg].Hash := SqHashName(strWide2Str(SqInfo^.MsgHdr.MsgTo, 35));
Inc(SqInfo^.SqBase.UId);
SqInfo^.SqBase.HighMsg := SqInfo^.SqBase.NumMsg;
KillExcess;
SqInfo^.CurrIdx := SqInfo^.SqBase.NumMsg;
WriteMsg := 0;
End;
If Not AlreadyLocked Then
If UnLockMsgBase Then;
End Else
WriteMsg := 5;
End;
Function TMsgBaseSquish.GetString (MaxLen: Word): String;
Var
WPos : Word;
WLen : Byte;
StrDone : Boolean;
StartSoft : Boolean;
CurrLen : Word;
TmpCh : Char;
Begin
StrDone := False;
CurrLen := 0;
WPos := 0;
WLen := 0;
StartSoft := LastSoft;
LastSoft := True;
While ((Not StrDone) And (CurrLen < MaxLen) And (Not SqInfo^.MsgDone)) Do Begin
TmpCh := GetChar;
Case TmpCh of
#00,
#13 : Begin
StrDone := True;
LastSoft := False;
End;
#10,
#141: ;
#32 : Begin
If ((CurrLen <> 0) or (Not StartSoft)) Then Begin
Inc (CurrLen);
WLen := CurrLen;
GetString[CurrLen] := TmpCh;
WPos := SqInfo^.TxtCtr;
End Else
StartSoft := False;
End;
Else
Inc(CurrLen);
GetString[CurrLen] := TmpCh;
End;
End;
If StrDone Then Begin
GetString[0] := Chr(CurrLen);
End Else
If SqInfo^.MsgDone Then Begin
GetString[0] := Chr(CurrLen);
End Else Begin
If WLen = 0 Then Begin
GetString[0] := Chr(CurrLen);
Dec(SqInfo^.TxtCtr);
End Else Begin
GetString[0] := Chr(WLen);
SqInfo^.TxtCtr := WPos;
End;
End;
End;
Function TMsgBaseSquish.EOM: Boolean;
Begin
EOM := (SqInfo^.TxtCtr >= SqInfo^.Frame.MsgLength) or (SqInfo^.MsgChars[SqInfo^.TxtCtr] = #0);
End;
Function TMsgBaseSquish.GetChar: Char;
Begin
If (SqInfo^.TxtCtr >= SqInfo^.Frame.MsgLength) or (SqInfo^.MsgChars[SqInfo^.TxtCtr] = #0) Then Begin
GetChar := #0;
SqInfo^.MsgDone := True;
End Else Begin
GetChar := SqInfo^.MsgChars[SqInfo^.TxtCtr];
Inc(SqInfo^.TxtCtr);
End;
End;
Function TMsgBaseSquish.GetHighWater: LongInt; {Get high water umsgid}
Begin
GetHighWater := LongInt(SqInfo^.SqBase.HighWater);
End;
Function TMsgBaseSquish.GetHighMsgNum: LongInt; {Get highest msg number}
Begin
GetHighMsgNum := LongInt(SqInfo^.SqBase.Uid) - 1;
End;
Procedure TMsgBaseSquish.ReadIdx;
Var
NumRead: LongInt;
Begin
If SqInfo^.SqiAlloc > 0 Then
If SqIdx <> Nil Then
FreeMem(SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
SqInfo^.SqiAlloc := FileSize(SqInfo^.SqiFile) + 100;
If SqInfo^.SqiAlloc > SqIdxArraySize Then
SqInfo^.SqiAlloc := SqIdxArraySize;
GetMem (SqIdx, SqInfo^.SqiAlloc * SizeOf(SqIdxType));
If SqIdx = nil Then
SqInfo^.Error := 999
Else Begin
Seek(SqInfo^.SqiFile, 0);
If IoResult = 0 Then Begin
If Not ioBlockRead(SqInfo^.SqiFile, SqIdx^, SqInfo^.SqiAlloc, NumRead) Then
SqInfo^.Error := ioCode;
End Else
SqInfo^.Error := 300;
End;
End;
Procedure TMsgBaseSquish.WriteIdx;
Var
Res : LongInt;
Begin
If SqIdx = nil Then
SqInfo^.Error := 999
Else Begin
Seek (SqInfo^.SqiFile, 0);
Truncate (SqInfo^.SqiFile);
If IoResult = 0 Then Begin
If Not ioBlockWrite(SqInfo^.SqiFile, SqIdx^, SqInfo^.SqBase.NumMsg, Res) Then
SqInfo^.Error := ioCode;
End Else
SqInfo^.Error := 300;
End;
End;
Procedure TMsgBaseSquish.SeekFirst(MsgNum: LongInt);
Begin
SqInfo^.CurrIdx := 1;
ReadIdx;
While ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and (MsgNum > LongInt(SqIdx^[SqInfo^.CurrIdx].UMsgId))) Do
SeekNext;
End;
Function TMsgBaseSquish.IdxHighest: LongInt;
Var
i : Word;
Tmp : LongInt;
Begin
Tmp := 0;
i := 1;
While i <= SqInfo^.SqBase.NumMsg Do Begin
If SqIdx^[i].UMsgId > Tmp Then Tmp := SqIdx^[i].UMsgId;
Inc(i);
End;
IdxHighest := Tmp;
End;
Function TMsgBaseSquish.GetMsgNum: LongInt;
Begin
If ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and (SqInfo^.CurrIdx > 0)) Then
GetMsgNum := LongInt(SqIdx^[SqInfo^.CurrIdx].UMsgId)
Else
GetMsgNum := -1;
End;
Procedure TMsgBaseSquish.SeekNext;
Begin
Inc(SqInfo^.CurrIdx);
End;
Procedure TMsgBaseSquish.SeekPrior;
Begin
If SqInfo^.CurrIdx > 1 Then
Dec(SqInfo^.CurrIdx)
Else
SqInfo^.CurrIdx := 0;
End;
Function TMsgBaseSquish.SeekFound: Boolean;
Begin
SeekFound := GetMsgNum >= 0;
End;
Function TMsgBaseSquish.GetIdxFramePos: LongInt;
Begin
If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
GetIdxFramePos := SqIdx^[SqInfo^.CurrIdx].Ofs
Else
GetIdxFramePos := -1;
End;
Function TMsgBaseSquish.GetIdxHash: LongInt;
Begin
If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then
GetIdxHash := SqIdx^[SqInfo^.CurrIdx].Hash
Else
GetIdxHash := 0;
End;
Function TMsgBaseSquish.IsLocal: Boolean; {Is current msg local}
Begin
IsLocal := ((SqInfo^.MsgHdr.Attr and SqMsgLocal) <> 0);
End;
Function TMsgBaseSquish.IsCrash: Boolean; {Is current msg crash}
Begin
IsCrash := ((SqInfo^.MsgHdr.Attr and SqMsgCrash) <> 0);
End;
Function TMsgBaseSquish.IsKillSent: Boolean; {Is current msg kill sent}
Begin
IsKillSent := ((SqInfo^.MsgHdr.Attr and SqMsgKill) <> 0);
End;
Function TMsgBaseSquish.IsSent: Boolean; {Is current msg sent}
Begin
IsSent := ((SqInfo^.MsgHdr.Attr and SqMsgSent) <> 0);
End;
Function TMsgBaseSquish.IsFAttach: Boolean; {Is current msg file attach}
Begin
IsFAttach := ((SqInfo^.MsgHdr.Attr and SqMsgFile) <> 0);
End;
Function TMsgBaseSquish.IsFileReq: Boolean; {Is current msg a file request}
Begin
IsFileReq := ((SqInfo^.MsgHdr.Attr and SqMsgFreq) <> 0);
End;
Function TMsgBaseSquish.IsRcvd: Boolean; {Is current msg received}
Begin
IsRcvd := ((SqInfo^.MsgHdr.Attr and SqMsgRcvd) <> 0);
End;
Function TMsgBaseSquish.IsPriv: Boolean; {Is current msg priviledged/private}
Begin
IsPriv := ((SqInfo^.MsgHdr.Attr and SqMsgPriv) <> 0);
End;
Function TMsgBaseSquish.IsEchoed: Boolean;
Begin
IsEchoed := ((SqInfo^.MsgHdr.Attr and SqMsgScanned) = 0);
End;
Function TMsgBaseSquish.IsDeleted: Boolean; {Is current msg deleted}
Begin
IsDeleted := False;
End;
Function TMsgBaseSquish.GetRefer: LongInt; {Get reply to of current msg}
Begin
GetRefer := LongInt(SqInfo^.MsgHdr.ReplyTo);
End;
Procedure TMsgBaseSquish.SetRefer(Num: LongInt); {Set reply to of current msg}
Begin
SqInfo^.MsgHdr.ReplyTo := LongInt(Num);
End;
Function TMsgBaseSquish.GetSeeAlso: LongInt; {Get see also msg}
Begin
GetSeeAlso := LongInt(SqInfo^.MsgHdr.Replies[1]);
End;
Procedure TMsgBaseSquish.SetSeeAlso(Num: LongInt); {Set see also msg}
Begin
SqInfo^.MsgHdr.Replies[1] := LongInt(Num);
End;
Procedure TMsgBaseSquish.SetAttr(St: Boolean; Mask: LongInt); {Set attribute}
Begin
If St Then
SqInfo^.MsgHdr.Attr := SqInfo^.MsgHdr.Attr or Mask
Else
SqInfo^.MsgHdr.Attr := SqInfo^.MsgHdr.Attr and (Not Mask);
End;
Procedure TMsgBaseSquish.SetLocal(St: Boolean); {Set local status}
Begin
SetAttr(St, SqMsgLocal);
End;
Procedure TMsgBaseSquish.SetRcvd(St: Boolean); {Set received status}
Begin
SetAttr(St, SqMsgRcvd);
End;
Procedure TMsgBaseSquish.SetPriv(St: Boolean); {Set priveledge vs public status}
Begin
SetAttr(St, SqMsgPriv);
End;
Procedure TMsgBaseSquish.SetEcho(ES: Boolean);
Begin
SetAttr(Not ES, SqMsgScanned);
End;
Procedure TMsgBaseSquish.SetCrash(St: Boolean); {Set crash netmail status}
Begin
SetAttr(St, SqMsgCrash);
End;
Procedure TMsgBaseSquish.SetHold (ST: Boolean);
Begin
SetAttr (ST, SqMsgHold);
End;
Procedure TMsgBaseSquish.SetKillSent(St: Boolean); {Set kill/sent netmail status}
Begin
SetAttr(St, SqMsgKill);
End;
Procedure TMsgBaseSquish.SetSent(St: Boolean); {Set sent netmail status}
Begin
SetAttr(St, SqMsgSent);
End;
Procedure TMsgBaseSquish.SetFAttach(St: Boolean); {Set file attach status}
Begin
SetAttr(St, SqMsgFile);
End;
Procedure TMsgBaseSquish.SetReqRct(St: Boolean); {Set request receipt status}
Begin
SetAttr(St, SqMsgRrq);
End;
Procedure TMsgBaseSquish.SetReqAud(St: Boolean); {Set request audit status}
Begin
SetAttr(St, SqMsgarq);
End;
Procedure TMsgBaseSquish.SetRetRct(St: Boolean); {Set return receipt status}
Begin
SetAttr(St, SqMsgCpt);
End;
Procedure TMsgBaseSquish.SetFileReq(St: Boolean); {Set file request status}
Begin
SetAttr(St, SqMsgFreq);
End;
Procedure TMsgBaseSquish.MsgStartUp;
Begin
SqInfo^.CurrentFramePos := GetIdxFramePos;
SqInfo^.CurrentUID := SqIdx^[SqInfo^.CurrIdx].UMsgId;
ReadFrame (SqInfo^.CurrentFramePos);
ReadMsgHdr (SqInfo^.CurrentFramePos);
End;
Procedure TMsgBaseSquish.MsgTxtStartUp;
Begin
ReadText(SqInfo^.CurrentFramePos);
End;
Procedure TMsgBaseSquish.SetMailType(MT: MsgMailType);
Begin
End;
Procedure TMsgBaseSquish.ReWriteHdr;
Var
AlreadyLocked : Boolean;
I : LongInt;
Begin
AlreadyLocked := SqInfo^.Locked;
If Not AlreadyLocked Then
If LockMsgBase Then;
WriteFrame (SqInfo^.CurrentFramePos);
WriteMsgHdr (SqInfo^.CurrentFramePos);
i := 1;
While ((i <= SqInfo^.SqBase.NumMsg) and (SqInfo^.CurrentFramePos <> SqIdx^[i].Ofs)) Do
Inc(i);
If SqIdx^[i].Ofs = SqInfo^.CurrentFramePos Then Begin
If IsRcvd Then
SqIdx^[i].Hash := 0
Else
SqIdx^[i].Hash := SqHashName(SqInfo^.MsgHdr.MsgTo);
End;
If Not AlreadyLocked Then
If UnLockMsgBase Then;
End;
Procedure TMsgBaseSquish.DeleteMsg;
Begin
KillMsg(SqInfo^.CurrentUID);
End;
Function TMsgBaseSquish.NumberOfMsgs: LongInt;
Var
TmpBase: SqBaseType;
Begin
If LoadFilePos(SqInfo^.FN + '.sqd', TmpBase, SizeOf(TmpBase), 0) = 0 Then
NumberOfMsgs := TmpBase.NumMsg
Else
NumberOfMsgs := 0;
End;
Function TMsgBaseSquish.GetLastRead (UNum: LongInt) : LongInt;
Begin
If LoadFilePos(SqInfo^.FN + '.sql', Result, 4, UNum * 4) <> 0 Then
Result := 0;
End;
Procedure TMsgBaseSquish.SetLastRead (UNum: LongInt; LR: LongInt);
Begin
If ((UNum + 1) * SizeOf(LR)) > FileByteSize(SqInfo^.FN + '.sql') Then
ExtendFile (SqInfo^.FN + '.sql', (UNum + 1) * SizeOf(LR));
SaveFilePos (SqInfo^.FN + '.sql', LR, SizeOf(LR), UNum * SizeOf(LR));
End;
Function TMsgBaseSquish.GetMsgLoc: LongInt;
Begin
GetMsgLoc := GetMsgNum;
End;
Procedure TMsgBaseSquish.SetMsgLoc(ML: LongInt);
Begin
SeekFirst(ML);
End;
(*
Procedure TMsgBaseSquish.YoursFirst (Name: String; Handle: String);
Begin
SqInfo^.CurrIdx := 0;
ReadIdx;
SqInfo^.SName := strUpper(Name);
SqInfo^.SHandle := strUpper(Handle);
SqInfo^.HName := SqHashName(Name);
SqInfo^.HHandle := SqHashName(Handle);
YoursNext;
End;
Procedure TMsgBaseSquish.YoursNext;
Var
WasFound: Boolean;
Begin
WasFound := False;
Inc (SqInfo^.CurrIdx);
While ((SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg) and (Not WasFound)) Do Begin
While ((SqIdx^[SqInfo^.CurrIdx].Hash <> SqInfo^.HName) And (SqIdx^[SqInfo^.CurrIdx].Hash <> SqInfo^.HHandle) And (SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg)) Do
Inc(SqInfo^.CurrIdx);
If SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg Then Begin
MsgStartUp;
If ((Not IsRcvd) and ((strUpper(GetTo) = SqInfo^.SName) or (strUpper(GetTo) = SqInfo^.SHandle))) Then
WasFound := True
Else
Inc (SqInfo^.CurrIdx);
End;
End;
End;
Function TMsgBaseSquish.YoursFound: Boolean;
Begin
YoursFound := SqInfo^.CurrIdx <= SqInfo^.SqBase.NumMsg;
End;
*)
Function TMsgBaseSquish.GetMsgDisplayNum: LongInt;
Begin
GetMsgDisplayNum := SqInfo^.CurrIdx;
End;
Function TMsgBaseSquish.GetTxtPos: LongInt;
Begin
GetTxtPos := SqInfo^.TxtCtr;
End;
Procedure TMsgBaseSquish.SetTxtPos(TP: LongInt);
Begin
SqInfo^.TxtCtr := TP;
End;
Procedure TMsgBaseSquish.EditMsgInit;
Begin
SqInfo^.TxtCtr := 0;
End;
Procedure TMsgBaseSquish.EditMsgSave;
Begin
(*
DeleteMsg;
Dec(SqInfo^.CurrentUID);
Dec(SqInfo^.SqBase.UId);
WriteMsg;
*)
ReWriteHdr;
End;
End.