home *** CD-ROM | disk | FTP | other *** search
- (*
- ** JAM(mbp) - The Joaquim-Andrew-Mats Message Base Proposal
- **
- ** Turbo Pascal API
- **
- ** Written by Joaquim Homrighausen.
- **
- ** ----------------------------------------------------------------------
- **
- ** jammb.pas (JAMmb)
- **
- ** Prototypes and definitions for the JAM message base API
- **
- ** Copyright 1993 Joaquim Homrighausen, Andrew Milner, Mats Birch, and
- ** Mats Wallin. ALL RIGHTS RESERVED.
- **
- ** 93-06-28 JoHo
- ** Initial coding
- *)
- UNIT JAMMB;
-
- {$IFNDEF VER55}
- {$A-,B-,E-,D+,L+,F-,I-,N-,O+,R-,S-,V-,X+}
- {$ELSE}
- {$A-,B-,E-,D+,L+,F-,I-,N-,O+,R-,S-,V-}
- {$ENDIF}
-
- INTERFACE
-
- USES
- JAM;
-
- {-API status codes}
-
- CONST
- JAMAPIMSG_NOTHING = 0;
- JAMAPIMSG_HDRPRINT = 1; {Header fingerprint missing or invalid}
- JAMAPIMSG_HDRPASSWORD = 2; {Invalid password for header file}
- JAMAPIMSG_MSGPASSWORD = 3; {Invalid password for message}
- JAMAPIMSG_ISOPEN = 4; {Message base is open}
- JAMAPIMSG_ISNOTOPEN = 5; {Message base is not open}
- JAMAPIMSG_ISNOTLOCKED = 6; {Message base is not locked}
- JAMAPIMSG_SEEKERROR = 7; {Unable to seek in file}
- JAMAPIMSG_CANTMKFILE = 8; {Unable to create file}
- JAMAPIMSG_CANTRDFILE = 9; {Unable to read file}
- JAMAPIMSG_CANTWRFILE = 10; {Unable to write file}
- JAMAPIMSG_CANTRMFILE = 11; {Unable to remove file}
- JAMAPIMSG_FIRSTMSG = 12; {Already on first message}
- JAMAPIMSG_NEWMODCOUNTER = 13; {ModCounter have been updated since read}
- JAMAPIMSG_NOMORETEXT = 14; {Read to end of message text}
- JAMAPIMSG_CANTLKFILE = 15; {Unable to lock message base}
- JAMAPIMSG_CANTFINDUSER = 16; {Unable to locate LastRead record}
- JAMAPIMSG_CANTFINDMSG = 17; {Unable to locate message to user}
- JAMAPIMSG_NOMOREMSGS = 18; {At end or beginning of file}
- JAMAPIMSG_BADHEADERSIG = 19; {Invalid message header signature}
- JAMAPIMSG_BADHEADERREV = 20; {Invalid message header revision}
- JAMAPIMSG_INVMSGNUM = 21; {Invalid message number specified}
-
- {-Values for FROMWHERE parameter to SeekFunc, indentical to those normally
- defined in most C compiler's IO.H as SEEK_SET, SEEK_CUR, and SEEK_END}
-
- JAMSEEK_SET = 0; {To specified position}
- JAMSEEK_CUR = 1; {From current position}
- JAMSEEK_END = 2; {From end of file}
-
- {-Return values for user comparison functions}
-
- ScanMsgHdrStop = 0;
- ScanMsgHdrDiscard = 1;
- ScanMsgHdrNextHdr = 2;
-
- ScanMsgIdxStop = 0;
- ScanMsgIdxNextMsg = 1;
-
- {-Basic object definition and user comparison definitions}
-
- TYPE
- JAMAPIPTR = ^JAMAPI;
-
- ScanMsgHdrFunc= FUNCTION(TheAPI:JAMAPIPTR):INTEGER;
- ScanMsgIdxFunc= FUNCTION(TheAPI:JAMAPIPTR):INTEGER;
-
- JAMAPI = OBJECT
- BaseName : FILENAMETYPE; {Path for message base}
- WorkBuf : JAMBUFPTR; {Workspace, initialized by user}
- WorkLen : LONGINT; {Length of workspace (above)}
- WorkPos : LONGINT; {Current position, for multi-reads}
- IsOpen : BOOLEAN; {Message base is open}
- HaveLock : BOOLEAN; {.JHR file is locked}
- Errno : INTEGER; {Last DOS error in case of error}
- APImsg : INTEGER; {API status message}
- HdrHandle : INTEGER; {File handle for .JHR file}
- TxtHandle : INTEGER; {File handle for .JDT file}
- IdxHandle : INTEGER; {File handle for .JDX file}
- LrdHandle : INTEGER; {File handle for .JLR file}
- LastMsgNum : LONGINT; {Last message number fetched}
- Idx : JAMIDXREC; {Message index record}
- Hdr : JAMHDR; {Message header record}
- HdrInfo : JAMHDRINFO; {Message header info record}
- SubFieldPtr : JAMSUBFIELDPTR; {Subfield record}
- LastLRDnum : LONGINT; {Last LastRead record read (0-based)}
- LastRead : JAMLREAD; {LastRead record}
-
- constructor Init;
- destructor Done; VIRTUAL;
-
- {-DOS file access functions, defined as VIRTUAL to be overriden by an
- object that inherits this object if you feel that these are not
- sufficient.}
-
- function CreateFile(FileName:FILENAMETYPE):INTEGER; virtual;
- function OpenFile(FileName:FILENAMETYPE):INTEGER; virtual;
- function CloseFile(Handle:INTEGER):INTEGER; virtual;
- function UnlinkFile(FileName:FILENAMETYPE):INTEGER; virtual;
- function LockFile(DoLock:BOOLEAN):INTEGER; virtual;
- function SeekFile(Handle:INTEGER; FromWhere:BYTE; FilePos:LONGINT):LONGINT; virtual;
- function ReadFile(Handle:INTEGER; VAR Buffer; DatLen:WORD):WORD; virtual;
- function WriteFile(Handle:INTEGER; VAR Buffer; DatLen:WORD):WORD; virtual;
-
- {-Function to convert uppercase to lowercase}
-
- procedure LowCaseBuf(var Buf; DatLen:WORD);
-
- {-JAM message base access functions}
-
- function OpenMB:BOOLEAN;
- function CreateMB:BOOLEAN;
- function CloseMB:BOOLEAN;
- function UnlinkMB:BOOLEAN;
- function ReIndexMB:BOOLEAN;
-
- function UpdHdrInfo(WriteIt:BOOLEAN):BOOLEAN;
- function LockMB(FetchHdrInfo:BOOLEAN):BOOLEAN;
- function UnlockMB(UpdateHdrInfo:BOOLEAN):BOOLEAN;
-
- function FindField(WhatField:LONGINT; var Position:LONGINT; MaxToScan:LONGINT):BOOLEAN;
- function AddField(WhatField:LONGINT; First:Boolean; DatLen:WORD; var Position:LONGINT; var Data):BOOLEAN;
-
- function FetchMsgIdx(WhatMsg:LONGINT):BOOLEAN;
- function FetchMsgHdr(WhatMsg:LONGINT; WithSubFields:BOOLEAN):BOOLEAN;
- function FetchNextMsgHdr(WithSubFields:BOOLEAN):BOOLEAN;
- function FetchPrevMsgHdr(WithSubFields:BOOLEAN):BOOLEAN;
- function FetchMsgTxt(FirstFetch:BOOLEAN):BOOLEAN;
-
- function ScanForMsgIdx(StartNum:LONGINT; ScanFwd:BOOLEAN; UserCompare:ScanMsgIdxFunc):BOOLEAN;
- function ScanForMsgHdr(StartNum:LONGINT; ScanFwd:BOOLEAN; UserCompare:ScanMsgHdrFunc):BOOLEAN;
-
- function StoreMsgHdr(WhatMsg:LONGINT):BOOLEAN;
- function StoreMsgIdx(WhatMsg:LONGINT):BOOLEAN;
- function StoreMsgTxt:BOOLEAN;
- function StoreMsgTxtBuf(var Buffer; BufLen:WORD; IsFirst:BOOLEAN):BOOLEAN;
-
- function FetchLastRead(UserID:LONGINT):BOOLEAN;
- function StoreLastRead(UpdateHdrInfo:BOOLEAN):BOOLEAN;
- END;{JAMAPI}
-
- IMPLEMENTATION
-
- USES
- Dos,
- JAMCRC32;
-
- {-Initializes object and its data members.}
- constructor JAMAPI.Init;
- BEGIN
- BaseName:='';
- WorkBuf:=NIL;
- WorkLen:=0;
- WorkPos:=0;
- IsOpen:=FALSE;
- HaveLock:=FALSE;
- Errno:=0;
- APImsg:=JAMAPIMSG_NOTHING;
- HdrHandle:=-1;
- TxtHandle:=-1;
- IdxHandle:=-1;
- LrdHandle:=-1;
- LastMsgNum:=0;
- LastLRDnum:=0;
- END;
-
- {-Deinitializes object and closes message base if it's open}
- destructor JAMAPI.Done;
- BEGIN
- {$IFDEF VER55}
- if (not CloseMB) then
- ;
- {$ELSE}
- CloseMB;
- {$ENDIF}
- END;
-
- {-DOS file access functions, defined as VIRTUAL to be overriden by an
- object that inherits this object if you feel that these are not
- sufficient. -------------------------------------------------------------}
-
- {-Create file, return handle or -1 on error}
- function JAMAPI.CreateFile(FileName:FILENAMETYPE):INTEGER;
- VAR
- az : ASCIIZ;
- r : registers;
- BEGIN
- {NUL terminate filename for DOS}
- move(FileName[1], az[1], length(FileName));
- az[Succ(length(FileName))]:=#0;
-
- r.AH:=$3c; {INT 21: Create file}
- r.CX:=0; {No special file attribute}
- r.DS:=seg(az); {Filename}
- r.DX:=ofs(az);
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- CreateFile:=-1; {Return error}
- END
- ELSE
- CreateFile:=r.AX; {No error, return handle}
- END;
-
- {-Open file, return handle or -1 on error, mode is ReadWrite/DenyNone/
- NoInherit}
- function JAMAPI.OpenFile(FileName:FILENAMETYPE):INTEGER;
- VAR
- az : ASCIIZ;
- r : registers;
- BEGIN
- {NUL terminate filename for DOS}
- move(FileName[1], az[1], length(FileName));
- az[Succ(length(FileName))]:=#0;
-
- r.AH:=$3d; {INT 21: Open file}
- r.AL:=194; {11000010: ReadWrite/DenyNone/NoInherit}
- r.DS:=seg(az); {Filename}
- r.DX:=ofs(az);
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- OpenFile:=-1; {Return error}
- END
- ELSE
- OpenFile:=r.AX; {No error, return handle}
- END;
-
- {-Close file pointed to by handle, return 0 or -1 on error}
- function JAMAPI.CloseFile(Handle:INTEGER):INTEGER;
- VAR
- r : registers;
- BEGIN
- r.AH:=$3e; {INT 21: Close file}
- r.BX:=Handle; {File handle}
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- CloseFile:=-1; {Return error}
- END
- ELSE
- CloseFile:=0; {No error}
- END;
-
- {-Unlink (delete) file, return handle or -1 on error}
- function JAMAPI.UnlinkFile(FileName:FILENAMETYPE):INTEGER;
- VAR
- az : ASCIIZ;
- r : registers;
- BEGIN
- {NUL terminate filename for DOS}
- move(FileName[1], az[1], length(FileName));
- az[Succ(length(FileName))]:=#0;
-
- r.AH:=$41; {INT 21: Unlink (delete) file}
- r.DS:=seg(az); {Filename}
- r.DX:=ofs(az);
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- UnlinkFile:=-1; {Return error}
- END
- ELSE
- UnlinkFile:=0; {No error}
- END;
-
- {-Lock or unlock header file, return 0 or -1 on error}
- function JAMAPI.LockFile(DoLock:BOOLEAN):INTEGER;
- VAR
- r : registers;
- BEGIN
- r.AH:=$5c; {INT 21: Lock/Unlock file region}
- if (DoLock) then
- r.AL:=0 {Lock file, AL=0}
- ELSE
- r.AL:=1; {Unlock file, AL=1}
- r.BX:=HdrHandle; {File handle (header file)}
- r.CX:=0; {Offset of region, high-order word}
- r.DX:=0; {Offset of region, low-order word}
- r.SI:=0; {Length of region, high-order word}
- r.DI:=1; {Length of region, low-order word}
-
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- LockFile:=-1; {Return error}
- END
- ELSE
- BEGIN
- LockFile:=0; {No error}
- HaveLock:=DoLock; {Make sure we know status}
- END;
- END;
-
- {-Seek to specified position (relative to FROMWHERE) in file, returns new
- position or -1 on error}
- function JAMAPI.SeekFile(Handle:INTEGER; FromWhere:BYTE; FilePos:LONGINT):LONGINT;
- VAR
- r : registers;
- BEGIN
- r.AH:=$42; {INT 21: Move file pointer (LSEEK)}
- r.AL:=FromWhere; {From where to seek}
- r.BX:=Handle; {File handle}
- r.CX:=WORD(FilePos shr 16); {Offset to seek to}
- r.DX:=WORD(FilePos); {Offset to seek to}
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- SeekFile:=$FFFFFFFF; {Return error}
- END
- ELSE
- SeekFile:=(LONGINT(r.DX) shl 16) or LONGINT(r.AX); {Return new position}
- END;
-
- {-Read data from file pointed to by Handle into Buffer. The maximum amount
- of data to read is contained in DatLen. The function returns the number
- of bytes read or $ffff on error.}
- function JAMAPI.ReadFile(Handle:INTEGER; VAR Buffer; DatLen:WORD):WORD;
- VAR
- r : registers;
- BEGIN
- r.AH:=$3f; {INT 21: Read from file or device}
- r.BX:=Handle; {File handle}
- r.DS:=seg(Buffer); {Buffer}
- r.DX:=ofs(Buffer);
- r.CX:=DatLen; {Amount to read (bytes)}
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- ReadFile:=$ffff; {Return error}
- END
- ELSE
- ReadFile:=r.AX; {Return amount read}
- END;
-
- {-Write data from Buffer to file pointed to by Handle. The maximum amount
- of data to write is contained in DatLen. The function returns the number
- of bytes written or $ffff on error.}
- function JAMAPI.WriteFile(Handle:INTEGER; VAR Buffer; DatLen:WORD):WORD;
- VAR
- r : registers;
- BEGIN
- r.AH:=$40; {INT 21: Write to file or device}
- r.BX:=Handle; {File handle}
- r.DS:=seg(Buffer); {Buffer}
- r.DX:=ofs(Buffer);
- r.CX:=DatLen; {Amount to write (bytes)}
- msdos(r); {Call DOS}
- if (r.Flags and FCarry<>0) then {Check carry flag (=error)}
- BEGIN
- Errno:=r.AX; {Save DOS error}
- WriteFile:=$ffff; {Return error}
- END
- ELSE
- WriteFile:=r.AX; {Return amount written}
- END;
-
- {-Function to convert uppercase to lowercase}
-
- procedure JAMAPI.LowCaseBuf(var Buf; DatLen:WORD);
- VAR
- JunkArray : ARRAY[1..MAXINT] of CHAR ABSOLUTE Buf;
- W : WORD;
- BEGIN
- for w:=1 to DatLen do
- if (JunkArray[w]>='A') and (JunkArray[w]<='Z') then
- inc(JunkArray[w], 32);
- END;
-
- {-JAM message base access functions. --------------------------------------}
-
- {-Opens message base. Returns TRUE on success or FALSE on error}
- function JAMAPI.OpenMB:BOOLEAN;
- VAR
- FileName : FILENAMETYPE;
- {$IFDEF VER55}
- JunkRet : INTEGER;
- {$ENDIF}
- BEGIN
- OpenMB:=FALSE;
-
- {Make sure it's not already open}
- if (IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISOPEN;
- OpenMB:=TRUE;
- exit;
- END
- ELSE
- APImsg:=JAMAPIMSG_NOTHING;
-
-
- {.JHR file}
- FileName:=BaseName+EXT_HDRFILE;
- HdrHandle:=OpenFile(FileName);
- if (HdrHandle<0) then
- exit;
-
- {Read fixed size block from header file}
- if (ReadFile(HdrHandle, HdrInfo, sizeof(JAMHDRINFO))<>sizeof(JAMHDRINFO)) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- {$ENDIF}
- exit;
- END;
- if (HdrInfo.BaseMsgNum=0) then
- inc(HdrInfo.BaseMsgNum);
-
- {.JDT file}
- FileName:=BaseName+EXT_TXTFILE;
- TxtHandle:=OpenFile(FileName);
- if (TxtHandle<0) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- {$ENDIF}
- exit;
- END;
-
- {.JDX file}
- FileName:=BaseName+EXT_IDXFILE;
- IdxHandle:=OpenFile(FileName);
- if (IdxHandle<0) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- JunkRet:=CloseFile(TxtHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- CloseFile(TxtHandle);
- {$ENDIF}
- exit;
- END;
-
- {.JLR file}
- FileName:=BaseName+EXT_LRDFILE;
- LrdHandle:=OpenFile(FileName);
- if (LrdHandle<0) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- JunkRet:=CloseFile(TxtHandle);
- JunkRet:=CloseFile(IdxHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- CloseFile(TxtHandle);
- CloseFile(IdxHandle);
- {$ENDIF}
- exit;
- END;
-
- {Everything went OK, return with success}
- IsOpen:=TRUE;
- OpenMB:=TRUE;
- END;
-
- {-Creates new message base. Returns TRUE on success or FALSE on error}
- function JAMAPI.CreateMB:BOOLEAN;
- VAR
- FileName : FILENAMETYPE;
- {$IFDEF VER55}
- JunkRet : INTEGER;
- {$ENDIF}
- BEGIN
- CreateMB:=FALSE;
-
- {Make sure it's not already open}
- if (IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISOPEN;
- CreateMB:=TRUE;
- exit;
- END
- ELSE
- APImsg:=JAMAPIMSG_NOTHING;
-
-
- {.JHR file}
- FileName:=BaseName+EXT_HDRFILE;
- HdrHandle:=CreateFile(FileName);
- if (HdrHandle<0) then
- exit;
-
- {Write fixed size block to header file}
- fillchar(HdrInfo, sizeof(JAMHDRINFO), 0);
- HdrInfo.PasswordCRC:=$FFFFFFFF;
- move(HEADERSIG, HdrInfo.Signature, sizeof(HdrInfo.Signature));
- HdrInfo.BaseMsgNum:=1;
-
- {-NOTE: The "DateCreated" field is still not filled in properly in the
- TP API}
-
- if (WriteFile(HdrHandle, HdrInfo, sizeof(JAMHDRINFO))<>sizeof(JAMHDRINFO)) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- JunkRet:=UnlinkFile(FileName);
- {$ELSE}
- CloseFile(HdrHandle);
- UnlinkFile(FileName);
- {$ENDIF}
- exit;
- END;
-
- {.JDT file}
- FileName:=BaseName+EXT_TXTFILE;
- TxtHandle:=CreateFile(FileName);
- if (TxtHandle<0) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- {$ENDIF}
- exit;
- END;
-
- {.JDX file}
- FileName:=BaseName+EXT_IDXFILE;
- IdxHandle:=CreateFile(FileName);
- if (IdxHandle<0) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- JunkRet:=CloseFile(TxtHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- CloseFile(TxtHandle);
- {$ENDIF}
- exit;
- END;
-
- {.JLR file}
- FileName:=BaseName+EXT_LRDFILE;
- LrdHandle:=CreateFile(FileName);
- if (LrdHandle<0) then
- BEGIN
- {$IFDEF VER55}
- JunkRet:=CloseFile(HdrHandle);
- JunkRet:=CloseFile(TxtHandle);
- JunkRet:=CloseFile(IdxHandle);
- {$ELSE}
- CloseFile(HdrHandle);
- CloseFile(TxtHandle);
- CloseFile(IdxHandle);
- {$ENDIF}
- exit;
- END;
-
- {Everything went OK, return with success}
- IsOpen:=TRUE;
- CreateMB:=TRUE;
- END;
-
- {-Close open message base. Returns TRUE on success or FALSE on error}
- function JAMAPI.CloseMB:BOOLEAN;
- {$IFDEF VER55}
- VAR
- JunkRet : INTEGER;
- {$ENDIF}
- BEGIN
- {Make sure it's not already open}
- if (IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_NOTHING;
- if (HaveLock) then
- {$IFDEF VER55}
- JunkRet:=LockFile(FALSE);
- JunkRet:=CloseFile(HdrHandle);
- JunkRet:=CloseFile(TxtHandle);
- JunkRet:=CloseFile(IdxHandle);
- JunkRet:=CloseFile(LrdHandle);
- {$ELSE}
- LockFile(FALSE);
- CloseFile(HdrHandle);
- CloseFile(TxtHandle);
- CloseFile(IdxHandle);
- CloseFile(LrdHandle);
- {$ENDIF}
- IsOpen:=FALSE;
- END
- ELSE
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- CloseMB:=TRUE;
- END;
-
- {-Deletes existing (closed) message base. Returns TRUE on success or FALSE
- on error}
- function JAMAPI.UnlinkMB:BOOLEAN;
- VAR
- FileName : FILENAMETYPE;
- j1, j2, j3, j4 : INTEGER;
- BEGIN
- {Make sure it's not already open}
- if (IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISOPEN;
- UnlinkMB:=FALSE;
- exit;
- END
- ELSE
- APImsg:=JAMAPIMSG_NOTHING;
-
- {.JDH file}
- FileName:=BaseName+EXT_HDRFILE;
- j1:=UnlinkFile(FileName);
-
- {.JDT file}
- FileName:=BaseName+EXT_TXTFILE;
- j2:=UnlinkFile(FileName);
-
- {.JDX file}
- FileName:=BaseName+EXT_IDXFILE;
- j3:=UnlinkFile(FileName);
-
- {.JLR file}
- FileName:=BaseName+EXT_LRDFILE;
- j4:=UnlinkFile(FileName);
-
- UnlinkMB:=BOOLEAN((j1=0) and (j2=0) and (j3=0) and (j4=0));
- END;
-
- {-Reindex an open message base. The message base must be locked by the
- application prior to calling this function. Returns TRUE on success or
- FALSE on error.}
- function JAMAPI.ReIndexMB:BOOLEAN;
- VAR
- FileName : FILENAMETYPE;
- TempIdxRec, IdxRec : JAMIDXREC;
- JunkBuf : ARRAY[1..110] of BYTE;
- SubPtr : JAMSUBFIELDPTR;
- NextOffset, CurIdxOffset, NextIdxOffset, IdxSize, JunkLong : LONGINT;
- Finished, Error, FoundField : BOOLEAN;
- SubDatLen, Junk : WORD;
- BEGIN
- ReIndexMB:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure we have lock}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Close index file}
- if (IdxHandle>=0) then
- BEGIN
- {$IFDEF VER55}
- IdxHandle:=CloseFile(IdxHandle);
- {$ELSE}
- CloseFile(IdxHandle);
- {$ENDIF}
- IdxHandle:=-1;
- END;
-
- {Create new index file}
- FileName:=BaseName+EXT_IDXFILE;
- IdxHandle:=CreateFile(FileName);
- if (IdxHandle<0) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTMKFILE;
- exit;
- END;
-
- {Process header file}
- NextOffset:=LONGINT(sizeof(JAMHDRINFO));
- CurIdxOffset:=0;
- IdxSize:=0;
- Finished:=FALSE;
- Error:=FALSE;
- SubPtr:=@JunkBuf;
-
- WHILE ((not Finished) and (not Error)) DO
- BEGIN
- {Seek to correct position in header file}
- if (SeekFile(HdrHandle, JAMSEEK_SET, NextOffset)<>NextOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END
- ELSE
- BEGIN
- {Read header}
- Junk:=ReadFile(HdrHandle, Hdr, sizeof(JAMHDR));
- if (Junk<>sizeof(JAMHDR)) then
- BEGIN
- if (Junk=0) then
- {Nothing left to read}
- Finished:=TRUE
- ELSE
- {Read error}
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- Error:=TRUE;
- END;
- END
- ELSE
- BEGIN
- {Set values}
- IdxRec.HdrOffset:=NextOffset;
-
- {-Search subfields if we have any and this header hasn't been
- deleted}
- if ((Hdr.SubfieldLen>0) and (Hdr.Attribute and MSG_DELETED=0)) then
- BEGIN
- FoundField:=FALSE;
- JunkLong:=0;
-
- REPEAT
- Junk:=ReadFile(HdrHandle, JunkBuf, 4);
- if (Junk<>4) then
- BEGIN
- if (Junk=0) then
- Finished:=TRUE
- ELSE
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- Error:=TRUE;
- END;
- END
- ELSE
- BEGIN
- inc(JunkLong, 4);
- SubDatLen:=WORD(SubPtr^.DatLen);
-
- {Is this what we're looking for?}
- if (SubPtr^.LoID=JAMSFLD_RECVRNAME) then
- BEGIN
- {Yes, read username}
- Junk:=ReadFile(HdrHandle, JunkBuf, SubDatLen);
- if (Junk=SubDatLen) then
- FoundField:=TRUE
- ELSE
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- Error:=TRUE;
- END;
- END
- ELSE
- {No, skip to next header}
- BEGIN
- inc(JunkLong, SubPtr^.DatLen);
- if (SeekFile(HdrHandle, JAMSEEK_CUR, SubPtr^.DatLen)<0) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- Error:=TRUE;
- END;
- END;
- END;
- UNTIL (FoundField) or (JunkLong>=Hdr.SubfieldLen) or (Error) or (Finished);
-
- if (FoundField) then
- BEGIN
- LowCaseBuf(JunkBuf, SubDatLen);
- IdxRec.UserCRC:=crc32(JunkBuf, SubDatLen, $FFFFFFFF);
- END
- ELSE
- IdxRec.UserCRC:=$FFFFFFFF;
- END
- ELSE
- {No subfields}
- IdxRec.UserCRC:=$FFFFFFFF;
-
- {Skip message if invalid message number}
- if (Hdr.MsgNum>=HdrInfo.BaseMsgNum) then
- BEGIN
- if (not Error) then
- BEGIN
- NextIdxOffset:=(Hdr.MsgNum-HdrInfo.BaseMsgNum)*LONGINT(sizeof(JAMIDXREC));
- if (CurIdxOffset<>NextIdxOffset) then
- BEGIN
- if (NextIdxOffset>IdxSize) then
- BEGIN
- if (SeekFile(IdxHandle, JAMSEEK_SET, IdxSize)<>IdxSize) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- Error:=TRUE;
- END;
-
- {Extend index and fill with empty index records}
- TempIdxRec.UserCRC:=$ffffffff;
- TempIdxRec.HdrOffset:=$ffffffff;
- WHILE (not Error) and (IdxSize<>NextIdxOffset) DO
- BEGIN
- if (WriteFile(IdxHandle, TempIdxRec, sizeof(JAMIDXREC))<>sizeof(JAMIDXREC)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTWRFILE;
- Error:=TRUE;
- END
- ELSE
- inc(IdxSize, LONGINT(sizeof(JAMIDXREC)));
- END;
- END
- ELSE
- if (SeekFile(IdxHandle, JAMSEEK_SET, NextIdxOffset)<>NextIdxOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- Error:=TRUE;
- END;
- END
- END;
-
- if (not Error) then
- BEGIN
- {Write index record}
- if (WriteFile(IdxHandle, IdxRec, sizeof(JAMIDXREC))<>sizeof(JAMIDXREC)) then
- BEGIN
- {Write error}
- APImsg:=JAMAPIMSG_CANTWRFILE;
- Error:=TRUE;
- END
- ELSE
- BEGIN
- CurIdxOffset:=NextIdxOffset+LONGINT(sizeof(JAMIDXREC));
- if (CurIdxOffset>IdxSize) then
- IdxSize:=CurIdxOffset;
- inc(NextOffset, LONGINT(sizeof(JAMHDR))+LONGINT(Hdr.SubfieldLen));
- END;
- END;
- END;
- END;{ReadOK}
- END;{SeekOK}
- END;{while}
- ReIndexMB:=(not Error);
- END;
-
- {-Fetch or update message header info block. Returns TRUE on success and
- FALSE on failure.}
- function JAMAPI.UpdHdrInfo(WriteIt:BOOLEAN):BOOLEAN;
- BEGIN
- UpdHdrInfo:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure we have lock if we need it}
- if (WriteIt) and (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Seek to beginning of file}
- if (SeekFile(HdrHandle, JAMSEEK_SET, 0)<>0) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
-
- if (WriteIt) then
- BEGIN
- {Update}
- inc(HdrInfo.ModCounter);
-
- if (HdrInfo.BaseMsgNum=0) then
- inc(HdrInfo.BaseMsgNum);
-
- if (WriteFile(HdrHandle, HdrInfo, sizeof(JAMHDRINFO))<>sizeof(JAMHDRINFO)) then
- BEGIN
- dec(HdrInfo.ModCounter);
- APImsg:=JAMAPIMSG_CANTWRFILE;
- exit;
- END;
- END
- ELSE
- {Read}
- BEGIN
- if (ReadFile(HdrHandle, HdrInfo, sizeof(JAMHDRINFO))<>sizeof(JAMHDRINFO)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
- if (HdrInfo.BaseMsgNum=0) then
- inc(HdrInfo.BaseMsgNum);
- END;
-
- APImsg:=JAMAPIMSG_NOTHING;
- UpdHdrInfo:=TRUE;
- END;
-
- {-Locks message base and if successful, optionally reads the header info
- block at the beginning of the header file. Returns TRUE on success or
- FALSE on failure.}
- function JAMAPI.LockMB(FetchHdrInfo:BOOLEAN):BOOLEAN;
- BEGIN
- LockMB:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Attempt to lock it if we don't already have a lock}
- if (not HaveLock) and (LockFile(TRUE)<>0) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTLKFILE;
- exit;
- END;
-
- {Read header info block if told to}
- if (FetchHdrInfo) then
- BEGIN
- if (not UpdHdrInfo(FALSE)) then
- exit;
- END;
-
- APImsg:=JAMAPIMSG_NOTHING;
- LockMB:=TRUE;
- END;
-
-
- {-Unlocks message base and if successful, optionally writes the header
- info block to the beginning of the header file. Returns TRUE upon
- success and FALSE upon failure.}
- function JAMAPI.UnlockMB(UpdateHdrInfo:BOOLEAN):BOOLEAN;
- BEGIN
- UnlockMB:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure we have a lock}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Update header info if told to before unlocking}
- if (UpdateHdrInfo) then
- BEGIN
- if (not UpdHdrInfo(TRUE)) then
- exit;
- END;
-
- {Unlock the file}
- {$IFDEF VER55}
- APImsg:=LockFile(FALSE);
- {$ELSE}
- LockFile(FALSE);
- {$ENDIF}
-
- APImsg:=JAMAPIMSG_NOTHING;
- UnlockMB:=TRUE;
- END;
-
- {-Find specified field in WorkBuf. Returns TRUE if the field is found and
- FALSE if the field is not found. The POSITION parameter is updated to
- point to the beginning of the found field.}
- function JAMAPI.FindField(WhatField:LONGINT; var Position:LONGINT; MaxToScan:LONGINT):BOOLEAN;
- BEGIN
- WHILE (Position<MaxToScan) DO
- BEGIN
- SubFieldPtr:=@WorkBuf^[Position];
- if (SubFieldPtr^.LoID=WORD(WhatField)) then
- BEGIN
- FindField:=TRUE;
- exit;
- END;
- inc(Position, SubFieldPtr^.DatLen + sizeof(JAMBINSUBFIELD));
- END;{while}
- FindField:=FALSE;
- END;
-
- {-Add specified field to WorkBuf. It requires that POSITION has been reset
- to one (1) prior to the first call. The POSITION parameter is updated to
- point to the first position after the newly added field. The FIRST
- parameter determines if the DatLen/ID fields should be copied. This
- allows multiple calls to this function to add more than 64kb to a
- subfield. Returns TRUE on success or FALSE if the requested field does
- not fit into WorkBuf}
- function JAMAPI.AddField(WhatField:LONGINT; First:Boolean; DatLen:WORD; var Position:LONGINT; var Data):BOOLEAN;
- VAR
- DummyField : JAMBINSUBFIELDPTR;
- BEGIN
- AddField:=TRUE;
- if (First) then
- BEGIN
- if ((LONGINT(sizeof(JAMBINSUBFIELD))+Pred(Position)+DatLen)>WorkLen) then
- BEGIN
- AddField:=FALSE;
- exit;
- END;
- DummyField:=@WorkBuf^[Position];
- DummyField^.LoID:=WORD(WhatField);
- DummyField^.HiID:=0;
- DummyField^.DatLen:=DatLen;
- inc(Position, sizeof(JAMBINSUBFIELD));
- END
- ELSE
- if ((DatLen+Pred(Position))>WorkLen) then
- BEGIN
- AddField:=FALSE;
- exit;
- END;
- move(Data, WorkBuf^[Position], DatLen);
- inc(Position, LONGINT(DatLen));
- END;
-
- {-Scan message index records starting at the specified number (STARTNUM).
- For each record found, the function calls USERCOMPARE. The Forward
- parameter determines the direction of the scan. The Idx record will
- contain the newly read message index record and. Returns TRUE if user
- function returned ScanMsgIdxStop and FALSE otherwise.}
- function JAMAPI.ScanForMsgIdx(StartNum:LONGINT; ScanFwd:BOOLEAN; UserCompare:ScanMsgIdxFunc):BOOLEAN;
- VAR
- WhatOffset : LONGINT;
- UserResult : INTEGER;
- ReadCount : WORD;
- BEGIN
- ScanForMsgIdx:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure the message number is valid}
- if (StartNum<HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_INVMSGNUM;
- exit;
- END;
-
- {Position of first index record}
- WhatOffset:=LONGINT((StartNum-HdrInfo.BaseMsgNum) * LONGINT(sizeof(JAMIDXREC)));
-
- {Seek to correct position if we're going forward}
- if (ScanFwd) then
- BEGIN
- if (SeekFile(IdxHandle, JAMSEEK_SET, WhatOffset)<>WhatOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- END;
-
- {Scan index records}
- WHILE TRUE DO
- BEGIN
- {Seek to correct position if we're going backwards}
- if (not ScanFwd) then
- BEGIN
- if (SeekFile(IdxHandle, JAMSEEK_SET, WhatOffset)<>WhatOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- END;
-
- ReadCount:=ReadFile(IdxHandle, Idx, sizeof(JAMIDXREC));
- if (ReadCount=sizeof(JAMIDXREC)) then
- BEGIN
- LastMsgNum:=StartNum;
-
- {Call user function and process result}
- UserResult:=UserCompare(@Self);
- if (UserResult=ScanMsgIdxStop) then
- BEGIN
- ScanForMsgIdx:=TRUE;
- exit;
- END
- ELSE
- BEGIN
- if (ScanFwd) then
- inc(StartNum)
- ELSE
- BEGIN
- if (StartNum=HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_NOMOREMSGS;
- exit;
- END
- ELSE
- BEGIN
- dec(StartNum);
- dec(WhatOffset, LONGINT(sizeof(JAMIDXREC)));
- END;
- END;
- END;
- END
- ELSE
- {Check for end of file, otherwise error}
- BEGIN
- if (ReadCount=0) and (ScanFwd) then
- APImsg:=JAMAPIMSG_NOMOREMSGS
- ELSE
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
- END;{while}
- END;
-
- {-Fetch specified message number. If WITHSUBFIELDS=TRUE, the function will
- attempt to read as much of the message's subfield data into the internal
- work buffer as possible. Returns TRUE on success and FALSE on failure.}
- function JAMAPI.FetchMsgHdr(WhatMsg:LONGINT; WithSubFields:BOOLEAN):BOOLEAN;
- VAR
- ReadCount : WORD;
- BEGIN
- FetchMsgHdr:=FALSE;
-
- {Fetch index record, checks for IsOpen}
- if (not FetchMsgIdx(WhatMsg)) then
- exit;
-
- {Fetch header}
- if (SeekFile(HdrHandle, JAMSEEK_SET, Idx.HdrOffset)<>Idx.HdrOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- if (ReadFile(HdrHandle, Hdr, sizeof(JAMHDR))<>sizeof(JAMHDR)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
-
- {Check header}
- if (Hdr.Signature<>HEADERSIG) then
- BEGIN
- APImsg:=JAMAPIMSG_BADHEADERSIG;
- exit;
- END;
- if (Hdr.Revision<>CurrentRevLev) then
- BEGIN
- APImsg:=JAMAPIMSG_BADHEADERREV;
- exit;
- END;
-
- {Fetch subfields if told to}
- if (WithSubFields) then
- BEGIN
- if (Hdr.SubfieldLen>WorkLen) then
- ReadCount:=WORD(WorkLen)
- ELSE
- ReadCount:=WORD(Hdr.SubfieldLen);
- END
- ELSE
- ReadCount:=0;
-
- if (ReadCount<>0) then
- BEGIN
- if (ReadFile(HdrHandle, WorkBuf^, ReadCount)<>ReadCount) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
- END;
-
- {Got it OK}
- APImsg:=JAMAPIMSG_NOTHING;
- FetchMsgHdr:=TRUE;
- END;
-
- {-Fetch index record with specified message number. Returns TRUE on success
- and FALSE on failure.}
- function JAMAPI.FetchMsgIdx(WhatMsg:LONGINT):BOOLEAN;
- VAR
- WhatOffset : LONGINT;
- BEGIN
- FetchMsgIdx:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure the message number is valid}
- if (WhatMsg<HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_INVMSGNUM;
- exit;
- END;
-
- {Fetch index record}
- WhatOffset:=LONGINT((WhatMsg-HdrInfo.BaseMsgNum) * LONGINT(sizeof(JAMIDXREC)));
- if (SeekFile(IdxHandle, JAMSEEK_SET, WhatOffset)<>WhatOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- if (ReadFile(IdxHandle, Idx, sizeof(JAMIDXREC))<>sizeof(JAMIDXREC)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
-
- {Update structure}
- LastMsgNum:=WhatMsg;
- APImsg:=JAMAPIMSG_NOTHING;
- FetchMsgIdx:=TRUE;
- END;
-
- {-Fetch header for message number following LASTMSGNUM. Returns TRUE on
- success and FALSE on failure.}
- function JAMAPI.FetchNextMsgHdr(WithSubFields:BOOLEAN):BOOLEAN;
- BEGIN
- FetchNextMsgHdr:=FetchMsgHdr(Succ(LastMsgNum), WithSubFields);
- END;
-
- {-Fetch header for message number preceding LASTMSGNUM. Returns TRUE on
- success and FALSE on failure.}
- function JAMAPI.FetchPrevMsgHdr(WithSubFields:BOOLEAN):BOOLEAN;
- BEGIN
- if (LastMsgNum>1) then
- FetchPrevMsgHdr:=FetchMsgHdr(Pred(LastMsgNum), WithSubFields)
- ELSE
- BEGIN
- APImsg:=JAMAPIMSG_FIRSTMSG;
- FetchPrevMsgHdr:=FALSE;
- END;
- END;
-
- {-Fetch text for specified message number. FIRSTFETCH determines if the
- function seeks to the actual text position or simply keeps reading.
- Returns TRUE on success and FALSE on failure.}
- function JAMAPI.FetchMsgTxt(FirstFetch:BOOLEAN):BOOLEAN;
- VAR
- RemainToRead : LONGINT;
- ReadCount : WORD;
- BEGIN
- FetchMsgTxt:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Seek to appropriate text position if this is first fetch}
- if (FirstFetch) then
- BEGIN
- if (SeekFile(TxtHandle, JAMSEEK_SET, Hdr.TxtOffset)<>Hdr.TxtOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END
- ELSE
- {Haven't read anything yet}
- WorkPos:=0;
- END;
-
- {Make sure we don't read more than we have}
- if (WorkPos>=Hdr.TxtLen) then
- BEGIN
- APImsg:=JAMAPIMSG_NOMORETEXT;
- FetchMsgTxt:=TRUE;
- exit;
- END;
-
- {Figure out how much to get}
- RemainToRead:=(Hdr.TxtLen-WorkPos);
- if (RemainToRead>WorkLen) then
- BEGIN
- ReadCount:=WORD(WorkLen);
- if (WorkLen>$0000fffe) then
- ReadCount:=$fffe;
- END
- ELSE
- BEGIN
- ReadCount:=WORD(RemainToRead);
- if (RemainToRead>$0000fffe) then
- ReadCount:=$fffe;
- END;
-
- {Get it from disk}
- if (ReadFile(TxtHandle, WorkBuf^, ReadCount)<>ReadCount) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
-
- {Got it OK}
- inc(WorkPos, LONGINT(ReadCount));
- APImsg:=JAMAPIMSG_NOTHING;
- FetchMsgTxt:=TRUE;
- END;
-
- {-Scan message headers starting at the specified number (STARTNUM). For
- each header found, the function calls USERCOMPARE. The Forward parameter
- determines the direction of the scan. The Hdr record will contain the
- newly read message header and if the header had any subfields, WorkBuf
- will contain as much subfield data as will fit. If all of the subfield
- data didn't fit and the USERCOMPARE function returns ScanMsgHdrDiscard,
- the function will read the remaining subfield data and call the user
- function again. Returns TRUE if user function returned ScanMsgHdrStop and
- FALSE otherwise.}
- function JAMAPI.ScanForMsgHdr(StartNum:LONGINT; ScanFwd:BOOLEAN; UserCompare:ScanMsgHdrFunc):BOOLEAN;
- VAR
- UserResult : INTEGER;
- MaxBlockToRead, JunkW : WORD;
- ReadBytes : LONGINT;
- BEGIN
- ScanForMsgHdr:=FALSE;
-
- {Make sure the message number is valid}
- if (StartNum<HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_INVMSGNUM;
- exit;
- END;
-
- {Scan headers}
- WHILE TRUE DO
- BEGIN
- {Seek to correct position for current message}
- if (not FetchMsgIdx(StartNum)) then
- exit;
- if (SeekFile(HdrHandle, JAMSEEK_SET, Idx.HdrOffset)<>Idx.HdrOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
-
- JunkW:=ReadFile(HdrHandle, Hdr, sizeof(JAMHDR));
- if (JunkW=sizeof(JAMHDR)) then
- BEGIN
- LastMsgNum:=StartNum;
-
- {If all subfield data will fit, read it and call user function}
- if (Hdr.SubfieldLen<=WorkLen) then
- BEGIN
- if (Hdr.SubfieldLen>0) then
- BEGIN
- if (ReadFile(HdrHandle, WorkBuf^, WORD(Hdr.SubfieldLen))<>WORD(Hdr.SubFieldLen)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
- END;
-
- {Call user function and process result}
- UserResult:=UserCompare(@Self);
- if (UserResult=ScanMsgHdrStop) then
- BEGIN
- ScanForMsgHdr:=TRUE;
- exit;
- END
- ELSE
- BEGIN
- if (ScanFwd) then
- inc(StartNum)
- ELSE
- BEGIN
- if (StartNum=HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_NOMOREMSGS;
- exit;
- END
- ELSE
- dec(StartNum);
- END;
- END;
- END
- ELSE
- {All subfield data won't fit, do segmented read/call}
- BEGIN
- ReadBytes:=0;
- if (WorkLen>$0000fffe) then
- MaxBlockToRead:=$fffe
- ELSE
- MaxBlockToRead:=WORD(WorkLen);
-
- REPEAT
- if (ReadFile(HdrHandle, WorkBuf^, MaxBlockToRead)<>MaxBlockToRead) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
-
- if (MaxBlockToRead>0) then
- UserResult:=UserCompare(@Self);
-
- inc(ReadBytes, LONGINT(MaxBlockToRead));
- if (Hdr.SubfieldLen-ReadBytes<LONGINT(MaxBlockToRead)) then
- MaxBlockToRead:=WORD(Hdr.SubfieldLen-ReadBytes);
-
- UNTIL (ReadBytes=Hdr.SubfieldLen) or
- (MaxBlockToRead=0) or
- (UserResult<>ScanMsgHdrDiscard);
-
- {We've read all subfield data or got told to do something else}
-
- if (UserResult=ScanMsgHdrStop) then
- BEGIN
- ScanForMsgHdr:=TRUE;
- exit;
- END
- ELSE
- BEGIN
- if (ScanFwd) then
- BEGIN
- {If we didn't read all data, seek to next header}
- if (MaxBlockToRead<>0) then
- BEGIN
- ReadBytes:=(Hdr.SubfieldLen-ReadBytes);
- if (SeekFile(HdrHandle, JAMSEEK_CUR, ReadBytes)<0) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- END;
- inc(StartNum);
- END
- ELSE
- BEGIN
- if (StartNum=HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_NOMOREMSGS;
- exit;
- END
- ELSE
- dec(StartNum);
- END;
- END;
- END;
- END
- ELSE
- {Check for end of file, otherwise error}
- BEGIN
- if (JunkW=0) and (ScanFwd) then
- APImsg:=JAMAPIMSG_NOMOREMSGS
- ELSE
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
- END;{while}
- END;
-
- {-Store message header with specified number. The HdrHandle's file offset
- will point to the end of the fixed-length header record when the function
- returns (if successful) so the application can write any subfields
- directly to the file. Returns TRUE on success and FALSE on failure.}
- function JAMAPI.StoreMsgHdr(WhatMsg:LONGINT):BOOLEAN;
- BEGIN
- StoreMsgHdr:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure it's locked}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Fetch index record}
- if (not FetchMsgIdx(WhatMsg)) then
- exit;
-
- {Update structure, even if below fails}
- Hdr.MsgNum:=WhatMsg;
-
- {Make sure header signature and revision is OK}
- move(HEADERSIG, Hdr.Signature, sizeof(Hdr.Signature));
- Hdr.Revision:=CurrentRevLev;
-
- {Write header}
- if (SeekFile(HdrHandle, JAMSEEK_SET, Idx.HdrOffset)<>Idx.HdrOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- if (WriteFile(HdrHandle, Hdr, sizeof(JAMHDR))<>sizeof(JAMHDR)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTWRFILE;
- exit;
- END;
-
- {Wrote it OK}
- APImsg:=JAMAPIMSG_NOTHING;
- StoreMsgHdr:=TRUE;
- END;
-
- {-Store message index record with specified number. The IdxHandle's file
- offset will point to the end of the fixed-length index record when the
- function returns (if successful). Returns TRUE on success and FALSE on
- failure.}
- function JAMAPI.StoreMsgIdx(WhatMsg:LONGINT):BOOLEAN;
- VAR
- WhatOffset : LONGINT;
- BEGIN
- StoreMsgIdx:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure it's locked}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Make sure the message number is valid}
- if (WhatMsg<HdrInfo.BaseMsgNum) then
- BEGIN
- APImsg:=JAMAPIMSG_INVMSGNUM;
- exit;
- END;
-
- {Write index record}
- WhatOffset:=LONGINT((WhatMsg-HdrInfo.BaseMsgNum) * LONGINT(sizeof(JAMIDXREC)));
- if (SeekFile(IdxHandle, JAMSEEK_SET, WhatOffset)<>WhatOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- if (WriteFile(IdxHandle, Idx, sizeof(JAMIDXREC))<>sizeof(JAMIDXREC)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTWRFILE;
- exit;
- END;
-
- {Wrote it OK}
- APImsg:=JAMAPIMSG_NOTHING;
- StoreMsgIdx:=TRUE;
- END;
-
- {-Store message text at current header's text position. The TxtHandle's
- file offset will point to the end of the written text block when the
- function returns (if successful). This assumes that the entire
- message text is stored in the internal buffer. See STOREMSGTXTBUF()
- for a function that takes an external parameter and length specifier.
- Returns TRUE on success and FALSE on failure.}
- function JAMAPI.StoreMsgTxt:BOOLEAN;
- BEGIN
- StoreMsgTxt:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure it's locked}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Write text}
- if (SeekFile(TxtHandle, JAMSEEK_SET, Hdr.TxtOffset)<>Hdr.TxtOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- if (WriteFile(TxtHandle, WorkBuf^, WORD(Hdr.TxtLen))<>WORD(Hdr.TxtLen)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTWRFILE;
- exit;
- END;
-
- {Wrote it OK}
- APImsg:=JAMAPIMSG_NOTHING;
- StoreMsgTxt:=TRUE;
- END;
-
- {-Store message text at current header's text position. The TxtHandle's
- file offset will point to the end of the written text block when the
- function returns (if successful). This assumes that the entire
- message text is stored in the internal buffer. The ISFIRST parameter
- determines if the function should seek to the position specified in
- the header before writing. This allows multiple calls to write large
- message texts. Returns TRUE on success and FALSE on failure.}
- function JAMAPI.StoreMsgTxtBuf(var Buffer; BufLen:WORD; IsFirst:BOOLEAN):BOOLEAN;
- BEGIN
- StoreMsgTxtBuf:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure it's locked}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Seek if told to}
- if (IsFirst) then
- BEGIN
- if (SeekFile(TxtHandle, JAMSEEK_SET, Hdr.TxtOffset)<>Hdr.TxtOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
- END;
-
- {Write text}
- if (WriteFile(TxtHandle, Buffer, BufLen)<>BufLen) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTWRFILE;
- exit;
- END;
-
- {Wrote it OK}
- APImsg:=JAMAPIMSG_NOTHING;
- StoreMsgTxtBuf:=TRUE;
- END;
-
- {-Fetch LastRead for passed UserID. Returns TRUE on success and FALSE on
- failure.}
- function JAMAPI.FetchLastRead(UserID:LONGINT):BOOLEAN;
- VAR
- ReadCount : WORD;
- LastReadRec : LONGINT;
- BEGIN
- FetchLastRead:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Seek to beginning of file}
- if (SeekFile(LrdHandle, JAMSEEK_SET, 0)<>0) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
-
- {Read file from top to bottom}
- LastReadRec:=0;
- WHILE (TRUE) DO
- BEGIN
- ReadCount:=ReadFile(LrdHandle, LastRead, sizeof(JAMLREAD));
- if (ReadCount<>sizeof(JAMLREAD)) then
- BEGIN
- if (ReadCount=0) then
- {End of file}
- APImsg:=JAMAPIMSG_CANTFINDUSER
- ELSE
- {Read error}
- APImsg:=JAMAPIMSG_CANTRDFILE;
- exit;
- END;
-
- {See if it matches what we want}
- if (LastRead.UserID=UserID) then
- BEGIN
- LastLRDnum:=LastReadRec;
- APImsg:=JAMAPIMSG_NOTHING;
- FetchLastRead:=TRUE;
- exit;
- END;
-
- {Next record number}
- inc(LastReadRec);
- END;{while}
- END;
-
- {-Store LastRead record and if successful, optionall updates the header
- info block (and its ModCounter) at the beginning of the header file.
- Returns TRUE upon success and FALSE upon failure.}
- function JAMAPI.StoreLastRead(UpdateHdrInfo:BOOLEAN):BOOLEAN;
- VAR
- UserOffset : LONGINT;
- BEGIN
- StoreLastRead:=FALSE;
-
- {Make sure it's open}
- if (not IsOpen) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTOPEN;
- exit;
- END;
-
- {Make sure it's locked}
- if (not HaveLock) then
- BEGIN
- APImsg:=JAMAPIMSG_ISNOTLOCKED;
- exit;
- END;
-
- {Seek to the appropriate position}
- UserOffset:=LONGINT(LastLRDnum * LONGINT(sizeof(JAMLREAD)));
- if (SeekFile(LrdHandle, JAMSEEK_SET, UserOffset)<>UserOffset) then
- BEGIN
- APImsg:=JAMAPIMSG_SEEKERROR;
- exit;
- END;
-
- {Write record}
- if (WriteFile(LrdHandle, LastRead, sizeof(JAMLREAD))<>sizeof(JAMLREAD)) then
- BEGIN
- APImsg:=JAMAPIMSG_CANTWRFILE;
- exit;
- END;
-
- {Update header info if told to}
- if (UpdateHdrInfo and not UpdHdrInfo(TRUE)) then
- exit;
-
- APImsg:=JAMAPIMSG_NOTHING;
- StoreLastRead:=TRUE;
- END;
-
- END.
-
- (* end of file "jammb.pas" *)
-