Initial import
This commit is contained in:
parent
fbb909c155
commit
4ab68fe2a8
|
@ -0,0 +1,42 @@
|
|||
Procedure DrawStatusScreen;
|
||||
Const
|
||||
IMAGEDATA_WIDTH=80;
|
||||
IMAGEDATA_DEPTH=25;
|
||||
IMAGEDATA_LENGTH=518;
|
||||
IMAGEDATA : array [1..518] of Char = (
|
||||
#1,#23,' ','M','y','s','t','i','c',' ','I','n','t','e','r','n','e',
|
||||
't',' ','S','e','r','v','e','r',#25,#30, #0,'t','e','l','n','e','t',
|
||||
'/','s','m','t','p','/','p','o','p','3','/','f','t','p','/','n','n',
|
||||
't','p',' ',#24, #8,#16,#26,'O','°',#24,'°', #1,'Ú',' ', #7,'C','o',
|
||||
'n','n','e','c','t','i','o','n','s',' ', #1,#26,'%','Ä','¿', #8,'°',
|
||||
#1,'Ú',' ', #7,'S','t','a','t','i','s','t','i','c','s',' ', #1,#26,
|
||||
#9,'Ä','¿', #8,'°',#24,'°', #1,'³',#25,'2','³', #8,'°', #1,'³',#25,
|
||||
#21,'³', #8,'°',#24,'°', #1,'³',#25,'2','³', #8,'°', #1,'³',#25, #5,
|
||||
#7,'P','o','r','t', #8,':',#25,#10, #1,'³', #8,'°',#24,'°', #1,'³',
|
||||
#25,'2','³', #8,'°', #1,'³',#25, #6, #7,'M','a','x', #8,':',#25,#10,
|
||||
#1,'³', #8,'°',#24,'°', #1,'³',#25,'2','³', #8,'°', #1,'³',#25, #3,
|
||||
#7,'A','c','t','i','v','e', #8,':',#25,#10, #1,'³', #8,'°',#24,'°',
|
||||
#1,'³',#25,'2','³', #8,'°', #1,'³',#25, #2, #7,'B','l','o','c','k',
|
||||
'e','d', #8,':',#25,#10, #1,'³', #8,'°',#24,'°', #1,'³',#25,'2','³',
|
||||
#8,'°', #1,'³',#25, #2, #7,'R','e','f','u','s','e','d', #8,':',#25,
|
||||
#10, #1,'³', #8,'°',#24,'°', #1,'³',#25,'2','³', #8,'°', #1,'³',#25,
|
||||
#4, #7,'T','o','t','a','l', #8,':',#25,#10, #1,'³', #8,'°',#24,'°',
|
||||
#1,'³',#25,'2','³', #8,'°', #1,'³',#25,#21,'³', #8,'°',#24,'°', #1,
|
||||
'À',#26,'2','Ä','Ù', #8,'°', #1,'À',#26,#21,'Ä','Ù', #8,'°',#24,#26,
|
||||
'O','°',#24,'°', #1,'Ú',' ', #7,'S','e','r','v','e','r',' ','S','t',
|
||||
'a','t','u','s',' ', #1,#26,'<','Ä','¿', #8,'°',#24,'°', #1,'³',#25,
|
||||
'K','³', #8,'°',#24,'°', #1,'³',#25,'K','³', #8,'°',#24,'°', #1,'³',
|
||||
#25,'K','³', #8,'°',#24,'°', #1,'³',#25,'K','³', #8,'°',#24,'°', #1,
|
||||
'³',#25,'K','³', #8,'°',#24,'°', #1,'³',#25,'K','³', #8,'°',#24,'°',
|
||||
#1,'³',#25,'K','³', #8,'°',#24,'°', #1,'³',#25,'K','³', #8,'°',#24,
|
||||
'°', #1,'À',#26,'K','Ä','Ù', #8,'°',#24,#26,'O','°',#24,#23,' ', #1,
|
||||
'T','A','B','/','S','w','i','t','c','h',' ','W','i','n','d','o','w',
|
||||
#25, #2,'E','N','T','E','R','/','S','n','o','o','p',#25, #2,'S','P',
|
||||
'A','C','E','/','L','o','c','a','l',#25, #2,'A','L','T','-','K','/',
|
||||
'K','i','l','l',' ','U','s','e','r',#25, #2,'E','S','C','/','S','h',
|
||||
'u','t','d','o','w','n',' ',#24);
|
||||
Begin
|
||||
Console.LoadScreenImage(ImageData, ImageData_Length, ImageData_Width, 1, 1);
|
||||
Console.WriteXY (1, 25, 113, strPadC('SPACE/Local TELNET TAB/Switch ESC/Shutdown', 79, ' '));
|
||||
// Console.WriteXY (25, 1, 113, strPadC(mysVersionText, 30, ' '));
|
||||
End;
|
|
@ -0,0 +1,827 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Client_FTP;
|
||||
|
||||
// does not send file/directory datestamps
|
||||
// does not support uploading (need to make bbs functions generic for this
|
||||
// and for mbbsutil -fupload command)
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
SysUtils,
|
||||
m_Strings,
|
||||
m_FileIO,
|
||||
m_Socket_Class,
|
||||
m_DateTime,
|
||||
MIS_Server,
|
||||
MIS_NodeData,
|
||||
MIS_Common;
|
||||
|
||||
Function CreateFTP (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
|
||||
Type
|
||||
TFTPServer = Class(TServerClient)
|
||||
Server : TServerManager;
|
||||
UserName : String[40];
|
||||
Password : String[20];
|
||||
LoggedIn : Boolean;
|
||||
GotQuit : Boolean;
|
||||
IsPassive : Boolean;
|
||||
InTransfer : Boolean;
|
||||
Cmd : String;
|
||||
Data : String;
|
||||
DataPort : Word;
|
||||
DataIP : String;
|
||||
DataSocket : TSocketClass;
|
||||
User : RecUser;
|
||||
UserPos : LongInt;
|
||||
FBasePos : LongInt;
|
||||
FBase : FBaseRec;
|
||||
SecLevel : RecSecurity;
|
||||
FileMask : String;
|
||||
|
||||
Constructor Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Procedure Execute; Override;
|
||||
Destructor Destroy; Override;
|
||||
|
||||
// Procedure dlog (S:String);
|
||||
|
||||
Procedure ResetSession;
|
||||
Procedure UpdateUserStats (TFBase: FBaseRec; FDir: FDirRec; DirPos: LongInt);
|
||||
Function CheckFileLimits (TempFBase: FBaseRec; FDir: FDirRec) : Byte;
|
||||
Function OpenDataSession : Boolean;
|
||||
Procedure CloseDataSession;
|
||||
Function ValidDirectory (TempBase: FBaseRec) : Boolean;
|
||||
Function FindDirectory (Var TempBase: FBaseRec) : LongInt;
|
||||
|
||||
Procedure cmdUSER;
|
||||
Procedure cmdPASS;
|
||||
Procedure cmdREIN;
|
||||
Procedure cmdPORT;
|
||||
Procedure cmdPASV;
|
||||
Procedure cmdCWD;
|
||||
Procedure cmdCDUP;
|
||||
Procedure cmdNLST;
|
||||
Procedure cmdLIST;
|
||||
Procedure cmdPWD;
|
||||
Procedure cmdRETR;
|
||||
Procedure cmdSTRU;
|
||||
Procedure cmdMODE;
|
||||
Procedure cmdSYST;
|
||||
Procedure cmdTYPE;
|
||||
Procedure cmdEPRT;
|
||||
Procedure cmdEPSV;
|
||||
Procedure cmdSIZE;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Const
|
||||
FTPTimeOut = 120; // Make this configurabe in MCFG?
|
||||
FileBufSize = 8 * 1024;
|
||||
|
||||
re_DataOpen = '125 Data connection already open';
|
||||
re_DataOpening = '150 File status okay; about to open data connection.';
|
||||
re_CommandOK = '200 Command okay.';
|
||||
re_NoCommand = '202 Command not implemented, superfluous at this site.';
|
||||
re_Greeting = '220 Mystic FTP server ready';
|
||||
re_Goodbye = '221 Goodbye';
|
||||
re_DataClosed = '226 Closing data connection.';
|
||||
re_XferOK = '226 Transfer OK';
|
||||
re_PassiveOK = '227 Entering Passive Mode ';
|
||||
re_LoggedIn = '230 User logged in, proceed.';
|
||||
re_DirOkay = '257 Working directory is now ';
|
||||
re_UserOkay = '331 User name okay, need password.';
|
||||
re_NoData = '425 Unable to open data connection';
|
||||
re_BadCommand = '503 Bad sequence of commands.';
|
||||
re_UserUnknown = '530 Not logged in.';
|
||||
re_BadPW = '530 Login or password incorrect';
|
||||
re_BadDir = '550 Directory change failed';
|
||||
re_BadFile = '550 File not found';
|
||||
re_NoAccess = '550 Access denied';
|
||||
re_DLLimit = '550 Download limit would be exceeded';
|
||||
re_DLRatio = '550 Download/upload ratio would be exceeded';
|
||||
|
||||
Function CreateFTP (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
Begin
|
||||
Result := TFTPServer.Create(Owner, CliSock);
|
||||
End;
|
||||
|
||||
Constructor TFTPServer.Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Begin
|
||||
Inherited Create(Owner, CliSock);
|
||||
|
||||
Server := Owner;
|
||||
End;
|
||||
|
||||
(*
|
||||
Procedure TFTPServer.dlog (S:String);
|
||||
Var
|
||||
T : Text;
|
||||
Begin
|
||||
Assign (T, 'd:\code\mystic1\misftp.log');
|
||||
Append (T);
|
||||
If IoResult <> 0 Then Rewrite(T);
|
||||
WriteLn(T, S);
|
||||
Close(T);
|
||||
End;
|
||||
*)
|
||||
|
||||
Procedure TFTPServer.ResetSession;
|
||||
Begin
|
||||
If Assigned(DataSocket) Then DataSocket.Free;
|
||||
|
||||
LoggedIn := False;
|
||||
GotQuit := False;
|
||||
UserName := '';
|
||||
Password := '';
|
||||
UserPos := -1;
|
||||
DataIP := '';
|
||||
DataPort := 20;
|
||||
DataSocket := NIL;
|
||||
IsPassive := False;
|
||||
FBasePos := -1;
|
||||
InTransfer := False;
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.UpdateUserStats (TFBase: FBaseRec; FDir: FDirRec; DirPos: LongInt);
|
||||
Var
|
||||
HistFile: File of HistoryRec;
|
||||
History : HistoryRec;
|
||||
FDirFile: File of FDirRec;
|
||||
UserFile: File of RecUser;
|
||||
Begin
|
||||
Inc (FDir.DLs);
|
||||
|
||||
Assign (UserFile, bbsConfig.DataPath + 'users.dat');
|
||||
ioReset (UserFile, SizeOf(RecUser), fmReadWrite + fmDenyWrite);
|
||||
ioSeek (UserFile, UserPos - 1);
|
||||
ioRead (UserFile, User);
|
||||
|
||||
If DateDos2Str(User.LastOn, 1) <> DateDos2Str(CurDateDos, 1) Then Begin
|
||||
User.CallsToday := 0;
|
||||
User.DLsToday := 0;
|
||||
User.DLkToday := 0;
|
||||
User.TimeLeft := SecLevel.Time
|
||||
End;
|
||||
|
||||
// need to check if it were an upload and do things accordingly
|
||||
|
||||
Inc (User.DLs);
|
||||
Inc (User.DLsToday);
|
||||
Inc (User.DLk, FDir.Size DIV 1024);
|
||||
Inc (User.DLkToday, FDir.Size DIV 1024);
|
||||
|
||||
ioSeek (UserFile, UserPos - 1);
|
||||
ioWrite (UserFile, User);
|
||||
Close (UserFile);
|
||||
|
||||
Assign (FDirFile, bbsConfig.DataPath + TFBase.FileName + '.dir');
|
||||
ioReset (FDirFile, SizeOf(FDirRec), fmReadWrite + fmDenyWrite);
|
||||
ioSeek (FDirFile, DirPos - 1);
|
||||
ioWrite (FDirFile, FDir);
|
||||
Close (FDirFile);
|
||||
|
||||
Assign (HistFile, bbsConfig.DataPath + 'history.dat');
|
||||
ioReset (HistFile, SizeOf(HistoryRec), fmReadWrite + fmDenyWrite);
|
||||
|
||||
If IoResult <> 0 Then ReWrite(HistFile);
|
||||
|
||||
History.Date := CurDateDos;
|
||||
|
||||
While Not Eof(HistFile) Do Begin
|
||||
ioRead (HistFile, History);
|
||||
|
||||
If DateDos2Str(History.Date, 1) = DateDos2Str(CurDateDos, 1) Then Begin
|
||||
ioSeek (HistFile, FilePos(HistFile) - 1);
|
||||
Break;
|
||||
End;
|
||||
End;
|
||||
|
||||
If Eof(HistFile) Then Begin
|
||||
FillChar(History, SizeOf(History), 0);
|
||||
History.Date := CurDateDos;
|
||||
End;
|
||||
|
||||
Inc (History.Downloads, 1);
|
||||
Inc (History.DownloadKB, FDir.Size DIV 1024);
|
||||
|
||||
ioWrite (HistFile, History);
|
||||
Close (HistFile);
|
||||
End;
|
||||
|
||||
Function TFTPServer.CheckFileLimits (TempFBase: FBaseRec; FDir: FDirRec) : Byte;
|
||||
{ 0 = OK to download }
|
||||
{ 1 = Offline or Invalid or Failed or NO ACCESS or no file (prompt 224)}
|
||||
{ 2 = DL per day limit exceeded (prompt 58) }
|
||||
{ 3 = UL/DL file ratio bad (prompt 211) }
|
||||
Begin
|
||||
Result := 1;
|
||||
|
||||
If Not FileExist(TempFBase.Path + FDir.Filename) Then Exit;
|
||||
|
||||
If Not CheckAccess(User, True, TempFBase.DLACS) Then Exit;
|
||||
|
||||
If FDir.Flags And FDirOffline <> 0 Then Exit;
|
||||
|
||||
If (FDir.Flags And FDirInvalid <> 0) And Not CheckAccess(User, True, bbsConfig.AcsDLUnvalid) Then Exit;
|
||||
If (FDir.Flags And FDirFailed <> 0) And Not CheckAccess(User, True, bbsConfig.AcsDLFailed) Then Exit;
|
||||
|
||||
If (FDir.Flags And FDirFree <> 0) or (User.Flags and UserNoRatio <> 0) or (TempFBase.IsFREE) Then Begin
|
||||
Result := 0;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If (User.DLsToday + 1 > SecLevel.MaxDLs) and (SecLevel.MaxDLs > 0) Then Begin
|
||||
Result := 2;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If SecLevel.DLRatio > 0 Then
|
||||
If (User.ULs * SecLevel.DLRatio) <= (User.DLs + 1) Then Begin
|
||||
Result := 3;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If SecLevel.DLKRatio > 0 Then
|
||||
If (User.ULk * SecLevel.DLkRatio) <= (User.DLk + (FDir.Size DIV 1024)) Then Begin
|
||||
Result := 3;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If (User.DLkToday + (FDir.Size DIV 1024) > SecLevel.MaxDLk) and (SecLevel.MaxDLk > 0) Then Begin
|
||||
Result := 2;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Result := 0;
|
||||
End;
|
||||
|
||||
Function TFTPServer.OpenDataSession : Boolean;
|
||||
Var
|
||||
WaitSock : TSocketClass;
|
||||
Begin
|
||||
Result := False;
|
||||
|
||||
If DataSocket <> NIL Then Begin
|
||||
Client.WriteLine(re_DataOpen);
|
||||
Result := True;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Client.WriteLine(re_DataOpening);
|
||||
|
||||
If IsPassive Then Begin
|
||||
WaitSock := TSocketClass.Create;
|
||||
|
||||
WaitSock.WaitInit(DataPort);
|
||||
|
||||
DataSocket := WaitSock.WaitConnection;
|
||||
|
||||
If Not Assigned(DataSocket) Then Begin
|
||||
WaitSock.Free;
|
||||
Client.WriteLine(re_NoData);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
WaitSock.Free;
|
||||
End Else Begin
|
||||
DataSocket := TSocketClass.Create;
|
||||
|
||||
If Not DataSocket.Connect(DataIP, DataPort) Then Begin
|
||||
Client.WriteLine(re_NoData);
|
||||
DataSocket.Free;
|
||||
DataSocket := NIL;
|
||||
Exit;
|
||||
End;
|
||||
End;
|
||||
|
||||
Result := True;
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.CloseDataSession;
|
||||
Begin
|
||||
If DataSocket <> NIL Then Begin
|
||||
Client.WriteLine(re_DataClosed);
|
||||
DataSocket.Free;
|
||||
DataSocket := NIL;
|
||||
End;
|
||||
End;
|
||||
|
||||
Function TFTPServer.ValidDirectory (TempBase: FBaseRec) : Boolean;
|
||||
Begin
|
||||
Result := CheckAccess(User, True, TempBase.FtpACS) and (TempBase.FtpName <> '');
|
||||
End;
|
||||
|
||||
Function TFTPServer.FindDirectory (Var TempBase: FBaseRec) : LongInt;
|
||||
Var
|
||||
FBaseFile : TBufFile;
|
||||
Found : Boolean;
|
||||
Begin
|
||||
Result := FBasePos;
|
||||
TempBase := FBase;
|
||||
FileMask := '*.*';
|
||||
|
||||
If Not LoggedIn Then Exit;
|
||||
If Data = '' Then Exit;
|
||||
|
||||
If (Pos('*', Data) > 0) or (Pos('.', Data) > 0) Then Begin
|
||||
FileMask := JustFile(Data);
|
||||
Data := JustPath(Data);
|
||||
End;
|
||||
|
||||
If Data = '/' Then Begin
|
||||
Result := -1;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If ((Data[1] = '/') or (Data[1] = '\')) Then Delete(Data, 1, 1);
|
||||
If ((Data[Length(Data)] = '/') or (Data[Length(Data)] = '\')) Then Delete(Data, Length(Data), 1);
|
||||
|
||||
If Data = '' Then Exit;
|
||||
|
||||
FBaseFile := TBufFile.Create(FileBufSize);
|
||||
|
||||
If FBaseFile.Open(bbsConfig.DataPath + 'fbases.dat', fmOpen, fmRWDN, SizeOf(FBaseRec)) Then Begin
|
||||
Found := False;
|
||||
|
||||
While Not FBaseFile.EOF Do Begin
|
||||
FBaseFile.Read(TempBase);
|
||||
|
||||
If (strUpper(TempBase.FtpName) = strUpper(Data)) and ValidDirectory(TempBase) Then Begin
|
||||
Result := FBaseFile.FilePos;
|
||||
Found := True;
|
||||
Break;
|
||||
End;
|
||||
End;
|
||||
End;
|
||||
|
||||
FBaseFile.Free;
|
||||
|
||||
If Not Found Then Begin
|
||||
If Pos('-', Data) > 0 Then
|
||||
FileMask := '*.*'
|
||||
Else
|
||||
FileMask := Data;
|
||||
|
||||
TempBase := FBase;
|
||||
Result := FBasePos;
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdUSER;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
If SearchForUser(Data, User, UserPos) Then Begin
|
||||
Client.WriteLine(re_UserOkay);
|
||||
UserName := Data;
|
||||
End Else
|
||||
Client.WriteLine(re_UserUnknown);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdPASS;
|
||||
Begin
|
||||
If (UserName = '') or (UserPos = -1) Then Begin
|
||||
Client.WriteLine(re_BadCommand);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If strUpper(Data) = User.Password Then Begin
|
||||
LoggedIn := True;
|
||||
|
||||
Client.WriteLine(re_LoggedIn);
|
||||
|
||||
GetSecurityLevel(User.Security, SecLevel);
|
||||
|
||||
Server.Server.Status (User.Handle + ' logged in');
|
||||
End Else
|
||||
Client.WriteLine(re_BadPW);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdREIN;
|
||||
Begin
|
||||
ResetSession;
|
||||
Client.WriteLine(re_Greeting);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdPORT;
|
||||
Var
|
||||
Count : Byte;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
For Count := 1 to 3 Do
|
||||
Data[Pos(',', Data)] := '.';
|
||||
|
||||
DataIP := Copy(Data, 1, Pos(',', Data) - 1);
|
||||
|
||||
Delete (Data, 1, Pos(',', Data));
|
||||
|
||||
WordRec(DataPort).Hi := strS2I(Copy(Data, 1, Pos(',', Data) - 1));
|
||||
WordRec(DataPort).Lo := strS2I(Copy(Data, Pos(',', Data) + 1, Length(Data)));
|
||||
|
||||
Client.WriteLine(re_CommandOK);
|
||||
|
||||
IsPassive := False;
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdPASV;
|
||||
Var
|
||||
WaitSock : TSocketClass;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
DataPort := Random(65535-60000) + 60000; // make configurable?!
|
||||
|
||||
Client.WriteLine(re_PassiveOK + '(' + strReplace(Client.HostIP, '.', ',') + ',' + strI2S(WordRec(DataPort).Hi) + ',' + strI2S(WordRec(DataPort).Lo) + ').');
|
||||
|
||||
IsPassive := True;
|
||||
|
||||
WaitSock := TSocketClass.Create;
|
||||
|
||||
WaitSock.WaitInit(DataPort);
|
||||
|
||||
DataSocket := WaitSock.WaitConnection;
|
||||
|
||||
If Not Assigned(DataSocket) Then Begin
|
||||
WaitSock.Free;
|
||||
Client.WriteLine(re_NoData);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
WaitSock.Free;
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdCDUP;
|
||||
Begin
|
||||
Client.WriteLine(re_DirOkay + '"/"');
|
||||
|
||||
FBasePos := -1;
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdCWD;
|
||||
Var
|
||||
TempBase : FBaseRec;
|
||||
TempPos : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
If (Data = '/') or (Copy(Data, 1, 2) = '..') Then Begin
|
||||
FBasePos := -1;
|
||||
Client.WriteLine(re_DirOkay + '"/"');
|
||||
Exit;
|
||||
End;
|
||||
|
||||
TempPos := FindDirectory(TempBase);
|
||||
|
||||
If TempPos = -1 Then Begin
|
||||
Client.WriteLine(re_BadDir);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Client.WriteLine(re_DirOkay + '"/' + TempBase.FtpName + '"');
|
||||
|
||||
FBase := TempBase;
|
||||
FBasePos := TempPos;
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdNLST;
|
||||
Var
|
||||
TempBase : FBaseRec;
|
||||
TempPos : LongInt;
|
||||
DirFile : TBufFile;
|
||||
Dir : FDirRec;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
TempPos := FindDirectory(TempBase);
|
||||
|
||||
If TempPos = -1 Then Begin
|
||||
OpenDataSession;
|
||||
CloseDataSession;
|
||||
// list files in root directory, so show nothing
|
||||
Exit;
|
||||
End;
|
||||
|
||||
OpenDataSession;
|
||||
|
||||
DirFile := TBufFile.Create(FileBufSize);
|
||||
|
||||
If DirFile.Open(bbsConfig.DataPath + TempBase.FileName + '.dir', fmOpenCreate, fmRWDN, SizeOf(FDirRec)) Then Begin
|
||||
While Not DirFile.EOF Do Begin
|
||||
DirFile.Read(Dir);
|
||||
|
||||
If (Dir.Flags And FDirDeleted <> 0) Then Continue;
|
||||
If (Dir.Flags And FDirInvalid <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeUnvalid)) Then Continue;
|
||||
If (Dir.Flags And FDirFailed <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeFailed)) Then Continue;
|
||||
|
||||
If WildcardMatch(FileMask, Dir.FileName) Then
|
||||
DataSocket.WriteLine(Dir.FileName);
|
||||
End;
|
||||
End;
|
||||
|
||||
DirFile.Free;
|
||||
|
||||
CloseDataSession;
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdPWD;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
If FBasePos = -1 Then
|
||||
Client.WriteLine(re_DirOkay + '"/"')
|
||||
Else
|
||||
Client.WriteLine(re_DirOkay + '"/' + FBase.FtpName + '"');
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdLIST;
|
||||
Var
|
||||
TempBase : FBaseRec;
|
||||
TempPos : LongInt;
|
||||
FBaseFile : TBufFile;
|
||||
DirFile : TBufFile;
|
||||
Dir : FDirRec;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
TempPos := FindDirectory(TempBase);
|
||||
|
||||
If TempPos = -1 Then Begin
|
||||
OpenDataSession;
|
||||
|
||||
FBaseFile := TBufFile.Create(FileBufSize);
|
||||
|
||||
If FBaseFile.Open(bbsConfig.DataPath + 'fbases.dat', fmOpen, fmRWDN, SizeOf(FBaseRec)) Then Begin
|
||||
While Not FBaseFile.EOF Do Begin
|
||||
FBaseFile.Read(TempBase);
|
||||
|
||||
If ValidDirectory(TempBase) and WildcardMatch(FileMask, TempBase.FtpName) Then
|
||||
DataSocket.WriteLine('drwxr-xr-x 1 ftp ftp 0 Jul 11 23:35 ' + TempBase.FtpName)
|
||||
End;
|
||||
End;
|
||||
|
||||
FBaseFile.Free;
|
||||
|
||||
CloseDataSession;
|
||||
|
||||
Exit;
|
||||
End;
|
||||
|
||||
OpenDataSession;
|
||||
|
||||
DirFile := TBufFile.Create(FileBufSize);
|
||||
|
||||
If DirFile.Open(bbsConfig.DataPath + TempBase.FileName + '.dir', fmOpenCreate, fmRWDN, SizeOf(FDirRec)) Then Begin
|
||||
While Not DirFile.EOF Do Begin
|
||||
DirFile.Read(Dir);
|
||||
|
||||
If (Dir.Flags And FDirDeleted <> 0) Then Continue;
|
||||
If (Dir.Flags And FDirInvalid <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeUnvalid)) Then Continue;
|
||||
If (Dir.Flags And FDirFailed <> 0) And (Not CheckAccess(User, True, bbsConfig.AcsSeeFailed)) Then Continue;
|
||||
|
||||
If WildcardMatch(FileMask, Dir.FileName) Then
|
||||
DataSocket.WriteLine('-rw-r--r-- 1 ftp ftp ' + strPadL(strI2S(Dir.Size), 13, ' ') + ' Jul 11 23:35 ' + Dir.FileName)
|
||||
End;
|
||||
End;
|
||||
|
||||
DirFile.Free;
|
||||
|
||||
CloseDataSession;
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdRETR;
|
||||
Var
|
||||
TempPos : LongInt;
|
||||
TempBase : FBaseRec;
|
||||
DirFile : TBufFile;
|
||||
Dir : FDirRec;
|
||||
Found : LongInt;
|
||||
F : File;
|
||||
Buf : Array[1..4096] of Byte;
|
||||
Tmp : LongInt;
|
||||
Res : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
TempPos := FindDirectory(TempBase);
|
||||
|
||||
If TempPos = -1 Then Begin
|
||||
Client.WriteLine(re_BadFile);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
DirFile := TBufFile.Create(FileBufSize);
|
||||
Found := -1;
|
||||
|
||||
If DirFile.Open(bbsConfig.DataPath + TempBase.FileName + '.dir', fmOpenCreate, fmRWDN, SizeOf(FDirRec)) Then Begin
|
||||
While Not DirFile.EOF Do Begin
|
||||
DirFile.Read(Dir);
|
||||
|
||||
If WildcardMatch(FileMask, Dir.FileName) Then Begin
|
||||
Found := DirFile.FilePos;
|
||||
Break;
|
||||
End;
|
||||
End;
|
||||
|
||||
DirFile.Free;
|
||||
|
||||
If Found = -1 Then Begin
|
||||
Client.WriteLine(re_BadFile);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Case CheckFileLimits(TempBase, Dir) of
|
||||
0 : Begin
|
||||
Assign (F, TempBase.Path + Dir.FileName);
|
||||
ioReset (F, 1, fmRWDN);
|
||||
|
||||
InTransfer := True;
|
||||
|
||||
OpenDataSession;
|
||||
|
||||
While Not Eof(F) Do Begin
|
||||
BlockRead (F, Buf, SizeOf(Buf), Res);
|
||||
|
||||
Repeat
|
||||
Tmp := DataSocket.WriteBuf(Buf, Res);
|
||||
Dec (Res, Tmp);
|
||||
Until Res = 0;
|
||||
End;
|
||||
|
||||
Close (F);
|
||||
|
||||
Client.WriteLine (re_XferOK);
|
||||
|
||||
CloseDataSession;
|
||||
|
||||
InTransfer := False;
|
||||
|
||||
UpdateUserStats(TempBase, Dir, Found);
|
||||
End;
|
||||
1 : Client.WriteLine(re_NoAccess);
|
||||
2 : Client.WriteLine(re_DLLimit);
|
||||
3 : Client.WriteLine(re_DLRatio);
|
||||
End;
|
||||
End Else
|
||||
Client.WriteLine(re_BadFile);
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdSTRU;
|
||||
Begin
|
||||
If strUpper(Data) = 'F' Then
|
||||
Client.WriteLine('200 FILE structure.')
|
||||
Else
|
||||
Client.WriteLine('504 Only FILE structure supported.');
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdMODE;
|
||||
Begin
|
||||
If strUpper(Data) = 'S' Then
|
||||
Client.WriteLine('200 STREAM mode.')
|
||||
Else
|
||||
Client.WriteLine('504 Only STREAM mode supported.');
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdSYST;
|
||||
Begin
|
||||
Client.WriteLine('215 UNIX Type: L8');
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdTYPE;
|
||||
Begin
|
||||
Client.WriteLine('200 All files sent in BINARY mode.');
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdEPRT;
|
||||
Var
|
||||
DataType : String;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
DataType := strWordGet(1, Data, '|');
|
||||
|
||||
If DataType = '1' Then Begin
|
||||
DataIP := strWordGet(2, Data, '|');
|
||||
DataPort := strS2I(strWordGet(3, Data, '|'));
|
||||
IsPassive := False;
|
||||
|
||||
Client.WriteLine(re_CommandOK);
|
||||
End Else
|
||||
Client.WriteLine('522 Network protocol not supported, use (1)');
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdEPSV;
|
||||
Var
|
||||
WaitSock : TSocketClass;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
If Data = '' Then Begin
|
||||
DataPort := Random(65535 - 60000) + 60000; // make configuratable
|
||||
IsPassive := True;
|
||||
|
||||
Client.WriteLine('229 Entering Extended Passive Mode (|||' + strI2S(DataPort) + '|)');
|
||||
|
||||
WaitSock := TSocketClass.Create;
|
||||
|
||||
WaitSock.WaitInit(DataPort);
|
||||
|
||||
DataSocket := WaitSock.WaitConnection;
|
||||
|
||||
If Not Assigned(DataSocket) Then Begin
|
||||
WaitSock.Free;
|
||||
Client.WriteLine(re_NoData);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
WaitSock.Free;
|
||||
End Else
|
||||
If Data = '1' Then
|
||||
Client.WriteLine(re_CommandOK)
|
||||
Else
|
||||
Client.WriteLine('522 Network protocol not supported, use (1)');
|
||||
|
||||
End Else
|
||||
Client.WriteLine(re_BadCommand);
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.cmdSIZE;
|
||||
Begin
|
||||
Client.WriteLine('550 Not implemented');
|
||||
End;
|
||||
|
||||
Procedure TFTPServer.Execute;
|
||||
Var
|
||||
Str : String;
|
||||
Begin
|
||||
cmdREIN;
|
||||
|
||||
Repeat
|
||||
If Client.WaitForData(FTPTimeOut * 1000) = 0 Then Break;
|
||||
|
||||
If Terminated Then Exit;
|
||||
|
||||
If Client.ReadLine(Str) = -1 Then Exit;
|
||||
|
||||
// dlog(Str);
|
||||
//server.server.status(str);
|
||||
|
||||
Cmd := strUpper(strWordGet(1, Str, ' '));
|
||||
|
||||
If Pos(' ', Str) > 0 Then
|
||||
Data := strStripB(Copy(Str, Pos(' ', Str) + 1, Length(Str)), ' ')
|
||||
Else
|
||||
Data := '';
|
||||
|
||||
If Cmd = 'CDUP' Then cmdCDUP Else
|
||||
If Cmd = 'CWD' Then cmdCWD Else
|
||||
If Cmd = 'EPRT' Then cmdEPRT Else
|
||||
If Cmd = 'EPSV' Then cmdEPSV Else
|
||||
If Cmd = 'LIST' Then cmdLIST Else
|
||||
If Cmd = 'MODE' Then cmdMODE Else
|
||||
If Cmd = 'NLST' Then cmdNLST Else
|
||||
If Cmd = 'NOOP' Then Client.WriteLine(re_CommandOK) Else
|
||||
If Cmd = 'PASS' Then cmdPASS Else
|
||||
If Cmd = 'PASV' Then cmdPASV Else
|
||||
If Cmd = 'PORT' Then cmdPORT Else
|
||||
If Cmd = 'PWD' Then cmdPWD ELse
|
||||
If Cmd = 'REIN' Then cmdREIN Else
|
||||
If Cmd = 'RETR' Then cmdRETR Else
|
||||
If Cmd = 'SIZE' Then cmdSIZE Else
|
||||
If Cmd = 'STRU' Then cmdSTRU Else
|
||||
If Cmd = 'SYST' Then cmdSYST Else
|
||||
If Cmd = 'TYPE' Then cmdTYPE Else
|
||||
If Cmd = 'USER' Then cmdUSER Else
|
||||
If Cmd = 'XPWD' Then cmdPWD Else
|
||||
If Cmd = 'QUIT' Then Begin
|
||||
GotQuit := True;
|
||||
Break;
|
||||
End Else
|
||||
Client.WriteLine(re_NoCommand);
|
||||
Until Terminated;
|
||||
|
||||
If GotQuit Then Begin
|
||||
Client.WriteLine(re_Goodbye);
|
||||
|
||||
Server.Server.Status (User.Handle + ' logged out');
|
||||
End;
|
||||
End;
|
||||
|
||||
Destructor TFTPServer.Destroy;
|
||||
Begin
|
||||
If Assigned(DataSocket) Then DataSocket.Free;
|
||||
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,141 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Client_POP3;
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
SysUtils,
|
||||
m_Strings,
|
||||
m_FileIO,
|
||||
m_Socket_Class,
|
||||
m_DateTime,
|
||||
MIS_Server,
|
||||
MIS_NodeData,
|
||||
MIS_Common;
|
||||
|
||||
Function CreatePOP3 (Owner: TServerManager; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
|
||||
Type
|
||||
TPOP3Server = Class(TServerClient)
|
||||
Server : TServerManager;
|
||||
UserName : String[40];
|
||||
Password : String[20];
|
||||
LoggedIn : Boolean;
|
||||
Cmd : String;
|
||||
Data : String;
|
||||
User : UserRec;
|
||||
UserPos : LongInt;
|
||||
|
||||
Constructor Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Procedure Execute; Override;
|
||||
Destructor Destroy; Override;
|
||||
|
||||
Procedure ResetSession;
|
||||
|
||||
Procedure cmdUSER;
|
||||
Procedure cmdPASS;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Const
|
||||
POP3TimeOut = 120;
|
||||
FileBufSize = 8 * 1024;
|
||||
|
||||
re_OK = '+OK ';
|
||||
re_Error = '-ERR ';
|
||||
|
||||
re_UnknownCommand = re_Error + 'Unknown command';
|
||||
re_UnknownUser = re_Error + 'Unknown user';
|
||||
re_BadLogin = re_Error + 'Bad credentials';
|
||||
|
||||
re_Greeting = 'Mystic POP3 Server';
|
||||
re_Goodbye = re_OK + 'Goodbye';
|
||||
re_SendUserPass = re_OK + 'Send user password';
|
||||
re_LoggedIn = re_OK + 'Welcome';
|
||||
|
||||
Function CreatePOP3 (Owner: TServerManager; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
Begin
|
||||
Result := TPOP3Server.Create(Owner, CliSock);
|
||||
End;
|
||||
|
||||
Constructor TPOP3Server.Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Begin
|
||||
Inherited Create(Owner, CliSock);
|
||||
|
||||
Server := Owner;
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.ResetSession;
|
||||
Begin
|
||||
LoggedIn := False;
|
||||
UserName := '';
|
||||
Password := '';
|
||||
UserPos := -1;
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdUSER;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
If SearchForUser(Data, User, UserPos) Then Begin
|
||||
Client.WriteLine(re_SendUserPass);
|
||||
UserName := Data;
|
||||
End Else
|
||||
Client.WriteLine(re_UnknownUser);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdPASS;
|
||||
Begin
|
||||
If (UserName = '') or (UserPos = -1) Then Begin
|
||||
Client.WriteLine(re_UnknownUser);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If strUpper(Data) = User.Password Then Begin
|
||||
LoggedIn := True;
|
||||
|
||||
Client.WriteLine(re_LoggedIn);
|
||||
End Else
|
||||
Client.WriteLine(re_BadLogin);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.Execute;
|
||||
Var
|
||||
Str : String;
|
||||
Begin
|
||||
ResetSession;
|
||||
Client.WriteLine(re_Greeting);
|
||||
|
||||
Repeat
|
||||
If Client.WaitForData(POP3TimeOut * 1000) = 0 Then Break;
|
||||
|
||||
If Terminated Then Exit;
|
||||
|
||||
If Client.ReadLine(Str) = -1 Then Exit;
|
||||
|
||||
server.server.status(str);
|
||||
|
||||
Cmd := strUpper(strWordGet(1, Str, ' '));
|
||||
|
||||
If Pos(' ', Str) > 0 Then
|
||||
Data := strStripB(Copy(Str, Pos(' ', Str) + 1, Length(Str)), ' ')
|
||||
Else
|
||||
Data := '';
|
||||
|
||||
If Cmd = 'PASS' Then cmdPASS Else
|
||||
If Cmd = 'QUIT' Then Break Else
|
||||
If Cmd = 'USER' Then cmdUSER Else
|
||||
Client.WriteLine(re_UnknownCommand);
|
||||
Until Terminated;
|
||||
|
||||
If Not Terminated Then Client.WriteLine(re_Goodbye);
|
||||
End;
|
||||
|
||||
Destructor TPOP3Server.Destroy;
|
||||
Begin
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,146 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Client_NNTP;
|
||||
|
||||
// lookup:
|
||||
// how to send greeting and goodbye?
|
||||
// how to send capabilities so far only AUTHINFO
|
||||
// determine base feature-set required
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
SysUtils,
|
||||
m_Strings,
|
||||
m_FileIO,
|
||||
m_Socket_Class,
|
||||
m_DateTime,
|
||||
MIS_Server,
|
||||
MIS_NodeData,
|
||||
MIS_Common;
|
||||
|
||||
Function CreateNNTP (Owner: TServerManager; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
|
||||
Type
|
||||
TNNTPServer = Class(TServerClient)
|
||||
Server : TServerManager;
|
||||
UserName : String[40];
|
||||
Password : String[20];
|
||||
LoggedIn : Boolean;
|
||||
Cmd : String;
|
||||
Data : String;
|
||||
User : RecUser;
|
||||
UserPos : LongInt;
|
||||
|
||||
Constructor Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Procedure Execute; Override;
|
||||
Destructor Destroy; Override;
|
||||
|
||||
Procedure ResetSession;
|
||||
|
||||
Procedure cmd_AUTHINFO;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Const
|
||||
NNTPTimeOut = 180; // make configurable
|
||||
|
||||
re_Greeting = 'Mystic BBS NNTP Server';
|
||||
re_Goodbye = 'Goodbye';
|
||||
|
||||
re_AuthOK = '281 Authentication accepted';
|
||||
re_AuthBad = '381 Authentication rejected';
|
||||
re_AuthPass = '381 Password required';
|
||||
re_AuthSync = '482 Bad Authentication sequence';
|
||||
re_Unknown = '500 Unknown command';
|
||||
re_UnknownOption = '501 Unknown option';
|
||||
|
||||
Function CreateNNTP (Owner: TServerManager; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
Begin
|
||||
Result := TNNTPServer.Create(Owner, CliSock);
|
||||
End;
|
||||
|
||||
Constructor TNNTPServer.Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Begin
|
||||
Inherited Create(Owner, CliSock);
|
||||
|
||||
Server := Owner;
|
||||
End;
|
||||
|
||||
Procedure TNNTPServer.ResetSession;
|
||||
Begin
|
||||
LoggedIn := False;
|
||||
UserName := '';
|
||||
Password := '';
|
||||
UserPos := -1;
|
||||
End;
|
||||
|
||||
Procedure TNNTPServer.cmd_AUTHINFO;
|
||||
Var
|
||||
NewCmd : String;
|
||||
NewData : String;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
NewCmd := strWordGet(1, Data, ' ');
|
||||
NewData := Copy(Data, Pos(' ', Data) + 1, 255);
|
||||
|
||||
If NewCmd = 'USER' Then Begin
|
||||
If SearchForUser(NewData, User, UserPos) Then Begin
|
||||
Client.WriteLine(re_AuthPass);
|
||||
UserName := NewData;
|
||||
End Else
|
||||
Client.WriteLine(re_AuthBad);
|
||||
End Else
|
||||
If NewCmd = 'PASS' Then Begin
|
||||
If UserPos = -1 Then
|
||||
Client.WriteLine(re_AuthSync)
|
||||
Else
|
||||
If strUpper(NewData) = User.Password Then Begin
|
||||
Client.WriteLine(re_AuthOK);
|
||||
LoggedIn := True;
|
||||
End Else
|
||||
Client.WriteLine(re_AuthBad);
|
||||
End Else
|
||||
Client.WriteLine(re_UnknownOption);
|
||||
End;
|
||||
|
||||
Procedure TNNTPServer.Execute;
|
||||
Var
|
||||
Str : String;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
Client.WriteLine(re_Greeting);
|
||||
|
||||
Repeat
|
||||
If Client.WaitForData(NNTPTimeOut * 1000) = 0 Then Break;
|
||||
|
||||
If Terminated Then Exit;
|
||||
|
||||
If Client.ReadLine(Str) = -1 Then Exit;
|
||||
|
||||
//server.server.status(str);
|
||||
|
||||
Cmd := strUpper(strWordGet(1, Str, ' '));
|
||||
|
||||
If Pos(' ', Str) > 0 Then
|
||||
Data := strStripB(Copy(Str, Pos(' ', Str) + 1, Length(Str)), ' ')
|
||||
Else
|
||||
Data := '';
|
||||
|
||||
If Cmd = 'AUTHINFO' Then cmd_AUTHINFO Else
|
||||
If Cmd = 'QUIT' Then Break Else
|
||||
Client.WriteLine(re_Unknown);
|
||||
Until Terminated;
|
||||
|
||||
If Not Terminated Then Client.WriteLine(re_Goodbye);
|
||||
End;
|
||||
|
||||
Destructor TNNTPServer.Destroy;
|
||||
Begin
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,497 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Client_POP3;
|
||||
|
||||
// RFC 1939
|
||||
// optional TOP and APOP not implemented
|
||||
// needs to reformat long messages > 79 chars?
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
MD5,
|
||||
Classes,
|
||||
SysUtils,
|
||||
m_Strings,
|
||||
m_FileIO,
|
||||
m_Socket_Class,
|
||||
m_DateTime,
|
||||
MIS_Server,
|
||||
MIS_NodeData,
|
||||
MIS_Common,
|
||||
BBS_MsgBase_ABS,
|
||||
BBS_MsgBase_JAM,
|
||||
BBS_MsgBase_Squish;
|
||||
|
||||
Function CreatePOP3 (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
|
||||
Const
|
||||
MaxMailBoxSize = 1000;
|
||||
|
||||
Type
|
||||
PMailMessageRec = ^TMailMessageRec;
|
||||
TMailMessageRec = Record
|
||||
MsgSize : LongInt;
|
||||
MD5 : String[32];
|
||||
Deleted : Boolean;
|
||||
GotRETR : Boolean;
|
||||
Text : TStringList;
|
||||
End;
|
||||
|
||||
TPOP3Server = Class(TServerClient)
|
||||
Server : TServerManager;
|
||||
UserName : String[40];
|
||||
Password : String[20];
|
||||
LoggedIn : Boolean;
|
||||
GotQuit : Boolean;
|
||||
Cmd : String;
|
||||
Data : String;
|
||||
User : RecUser;
|
||||
UserPos : LongInt;
|
||||
MailInfo : Array[1..MaxMailBoxSize] of PMailMessageRec;
|
||||
MailSize : LongInt;
|
||||
|
||||
Constructor Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Procedure Execute; Override;
|
||||
Destructor Destroy; Override;
|
||||
|
||||
Procedure ResetSession;
|
||||
Procedure CreateMailBoxData;
|
||||
Procedure DeleteMessages;
|
||||
Function GetMessageUID (Var MsgBase: PMsgBaseABS) : String;
|
||||
Procedure GetMessageCount (Var TotalMsg: LongInt; Var TotalSize: LongInt);
|
||||
|
||||
Procedure cmdLIST;
|
||||
Procedure cmdUSER;
|
||||
Procedure cmdPASS;
|
||||
Procedure cmdSTAT;
|
||||
Procedure cmdUIDL;
|
||||
Procedure cmdRETR;
|
||||
Procedure cmdRSET;
|
||||
Procedure cmdDELE;
|
||||
Procedure cmdTOP;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Const
|
||||
POP3TimeOut : SmallInt = 900; { MCFG? }
|
||||
DeleteOnRETR : Boolean = False; { MCFG? }
|
||||
|
||||
re_OK = '+OK ';
|
||||
re_Error = '-ERR ';
|
||||
|
||||
re_UnknownCommand = re_Error + 'Unknown command';
|
||||
re_UnknownUser = re_Error + 'Unknown user';
|
||||
re_BadLogin = re_Error + 'Bad credentials';
|
||||
re_NotLoggedIn = re_Error + 'Not logged in';
|
||||
re_UnknownMail = re_Error + 'Unknown message';
|
||||
|
||||
re_Greeting = re_OK + 'Mystic POP3 Server';
|
||||
re_Goodbye = re_OK + 'Goodbye';
|
||||
re_SendUserPass = re_OK + 'Send user password';
|
||||
re_LoggedIn = re_OK + 'Welcome';
|
||||
re_GetMessage = re_OK + 'Sending message ';
|
||||
re_ResetOK = re_OK + 'Messages reset';
|
||||
re_MsgDeleted = re_OK + 'Message deleted';
|
||||
|
||||
Function CreatePOP3 (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
Begin
|
||||
Result := TPOP3Server.Create(Owner, CliSock);
|
||||
End;
|
||||
|
||||
Constructor TPOP3Server.Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Begin
|
||||
Inherited Create(Owner, CliSock);
|
||||
|
||||
Server := Owner;
|
||||
MailSize := 0;
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.ResetSession;
|
||||
Var
|
||||
Count : LongInt;
|
||||
Begin
|
||||
LoggedIn := False;
|
||||
GotQuit := False;
|
||||
UserName := '';
|
||||
Password := '';
|
||||
UserPos := -1;
|
||||
|
||||
For Count := 1 to MailSize Do
|
||||
If MailInfo[Count] <> NIL Then Begin
|
||||
If Assigned(MailInfo[Count].Text) Then
|
||||
MailInfo[Count].Text.Free;
|
||||
|
||||
Dispose (MailInfo[Count]);
|
||||
End;
|
||||
|
||||
MailSize := 0;
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.GetMessageCount (Var TotalMsg: LongInt; Var TotalSize: LongInt);
|
||||
Var
|
||||
Count : LongInt;
|
||||
Begin
|
||||
TotalMsg := 0;
|
||||
TotalSize := 0;
|
||||
|
||||
For Count := 1 to MailSize Do
|
||||
If Not MailInfo[Count].Deleted Then Begin
|
||||
Inc (TotalMsg);
|
||||
Inc (TotalSize, MailInfo[Count].MsgSize);
|
||||
End;
|
||||
End;
|
||||
|
||||
Function TPOP3Server.GetMessageUID (Var MsgBase: PMsgBaseABS) : String;
|
||||
Var
|
||||
TempStr : String;
|
||||
Begin
|
||||
// FP might calc this wrong if we do it all at once, so annoying
|
||||
|
||||
TempStr := strI2S(User.PermIdx);
|
||||
TempStr := TempStr + MsgBase^.GetFrom;
|
||||
TempStr := TempStr + MsgBase^.GetDate;
|
||||
TempStr := TempStr + MsgBase^.GetTime;
|
||||
|
||||
Result := MD5Print(MD5String(TempStr));
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.CreateMailBoxData;
|
||||
Var
|
||||
MBaseFile : File of MBaseRec;
|
||||
MBase : MBaseRec;
|
||||
MsgBase : PMsgBaseABS;
|
||||
|
||||
Function ParseDateTime (Date, Time : String) : String;
|
||||
Begin
|
||||
DateSeparator := '-';
|
||||
ParseDateTime := FormatDateTime('ddd, dd mmm yyyy hh:nn:ss', StrToDateTime(Date + ' ' + Time));
|
||||
End;
|
||||
|
||||
Procedure AddLine (Str: String);
|
||||
Begin
|
||||
MailInfo[MailSize].Text.Add(Str);
|
||||
|
||||
Inc (MailInfo[MailSize].MsgSize, Length(Str) + 2); {CRLF}
|
||||
End;
|
||||
|
||||
Begin
|
||||
Assign (MBaseFile, bbsConfig.DataPath + 'mbases.dat');
|
||||
|
||||
If Not ioReset(MBaseFile, SizeOf(MBaseRec), fmRWDN) Then Exit;
|
||||
|
||||
ioRead (MBaseFile, MBase);
|
||||
Close (MBaseFile);
|
||||
|
||||
Case MBase.BaseType of
|
||||
0 : MsgBase := New(PMsgBaseJAM, Init);
|
||||
1 : MsgBase := New(PMsgBaseSquish, Init);
|
||||
End;
|
||||
|
||||
MsgBase^.SetMsgPath (MBase.Path + MBase.FileName);
|
||||
|
||||
If Not MsgBase^.OpenMsgBase Then Begin
|
||||
Dispose (MsgBase, Done);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
MsgBase^.YoursFirst(User.RealName, User.Handle);
|
||||
|
||||
While MsgBase^.YoursFound Do Begin
|
||||
MsgBase^.MsgStartup;
|
||||
MsgBase^.MsgTxtStartup;
|
||||
|
||||
Inc (MailSize);
|
||||
|
||||
New (MailInfo[MailSize]);
|
||||
|
||||
MailInfo[MailSize].Text := TStringList.Create;
|
||||
|
||||
AddLine ('Date: ' + ParseDateTime(MsgBase^.GetDate, MsgBase^.GetTime));
|
||||
AddLine ('From: ' + MsgBase^.GetFrom + ' <' + strReplace(MsgBase^.GetFrom, ' ', '_') + '@' + bbsConfig.inetDomain + '>');
|
||||
AddLine ('X-Mailer: Mystic BBS ' + mysVersion);
|
||||
AddLine ('To: ' + MsgBase^.GetTo + ' <' + strReplace(MsgBase^.GetTo, ' ', '_') + '@' + bbsConfig.inetDomain + '>');
|
||||
AddLine ('Subject: ' + MsgBase^.GetSubj);
|
||||
AddLine ('Content-Type: text/plain; charset=us-ascii');
|
||||
AddLine ('');
|
||||
|
||||
While Not MsgBase^.EOM Do
|
||||
AddLine(MsgBase^.GetString(79));
|
||||
|
||||
MailInfo[MailSize].MD5 := GetMessageUID(MsgBase);
|
||||
MailInfo[MailSize].GotRETR := False;
|
||||
MailInfo[MailSize].Deleted := False;
|
||||
|
||||
MsgBase^.YoursNext;
|
||||
End;
|
||||
|
||||
MsgBase^.CloseMsgBase;
|
||||
|
||||
Dispose (MsgBase, Done);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.DeleteMessages;
|
||||
Var
|
||||
Count : LongInt;
|
||||
MBaseFile : File of MBaseRec;
|
||||
MBase : MBaseRec;
|
||||
MsgBase : PMsgBaseABS;
|
||||
Begin
|
||||
Assign (MBaseFile, bbsConfig.DataPath + 'mbases.dat');
|
||||
|
||||
If Not ioReset(MBaseFile, SizeOf(MBaseRec), fmRWDN) Then Exit;
|
||||
|
||||
ioRead (MBaseFile, MBase);
|
||||
Close (MBaseFile);
|
||||
|
||||
Case MBase.BaseType of
|
||||
0 : MsgBase := New(PMsgBaseJAM, Init);
|
||||
1 : MsgBase := New(PMsgBaseSquish, Init);
|
||||
End;
|
||||
|
||||
MsgBase^.SetMsgPath (MBase.Path + MBase.FileName);
|
||||
|
||||
If Not MsgBase^.OpenMsgBase Then Begin
|
||||
Dispose (MsgBase, Done);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
For Count := 1 to MailSize Do Begin
|
||||
If MailInfo[Count].Deleted or (MailInfo[Count].GotRETR and DeleteOnRETR) Then Begin
|
||||
MsgBase^.YoursFirst(User.RealName, User.Handle);
|
||||
|
||||
While MsgBase^.YoursFound Do Begin
|
||||
MsgBase^.MsgStartUp;
|
||||
|
||||
If GetMessageUID(MsgBase) = MailInfo[Count].MD5 Then Begin
|
||||
MsgBase^.DeleteMsg;
|
||||
Break;
|
||||
End;
|
||||
|
||||
MsgBase^.YoursNext;
|
||||
End;
|
||||
End;
|
||||
End;
|
||||
|
||||
MsgBase^.CloseMsgBase;
|
||||
|
||||
Dispose (MsgBase, Done);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdUSER;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
If SearchForUser(Data, User, UserPos) Then Begin
|
||||
Client.WriteLine(re_SendUserPass);
|
||||
UserName := Data;
|
||||
End Else
|
||||
Client.WriteLine(re_UnknownUser);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdPASS;
|
||||
Begin
|
||||
If (UserName = '') or (UserPos = -1) Then Begin
|
||||
Client.WriteLine(re_UnknownUser);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If strUpper(Data) = User.Password Then Begin
|
||||
LoggedIn := True;
|
||||
|
||||
CreateMailboxData;
|
||||
|
||||
Client.WriteLine(re_LoggedIn);
|
||||
|
||||
Server.Server.Status(User.Handle + ' logged in');
|
||||
End Else
|
||||
Client.WriteLine(re_BadLogin);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdSTAT;
|
||||
Var
|
||||
DataSize : LongInt;
|
||||
DataMsg : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
GetMessageCount(DataMsg, DataSize);
|
||||
|
||||
Client.WriteLine(re_OK + strI2S(DataMsg) + ' ' + strI2O(Datasize));
|
||||
End Else
|
||||
Client.WriteLine(re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdLIST;
|
||||
Var
|
||||
MsgNum : LongInt;
|
||||
MsgSize : LongInt;
|
||||
Count : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
|
||||
If Data <> '' Then Begin
|
||||
MsgNum := strS2I(Data);
|
||||
|
||||
If (MsgNum > 0) and (MsgNum <= MailSize) and (Not MailInfo[MsgNum].Deleted) Then
|
||||
Client.WriteLine(re_OK + strI2S(MsgNum) + ' ' + strI2O(MailInfo[MsgNum].MsgSize))
|
||||
Else
|
||||
Client.WriteLine(re_UnknownMail);
|
||||
End Else Begin
|
||||
GetMessageCount(MsgNum, MsgSize);
|
||||
|
||||
Client.WriteLine (re_OK + strI2S(MsgNum) + ' messages (' + strI2O(MsgSize) + ' octets)');
|
||||
|
||||
For Count := 1 to MailSize Do
|
||||
If Not MailInfo[Count].Deleted Then
|
||||
Client.WriteLine (strI2S(Count) + ' ' + strI2O(MailInfo[Count].MsgSize));
|
||||
|
||||
Client.WriteLine('.');
|
||||
End;
|
||||
End Else
|
||||
Client.WriteLine(re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdUIDL;
|
||||
Var
|
||||
MsgNum : LongInt;
|
||||
Count : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
If Data <> '' Then Begin
|
||||
MsgNum := strS2I(Data);
|
||||
|
||||
If (MsgNum > 0) and (MsgNum <= MailSize) and (Not MailInfo[MsgNum].Deleted) Then
|
||||
Client.WriteLine(re_OK + strI2S(MsgNum) + ' ' + MailInfo[MsgNum].MD5)
|
||||
Else
|
||||
Client.WriteLine(re_UnknownMail);
|
||||
End Else Begin
|
||||
Client.WriteLine (re_OK + 'Message list follows');
|
||||
|
||||
For Count := 1 to MailSize Do
|
||||
If Not MailInfo[Count].Deleted Then Begin
|
||||
Client.WriteLine (strI2S(Count) + ' ' + MailInfo[Count].MD5);
|
||||
End;
|
||||
Client.WriteLine('.');
|
||||
End;
|
||||
End Else
|
||||
Client.WriteLine(re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdRETR;
|
||||
Var
|
||||
MsgNum : LongInt;
|
||||
Count : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
MsgNum := strS2I(Data);
|
||||
|
||||
If (MsgNum > 0) and (MsgNum <= MailSize) and (Not MailInfo[MsgNum].Deleted) Then Begin
|
||||
Client.WriteLine (re_GetMessage + strI2S(MsgNum));
|
||||
|
||||
For Count := 0 to MailInfo[MsgNum].Text.Count - 1 Do
|
||||
Client.WriteLine(MailInfo[MsgNum].Text[Count]);
|
||||
|
||||
Client.WriteLine('.');
|
||||
|
||||
MailInfo[MsgNum].GotRETR := True;
|
||||
End Else
|
||||
Client.WriteLine(re_UnknownMail);
|
||||
End Else
|
||||
Client.WriteLine(re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdRSET;
|
||||
Var
|
||||
Count : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
For Count := 1 to MailSize Do
|
||||
MailInfo[Count].Deleted := False;
|
||||
|
||||
Client.WriteLine (re_ResetOK);
|
||||
End Else
|
||||
Client.WriteLine (re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdDELE;
|
||||
Var
|
||||
MsgNum : LongInt;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
MsgNum := strS2I(Data);
|
||||
|
||||
If (MsgNum > 0) and (MsgNum <= MailSize) and (Not MailInfo[MsgNum].Deleted) Then Begin
|
||||
MailInfo[MsgNum].Deleted := True;
|
||||
|
||||
Client.WriteLine(re_MsgDeleted);
|
||||
End Else
|
||||
Client.WriteLine(re_UnknownMail);
|
||||
End Else
|
||||
Client.WriteLine(re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.cmdTOP;
|
||||
Begin
|
||||
If LoggedIn Then Begin
|
||||
End Else
|
||||
Client.WriteLine(re_NotLoggedIn);
|
||||
End;
|
||||
|
||||
Procedure TPOP3Server.Execute;
|
||||
Var
|
||||
Str : String;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
Client.WriteLine(re_Greeting);
|
||||
|
||||
Repeat
|
||||
If Client.WaitForData(POP3TimeOut * 1000) = 0 Then Break;
|
||||
|
||||
If Terminated Then Exit;
|
||||
|
||||
If Client.ReadLine(Str) = -1 Then Exit;
|
||||
|
||||
Cmd := strUpper(strWordGet(1, Str, ' '));
|
||||
|
||||
If Pos(' ', Str) > 0 Then
|
||||
Data := strStripB(Copy(Str, Pos(' ', Str) + 1, Length(Str)), ' ')
|
||||
Else
|
||||
Data := '';
|
||||
|
||||
// If Cmd = 'APOP' Then cmdAPOP Else
|
||||
If Cmd = 'DELE' Then cmdDELE Else
|
||||
If Cmd = 'LIST' Then cmdLIST Else
|
||||
If Cmd = 'NOOP' Then Client.WriteLine(re_OK) Else
|
||||
If Cmd = 'PASS' Then cmdPASS Else
|
||||
If Cmd = 'RETR' Then cmdRETR Else
|
||||
If Cmd = 'RSET' Then cmdRSET Else
|
||||
If Cmd = 'STAT' Then cmdSTAT Else
|
||||
// If Cmd = 'TOP' Then cmdTOP Else
|
||||
If Cmd = 'UIDL' Then cmdUIDL Else
|
||||
If Cmd = 'USER' Then cmdUSER Else
|
||||
If Cmd = 'QUIT' Then Begin
|
||||
GotQuit := True;
|
||||
Break;
|
||||
End Else
|
||||
Client.WriteLine(re_UnknownCommand);
|
||||
Until Terminated;
|
||||
|
||||
If GotQuit Then Begin
|
||||
Client.WriteLine(re_Goodbye);
|
||||
|
||||
Server.Server.Status (User.Handle + ' logged out');
|
||||
|
||||
DeleteMessages;
|
||||
End;
|
||||
End;
|
||||
|
||||
Destructor TPOP3Server.Destroy;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,329 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Client_SMTP;
|
||||
|
||||
{ update e-mails post stats }
|
||||
{ update bbs history }
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
Classes,
|
||||
SysUtils,
|
||||
m_Strings,
|
||||
m_FileIO,
|
||||
m_Socket_Class,
|
||||
m_DateTime,
|
||||
bbs_MsgBase_ABS,
|
||||
bbs_MsgBase_JAM,
|
||||
bbs_MsgBase_Squish,
|
||||
MIS_Server,
|
||||
MIS_NodeData,
|
||||
MIS_Common;
|
||||
|
||||
Function CreateSMTP (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
|
||||
Type
|
||||
TSMTPServer = Class(TServerClient)
|
||||
Server : TServerManager;
|
||||
User : RecUser;
|
||||
UserPos : LongInt;
|
||||
Cmd : String;
|
||||
Data : String;
|
||||
EndSession : Boolean;
|
||||
FromName : String;
|
||||
FromPos : LongInt;
|
||||
ToList : TStringList;
|
||||
|
||||
Constructor Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Procedure Execute; Override;
|
||||
Destructor Destroy; Override;
|
||||
|
||||
Procedure ResetSession;
|
||||
Function ValidateNameAndDomain (IsFrom: Boolean) : Boolean;
|
||||
|
||||
Procedure cmdHELO;
|
||||
Procedure cmdRSET;
|
||||
Procedure cmdMAIL;
|
||||
Procedure cmdRCPT;
|
||||
Procedure cmdDATA;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Const
|
||||
SMTPTimeOut = 120; { MCFG }
|
||||
SMTPHackThresh = 10000;
|
||||
|
||||
re_Goodbye = '221 Goodbye';
|
||||
re_UnknownCmd = '502 Unknown command';
|
||||
re_OK = '250 OK';
|
||||
re_BadUser = '550 No such user here';
|
||||
re_NeedMail = '503 Must send MAIL FROM: first';
|
||||
re_NeedRcpt = '503 Must send RCPT TO: first';
|
||||
re_ErrorSending = '550 Mailbox not found';
|
||||
|
||||
Function CreateSMTP (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
Begin
|
||||
Result := TSMTPServer.Create(Owner, CliSock);
|
||||
End;
|
||||
|
||||
Constructor TSMTPServer.Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Begin
|
||||
Inherited Create(Owner, CliSock);
|
||||
|
||||
Server := Owner;
|
||||
End;
|
||||
|
||||
Function TSMTPServer.ValidateNameAndDomain (IsFrom: Boolean) : Boolean;
|
||||
Var
|
||||
InName : String;
|
||||
InDomain : String;
|
||||
Begin
|
||||
Result := False;
|
||||
|
||||
InName := strReplace(Copy(Data, Pos('<', Data) + 1, Pos('@', Data) - Pos('<', Data) - 1), '_', ' ');
|
||||
InDomain := Copy(Data, Pos('@', Data) + 1, Pos('>', Data) - Pos('@', Data) - 1);
|
||||
|
||||
If IsFrom Then
|
||||
Server.Server.Status('User: ' + InName + ' Domain: ' + InDomain);
|
||||
|
||||
If InDomain <> bbsConfig.iNetDomain Then Begin
|
||||
Server.Server.Status('Refused by domain: ' + InName + '@' + InDomain);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Result := SearchForUser(InName, User, UserPos);
|
||||
|
||||
If Not Result Then
|
||||
Server.Server.Status('Refused by name: ' + InName + '@' + InDomain);
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.ResetSession;
|
||||
Begin
|
||||
UserPos := -1;
|
||||
FromName := '';
|
||||
FromPos := -1;
|
||||
EndSession := False;
|
||||
|
||||
If Assigned(ToList) Then ToList.Free;
|
||||
|
||||
ToList := TStringList.Create;
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.cmdHELO;
|
||||
Begin
|
||||
Client.WriteLine('250 ' + bbsConfig.inetDomain);
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.cmdRSET;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
Client.WriteLine(re_OK);
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.cmdMAIL;
|
||||
Begin
|
||||
If ValidateNameAndDomain(True) Then Begin
|
||||
FromName := User.Handle;
|
||||
|
||||
Client.WriteLine (re_OK)
|
||||
End Else
|
||||
Client.WriteLine (re_BadUser);
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.cmdRCPT;
|
||||
Begin
|
||||
If FromName = '' Then Begin
|
||||
Client.WriteLine (re_NeedMail);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If ValidateNameAndDomain(False) Then Begin
|
||||
ToList.Add(User.Handle);
|
||||
|
||||
Client.WriteLine (re_OK);
|
||||
End Else
|
||||
Client.WriteLine (re_BadUser);
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.cmdDATA;
|
||||
Var
|
||||
InData : String;
|
||||
HackCount : LongInt;
|
||||
MBaseFile : File of MBaseRec;
|
||||
MBase : MBaseRec;
|
||||
MsgBase : PMsgBaseABS;
|
||||
MsgText : TStringList;
|
||||
MsgSubject : String;
|
||||
MsgLoop : LongInt;
|
||||
Count : LongInt;
|
||||
Count2 : LongInt;
|
||||
Str : String;
|
||||
Begin
|
||||
If FromName = '' Then Begin
|
||||
Client.WriteLine (re_NeedMail);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
If ToList.Count = 0 Then Begin
|
||||
Client.WriteLine (re_NeedRcpt);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Client.WriteLine ('354 Start mail input; end with <CRLF>.<CRLF>');
|
||||
|
||||
MsgText := TStringList.Create;
|
||||
|
||||
Repeat
|
||||
Client.ReadLine(InData);
|
||||
|
||||
If InData = '.' Then Break;
|
||||
|
||||
If MsgText.Count >= mysMaxMsgLines Then Begin
|
||||
HackCount := 0;
|
||||
|
||||
While Not Terminated And (InData <> '.') Do Begin
|
||||
// todo: what happens if they never send an EOL... could still flood
|
||||
|
||||
Client.ReadLine(InData);
|
||||
Inc (HackCount);
|
||||
|
||||
If HackCount >= SMTPHackThresh Then Begin
|
||||
EndSession := True; // someone is being a douchebag
|
||||
Server.Server.Status('Flood attempt from ' + FromName + ' (' + Client.PeerIP + '); Goodbye');
|
||||
MsgText.Free;
|
||||
Exit;
|
||||
End;
|
||||
End;
|
||||
|
||||
Break;
|
||||
End;
|
||||
|
||||
MsgText.Add(InData);
|
||||
Until False;
|
||||
|
||||
Assign (MBaseFile, bbsConfig.DataPath + 'mbases.dat');
|
||||
ioReset (MBaseFile, SizeOf(MBaseRec), fmRWDN);
|
||||
ioRead (MBaseFile, MBase);
|
||||
Close (MBaseFile);
|
||||
|
||||
Case MBase.BaseType of
|
||||
0 : MsgBase := New(PMsgBaseJAM, Init);
|
||||
1 : MsgBase := New(PMsgBaseSquish, Init);
|
||||
End;
|
||||
|
||||
MsgBase^.SetMsgPath (MBase.Path + MBase.FileName);
|
||||
|
||||
If Not MsgBase^.OpenMsgBase Then
|
||||
If Not MsgBase^.CreateMsgBase (MBase.MaxMsgs, MBase.MaxAge) Then Begin
|
||||
Dispose(MsgBase, Done);
|
||||
MsgText.Free;
|
||||
Client.WriteLine(re_ErrorSending);
|
||||
Exit;
|
||||
End Else
|
||||
If Not MsgBase^.OpenMsgBase Then Begin
|
||||
Dispose(MsgBase, Done);
|
||||
MsgText.Free;
|
||||
Client.WriteLine(re_ErrorSending);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
MsgSubject := '';
|
||||
Count := 0;
|
||||
|
||||
While Count < MsgText.Count Do Begin
|
||||
If Pos('Subject:', MsgText.Strings[Count]) > 0 Then
|
||||
MsgSubject := Copy(MsgText.Strings[Count], 10, Length(MsgText.Strings[Count]))
|
||||
Else
|
||||
If MsgText.Strings[Count] = '' Then Begin
|
||||
While (MsgText.Strings[Count] = '') And (Count < MsgText.Count) Do Inc(Count);
|
||||
Break;
|
||||
End;
|
||||
|
||||
Inc (Count);
|
||||
End;
|
||||
|
||||
If Count = MsgText.Count Then Begin
|
||||
Client.WriteLine(re_ErrorSending);
|
||||
MsgText.Free;
|
||||
Exit;
|
||||
End;
|
||||
|
||||
For MsgLoop := 0 To ToList.Count - 1 Do Begin
|
||||
Server.Server.Status('Sending mail from ' + FromName + ' to ' + ToList.Strings[MsgLoop]);
|
||||
|
||||
MsgBase^.StartNewMsg;
|
||||
|
||||
MsgBase^.SetLocal (True);
|
||||
MsgBase^.SetMailType (mmtNormal);
|
||||
MsgBase^.SetPriv (True);
|
||||
MsgBase^.SetDate (FormatDateTime('mm/dd/yy', Now));
|
||||
MsgBase^.SetTime (FormatDateTime('hh:nn', Now));
|
||||
MsgBase^.SetFrom (FromName);
|
||||
MsgBase^.SetTo (ToList.Strings[MsgLoop]);
|
||||
MsgBase^.SetSubj (MsgSubject);
|
||||
|
||||
For Count2 := Count to MsgText.Count - 1 Do Begin
|
||||
Str := MsgText.Strings[Count2];
|
||||
|
||||
If Length(Str) > 79 Then Str[0] := #79;
|
||||
|
||||
MsgBase^.DoStringLn(Str);
|
||||
End;
|
||||
|
||||
MsgBase^.WriteMsg;
|
||||
End;
|
||||
|
||||
MsgBase^.CloseMsgBase;
|
||||
|
||||
Dispose (MsgBase, Done);
|
||||
|
||||
Client.WriteLine(re_OK);
|
||||
End;
|
||||
|
||||
Procedure TSMTPServer.Execute;
|
||||
Var
|
||||
Str : String;
|
||||
Begin
|
||||
ResetSession;
|
||||
|
||||
Client.WriteLine('220 ' + bbsConfig.iNetDomain + ' Mystic SMTP Ready');
|
||||
|
||||
Repeat
|
||||
If Client.WaitForData(SMTPTimeOut * 1000) = 0 Then Break;
|
||||
|
||||
If Terminated Then Exit;
|
||||
|
||||
If Client.ReadLine(Str) = -1 Then Exit;
|
||||
|
||||
Cmd := strUpper(strWordGet(1, Str, ' '));
|
||||
|
||||
If Pos(' ', Str) > 0 Then
|
||||
Data := strStripB(Copy(Str, Pos(' ', Str) + 1, Length(Str)), ' ')
|
||||
Else
|
||||
Data := '';
|
||||
|
||||
If Cmd = 'DATA' Then cmdDATA Else
|
||||
If Cmd = 'EHLO' Then cmdHELO Else
|
||||
If Cmd = 'HELO' Then cmdHELO Else
|
||||
If Cmd = 'MAIL' Then cmdMAIL Else
|
||||
If Cmd = 'NOOP' Then Client.WriteLine(re_OK) Else
|
||||
If Cmd = 'RCPT' Then cmdRCPT Else
|
||||
If Cmd = 'RSET' Then cmdRSET Else
|
||||
If Cmd = 'QUIT' Then Break Else
|
||||
Client.WriteLine(re_UnknownCmd);
|
||||
Until Terminated or EndSession;
|
||||
|
||||
If Not Terminated And Not EndSession Then Client.WriteLine(re_Goodbye);
|
||||
End;
|
||||
|
||||
Destructor TSMTPServer.Destroy;
|
||||
Begin
|
||||
If Assigned(ToList) Then ToList.Free;
|
||||
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,135 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Client_Telnet;
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
{$IFDEF UNIX}
|
||||
Unix,
|
||||
{$ENDIF}
|
||||
{$IFDEF WIN32}
|
||||
Windows,
|
||||
{$ENDIF}
|
||||
m_Strings,
|
||||
m_Socket_Class,
|
||||
MIS_Common,
|
||||
MIS_NodeData,
|
||||
MIS_Server;
|
||||
|
||||
Function CreateTelnet (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
{ must match server create or there will be access violations }
|
||||
|
||||
Type
|
||||
TTelnetServer = Class(TServerClient)
|
||||
ND : TNodeData;
|
||||
Constructor Create (Owner: TServerManager; ND: TNodeData; CliSock: TSocketClass);
|
||||
Procedure Execute; Override;
|
||||
Destructor Destroy; Override;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Function CreateTelnet (Owner: TServerManager; Config: RecConfig; ND: TNodeData; CliSock: TSocketClass) : TServerClient;
|
||||
Begin
|
||||
Result := TTelnetServer.Create(Owner, ND, CliSock);
|
||||
End;
|
||||
|
||||
Constructor TTelnetServer.Create (Owner: TServerManager; ND: TNodeData; CliSock: TSocketClass);
|
||||
Begin
|
||||
Inherited Create(Owner, CliSock);
|
||||
|
||||
Self.ND := ND;
|
||||
End;
|
||||
|
||||
{$IFDEF WIN32}
|
||||
Procedure TTelnetServer.Execute;
|
||||
Var
|
||||
Cmd : String;
|
||||
SI : TStartupInfo;
|
||||
PI : TProcessInformation;
|
||||
Num : LongInt;
|
||||
NI : TNodeInfoRec;
|
||||
PassHandle : LongInt;
|
||||
Begin
|
||||
If Not DuplicateHandle (
|
||||
GetCurrentProcess,
|
||||
Client.FSocketHandle,
|
||||
GetCurrentProcess,
|
||||
@PassHandle,
|
||||
0,
|
||||
TRUE,
|
||||
DUPLICATE_SAME_ACCESS) Then Exit;
|
||||
|
||||
Num := ND.GetFreeNode;
|
||||
Cmd := 'mystic.exe -n' + strI2S(Num) + ' -TID' + strI2S(PassHandle) + ' -IP' + Client.FPeerIP + ' -HOST' + Client.FPeerName + #0;
|
||||
|
||||
FillChar(NI, SizeOf(NI), 0);
|
||||
|
||||
NI.Num := Num;
|
||||
NI.Busy := True;
|
||||
NI.IP := Client.FPeerIP;
|
||||
NI.User := 'Unknown';
|
||||
NI.Action := 'Logging In';
|
||||
|
||||
ND.SetNodeInfo(Num, NI);
|
||||
|
||||
FillChar(SI, SizeOf(SI), 0);
|
||||
FillChar(PI, SizeOf(PI), 0);
|
||||
|
||||
SI.dwFlags := STARTF_USESHOWWINDOW;
|
||||
SI.wShowWindow := SW_SHOWMINNOACTIVE;
|
||||
|
||||
If CreateProcess(NIL, PChar(@Cmd[1]),
|
||||
NIL, NIL, True, create_new_console + normal_priority_class, NIL, NIL, SI, PI) Then
|
||||
WaitForSingleObject (PI.hProcess, INFINITE);
|
||||
|
||||
NI.Busy := False;
|
||||
NI.IP := '';
|
||||
NI.User := '';
|
||||
NI.Action := '';
|
||||
|
||||
ND.SetNodeInfo(Num, NI);
|
||||
End;
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF UNIX}
|
||||
Procedure TTelnetServer.Execute;
|
||||
Var
|
||||
Cmd : String;
|
||||
Num : LongInt;
|
||||
NI : TNodeInfoRec;
|
||||
PassHandle : LongInt;
|
||||
Begin
|
||||
PassHandle := Client.FSocketHandle;
|
||||
|
||||
Num := ND.GetFreeNode;
|
||||
Cmd := './mystic -n' + strI2S(Num) + ' -TID' + strI2S(PassHandle) + ' -UID' + Client.FPeerIP;
|
||||
|
||||
FillChar(NI, SizeOf(NI), 0);
|
||||
|
||||
NI.Num := Num;
|
||||
NI.Busy := True;
|
||||
NI.IP := Client.FPeerIP;
|
||||
NI.User := 'Unknown';
|
||||
NI.Action := 'Logging In';
|
||||
|
||||
ND.SetNodeInfo(Num, NI);
|
||||
|
||||
fpSystem(Cmd);
|
||||
|
||||
NI.Busy := False;
|
||||
NI.IP := '';
|
||||
NI.User := '';
|
||||
NI.Action := '';
|
||||
|
||||
ND.SetNodeInfo(Num, NI);
|
||||
End;
|
||||
{$ENDIF}
|
||||
|
||||
Destructor TTelnetServer.Destroy;
|
||||
Begin
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,241 @@
|
|||
Unit MIS_Common;
|
||||
|
||||
{$I M_OPS.PAS}
|
||||
|
||||
Interface
|
||||
|
||||
{$I RECORDS.PAS}
|
||||
|
||||
Var
|
||||
bbsConfig : RecConfig;
|
||||
|
||||
Function SearchForUser (UN: String; Var Rec: RecUser; Var RecPos: LongInt) : Boolean;
|
||||
Function CheckAccess (User: RecUser; IgnoreGroup: Boolean; Str: String) : Boolean;
|
||||
Function WildcardMatch (Wildcard, FName: String) : Boolean;
|
||||
Function GetSecurityLevel (Level: Byte; SecLevel: RecSecurity) : Boolean;
|
||||
|
||||
Implementation
|
||||
|
||||
Uses
|
||||
m_FileIO,
|
||||
m_DateTime,
|
||||
m_Strings;
|
||||
|
||||
Function SearchForUser (UN: String; Var Rec: RecUser; Var RecPos: LongInt) : Boolean;
|
||||
Var
|
||||
UserFile : TBufFile;
|
||||
Begin
|
||||
Result := False;
|
||||
UN := strUpper(UN);
|
||||
|
||||
If UN = '' Then Exit;
|
||||
|
||||
UserFile := TBufFile.Create(4096);
|
||||
|
||||
If UserFile.Open(bbsConfig.DataPath + 'users.dat', fmOpen, fmRWDN, SizeOf(RecUser)) Then
|
||||
While Not UserFile.EOF Do Begin
|
||||
UserFile.Read(Rec);
|
||||
|
||||
If Rec.Flags AND UserDeleted <> 0 Then Continue;
|
||||
|
||||
If (UN = strUpper(Rec.RealName)) or (UN = strUpper(Rec.Handle)) Then Begin
|
||||
RecPos := UserFile.FilePos;
|
||||
Result := True;
|
||||
Break;
|
||||
End;
|
||||
End;
|
||||
|
||||
UserFile.Free;
|
||||
End;
|
||||
|
||||
Function CheckAccess (User: RecUser; IgnoreGroup: Boolean; Str: String) : Boolean;
|
||||
Const
|
||||
OpCmds = ['%', '^', '(', ')', '&', '!', '|'];
|
||||
AcsCmds = ['A', 'D', 'E', 'F', 'G', 'H', 'M', 'N', 'O', 'S', 'T', 'U', 'W', 'Z'];
|
||||
Var
|
||||
Key : Char;
|
||||
Data : String;
|
||||
Check : Boolean;
|
||||
Out : String;
|
||||
First : Boolean;
|
||||
|
||||
Procedure CheckCommand;
|
||||
Var
|
||||
Res : Boolean;
|
||||
Temp1 : LongInt;
|
||||
Temp2 : LongInt;
|
||||
Begin
|
||||
Res := False;
|
||||
|
||||
Case Key of
|
||||
'A' : Res := True;
|
||||
'D' : Res := (Ord(Data[1]) - 64) in User.AF2;
|
||||
'E' : Case Data[1] of
|
||||
'1' : Res := True;
|
||||
'0' : Res := True;
|
||||
End;
|
||||
'F' : Res := (Ord(Data[1]) - 64) in User.AF1;
|
||||
'G' : If IgnoreGroup Then Begin
|
||||
First := True;
|
||||
Check := False;
|
||||
Data := '';
|
||||
Exit;
|
||||
End Else
|
||||
Res := User.LastMGroup = strS2I(Data);
|
||||
'H' : Res := strS2I(Data) < strS2I(Copy(TimeDos2Str(CurDateDos, False), 1, 2));
|
||||
'M' : Res := strS2I(Data) < strS2I(Copy(TimeDos2Str(CurDateDos, False), 4, 2));
|
||||
'N' : Res := True;
|
||||
'O' : Case Data[1] of
|
||||
'A' : Res := True;
|
||||
'I' : Res := True;
|
||||
'K' : Res := True;
|
||||
'P' : If (User.Calls > 0) And (User.Flags AND UserNoRatio = 0) Then Begin
|
||||
//Temp1 := Round(Security.PCRatio / 100 * 100);
|
||||
//Temp2 := Round(User.ThisUser.Posts / User.ThisUser.Calls * 100);
|
||||
//Res := (Temp2 >= Temp1);
|
||||
Res := True;
|
||||
End Else
|
||||
Res := True;
|
||||
End;
|
||||
'S' : Res := User.Security >= strS2I(Data);
|
||||
'T' : Res := True;
|
||||
'U' : Res := User.PermIdx = strS2I(Data);
|
||||
'W' : Res := strS2I(Data) = m_DateTime.DayOfWeek;
|
||||
'Z' : If IgnoreGroup Then Begin
|
||||
Check := False;
|
||||
First := True;
|
||||
Data := '';
|
||||
Exit;
|
||||
End Else
|
||||
Res := strS2I(Data) = User.LastFGroup;
|
||||
End;
|
||||
|
||||
If Res Then Out := Out + '^' Else Out := Out + '%';
|
||||
|
||||
Check := False;
|
||||
First := True;
|
||||
Data := '';
|
||||
End;
|
||||
|
||||
Var
|
||||
A : Byte;
|
||||
Paran1 : Byte;
|
||||
Paran2 : Byte;
|
||||
Ch1 : Char;
|
||||
Ch2 : Char;
|
||||
S1 : String;
|
||||
S2 : String;
|
||||
Begin
|
||||
Data := '';
|
||||
Out := '';
|
||||
Check := False;
|
||||
Str := strUpper(Str);
|
||||
First := True;
|
||||
|
||||
For A := 1 to Length(Str) Do
|
||||
If Str[A] in OpCmds Then Begin
|
||||
If Check Then CheckCommand;
|
||||
Out := Out + Str[A];
|
||||
End Else
|
||||
If (Str[A] in AcsCmds) and (First or Check) Then Begin
|
||||
If Check Then CheckCommand;
|
||||
Key := Str[A];
|
||||
If First Then First := False;
|
||||
End Else Begin
|
||||
Data := Data + Str[A];
|
||||
Check := True;
|
||||
If A = Length(Str) Then CheckCommand;
|
||||
End;
|
||||
|
||||
Out := '(' + Out + ')';
|
||||
|
||||
While Pos('&', Out) <> 0 Do Delete (Out, Pos('&', Out), 1);
|
||||
|
||||
While Pos('(', Out) <> 0 Do Begin
|
||||
Paran2 := 1;
|
||||
While ((Out[Paran2] <> ')') And (Paran2 <= Length(Out))) Do Begin
|
||||
If (Out[Paran2] = '(') Then Paran1 := Paran2;
|
||||
Inc (Paran2);
|
||||
End;
|
||||
|
||||
S1 := Copy(Out, Paran1 + 1, (Paran2 - Paran1) - 1);
|
||||
|
||||
While Pos('!', S1) <> 0 Do Begin
|
||||
A := Pos('!', S1) + 1;
|
||||
If S1[A] = '^' Then S1[A] := '%' Else
|
||||
If S1[A] = '%' Then S1[A] := '^';
|
||||
Delete (S1, A - 1, 1);
|
||||
End;
|
||||
|
||||
While Pos('|', S1) <> 0 Do Begin
|
||||
A := Pos('|', S1) - 1;
|
||||
Ch1 := S1[A];
|
||||
Ch2 := S1[A + 2];
|
||||
|
||||
If (Ch1 in ['%', '^']) and (Ch2 in ['%', '^']) Then Begin
|
||||
Delete (S1, A, 3);
|
||||
If (Ch1 = '^') or (Ch2 = '^') Then
|
||||
Insert ('^', S1, A)
|
||||
Else
|
||||
Insert ('%', S1, A)
|
||||
End Else
|
||||
Delete (S1, A + 1, 1);
|
||||
End;
|
||||
|
||||
While Pos('%%', S1) <> 0 Do Delete (S1, Pos('%%', S1), 1);
|
||||
While Pos('^^', S1) <> 0 Do Delete (S1, Pos('^^', S1), 1);
|
||||
While Pos('%^', S1) <> 0 Do Delete (S1, Pos('%^', S1) + 1, 1);
|
||||
While Pos('^%', S1) <> 0 Do Delete (S1, Pos('^%', S1), 1);
|
||||
|
||||
Delete (Out, Paran1, (Paran2 - Paran1) + 1);
|
||||
Insert (S1, Out, Paran1);
|
||||
End;
|
||||
|
||||
Result := Pos('%', Out) = 0;
|
||||
End;
|
||||
|
||||
Function WildcardMatch (Wildcard, FName: String) : Boolean;
|
||||
Begin
|
||||
Result := False;
|
||||
|
||||
If FName = '' Then Exit;
|
||||
|
||||
Case Wildcard[1] of
|
||||
'*' : Begin
|
||||
If FName[1] = '.' Then Exit;
|
||||
If Length(Wildcard) = 1 Then Result := True;
|
||||
If (Length(Wildcard) > 1) and (Wildcard[2] = '.') and (Length(FName) > 0) Then
|
||||
Result := WildCardMatch(Copy(Wildcard, 3, Length(Wildcard) - 2), Copy(FName, Pos('.', FName) + 1, Length(FName)-Pos('.', FName)));
|
||||
End;
|
||||
'?' : If Ord(Wildcard[0]) = 1 Then
|
||||
Result := True
|
||||
Else
|
||||
Result := WildCardMatch(Copy(Wildcard, 2, Length(Wildcard) - 1), Copy(FName, 2, Length(FName) - 1));
|
||||
Else
|
||||
If FName[1] = Wildcard[1] Then
|
||||
If Length(wildcard) > 1 Then
|
||||
Result := WildCardMatch(Copy(Wildcard, 2, Length(Wildcard) - 1), Copy(FName, 2, Length(FName) - 1))
|
||||
Else
|
||||
Result := (Length(FName) = 1) And (Length(Wildcard) = 1);
|
||||
End;
|
||||
End;
|
||||
|
||||
Function GetSecurityLevel (Level: Byte; SecLevel: RecSecurity) : Boolean;
|
||||
Var
|
||||
SecLevelFile : File of RecSecurity;
|
||||
Begin
|
||||
Result := False;
|
||||
|
||||
Assign (SecLevelFile, bbsConfig.DataPath + 'security.dat');
|
||||
|
||||
If Not ioReset (SecLevelFile, SizeOf(SecLevel), fmRWDN) Then Exit;
|
||||
|
||||
ioSeek (SecLevelFile, Level - 1);
|
||||
ioRead (SecLevelFile, SecLevel);
|
||||
Close (SecLevelFile);
|
||||
|
||||
Result := True;
|
||||
End;
|
||||
|
||||
|
||||
End.
|
|
@ -0,0 +1,115 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_NodeData;
|
||||
|
||||
// annoying node data class used until we fuse MIS and Mystic together
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
MIS_Common;
|
||||
|
||||
Type
|
||||
TNodeInfoRec = Record
|
||||
Num : Byte;
|
||||
Busy : Boolean;
|
||||
User : String;
|
||||
Action : String;
|
||||
IP : String;
|
||||
End;
|
||||
|
||||
TNodeData = Class
|
||||
NodeInfo : Array[1..199] of TNodeInfoRec;
|
||||
NodeTotal : Byte;
|
||||
Critical : TRTLCriticalSection;
|
||||
|
||||
Constructor Create (Nodes: Byte);
|
||||
Destructor Destroy; Override;
|
||||
Function GetNodeTotal : LongInt;
|
||||
Function GetNodeInfo (Num: Byte; Var NI: TNodeInfoRec): Boolean;
|
||||
Procedure SetNodeInfo (Num: Byte; NI: TNodeInfoRec);
|
||||
Function GetFreeNode : LongInt;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Uses
|
||||
m_FileIO,
|
||||
m_Strings;
|
||||
|
||||
Function TNodeData.GetFreeNode : LongInt;
|
||||
Var
|
||||
Count : LongInt;
|
||||
Begin
|
||||
EnterCriticalSection(Critical);
|
||||
|
||||
Result := -1;
|
||||
|
||||
For Count := 1 to NodeTotal Do
|
||||
If Not NodeInfo[Count].Busy Then Begin
|
||||
NodeInfo[Count].Busy := True;
|
||||
Result := NodeInfo[Count].Num;
|
||||
Break;
|
||||
End;
|
||||
|
||||
LeaveCriticalSection(Critical);
|
||||
End;
|
||||
|
||||
Function TNodeData.GetNodeInfo (Num: Byte; Var NI: TNodeInfoRec) : Boolean;
|
||||
Begin
|
||||
EnterCriticalSection(Critical);
|
||||
|
||||
Result := False;
|
||||
|
||||
FillChar(NI, SizeOf(NI), 0);
|
||||
|
||||
If Num <= NodeTotal Then Begin
|
||||
NI := NodeInfo[Num];
|
||||
Result := True;
|
||||
End;
|
||||
|
||||
LeaveCriticalSection(Critical);
|
||||
End;
|
||||
|
||||
Procedure TNodeData.SetNodeInfo (Num: Byte; NI: TNodeInfoRec);
|
||||
Var
|
||||
Count : LongInt;
|
||||
Begin
|
||||
EnterCriticalSection(Critical);
|
||||
|
||||
For Count := 1 to NodeTotal Do
|
||||
If NodeInfo[Count].Num = Num Then
|
||||
NodeInfo[Count] := NI;
|
||||
|
||||
LeaveCriticalSection(Critical);
|
||||
End;
|
||||
|
||||
Function TNodeData.GetNodeTotal : LongInt;
|
||||
Begin
|
||||
EnterCriticalSection(Critical);
|
||||
|
||||
Result := NodeTotal;
|
||||
|
||||
LeaveCriticalSection(Critical);
|
||||
End;
|
||||
|
||||
Constructor TNodeData.Create (Nodes: Byte);
|
||||
Var
|
||||
Count : SmallInt;
|
||||
Begin
|
||||
InitCriticalSection(Critical);
|
||||
|
||||
NodeTotal := Nodes;
|
||||
|
||||
For Count := 1 to NodeTotal Do
|
||||
NodeInfo[Count].Num := Count;
|
||||
End;
|
||||
|
||||
Destructor TNodeData.Destroy;
|
||||
Begin
|
||||
DoneCriticalSection(Critical);
|
||||
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,262 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MIS_Server;
|
||||
|
||||
Interface
|
||||
|
||||
Uses
|
||||
Classes,
|
||||
m_Socket_Class,
|
||||
MIS_Common,
|
||||
MIS_NodeData;
|
||||
|
||||
Type
|
||||
TServerManager = Class;
|
||||
TServerClient = Class;
|
||||
TServerCreateProc = Function (Manager: TServerManager; Config: RecConfig; ND: TNodeData; Client: TSocketClass): TServerClient;
|
||||
|
||||
TServerManager = Class(TThread)
|
||||
NodeInfo : TNodeData;
|
||||
Server : TSocketClass;
|
||||
ClientList : TList;
|
||||
NewClientProc : TServerCreateProc;
|
||||
Config : RecConfig;
|
||||
ClientMax : LongInt;
|
||||
ClientMaxIPs : LongInt;
|
||||
ClientRefused : LongInt;
|
||||
ClientBlocked : LongInt;
|
||||
ClientTotal : LongInt;
|
||||
ClientActive : LongInt;
|
||||
Port : LongInt;
|
||||
TextPath : String[80];
|
||||
|
||||
Constructor Create (Config: RecConfig; PortNum: Word; CliMax: Word; ND: TNodeData; CreateProc: TServerCreateProc);
|
||||
Destructor Destroy; Override;
|
||||
Procedure Execute; Override;
|
||||
Function CheckIP (IP, Mask: String) : Boolean;
|
||||
Function IsBlockedIP (Var Client: TSocketClass) : Boolean;
|
||||
Function DuplicateIPs (Var Client: TSocketClass) : Byte;
|
||||
End;
|
||||
|
||||
TServerClient = Class(TThread)
|
||||
Client : TSocketClass;
|
||||
Manager : TServerManager;
|
||||
|
||||
Constructor Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Destructor Destroy; Override;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Uses
|
||||
m_Strings,
|
||||
m_DateTime;
|
||||
|
||||
Constructor TServerManager.Create (Config: RecConfig; PortNum: Word; CliMax: Word; ND: TNodeData; CreateProc: TServerCreateProc);
|
||||
Var
|
||||
Count : Byte;
|
||||
Begin
|
||||
Inherited Create(False);
|
||||
|
||||
Port := PortNum;
|
||||
ClientMax := CliMax;
|
||||
ClientRefused := 0;
|
||||
ClientBlocked := 0;
|
||||
ClientTotal := 0;
|
||||
ClientActive := 0;
|
||||
ClientMaxIPs := 1;
|
||||
NewClientProc := CreateProc;
|
||||
Server := TSocketClass.Create;
|
||||
ClientList := TList.Create;
|
||||
TextPath := Config.DataPath;
|
||||
NodeInfo := ND;
|
||||
Config := Config;
|
||||
|
||||
For Count := 1 to ClientMax Do
|
||||
ClientList.Add(NIL);
|
||||
|
||||
FreeOnTerminate := False;
|
||||
End;
|
||||
|
||||
Function TServerManager.CheckIP (IP, Mask: String) : Boolean;
|
||||
Var
|
||||
A : Byte;
|
||||
Count : Byte;
|
||||
Str : String;
|
||||
Str2 : String;
|
||||
EndIt : Byte;
|
||||
Begin
|
||||
Result := True;
|
||||
|
||||
For Count := 1 to 4 Do Begin
|
||||
If Count < 4 Then Begin
|
||||
Str := Copy(IP, 1, Pos('.', IP) - 1);
|
||||
Str2 := Copy(Mask, 1, Pos('.', Mask) - 1);
|
||||
Delete (IP, 1, Pos('.', IP));
|
||||
Delete (Mask, 1, Pos('.', Mask));
|
||||
End Else Begin
|
||||
Str := Copy(IP, 1, Length(IP));
|
||||
Str2 := Copy(Mask, 1, Length(Mask));
|
||||
End;
|
||||
|
||||
For A := 1 to Length(Str) Do
|
||||
If Str2[A] = '*' Then
|
||||
Break
|
||||
Else
|
||||
If Str[A] <> Str2[A] Then Begin
|
||||
Result := False;
|
||||
Break;
|
||||
End;
|
||||
|
||||
If Not Result Then Break;
|
||||
End;
|
||||
End;
|
||||
|
||||
Function TServerManager.IsBlockedIP (Var Client: TSocketClass) : Boolean;
|
||||
Var
|
||||
TF : Text;
|
||||
Str : String;
|
||||
Begin
|
||||
Result := False;
|
||||
FileMode := 66;
|
||||
|
||||
Assign (TF, TextPath + 'badip.txt');
|
||||
Reset (TF);
|
||||
|
||||
If IoResult = 0 Then Begin
|
||||
While Not Eof(TF) Do Begin
|
||||
ReadLn (TF, Str);
|
||||
If CheckIP (Client.PeerIP, Str) Then Begin
|
||||
Result := True;
|
||||
Break;
|
||||
End;
|
||||
End;
|
||||
|
||||
Close (TF);
|
||||
End;
|
||||
End;
|
||||
|
||||
Function TServerManager.DuplicateIPs (Var Client: TSocketClass) : Byte;
|
||||
Var
|
||||
Count : Byte;
|
||||
Begin
|
||||
Result := 0;
|
||||
|
||||
For Count := 0 to ClientMax - 1 Do
|
||||
If ClientList[Count] <> NIL Then // use Assigned?
|
||||
If Client.PeerIP = TSocketClass(ClientList[Count]).PeerIP Then
|
||||
Inc(Result);
|
||||
End;
|
||||
|
||||
Procedure TServerManager.Execute;
|
||||
Var
|
||||
NewClient : TSocketClass;
|
||||
Begin
|
||||
Repeat Until Server <> NIL; // Synchronize with server class
|
||||
Repeat Until Server.SocketStatus <> NIL; // Syncronize with status class
|
||||
|
||||
Server.WaitInit(Port);
|
||||
|
||||
If Terminated Then Exit;
|
||||
|
||||
If ClientMax = 0 Then
|
||||
Server.Status('WARNING: At least one server is configured with 0 max clients.');
|
||||
|
||||
Server.Status('Opening server socket on port ' + strI2S(Port));
|
||||
|
||||
Repeat
|
||||
NewClient := Server.WaitConnection;
|
||||
|
||||
If NewClient = NIL Then Break; // time to shutdown the server...
|
||||
|
||||
If (ClientMax > 0) And (ClientActive >= ClientMax) Then Begin
|
||||
Inc (ClientRefused);
|
||||
Server.Status ('BUSY: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
|
||||
If Not NewClient.WriteFile(TextPath + 'busy.txt') Then NewClient.WriteLine('BUSY');
|
||||
NewClient.Free;
|
||||
End Else
|
||||
If IsBlockedIP(NewClient) Then Begin
|
||||
Inc (ClientBlocked);
|
||||
Server.Status('BLOCK: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
|
||||
If Not NewClient.WriteFile(TextPath + 'blocked.txt') Then NewClient.WriteLine('BLOCKED');
|
||||
NewClient.Free;
|
||||
End Else
|
||||
If (ClientMaxIPs > 0) and (DuplicateIPs(NewClient) > ClientMaxIPs) Then Begin
|
||||
Inc (ClientRefused);
|
||||
Server.Status('MULTI: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
|
||||
If Not NewClient.WriteFile(TextPath + 'dupeip.txt') Then NewClient.WriteLine('Only ' + strI2S(ClientMaxIPs) + ' connection(s) per user');
|
||||
NewClient.Free;
|
||||
End Else Begin
|
||||
Inc (ClientTotal);
|
||||
Inc (ClientActive);
|
||||
Server.Status ('Connect: ' + NewClient.PeerIP + ' (' + NewClient.PeerName + ')');
|
||||
|
||||
NewClientProc(Self, Config, NodeInfo, NewClient);
|
||||
End;
|
||||
Until Terminated;
|
||||
|
||||
Server.Status ('Shutting down server...');
|
||||
End;
|
||||
|
||||
Destructor TServerManager.Destroy;
|
||||
Var
|
||||
Count : LongInt;
|
||||
Angry : Byte;
|
||||
Begin
|
||||
Angry := 20; // about 5 seconds before we get mad at thread...
|
||||
|
||||
ClientList.Pack;
|
||||
|
||||
While (ClientList.Count > 0) and (Angry > 0) Do Begin
|
||||
For Count := 0 To ClientList.Count - 1 Do
|
||||
If ClientList[Count] <> NIL Then Begin
|
||||
TServerClient(ClientList[Count]).Client.Disconnect;
|
||||
TServerClient(ClientList[Count]).Terminate;
|
||||
End;
|
||||
|
||||
WaitMS(250);
|
||||
|
||||
Dec (Angry);
|
||||
|
||||
ClientList.Pack;
|
||||
End;
|
||||
|
||||
ClientList.Free;
|
||||
Server.Free;
|
||||
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
Constructor TServerClient.Create (Owner: TServerManager; CliSock: TSocketClass);
|
||||
Var
|
||||
Count : Byte;
|
||||
Begin
|
||||
Manager := Owner;
|
||||
Client := CliSock;
|
||||
|
||||
For Count := 0 to Manager.ClientMax - 1 Do
|
||||
If Manager.ClientList[Count] = NIL Then Begin
|
||||
Manager.ClientList[Count] := Self;
|
||||
Break;
|
||||
End;
|
||||
|
||||
Inherited Create(False);
|
||||
|
||||
FreeOnTerminate := True;
|
||||
End;
|
||||
|
||||
Destructor TServerClient.Destroy;
|
||||
Begin
|
||||
Client.Free;
|
||||
|
||||
Manager.ClientList[Manager.ClientList.IndexOf(Self)] := NIL;
|
||||
|
||||
If Manager.Server <> NIL Then
|
||||
Manager.Server.StatusUpdated := True;
|
||||
|
||||
Dec (Manager.ClientActive);
|
||||
|
||||
Inherited Destroy;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,305 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit mkcrap;
|
||||
|
||||
// this is various functions and procedures used by JAM/Squish...
|
||||
// these should be removed and/or incorporated into mystic's code base as
|
||||
// soon as possible.
|
||||
|
||||
// CHANGE JAM TEMP BUFFER.. ADD SETBUFFERFILE METHOD TO MSGBASE OBJECTS!!!!
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
dos;
|
||||
|
||||
Function ToUnixDate(FDate: LongInt): LongInt;
|
||||
Function DTToUnixDate(DT: DateTime): LongInt;
|
||||
Procedure UnixToDT(SecsPast: LongInt; Var Dt: DateTime);
|
||||
Function SaveFile(FN: String; Var Rec; FS: Word): Word;
|
||||
Procedure Str2Az(Str: String; MaxLen: Byte; Var AZStr); {Convert string to asciiz}
|
||||
Function FormattedDate(DT: DateTime; Mask: String): String;
|
||||
Function LoadFile(FN: String; Var Rec; FS: Word): Word;
|
||||
Function LoadFilePos(FN: String; Var Rec; FS: Word; FPos: LongInt): Word;
|
||||
Function GetFileSize (FN : String) : LongInt;
|
||||
Function ExtendFile(FN: String; ToSize: LongInt): Word;
|
||||
Function SaveFilePos(FN: String; Var Rec; FS: Word; FPos: LongInt): Word;
|
||||
|
||||
implementation
|
||||
|
||||
Uses
|
||||
m_FileIO,
|
||||
m_DateTime,
|
||||
m_Strings;
|
||||
|
||||
Const
|
||||
DATEC1970 = 2440588;
|
||||
// DATED0 = 1461;
|
||||
// DATED1 = 146097;
|
||||
// DATED2 = 1721119;
|
||||
|
||||
Function DTToUnixDate(DT: DateTime): LongInt;
|
||||
Var
|
||||
SecsPast, DaysPast: LongInt;
|
||||
Begin
|
||||
DateG2J (DT.Year, DT.Month, DT.Day, DaysPast);
|
||||
DaysPast := DaysPast - DATEc1970;
|
||||
SecsPast := DaysPast * 86400;
|
||||
SecsPast := SecsPast + (LongInt(DT.Hour) * 3600) + (DT.Min * 60) + (DT.Sec);
|
||||
DTToUnixDate := SecsPast;
|
||||
End;
|
||||
|
||||
Function ToUnixDate(FDate: LongInt): LongInt;
|
||||
Var
|
||||
DT: DateTime;
|
||||
Begin
|
||||
UnpackTime(Fdate, DT);
|
||||
ToUnixDate := DTToUnixDate(Dt);
|
||||
End;
|
||||
|
||||
Procedure UnixToDT(SecsPast: LongInt; Var Dt: DateTime);
|
||||
Var
|
||||
DateNum : LongInt; //might be able to remove this
|
||||
Begin
|
||||
Datenum := (SecsPast Div 86400) + DATEc1970;
|
||||
|
||||
FillChar(DT, SizeOf(DT), 0);
|
||||
|
||||
DateJ2G(DateNum, SmallInt(DT.Year), SmallInt(DT.Month), SmallInt(DT.Day));
|
||||
|
||||
SecsPast := SecsPast Mod 86400;
|
||||
DT.Hour := SecsPast Div 3600;
|
||||
SecsPast := SecsPast Mod 3600;
|
||||
DT.Min := SecsPast Div 60;
|
||||
DT.Sec := SecsPast Mod 60;
|
||||
End;
|
||||
|
||||
Function SaveFilePos(FN: String; Var Rec; FS: Word; FPos: LongInt): Word;
|
||||
Var
|
||||
F: File;
|
||||
Error: Word;
|
||||
temp:longint;
|
||||
Begin
|
||||
Error := 0;
|
||||
assign (f, fn);
|
||||
|
||||
FileMode := fmReadWrite + fmDenyNone;
|
||||
If FileExist(FN) Then Begin
|
||||
reset(f,1);
|
||||
if ioresult <> 0 then error := ioresult;
|
||||
End Else Begin
|
||||
ReWrite(F,1);
|
||||
Error := IoResult;
|
||||
End;
|
||||
If Error = 0 Then Begin
|
||||
Seek(F, FPos);
|
||||
Error := IoResult;
|
||||
End;
|
||||
If Error = 0 Then
|
||||
If FS > 0 Then Begin
|
||||
If Not ioBlockWrite(F, Rec, FS, Temp) Then Error := ioCode;
|
||||
End;
|
||||
If Error = 0 Then Begin
|
||||
Close(F);
|
||||
Error := IoResult;
|
||||
End;
|
||||
SaveFilePos := Error;
|
||||
End;
|
||||
|
||||
Function SaveFile(FN: String; Var Rec; FS: Word): Word;
|
||||
Begin
|
||||
SaveFile := SaveFilePos(FN, Rec, FS, 0);
|
||||
End;
|
||||
|
||||
|
||||
|
||||
Procedure Str2Az(Str: String; MaxLen: Byte; Var AZStr); {Convert string to asciiz}
|
||||
Begin
|
||||
If Length(Str) >= MaxLen Then
|
||||
Begin
|
||||
Str[MaxLen] := #0;
|
||||
Move(Str[1], AZStr, MaxLen);
|
||||
End
|
||||
Else
|
||||
Begin
|
||||
Str[Length(Str) + 1] := #0;
|
||||
Move(Str[1], AZStr, Length(Str) + 1);
|
||||
End;
|
||||
End;
|
||||
|
||||
Function MonthStr(MonthNo: Word): String;
|
||||
Begin
|
||||
Case MonthNo of
|
||||
01: MonthStr := 'Jan';
|
||||
02: MonthStr := 'Feb';
|
||||
03: MonthStr := 'Mar';
|
||||
04: MonthStr := 'Apr';
|
||||
05: MonthStr := 'May';
|
||||
06: MonthStr := 'Jun';
|
||||
07: MonthStr := 'Jul';
|
||||
08: MonthStr := 'Aug';
|
||||
09: MonthStr := 'Sep';
|
||||
10: MonthStr := 'Oct';
|
||||
11: MonthStr := 'Nov';
|
||||
12: MonthStr := 'Dec';
|
||||
Else
|
||||
MonthStr := '???';
|
||||
End;
|
||||
End;
|
||||
|
||||
|
||||
Function FormattedDate(DT: DateTime; Mask: String): String;
|
||||
Var
|
||||
DStr : String[2];
|
||||
MStr : String[2];
|
||||
MNStr : String[3];
|
||||
YStr : String[4];
|
||||
HourStr : String[2];
|
||||
MinStr : String[2];
|
||||
SecStr : String[2];
|
||||
TmpStr : String;
|
||||
CurrPos : Word;
|
||||
i : Word;
|
||||
Begin
|
||||
TmpStr := Mask;
|
||||
Mask := strUpper(Mask);
|
||||
DStr := Copy(strPadL(strI2S(Dt.Day), 2, '0'), 1, 2);
|
||||
MStr := Copy(strPadL(strI2S(Dt.Month), 2, '0'), 1, 2);
|
||||
YStr := Copy(strPadL(strI2S(Dt.Year), 4, '0'), 1, 4);
|
||||
HourStr := Copy(strPadL(strI2S(Dt.Hour), 2, ' '), 1, 2);
|
||||
MinStr := Copy(strPadL(strI2S(Dt.Min), 2, '0'), 1, 2);
|
||||
SecStr := Copy(strPadL(strI2S(Dt.Sec), 2, '0'), 1, 2);
|
||||
MNStr := MonthStr(Dt.Month);
|
||||
If (Pos('YYYY', Mask) = 0) Then YStr := Copy(YStr,3,2);
|
||||
CurrPos := Pos('DD', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(DStr) Do
|
||||
TmpStr[CurrPos + i - 1] := DStr[i];
|
||||
CurrPos := Pos('YY', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(YStr) Do
|
||||
TmpStr[CurrPos + i - 1] := YStr[i];
|
||||
CurrPos := Pos('MM', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(MStr) Do
|
||||
TmpStr[CurrPos + i - 1] := MStr[i];
|
||||
CurrPos := Pos('HH', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(HourStr) Do
|
||||
TmpStr[CurrPos + i - 1] := HourStr[i];
|
||||
CurrPos := Pos('SS', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(SecStr) Do
|
||||
TmpStr[CurrPos + i - 1] := SecStr[i];
|
||||
CurrPos := Pos('II', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(MinStr) Do
|
||||
TmpStr[CurrPos + i - 1] := MinStr[i];
|
||||
CurrPos := Pos('NNN', Mask);
|
||||
If CurrPos > 0 Then
|
||||
For i := 1 to Length(MNStr) Do
|
||||
TmpStr[CurrPos + i - 1] := MNStr[i];
|
||||
FormattedDate := TmpStr;
|
||||
End;
|
||||
|
||||
|
||||
Function LoadFilePos(FN: String; Var Rec; FS: Word; FPos: LongInt): Word;
|
||||
Var
|
||||
F: File;
|
||||
Error: Word;
|
||||
NumRead: LongInt;
|
||||
Begin
|
||||
Error := 0;
|
||||
If Not FileExist(FN) Then Error := 8888;
|
||||
If Error = 0 Then assign (f, fn);
|
||||
FileMode := fmReadWrite + fmDenyNone;
|
||||
reset (f, 1);
|
||||
error := ioresult;
|
||||
If Error = 0 Then Begin
|
||||
Seek(F, FPos);
|
||||
Error := IoResult;
|
||||
End;
|
||||
If Error = 0 Then
|
||||
If Not ioBlockRead(F, Rec, FS, NumRead) Then
|
||||
Error := ioCode;
|
||||
If Error = 0 Then
|
||||
Begin
|
||||
Close(F);
|
||||
Error := IoResult;
|
||||
End;
|
||||
LoadFilePos := Error;
|
||||
End;
|
||||
|
||||
Function LoadFile(FN: String; Var Rec; FS: Word): Word;
|
||||
Begin
|
||||
LoadFile := LoadFilePos(FN, Rec, FS, 0);
|
||||
End;
|
||||
|
||||
Function GetFileSize (FN : String) : LongInt;
|
||||
Var
|
||||
SR : SearchRec;
|
||||
Begin
|
||||
FindFirst (FN, AnyFile, SR);
|
||||
If DosError = 0 Then
|
||||
GetFileSize := SR.Size
|
||||
Else
|
||||
GetFileSize := -1;
|
||||
End;
|
||||
|
||||
Function ExtendFile(FN: String; ToSize: LongInt): Word;
|
||||
{Pads file with nulls to specified size}
|
||||
Type
|
||||
FillType = Array[1..8000] of Byte;
|
||||
|
||||
Var
|
||||
F: File;
|
||||
Error: Word;
|
||||
FillRec: ^FillType;
|
||||
temp:longint;
|
||||
|
||||
Begin
|
||||
Error := 0;
|
||||
New(FillRec);
|
||||
If FillRec = Nil Then
|
||||
Error := 10;
|
||||
If Error = 0 Then
|
||||
Begin
|
||||
FillChar(FillRec^, SizeOf(FillRec^), 0);
|
||||
Assign(F, FN);
|
||||
FileMode := fmReadWrite + fmDenyNone;
|
||||
If FileExist(FN) Then Begin
|
||||
reset(f,1);
|
||||
if ioresult <> 0 then error := ioresult;
|
||||
End
|
||||
Else
|
||||
Begin
|
||||
ReWrite(F,1);
|
||||
Error := IoResult;
|
||||
End;
|
||||
End;
|
||||
If Error = 0 Then
|
||||
Begin
|
||||
Seek(F, FileSize(F));
|
||||
Error := IoResult;
|
||||
End;
|
||||
If Error = 0 Then
|
||||
Begin
|
||||
While ((FileSize(F) < (ToSize - SizeOf(FillRec^))) and (Error = 0)) Do
|
||||
Begin
|
||||
If Not ioBlockWrite(F, FillRec^, SizeOf(FillRec^), Temp) Then
|
||||
Error := ioCode;
|
||||
End;
|
||||
End;
|
||||
If ((Error = 0) and (FileSize(F) < ToSize)) Then Begin
|
||||
If Not ioBlockWrite(F, FillRec^, ToSize - FileSize(F), temp) Then
|
||||
Error := ioCode;
|
||||
End;
|
||||
If Error = 0 Then Begin
|
||||
Close(F);
|
||||
Error := IoResult;
|
||||
End;
|
||||
Dispose(FillRec);
|
||||
ExtendFile := Error;
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,365 @@
|
|||
|
||||
Function cGetVarChar (T: TIdentTypes) : Char;
|
||||
Begin
|
||||
Case T of
|
||||
iString : Result := 's';
|
||||
iChar : Result := 'c';
|
||||
iByte : Result := 'b';
|
||||
iShort : Result := 'h';
|
||||
iWord : Result := 'w';
|
||||
iInteger : Result := 'i';
|
||||
iLongInt : Result := 'l';
|
||||
iReal : Result := 'r';
|
||||
iBool : Result := 'o';
|
||||
iFile : Result := 'f';
|
||||
iRecord : Result := 'x';
|
||||
Else
|
||||
Result := ' ';
|
||||
End;
|
||||
End;
|
||||
|
||||
Function cVarType (C: Char) : TIdentTypes;
|
||||
begin
|
||||
case UpCase(c) of
|
||||
'S' : cVarType := iString;
|
||||
'C' : cVarType := iChar;
|
||||
'B' : cVarType := iByte;
|
||||
'H' : cVarType := iShort;
|
||||
'W' : cVarType := iWord;
|
||||
'I' : cVarType := iInteger;
|
||||
'L' : cVarType := iLongInt;
|
||||
'R' : cVarType := iReal;
|
||||
'O' : cVarType := iBool;
|
||||
'F' : cVarType := iFile;
|
||||
'X' : cVarType := iRecord;
|
||||
else
|
||||
cVarType := iNone;
|
||||
end;
|
||||
end;
|
||||
|
||||
Function xVarSize (T: TIdentTypes) : Word;
|
||||
Begin
|
||||
Case T of
|
||||
iRecord,
|
||||
iNone : xVarSize := 0;
|
||||
iString : xVarSize := 256;
|
||||
iChar : xVarSize := 1;
|
||||
iByte : xVarSize := 1;
|
||||
iShort : xVarSize := 1;
|
||||
iWord : xVarSize := 2;
|
||||
iInteger : xVarSize := 2;
|
||||
iLongInt : xVarSize := 4;
|
||||
iReal : xVarSize := SizeOf(Real); // {$IFDEF FPC}8{$ELSE}6{$ENDIF};
|
||||
iBool : xVarSize := 1;
|
||||
iFile : xVarSize := SizeOf(File); // was 128;
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure InitProcedures (O: Pointer; S: Pointer; Var CV: VarDataRec; Var X: Word; Var IW: Word; Mode: Byte);
|
||||
|
||||
Procedure AddProc ({$IFDEF MPLPARSER} I: String; {$ENDIF} P: String; T: TIdentTypes);
|
||||
Begin
|
||||
Inc(X);
|
||||
New(CV[X]);
|
||||
|
||||
With CV[X]^ Do Begin
|
||||
VarID := IW;
|
||||
Inc(IW);
|
||||
vType := T;
|
||||
Move(P[1], Params, Ord(P[0]));
|
||||
NumParams := Ord(p[0]);
|
||||
{$IFNDEF MPLPARSER}
|
||||
VarSize := 0;
|
||||
DataSize := 0;
|
||||
Data := NIL;
|
||||
ProcPos := 0;
|
||||
Kill := True;
|
||||
FillChar (pID, SizeOf(pID), 0);
|
||||
{$ELSE}
|
||||
Ident := I;
|
||||
InProc := False;
|
||||
Proc := True;
|
||||
{$ENDIF}
|
||||
ArrPos := 0;
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure AddStr ({$IFDEF MPLPARSER} I: String; {$ENDIF} T: TIdentTypes; SI: Word);
|
||||
Begin
|
||||
Inc(X);
|
||||
New(CV[X]);
|
||||
|
||||
With cV[x]^ Do Begin
|
||||
VarID := IW;
|
||||
Inc(IW);
|
||||
vType := T;
|
||||
NumParams := 0;
|
||||
{$IFNDEF MPLPARSER}
|
||||
VarSize := SI + 1;
|
||||
DataSize := VarSize;
|
||||
GetMem (Data, DataSize);
|
||||
FillChar (Data^, DataSize, 0);
|
||||
FillChar (pID, SizeOf(pID), 0); //cant we just assign it to 0 here?
|
||||
ProcPos := 0;
|
||||
Kill := True;
|
||||
{$ELSE}
|
||||
Ident := I;
|
||||
InProc := False;
|
||||
Proc := False;
|
||||
{$ENDIF}
|
||||
ArrPos := 0;
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure AddVar ({$IFDEF MPLPARSER} I: String; {$ENDIF} T: TIdentTypes);
|
||||
Begin
|
||||
AddStr ({$IFDEF MPLPARSER} I, {$ENDIF} T, xVarSize(T) - 1);
|
||||
End;
|
||||
|
||||
Procedure AddPointer ({$IFDEF MPLPARSER} I: String; {$ENDIF} T: TIdentTypes; SI: Word; PD: Pointer);
|
||||
Begin
|
||||
Inc(x);
|
||||
New(cV[x]);
|
||||
|
||||
With cV[x]^ Do Begin
|
||||
VarID := IW;
|
||||
Inc(IW);
|
||||
vType := t;
|
||||
NumParams := 0;
|
||||
{$IFNDEF MPLPARSER}
|
||||
If T = iString Then VarSize := SI + 1 Else VarSize := SI;
|
||||
DataSize := VarSize;
|
||||
Data := PD;
|
||||
FillChar (pID, SizeOf(pID), 0);
|
||||
ProcPos := 0;
|
||||
Kill := False;
|
||||
{$ELSE}
|
||||
Ident := I;
|
||||
InProc := False;
|
||||
Proc := False;
|
||||
{$ENDIF}
|
||||
ArrPos := 0;
|
||||
End;
|
||||
End;
|
||||
|
||||
Begin
|
||||
Case Mode of
|
||||
0 : Begin
|
||||
IW := 0;
|
||||
|
||||
AddProc ({$IFDEF MPLPARSER} 'write', {$ENDIF} 's', iNone); // 0
|
||||
AddProc ({$IFDEF MPLPARSER} 'writeln', {$ENDIF} 's', iNone); // 1
|
||||
AddProc ({$IFDEF MPLPARSER} 'clrscr', {$ENDIF} '', iNone); // 2
|
||||
AddProc ({$IFDEF MPLPARSER} 'clreol', {$ENDIF} '', iNone); // 3
|
||||
AddProc ({$IFDEF MPLPARSER} 'gotoxy', {$ENDIF} 'bb', iNone); // 4
|
||||
AddProc ({$IFDEF MPLPARSER} 'wherex', {$ENDIF} '', iByte); // 5
|
||||
AddProc ({$IFDEF MPLPARSER} 'wherey', {$ENDIF} '', iByte); // 6
|
||||
AddProc ({$IFDEF MPLPARSER} 'readkey', {$ENDIF} '', iString); // 7
|
||||
AddProc ({$IFDEF MPLPARSER} 'delay', {$ENDIF} 'l', iNone); // 8
|
||||
AddProc ({$IFDEF MPLPARSER} 'random', {$ENDIF} 'l', iLongInt); // 9
|
||||
AddProc ({$IFDEF MPLPARSER} 'chr', {$ENDIF} 'b', iChar); // 10
|
||||
AddProc ({$IFDEF MPLPARSER} 'ord', {$ENDIF} 's', iByte); // 11
|
||||
AddProc ({$IFDEF MPLPARSER} 'copy', {$ENDIF} 'sll', iString); // 12
|
||||
AddProc ({$IFDEF MPLPARSER} 'delete', {$ENDIF} 'Sll', iNone); // 13
|
||||
AddProc ({$IFDEF MPLPARSER} 'insert', {$ENDIF} 'sSl', iNone); // 14
|
||||
AddProc ({$IFDEF MPLPARSER} 'length', {$ENDIF} 's', iLongInt); // 15
|
||||
AddProc ({$IFDEF MPLPARSER} 'odd', {$ENDIF} 'l', iBool); // 16
|
||||
AddProc ({$IFDEF MPLPARSER} 'pos', {$ENDIF} 'ss', iLongInt); // 17
|
||||
AddProc ({$IFDEF MPLPARSER} 'keypressed', {$ENDIF} '', iBool); // 18
|
||||
AddProc ({$IFDEF MPLPARSER} 'padrt', {$ENDIF} 'sbs', iString); // 19
|
||||
AddProc ({$IFDEF MPLPARSER} 'padlt', {$ENDIF} 'sbs', iString); // 20
|
||||
AddProc ({$IFDEF MPLPARSER} 'padct', {$ENDIF} 'sbs', iString); // 21
|
||||
AddProc ({$IFDEF MPLPARSER} 'upper', {$ENDIF} 's', iString); // 22
|
||||
AddProc ({$IFDEF MPLPARSER} 'lower', {$ENDIF} 's', iString); // 23
|
||||
AddProc ({$IFDEF MPLPARSER} 'strrep', {$ENDIF} 'sb', iString); // 24
|
||||
AddProc ({$IFDEF MPLPARSER} 'strcomma', {$ENDIF} 'l', iString); // 25
|
||||
AddProc ({$IFDEF MPLPARSER} 'int2str', {$ENDIF} 'l', iString); // 26
|
||||
AddProc ({$IFDEF MPLPARSER} 'str2int', {$ENDIF} 's', iLongInt); // 27
|
||||
AddProc ({$IFDEF MPLPARSER} 'int2hex', {$ENDIF} 'l', iString); // 28
|
||||
AddProc ({$IFDEF MPLPARSER} 'wordget', {$ENDIF} 'bss', iString); // 29
|
||||
AddProc ({$IFDEF MPLPARSER} 'wordpos', {$ENDIF} 'bss', iByte); // 30
|
||||
AddProc ({$IFDEF MPLPARSER} 'wordcount', {$ENDIF} 'ss', iByte); // 31
|
||||
AddProc ({$IFDEF MPLPARSER} 'stripl', {$ENDIF} 'ss', iString); // 32
|
||||
AddProc ({$IFDEF MPLPARSER} 'stripr', {$ENDIF} 'ss', iString); // 33
|
||||
AddProc ({$IFDEF MPLPARSER} 'stripb', {$ENDIF} 'ss', iString); // 34
|
||||
AddProc ({$IFDEF MPLPARSER} 'striplow', {$ENDIF} 's', iString); // 35
|
||||
AddProc ({$IFDEF MPLPARSER} 'stripmci', {$ENDIF} 's', iString); // 36
|
||||
AddProc ({$IFDEF MPLPARSER} 'mcilength', {$ENDIF} 's', iByte); // 37
|
||||
AddProc ({$IFDEF MPLPARSER} 'initials', {$ENDIF} 's', iString); // 38
|
||||
AddProc ({$IFDEF MPLPARSER} 'strwrap', {$ENDIF} 'SSb', iByte); // 39
|
||||
AddProc ({$IFDEF MPLPARSER} 'replace', {$ENDIF} 'sss', iString); // 40
|
||||
AddProc ({$IFDEF MPLPARSER} 'readenv', {$ENDIF} 's', iString); // 41
|
||||
AddProc ({$IFDEF MPLPARSER} 'fileexist', {$ENDIF} 's', iBool); // 42
|
||||
AddProc ({$IFDEF MPLPARSER} 'fileerase', {$ENDIF} 's', iNone); // 43
|
||||
AddProc ({$IFDEF MPLPARSER} 'direxist', {$ENDIF} 's', iBool); // 44
|
||||
AddProc ({$IFDEF MPLPARSER} 'timermin', {$ENDIF} '', iLongInt); // 45
|
||||
AddProc ({$IFDEF MPLPARSER} 'timer', {$ENDIF} '', iLongInt); // 46
|
||||
AddProc ({$IFDEF MPLPARSER} 'datetime', {$ENDIF} '', iLongInt); // 47
|
||||
AddProc ({$IFDEF MPLPARSER} 'datejulian', {$ENDIF} '', iLongInt); // 48
|
||||
AddProc ({$IFDEF MPLPARSER} 'datestr', {$ENDIF} 'lb', iString); // 49
|
||||
AddProc ({$IFDEF MPLPARSER} 'datestrjulian', {$ENDIF} 'lb', iString); // 50
|
||||
AddProc ({$IFDEF MPLPARSER} 'date2dos', {$ENDIF} 's', iLongInt); // 51
|
||||
AddProc ({$IFDEF MPLPARSER} 'date2julian', {$ENDIF} 's', iLongInt); // 52
|
||||
AddProc ({$IFDEF MPLPARSER} 'dateg2j', {$ENDIF} 'lllL', iNone); // 53
|
||||
AddProc ({$IFDEF MPLPARSER} 'datej2g', {$ENDIF} 'liii', iNone); // 54
|
||||
AddProc ({$IFDEF MPLPARSER} 'datevalid', {$ENDIF} 's', iString); // 55
|
||||
AddProc ({$IFDEF MPLPARSER} 'timestr', {$ENDIF} 'lo', iString); // 56
|
||||
AddProc ({$IFDEF MPLPARSER} 'dayofweek', {$ENDIF} '', iByte); // 57
|
||||
AddProc ({$IFDEF MPLPARSER} 'daysago', {$ENDIF} 'l', iLongInt); // 58
|
||||
AddProc ({$IFDEF MPLPARSER} 'justfile', {$ENDIF} 's', iString); // 59
|
||||
AddProc ({$IFDEF MPLPARSER} 'justfilename', {$ENDIF} 's', iString); // 60
|
||||
AddProc ({$IFDEF MPLPARSER} 'justfileext', {$ENDIF} 's', iString); // 61
|
||||
AddProc ({$IFDEF MPLPARSER} 'fassign', {$ENDIF} 'Fsl', iNone); // 62
|
||||
AddProc ({$IFDEF MPLPARSER} 'freset', {$ENDIF} 'F', iNone); // 63
|
||||
AddProc ({$IFDEF MPLPARSER} 'frewrite', {$ENDIF} 'F', iNone); // 64
|
||||
AddProc ({$IFDEF MPLPARSER} 'fclose', {$ENDIF} 'F', iNone); // 65
|
||||
AddProc ({$IFDEF MPLPARSER} 'fseek', {$ENDIF} 'Fl', iNone); // 66
|
||||
AddProc ({$IFDEF MPLPARSER} 'feof', {$ENDIF} 'F', iBool); // 67
|
||||
AddProc ({$IFDEF MPLPARSER} 'fsize', {$ENDIF} 'F', iLongInt); // 68
|
||||
AddProc ({$IFDEF MPLPARSER} 'fpos', {$ENDIF} 'F', iLongInt); // 69
|
||||
AddProc ({$IFDEF MPLPARSER} 'fread', {$ENDIF} 'F*w', iNone); // 70
|
||||
AddProc ({$IFDEF MPLPARSER} 'fwrite', {$ENDIF} 'F*w', iNone); // 71
|
||||
AddProc ({$IFDEF MPLPARSER} 'freadln', {$ENDIF} 'FS', iNone); // 72
|
||||
AddProc ({$IFDEF MPLPARSER} 'fwriteln', {$ENDIF} 'Fs', iNone); // 73
|
||||
AddProc ({$IFDEF MPLPARSER} 'pathchar', {$ENDIF} '', iChar); // 74
|
||||
AddProc ({$IFDEF MPLPARSER} 'bitcheck', {$ENDIF} 'b*', iBool); // 75
|
||||
AddProc ({$IFDEF MPLPARSER} 'bittoggle', {$ENDIF} 'b*', iNone); // 76
|
||||
AddProc ({$IFDEF MPLPARSER} 'bitset', {$ENDIF} 'b*o', iNone); // 77
|
||||
AddProc ({$IFDEF MPLPARSER} 'findfirst', {$ENDIF} 'sw', iNone); // 78
|
||||
AddProc ({$IFDEF MPLPARSER} 'findnext', {$ENDIF} '', iNone); // 79
|
||||
AddProc ({$IFDEF MPLPARSER} 'findclose', {$ENDIF} '', iNone); // 80
|
||||
AddProc ({$IFDEF MPLPARSER} 'justpath', {$ENDIF} 's', iString); // 81
|
||||
AddProc ({$IFDEF MPLPARSER} 'randomize', {$ENDIF} '', iNone); // 82
|
||||
AddProc ({$IFDEF MPLPARSER} 'paramcount', {$ENDIF} '', iByte); // 83
|
||||
AddProc ({$IFDEF MPLPARSER} 'paramstr', {$ENDIF} 'b', iString); // 84
|
||||
AddProc ({$IFDEF MPLPARSER} 'textattr', {$ENDIF} '', iByte); // 85
|
||||
AddProc ({$IFDEF MPLPARSER} 'textcolor', {$ENDIF} 'b', iNone); // 86
|
||||
AddProc ({$IFDEF MPLPARSER} 'addslash', {$ENDIF} 's', iString); // 87
|
||||
AddProc ({$IFDEF MPLPARSER} 'strippipe', {$ENDIF} 's', iString); // 88
|
||||
|
||||
IW := 500; // BEGIN BBS-SPECIFIC STUFF
|
||||
|
||||
AddProc ({$IFDEF MPLPARSER} 'input', {$ENDIF} 'bbbs', iString); // 500
|
||||
AddProc ({$IFDEF MPLPARSER} 'getuser', {$ENDIF} 'l', iBool); // 501
|
||||
AddProc ({$IFDEF MPLPARSER} 'onekey', {$ENDIF} 'so', iChar); // 502
|
||||
AddProc ({$IFDEF MPLPARSER} 'getthisuser', {$ENDIF} '', iNone); // 503
|
||||
AddProc ({$IFDEF MPLPARSER} 'inputyn', {$ENDIF} 's', iBool); // 504
|
||||
AddProc ({$IFDEF MPLPARSER} 'inputny', {$ENDIF} 's', iBool); // 505
|
||||
AddProc ({$IFDEF MPLPARSER} 'dispfile', {$ENDIF} 's', iBool); // 506
|
||||
AddProc ({$IFDEF MPLPARSER} 'filecopy', {$ENDIF} 'ss', iBool); // 507
|
||||
AddProc ({$IFDEF MPLPARSER} 'menucmd', {$ENDIF} 'ss', iNone); // 508
|
||||
AddProc ({$IFDEF MPLPARSER} 'stuffkey', {$ENDIF} 's', iNone); // 509
|
||||
AddProc ({$IFDEF MPLPARSER} 'acs', {$ENDIF} 's', iBool); // 510
|
||||
AddProc ({$IFDEF MPLPARSER} 'upuser', {$ENDIF} 'i', iNone); // 511
|
||||
AddProc ({$IFDEF MPLPARSER} 'setusertime', {$ENDIF} 'i', iNone); // 512
|
||||
AddProc ({$IFDEF MPLPARSER} 'hangup', {$ENDIF} '', iNone); // 513
|
||||
AddProc ({$IFDEF MPLPARSER} 'getmbase', {$ENDIF} 'l', iBool); // 514
|
||||
AddProc ({$IFDEF MPLPARSER} 'getprompt', {$ENDIF} 'l', iString); // 515
|
||||
AddProc ({$IFDEF MPLPARSER} 'getmgroup', {$ENDIF} 'l', iBool); // 516
|
||||
AddProc ({$IFDEF MPLPARSER} 'purgeinput', {$ENDIF} '', iNone); // 517
|
||||
AddProc ({$IFDEF MPLPARSER} 'getfbase', {$ENDIF} 'l', iBool); // 518
|
||||
AddProc ({$IFDEF MPLPARSER} 'getfgroup', {$ENDIF} 'l', iBool); // 519
|
||||
AddProc ({$IFDEF MPLPARSER} 'sysoplog', {$ENDIF} 's', iNone); // 520
|
||||
AddProc ({$IFDEF MPLPARSER} 'movex', {$ENDIF} 'b', iNone); // 521
|
||||
AddProc ({$IFDEF MPLPARSER} 'movey', {$ENDIF} 'b', iNone); // 522
|
||||
AddProc ({$IFDEF MPLPARSER} 'writepipe', {$ENDIF} 's', iNone); // 523
|
||||
AddProc ({$IFDEF MPLPARSER} 'writepipeln', {$ENDIF} 's', iNone); // 524
|
||||
AddProc ({$IFDEF MPLPARSER} 'writeraw', {$ENDIF} 's', iNone); // 525
|
||||
AddProc ({$IFDEF MPLPARSER} 'writerawln', {$ENDIF} 's', iNone); // 526
|
||||
AddProc ({$IFDEF MPLPARSER} 'mci2str', {$ENDIF} 's', iString); // 527
|
||||
AddProc ({$IFDEF MPLPARSER} 'getusertime', {$ENDIF} '', iInteger); // 528
|
||||
AddProc ({$IFDEF MPLPARSER} 'getscreeninfo', {$ENDIF} 'bBBB', iNone); // 529
|
||||
AddProc ({$IFDEF MPLPARSER} 'setprompt', {$ENDIF} 'bs', iNone); // 530
|
||||
AddProc ({$IFDEF MPLPARSER} 'moreprompt', {$ENDIF} '', iChar); // 531
|
||||
AddProc ({$IFDEF MPLPARSER} 'pause', {$ENDIF} '', iNone); // 532
|
||||
AddProc ({$IFDEF MPLPARSER} 'setpromptinfo', {$ENDIF} 'bs', iNone); // 533
|
||||
AddProc ({$IFDEF MPLPARSER} 'bufflush', {$ENDIF} '', iNone); // 534
|
||||
AddProc ({$IFDEF MPLPARSER} 'strmci', {$ENDIF} 's', iString); // 535
|
||||
AddProc ({$IFDEF MPLPARSER} 'getcharxy', {$ENDIF} 'bb', iChar); // 536
|
||||
AddProc ({$IFDEF MPLPARSER} 'getattrxy', {$ENDIF} 'bb', iByte); // 537
|
||||
|
||||
{ END OF PROCEDURE DEFINITIONS }
|
||||
|
||||
AddPointer ({$IFDEF MPLPARSER} 'ioresult', {$ENDIF} iLongInt, 4, {$IFNDEF MPLPARSER} @TInterpEngine(S).IoError {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'doserror', {$ENDIF} iInteger, 2, {$IFNDEF MPLPARSER} @DosError {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'progparams', {$ENDIF} iString, 256, {$IFNDEF MPLPARSER} @TInterpEngine(S).ParamsStr {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'progname', {$ENDIF} iString, 256, {$IFNDEF MPLPARSER} @TInterpEngine(S).MPEName {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'graphics', {$ENDIF} iByte, 1, {$IFNDEF MPLPARSER} @Session.io.Graphics {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'isarrow', {$ENDIF} iBool, 1, {$IFNDEF MPLPARSER} @Session.io.IsArrow {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'nodenum', {$ENDIF} iByte, 1, {$IFNDEF MPLPARSER} @Session.NodeNum {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'local', {$ENDIF} iBool, 1, {$IFNDEF MPLPARSER} @Session.LocalMode {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'allowarrow', {$ENDIF} iBool, 1, {$IFNDEF MPLPARSER} @Session.io.AllowArrow {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'ignoregroups', {$ENDIF} iBool, 1, {$IFNDEF MPLPARSER} @Session.User.IgnoreGroup {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'pausepos', {$ENDIF} iByte, 1, {$IFNDEF MPLPARSER} @Session.io.PausePtr {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'allowmci', {$ENDIF} iBool, 1, {$IFNDEF MPLPARSER} @Session.io.PausePtr {$ELSE} NIL {$ENDIF});
|
||||
|
||||
{$IFNDEF MPLPARSER} TInterpEngine(S).IdxVarDir := X + 1; {$ENDIF}
|
||||
|
||||
AddPointer ({$IFDEF MPLPARSER} 'dirname', {$ENDIF} iString, 256, {$IFNDEF MPLPARSER} @TInterpEngine(S).DirInfo.Name {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'dirsize', {$ENDIF} iLongInt, 4, {$IFNDEF MPLPARSER} @TInterpEngine(S).DirInfo.Size {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'dirtime', {$ENDIF} iLongInt, 4, {$IFNDEF MPLPARSER} @TInterpEngine(S).DirInfo.Time {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'dirattr', {$ENDIF} iByte, 1, {$IFNDEF MPLPARSER} @TInterpEngine(S).DirInfo.Attr {$ELSE} NIL {$ENDIF});
|
||||
End;
|
||||
1 : Begin
|
||||
{$IFNDEF MPLPARSER} TInterpEngine(S).IdxVarUser := X + 1; {$ENDIF}
|
||||
|
||||
AddVar ({$IFDEF MPLPARSER} 'userpermidx', {$ENDIF} iLongInt);
|
||||
AddStr ({$IFDEF MPLPARSER} 'username', {$ENDIF} iString, 30);
|
||||
AddStr ({$IFDEF MPLPARSER} 'useralias', {$ENDIF} iString, 30);
|
||||
AddStr ({$IFDEF MPLPARSER} 'useraddress', {$ENDIF} iString, 30);
|
||||
AddVar ({$IFDEF MPLPARSER} 'usersec', {$ENDIF} iInteger);
|
||||
AddVar ({$IFDEF MPLPARSER} 'usersex', {$ENDIF} iChar);
|
||||
AddVar ({$IFDEF MPLPARSER} 'userfirston', {$ENDIF} iLongInt);
|
||||
AddVar ({$IFDEF MPLPARSER} 'userlaston', {$ENDIF} iLongInt);
|
||||
AddVar ({$IFDEF MPLPARSER} 'userdatetype', {$ENDIF} iByte);
|
||||
AddVar ({$IFDEF MPLPARSER} 'usercalls', {$ENDIF} iLongInt);
|
||||
AddVar ({$IFDEF MPLPARSER} 'userpassword', {$ENDIF} iString);
|
||||
AddVar ({$IFDEF MPLPARSER} 'userflags', {$ENDIF} iByte);
|
||||
End;
|
||||
2 : Begin
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgsyspath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.SystemPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgdatapath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.DataPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfglogspath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.LogsPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgmsgspath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.MsgsPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgattpath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.AttachPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgqwkpath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.QwkPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgmenupath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Session.Lang.MenuPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgtextpath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Session.Lang.TextPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgmpepath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Config.ScriptPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgtemppath', {$ENDIF} iString, mysMaxPathSize, {$IFNDEF MPLPARSER} @Session.TempPath {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgtimeout', {$ENDIF} iWord, 4, {$IFNDEF MPLPARSER} @Config.Inactivity {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfgseeinvis', {$ENDIF} iString, 20, {$IFNDEF MPLPARSER} @Config.AcsSeeInvis {$ELSE} NIL {$ENDIF});
|
||||
AddPointer ({$IFDEF MPLPARSER} 'cfginettnmax', {$ENDIF} iByte, 1, {$IFNDEF MPLPARSER} @Config.INetTNMax {$ELSE} NIL {$ENDIF});
|
||||
End;
|
||||
3 : Begin
|
||||
{$IFNDEF MPLPARSER} TInterpEngine(S).IdxVarMBase := X + 1; {$ENDIF}
|
||||
|
||||
AddVar ({$IFDEF MPLPARSER} 'mbaseindex', {$ENDIF} iInteger);
|
||||
AddStr ({$IFDEF MPLPARSER} 'mbasename', {$ENDIF} iString, 40);
|
||||
AddStr ({$IFDEF MPLPARSER} 'mbaseacs', {$ENDIF} iString, 20);
|
||||
AddStr ({$IFDEF MPLPARSER} 'mbaseracs', {$ENDIF} iString, 20);
|
||||
AddStr ({$IFDEF MPLPARSER} 'mbasepacs', {$ENDIF} iString, 20);
|
||||
AddStr ({$IFDEF MPLPARSER} 'mbasesacs', {$ENDIF} iString, 20);
|
||||
End;
|
||||
4 : Begin
|
||||
{$IFNDEF MPLPARSER} TInterpEngine(S).IdxVarMGroup := X + 1; {$ENDIF}
|
||||
|
||||
AddStr ({$IFDEF MPLPARSER} 'mgroupname', {$ENDIF} iString, 30);
|
||||
AddStr ({$IFDEF MPLPARSER} 'mgroupacs', {$ENDIF} iString, 30);
|
||||
AddVar ({$IFDEF MPLPARSER} 'mgrouphidden', {$ENDIF} iBool);
|
||||
End;
|
||||
5 : Begin
|
||||
{$IFNDEF MPLPARSER} TInterpEngine(S).IdxVarFBase := X + 1; {$ENDIF}
|
||||
|
||||
AddStr ({$IFDEF MPLPARSER} 'fbasename', {$ENDIF} iString, 40);
|
||||
AddStr ({$IFDEF MPLPARSER} 'fbaseacs', {$ENDIF} iString, 30);
|
||||
End;
|
||||
6 : Begin
|
||||
{$IFNDEF MPLPARSER} TInterpEngine(S).IdxVarFGroup := X + 1; {$ENDIF}
|
||||
|
||||
AddStr ({$IFDEF MPLPARSER} 'fgroupname', {$ENDIF} iString, 30);
|
||||
AddStr ({$IFDEF MPLPARSER} 'fgroupacs', {$ENDIF} iString, 30);
|
||||
AddVar ({$IFDEF MPLPARSER} 'fgrouphidden', {$ENDIF} iBool);
|
||||
End;
|
||||
End;
|
||||
End;
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,156 @@
|
|||
{$I M_OPS.PAS}
|
||||
|
||||
Unit MPL_FileIO;
|
||||
|
||||
// all file io units should be compiled into one source file...
|
||||
// also, make this ONLY allocate the size of the file if the file size is
|
||||
// less than the buffer.
|
||||
|
||||
Interface
|
||||
|
||||
Const
|
||||
MaxBufferSize = 64 * 1024;
|
||||
|
||||
Type
|
||||
PCharRec = ^TCharRec;
|
||||
TCharRec = Array[0..MaxBufferSize - 1] of Char;
|
||||
|
||||
PCharFile = ^TCharFile;
|
||||
TCharFile = Object
|
||||
BufSize : LongInt;
|
||||
Buffer : PCharRec;
|
||||
BufRead : LongInt;
|
||||
BufStart : LongInt;
|
||||
BufEnd : LongInt;
|
||||
BufPos : LongInt;
|
||||
InFile : File;
|
||||
BufEOF : Boolean;
|
||||
|
||||
Constructor Init (BufferSize: LongInt);
|
||||
Destructor Done;
|
||||
|
||||
Function Open (FN : String) : Boolean;
|
||||
Procedure Close;
|
||||
Function Read : Char;
|
||||
Procedure BlockRead (Var Buf; Size: LongInt; Var Count: LongInt);
|
||||
Procedure Seek (FP : LongInt);
|
||||
Function FilePos : LongInt;
|
||||
Function FileSize : LongInt;
|
||||
Function EOF : Boolean;
|
||||
Procedure FillBuffer;
|
||||
End;
|
||||
|
||||
Implementation
|
||||
|
||||
Function TCharFile.FilePos : LongInt;
|
||||
Begin
|
||||
FilePos := BufStart + BufPos;
|
||||
End;
|
||||
|
||||
Procedure TCharFile.FillBuffer;
|
||||
Var
|
||||
Start : LongInt;
|
||||
Begin
|
||||
Start := System.FilePos(InFile);
|
||||
|
||||
System.BlockRead (InFile, Buffer^[0], BufSize, BufRead);
|
||||
|
||||
BufStart := Start;
|
||||
BufEnd := Start + BufRead;
|
||||
BufPos := 0;
|
||||
BufEOF := System.EOF(InFile);
|
||||
End;
|
||||
|
||||
Constructor TCharFile.Init (BufferSize: LongInt);
|
||||
Begin
|
||||
BufSize := BufferSize;
|
||||
BufStart := 0;
|
||||
BufEnd := 0;
|
||||
BufPos := 0;
|
||||
BufEOF := False;
|
||||
BufRead := 0;
|
||||
Buffer := NIL;
|
||||
End;
|
||||
|
||||
Destructor TCharFile.Done;
|
||||
Begin
|
||||
If Assigned(Buffer) Then Begin
|
||||
FreeMem (Buffer, BufSize);
|
||||
Buffer := NIL;
|
||||
End;
|
||||
End;
|
||||
|
||||
Function TCharFile.Open (FN : String) : Boolean;
|
||||
Begin
|
||||
Open := False;
|
||||
FileMode := 66;
|
||||
|
||||
Assign (InFile, FN);
|
||||
Reset (InFile, 1);
|
||||
|
||||
If IoResult <> 0 Then Exit;
|
||||
|
||||
If BufSize > System.FileSize(InFile) Then
|
||||
BufSize := System.FileSize(InFile);
|
||||
|
||||
If Assigned(Buffer) Then Done;
|
||||
|
||||
GetMem (Buffer, BufSize);
|
||||
|
||||
FillBuffer;
|
||||
|
||||
Open := True;
|
||||
End;
|
||||
|
||||
Procedure TCharFile.Close;
|
||||
Begin
|
||||
System.Close (InFile);
|
||||
Done;
|
||||
End;
|
||||
|
||||
Function TCharFile.Read : Char;
|
||||
Begin
|
||||
If BufPos >= BufSize Then FillBuffer;
|
||||
|
||||
Read := Buffer^[BufPos];
|
||||
|
||||
Inc (BufPos);
|
||||
End;
|
||||
|
||||
Procedure TCharFile.BlockRead (Var Buf; Size: LongInt; Var Count: LongInt);
|
||||
Begin
|
||||
If BufPos + Size >= BufRead Then Begin
|
||||
If Size > BufSize Then Size := BufSize;
|
||||
System.Seek(InFile, BufStart + BufPos);
|
||||
FillBuffer;
|
||||
If BufRead < Size Then Size := BufRead;
|
||||
End;
|
||||
|
||||
Move (Buffer^[BufPos], Buf, Size);
|
||||
|
||||
Inc (BufPos, Size);
|
||||
|
||||
Count := Size;
|
||||
End;
|
||||
|
||||
Procedure TCharFile.Seek (FP : LongInt);
|
||||
Begin
|
||||
If (FP >= BufStart) and (FP < BufEnd) Then
|
||||
BufPos := (BufEnd - (BufEnd - FP)) - BufStart
|
||||
Else Begin
|
||||
System.Seek(InFile, FP);
|
||||
FillBuffer;
|
||||
End;
|
||||
End;
|
||||
|
||||
Function TCharFile.EOF : Boolean;
|
||||
Begin
|
||||
EOF := (BufStart + BufPos >= BufEnd) and BufEOF;
|
||||
End;
|
||||
|
||||
Function TCharFile.FileSize : LongInt;
|
||||
Begin
|
||||
FileSize := System.FileSize(InFile);
|
||||
End;
|
||||
|
||||
End.
|
|
@ -0,0 +1,294 @@
|
|||
Type
|
||||
TIdentTypes = (
|
||||
iNone,
|
||||
iString,
|
||||
iChar,
|
||||
iByte,
|
||||
iShort,
|
||||
iWord,
|
||||
iInteger,
|
||||
iLongInt,
|
||||
iReal,
|
||||
iBool,
|
||||
iFile,
|
||||
iRecord
|
||||
);
|
||||
|
||||
TTokenOpsRec = (
|
||||
opBlockOpen, // 1
|
||||
opBlockClose, // 2
|
||||
opVarDeclare, // 3
|
||||
opStr, // 4
|
||||
opChar, // 5
|
||||
opByte, // 6
|
||||
opShort, // 7
|
||||
opWord, // 8
|
||||
opInt, // 9
|
||||
opLong, // 10
|
||||
opReal, // 11
|
||||
opBool, // 12
|
||||
opSetVar, // 13
|
||||
opLeftParan, // 14
|
||||
opRightParan, // 15
|
||||
opVariable, // 16
|
||||
opOpenString, // 17
|
||||
opCloseString, // 18
|
||||
opProcDef, // 19
|
||||
opProcExec, // 20
|
||||
opParamSep, // 21
|
||||
opFor, // 22
|
||||
opTo, // 23
|
||||
opDownTo, // 24
|
||||
opTrue, // 25
|
||||
opFalse, // 26
|
||||
opEqual, // 27
|
||||
opNotEqual, // 28
|
||||
opGreater, // 29
|
||||
opLess, // 30
|
||||
opEqGreat, // 31
|
||||
opEqLess, // 32
|
||||
opStrAdd, // 33
|
||||
opProcType, // 34
|
||||
opIf, // 35
|
||||
opElse, // 36
|
||||
opWhile, // 37
|
||||
opOpenNum, // 38
|
||||
opCloseNum, // 39
|
||||
opRepeat, // 40
|
||||
opNot, // 41
|
||||
opAnd, // 42
|
||||
opOr, // 43
|
||||
opStrArray, // 44
|
||||
opArrDef, // 45
|
||||
opStrSize, // 46
|
||||
opVarNormal, // 47
|
||||
opGoto, // 48
|
||||
opHalt, // 49
|
||||
opCase, // 50
|
||||
opNumRange, // 51
|
||||
opTypeRec, // 52
|
||||
opBreak, // 53
|
||||
opContinue, // 54
|
||||
opUses, // 55
|
||||
opExit, // 56
|
||||
opNone // 57
|
||||
);
|
||||
|
||||
Const
|
||||
mplVer = '110';
|
||||
mplVersion = '[MPX ' + mplVer +']' + #26;
|
||||
mplVerLength = 10;
|
||||
mplExtSource = '.mps';
|
||||
mplExtExecute = '.mpx';
|
||||
mplMaxInclude = 10;
|
||||
mplMaxFiles = 20;
|
||||
mplMaxIdentLen = 20;
|
||||
mplMaxVars = 2500;
|
||||
mplMaxGotos = 100;
|
||||
mplMaxCaseNums = 20;
|
||||
mplMaxVarDeclare = 20;
|
||||
mplMaxArrayDem = 3; //cannot be changed yet
|
||||
mplMaxProcParams = 8;
|
||||
mplMaxRecords = 20;
|
||||
mplMaxRecFields = 40;
|
||||
mplMaxDataSize = 65535;
|
||||
mplMaxConsts = 100;
|
||||
|
||||
Const
|
||||
chNumber = ['0'..'9','.'];
|
||||
chIdent1 = ['a'..'z','A'..'Z','_'];
|
||||
chIdent2 = ['a'..'z','A'..'Z','0'..'9','_'];
|
||||
chDigit = ['0'..'9'];
|
||||
chHexDigit = ['0'..'9','A'..'F','a'..'f'];
|
||||
|
||||
{$IFNDEF MPLPARSER}
|
||||
mpxEndOfFile = 1;
|
||||
mpxInvalidFile = 2;
|
||||
mpxVerMismatch = 3;
|
||||
mpxUnknownOp = 4;
|
||||
mpxMultiInit = 5;
|
||||
mpxDivisionByZero = 6;
|
||||
mpxMathematical = 7;
|
||||
{$ELSE}
|
||||
mpsEndOfFile = 1;
|
||||
mpsFileNotfound = 2;
|
||||
mpsFileRecurse = 3;
|
||||
mpsOutputFile = 4;
|
||||
mpsExpected = 5;
|
||||
mpsUnknownIdent = 6;
|
||||
mpsInStatement = 7;
|
||||
mpsIdentTooLong = 8;
|
||||
mpsExpIdentifier = 9;
|
||||
mpsTooManyVars = 10;
|
||||
mpsDupIdent = 11;
|
||||
mpsOverMaxDec = 12;
|
||||
mpsTypeMismatch = 13;
|
||||
mpsSyntaxError = 14;
|
||||
mpsStringNotClosed = 15;
|
||||
mpsStringTooLong = 16;
|
||||
mpsTooManyParams = 17;
|
||||
mpsBadProcRef = 18;
|
||||
mpsNumExpected = 19;
|
||||
mpsToOrDowntoExp = 20;
|
||||
mpsExpOperator = 21;
|
||||
mpsOverArrayDim = 22;
|
||||
mpsNoInitArray = 23;
|
||||
mpsTooManyGotos = 24;
|
||||
mpsDupLabel = 25;
|
||||
mpsLabelNotFound = 26;
|
||||
mpsFileParamVar = 27;
|
||||
mpsBadFunction = 28;
|
||||
mpsOperation = 29;
|
||||
mpsOverMaxCase = 30;
|
||||
mpsTooManyFields = 31;
|
||||
mpsDataTooBig = 32;
|
||||
mpsMaxConsts = 33;
|
||||
{$ENDIF}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
{$IFDEF MPLPARSER}
|
||||
Type
|
||||
TTokenWordRec = (wBlockOpen, wBlockClose, wVarDeclare, wVarSep,
|
||||
wSetVar, wLeftParan, wRightParan, wOpenString,
|
||||
wCloseString, wStrAdd, wCharPrefix, wProcDef,
|
||||
wOpenParam, wCloseParam, wParamVar, wParamSpec,
|
||||
wFuncSpec, wParamSep, wFor, wTo,
|
||||
wDownTo, wDo, wTrue, wFalse,
|
||||
wOpEqual, wOpNotEqual, wOpGreater, wOpLess,
|
||||
wOpEqGreat, wOpEqLess, wIf, wThen,
|
||||
wElse, wWhile, wRepeat, wUntil,
|
||||
wNot, wAnd, wOr, wOpenArray,
|
||||
wCloseArray, wArrSep, wVarDef, wOpenStrSize,
|
||||
wCloseStrSize, wGoto, wLabel, wHalt,
|
||||
wVarSep2, wFuncDef, wArray, wCaseStart,
|
||||
wCaseOf, wNumRange, wType, wConst,
|
||||
wBreak, wContinue, wUses, wExit,
|
||||
wHexPrefix, wExpAnd, wExpOr, wExpXor,
|
||||
wExpShl, wExpShr);
|
||||
{$ENDIF}
|
||||
|
||||
|
||||
Const
|
||||
{$IFDEF MPLPARSER}
|
||||
tkv : Array[TIdentTypes] of String[mplMaxIdentLen] = (
|
||||
'none', 'string', 'char', 'byte',
|
||||
'shortint', 'word', 'integer', 'longint',
|
||||
'real', 'boolean', 'file', 'record');
|
||||
|
||||
Type
|
||||
TTokenWordType = Array[TTokenWordRec] of String[mplMaxIdentLen];
|
||||
|
||||
Const
|
||||
wTokensPascal : TTokenWordType = (
|
||||
'begin', 'end', 'var', ',',
|
||||
':=', '(', ')', '''',
|
||||
'''', '+', '#', 'procedure',
|
||||
'(', ')', '+', ';',
|
||||
':', ',', 'for', 'to',
|
||||
'downto', 'do', 'true', 'false',
|
||||
'=', '<>', '>', '<',
|
||||
'>=', '<=', 'if', 'then',
|
||||
'else', 'while', 'repeat', 'until',
|
||||
'not', 'and', 'or', '[',
|
||||
']', ',', '=', '[',
|
||||
']', 'goto', ':', 'halt',
|
||||
':', 'function', 'array', 'case',
|
||||
'of', '..', 'type', 'const',
|
||||
'break', 'continue', 'uses', 'exit',
|
||||
'$', 'and', 'or', 'xor', 'shl', 'shr'
|
||||
);
|
||||
|
||||
wTokensIPLC : TTokenWordType = (
|
||||
'{', '}', '@', ',',
|
||||
'=', '(', ')', '"',
|
||||
'"', '+', '#', 'proc',
|
||||
'(', ')', '+', ';',
|
||||
':', ',', 'for', 'to',
|
||||
'downto', 'do', 'true', 'false',
|
||||
'==', '<>', '>', '<',
|
||||
'>=', '<=', 'if', 'then',
|
||||
'else', 'while', 'repeat', 'until',
|
||||
'!', '&&', '||', '(',
|
||||
')', ',', '=', '[',
|
||||
']', 'goto', ':', 'halt',
|
||||
':', 'func', 'array', 'switch',
|
||||
'of', '..', 'type', 'const',
|
||||
'break', 'continue', 'uses', 'exit',
|
||||
'$', '&', '|', 'xor', '<<', '>>'
|
||||
);
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
vNums : Set of TIdentTypes = [iByte, iShort, iWord, iInteger, iLongInt, iReal];
|
||||
vStrings : Set of TIdentTypes = [iChar, iString];
|
||||
|
||||
Type
|
||||
{$IFNDEF MPLPARSER}
|
||||
PStack = ^TStack;
|
||||
TStack = Array[1..mplMaxDataSize] of Byte;
|
||||
TArrayInfo = Array[1..mplMaxArrayDem] of Word;
|
||||
|
||||
(*
|
||||
// MEMORY SAVING... could be 28 bytes per var?!?!
|
||||
// could at least make a procrec that tvarrec links to via a pointer. would
|
||||
// save us about 25 bytes per var... which is about half the memory. we
|
||||
// could also remove IsProc var in TVar because we could just check to see
|
||||
// if Proc : Pointer is assigned...
|
||||
PProcInfoRec = ^TProcInfoRec;
|
||||
TProcInfoRec = Record
|
||||
Params : Array[1..mplMaxProcParams] of Char;
|
||||
ParamID : Array[1..mplMaxProcParams] of Word;
|
||||
NumParams : Byte;
|
||||
Position : LongInt;
|
||||
End;
|
||||
*)
|
||||
|
||||
PVarRec = ^TVarRec;
|
||||
TVarRec = Record
|
||||
VarID : Word;
|
||||
vType : TIdentTypes;
|
||||
Params : Array[1..mplMaxProcParams] of Char;
|
||||
NumParams : Byte;
|
||||
pID : Array[1..mplMaxProcParams] of Word;
|
||||
ProcPos : LongInt;
|
||||
DataSize : Word;
|
||||
VarSize : Word;
|
||||
Data : PStack;
|
||||
Kill : Boolean;
|
||||
ArrPos : Byte;
|
||||
ArrDim : TArrayInfo;
|
||||
End;
|
||||
|
||||
PRecordRec = ^TRecordRec;
|
||||
TRecordRec = Record
|
||||
// RecID : Word; needed when Record variable type is added
|
||||
RecStart : Word;
|
||||
NumFields : Word;
|
||||
End;
|
||||
|
||||
VarDataRec = Array[1..mplMaxVars] of PVarRec;
|
||||
RecDataRec = Array[1..mplMaxRecords] of PRecordRec;
|
||||
{$ELSE}
|
||||
PVarRec = ^TVarRec;
|
||||
TVarRec = Record
|
||||
VarID : Word;
|
||||
Ident : String[mplMaxIdentLen];
|
||||
VType : TIdentTypes;
|
||||
Params : Array[1..mplMaxProcParams] of Char;
|
||||
NumParams : Byte;
|
||||
InProc : Boolean;
|
||||
Proc : Boolean;
|
||||
ArrPos : Byte;
|
||||
End;
|
||||
|
||||
PGotoRec = ^TGotoRec;
|
||||
TGotoRec = Record
|
||||
Ident : String[mplMaxIdentLen];
|
||||
xPos : LongInt;
|
||||
Stat : Byte;
|
||||
End;
|
||||
|
||||
VarDataRec = Array[1..mplMaxVars] of PVarRec;
|
||||
{$ENDIF}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// ====================================================================
|
||||
// Mystic BBS Software Copyright 1997-2012 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}
|
||||
|
||||
Program MPLC;
|
||||
|
||||
Uses
|
||||
m_Output,
|
||||
m_Strings,
|
||||
Dos,
|
||||
MPL_Compile;
|
||||
|
||||
Var
|
||||
SavedX : Byte;
|
||||
Console : TOutput;
|
||||
WasError : Boolean;
|
||||
|
||||
Procedure Status (Info: TParserUpdateInfo);
|
||||
Begin
|
||||
Case Info.Mode of
|
||||
StatusStart : Begin
|
||||
Console.WriteStr('Compiling ' + Info.FileName + ' ... ');
|
||||
SavedX := Console.CursorX;
|
||||
End;
|
||||
StatusUpdate : Begin
|
||||
Console.CursorXY (SavedX, Console.CursorY);
|
||||
Console.WriteStr (strPadL(strI2S(Info.Percent), 3, ' ') + '%');
|
||||
End;
|
||||
StatusDone : If Info.ErrorType = 0 Then Begin
|
||||
Console.CursorXY (SavedX, Console.CursorY);
|
||||
Console.WriteLine ('Success!');
|
||||
End Else Begin
|
||||
WasError := True;
|
||||
Console.WriteLine(#13#10#13#10'Error in ' + Info.FileName + ' (Line:' + strI2S(Info.ErrorLine) + ', Col:' + strI2S(Info.ErrorCol) + '): ' + Info.ErrorText);
|
||||
End;
|
||||
End;
|
||||
End;
|
||||
|
||||
Var
|
||||
Parser : TParserEngine;
|
||||
Dir : SearchRec;
|
||||
Begin
|
||||
WasError := False;
|
||||
Console := TOutput.Create(True);
|
||||
|
||||
Console.WriteLine (#13#10'Mystic BBS Programming Language Compiler Version ' + mysVersion);
|
||||
Console.WriteLine ('Copyright (C) 1997-2011 By James Coyle. All Rights Reserved.'#13#10);
|
||||
|
||||
If ParamCount = 0 Then
|
||||
WriteLn ('MPLC [filename] or MPLC -ALL')
|
||||
Else Begin
|
||||
If Pos('-ALL', strUpper(ParamStr(1))) > 0 Then Begin
|
||||
FindFirst ('*.mps', AnyFile - Directory - VolumeID, Dir);
|
||||
While DosError = 0 Do Begin
|
||||
Parser := TParserEngine.Create(Status);
|
||||
If Not Parser.Compile(Dir.Name) Then Begin
|
||||
Parser.Free;
|
||||
Break;
|
||||
End;
|
||||
FindNext(Dir);
|
||||
Parser.Free;
|
||||
End;
|
||||
FindClose(Dir);
|
||||
End Else Begin
|
||||
Parser := TParserEngine.Create(Status);
|
||||
Parser.Compile(ParamStr(1));
|
||||
Parser.Free;
|
||||
End;
|
||||
End;
|
||||
|
||||
Console.Free;
|
||||
|
||||
If WasError Then Halt(1);
|
||||
End.
|
|
@ -0,0 +1,555 @@
|
|||
// 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/>.
|
||||
|
||||
Program MP;
|
||||
|
||||
{ when DELETEing a message, the pointers are one less than they should be }
|
||||
{ should be fixed, but may cause other problems. commented out the last }
|
||||
{ read updating in the msgkill part of the program }
|
||||
|
||||
{ also when a user is reading a base, it could cause MP to crash with an }
|
||||
{ RTE 005: access violation error }
|
||||
|
||||
{$I M_OPS.PAS}
|
||||
|
||||
Uses
|
||||
m_FileIO,
|
||||
m_Strings,
|
||||
m_DateTime,
|
||||
CRT,
|
||||
DOS;
|
||||
|
||||
{$I RECORDS.PAS}
|
||||
|
||||
Const
|
||||
PackVer = '1.2';
|
||||
Jam_Deleted = $80000000;
|
||||
JamSubBufSize = 4096;
|
||||
|
||||
Type
|
||||
JamSubBuffer = Array[1..JamSubBufSize] of Char;
|
||||
|
||||
JamHdrType = Record
|
||||
Signature : Array[1..4] of Char;
|
||||
Created : LongInt;
|
||||
ModCounter : LongInt;
|
||||
ActiveMsgs : LongInt;
|
||||
PwdCRC : LongInt;
|
||||
BaseMsgNum : LongInt;
|
||||
HighWaterMark : Longint;
|
||||
Extra : Array[1..996] of Char;
|
||||
End;
|
||||
|
||||
JamMsgHdrType = Record
|
||||
Signature : Array[1..4] of Char;
|
||||
Rev : Word;
|
||||
Resvd : Word;
|
||||
SubFieldLen : LongInt;
|
||||
TimesRead : LongInt;
|
||||
MsgIdCrc : LongInt;
|
||||
ReplyCrc : LongInt;
|
||||
ReplyTo : LongInt;
|
||||
ReplyFirst : LongInt;
|
||||
ReplyNext : LongInt;
|
||||
DateWritten : LongInt;
|
||||
DateRcvd : LongInt;
|
||||
DateArrived : LongInt;
|
||||
MsgNumber : LongInt;
|
||||
Attr1 : LongInt;
|
||||
Attr2 : LongInt;
|
||||
TextOfs : LongInt;
|
||||
TextLen : LongInt;
|
||||
PwdCrc : LongInt;
|
||||
Cost : LongInt;
|
||||
End;
|
||||
|
||||
JamIdxType = Record
|
||||
MsgToCrc : LongInt;
|
||||
HdrLoc : LongInt;
|
||||
End;
|
||||
|
||||
JamLastType = Record
|
||||
NameCrc : LongInt;
|
||||
UserNum : LongInt;
|
||||
LastRead : LongInt;
|
||||
HighRead : LongInt;
|
||||
End;
|
||||
|
||||
SubFieldType = Record
|
||||
LoId : Word;
|
||||
HiId : Word;
|
||||
DataLen : LongInt;
|
||||
Data : Array[1..1000] of Char;
|
||||
End;
|
||||
|
||||
TxtType = Array[1..65000] of Char;
|
||||
|
||||
JamType = Record
|
||||
Hdr : JamHdrType;
|
||||
MsgHdr : JamMsgHdrType;
|
||||
HdrFile : File;
|
||||
Idx : JamIdxType;
|
||||
IdxFile : File of JamIdxType;
|
||||
Last : JamLastType;
|
||||
LastFile : File of JamLastType;
|
||||
TxtFile : File;
|
||||
SubField : SubFieldType;
|
||||
End;
|
||||
|
||||
Const
|
||||
SpinStr : String[8] = ('\|/-\|/-');
|
||||
SpinPos : Byte = 1;
|
||||
SkipFirst : Boolean = False;
|
||||
PackMsgs : Boolean = False;
|
||||
|
||||
Var
|
||||
ConfigFile : File of RecConfig;
|
||||
MBaseFile : File of MBaseRec;
|
||||
Config : RecConfig;
|
||||
MBase : MBaseRec;
|
||||
|
||||
Const
|
||||
DATEC1970 = 2440588;
|
||||
DATED0 = 1461;
|
||||
DATED1 = 146097;
|
||||
DATED2 = 1721119;
|
||||
|
||||
Procedure UnixToDT(SecsPast: LongInt; Var Dt: DateTime);
|
||||
Var
|
||||
DateNum : LongInt;
|
||||
N1 : Word;
|
||||
Begin
|
||||
Datenum := (SecsPast Div 86400) + DATEc1970;
|
||||
|
||||
DateJ2G(DateNum, SmallInt(N1), SmallInt(DT.Month), SmallInt(DT.day));
|
||||
DT.Year := N1;
|
||||
|
||||
SecsPast := SecsPast Mod 86400;
|
||||
DT.Hour := SecsPast Div 3600;
|
||||
SecsPast := SecsPast Mod 3600;
|
||||
DT.Min := SecsPast Div 60;
|
||||
DT.Sec := SecsPast Mod 60;
|
||||
End;
|
||||
|
||||
Procedure PWrite (Str : String);
|
||||
Var
|
||||
A : Byte;
|
||||
Code : String[2];
|
||||
Begin
|
||||
A := 1;
|
||||
While A <= Length(Str) Do Begin
|
||||
If (Str[A] = '|') and (A < Length(Str) - 1) Then Begin
|
||||
Code := Copy(Str, A + 1, 2);
|
||||
|
||||
If (Code = '00') or (strS2I(Code) > 0) Then Begin
|
||||
If strS2I(Code) < 16 Then
|
||||
TextColor(strS2I(Code))
|
||||
Else
|
||||
TextBackground(strS2I(Code) - 16);
|
||||
End Else
|
||||
Write(Str[A] + Code);
|
||||
|
||||
Inc (A, 2);
|
||||
End Else
|
||||
Write(Str[A]);
|
||||
|
||||
Inc(A);
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure PWriteLN (Str : String);
|
||||
Begin
|
||||
PWrite (Str + #13#10);
|
||||
End;
|
||||
|
||||
Procedure UpdateSpin;
|
||||
Begin
|
||||
Write (#8 + SpinStr[SpinPos]);
|
||||
Inc (SpinPos);
|
||||
|
||||
If SpinPos > 8 Then SpinPos := 1;
|
||||
End;
|
||||
|
||||
Procedure PackJAMBase (Var TotalKilled : LongInt; Var SavedBytes : LongInt);
|
||||
Var
|
||||
BasePath : String;
|
||||
OldHdrFile : File;
|
||||
OldTxtFile : File;
|
||||
OldIdxFile : File of JamIdxType;
|
||||
NewHdrFile : File;
|
||||
NewTxtFile : File;
|
||||
NewIdxFile : File of JamIdxType;
|
||||
TmpHdrFile : File;
|
||||
LastFile : File of JamLastType;
|
||||
Last : JamLastType;
|
||||
SigHdr : JamHdrType;
|
||||
MsgHdr : JamMsgHdrType;
|
||||
TmpSigHdr : JamHdrType;
|
||||
TmpMsgHdr : JamMsgHdrType;
|
||||
MsgIdx : JamIdxType;
|
||||
TxtBuf : ^TxtType;
|
||||
SubField : SubFieldType;
|
||||
Count : LongInt;
|
||||
Killed : Boolean;
|
||||
KillOffset : LongInt;
|
||||
LimitKill : Boolean;
|
||||
TotalMsgs : LongInt;
|
||||
MsgDateTime : DateTime;
|
||||
Temp : LongInt;
|
||||
HaveHdr : Boolean;
|
||||
Begin
|
||||
PWrite ('|07Processing |08-> |07' + strPadR(MBase.Name, 35, ' ') + '|08 -> |07');
|
||||
|
||||
BasePath := MBase.Path + MBase.FileName;
|
||||
|
||||
Assign (OldHdrFile, BasePath + '.jhr');
|
||||
Assign (OldTxtFile, BasePath + '.jdt');
|
||||
Assign (OldIdxFile, BasePath + '.jdx');
|
||||
|
||||
{$I-} Reset (OldHdrFile, 1); {$I+}
|
||||
If IOResult <> 0 Then Exit;
|
||||
|
||||
{$I-} Reset (OldTxtFile, 1); {$I+}
|
||||
If IOResult <> 0 Then Begin
|
||||
Close (OldHdrFile);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
{$I-} Reset (OldIdxFile); {$I+}
|
||||
If IoResult <> 0 Then Begin
|
||||
Close (OldHdrFile);
|
||||
Close (OldTxtFile);
|
||||
Exit;
|
||||
End;
|
||||
|
||||
Assign (LastFile, BasePath + '.jlr');
|
||||
{$I-} Reset (LastFile); {$I+}
|
||||
If IoResult <> 0 Then ReWrite (LastFile);
|
||||
Close (LastFile);
|
||||
|
||||
Assign (NewHdrFile, BasePath + '._hr');
|
||||
ReWrite (NewHdrFile, 1);
|
||||
Assign (NewTxtFile, BasePath + '._dt');
|
||||
ReWrite (NewTxtFile, 1);
|
||||
Assign (NewIdxFile, BasePath + '._dx');
|
||||
ReWrite (NewIdxFile);
|
||||
|
||||
BlockRead (OldHdrFile, SigHdr, SizeOf(SigHdr));
|
||||
|
||||
Inc (SigHdr.ModCounter);
|
||||
|
||||
BlockWrite (NewHdrFile, SigHdr, SizeOf(SigHdr));
|
||||
|
||||
If SigHdr.ActiveMsgs > MBase.MaxMsgs Then
|
||||
KillOffset := SigHdr.ActiveMsgs - MBase.MaxMsgs
|
||||
Else
|
||||
KillOffset := 0;
|
||||
|
||||
TotalMsgs := 0;
|
||||
TotalKilled := 0;
|
||||
|
||||
New (TxtBuf);
|
||||
|
||||
While Not Eof(OldIdxFile) Do Begin
|
||||
UpdateSpin;
|
||||
|
||||
Read (OldIdxFile, MsgIdx);
|
||||
|
||||
If MsgIdx.HdrLoc = -1 Then Begin
|
||||
Killed := True;
|
||||
LimitKill := False;
|
||||
HaveHdr := False;
|
||||
End Else Begin
|
||||
Seek (OldHdrFile, MsgIdx.HdrLoc);
|
||||
|
||||
BlockRead (OldHdrFile, MsgHdr, SizeOf(MsgHdr));
|
||||
|
||||
LimitKill := False;
|
||||
Killed := MsgHdr.Attr1 and Jam_Deleted <> 0;
|
||||
HaveHdr := True;
|
||||
|
||||
If MBase.MaxAge > 0 Then Begin
|
||||
UnixToDT (MsgHdr.DateWritten, MsgDateTime);
|
||||
PackTime (MsgDateTime, Temp);
|
||||
|
||||
LimitKill := DaysAgo(Temp) > MBase.MaxAge;
|
||||
Killed := Killed or LimitKill;
|
||||
End;
|
||||
|
||||
If MBase.MaxMsgs > 0 Then
|
||||
If KillOffset > 0 Then Begin
|
||||
Dec (KillOffset);
|
||||
LimitKill := True;
|
||||
Killed := True;
|
||||
End;
|
||||
|
||||
If SkipFirst and (MBase.NetType = 0) and (TotalMsgs = 0) and (MsgHdr.Attr1 and Jam_Deleted = 0) Then
|
||||
Killed := False;
|
||||
End;
|
||||
|
||||
If Killed Then Begin
|
||||
Inc (TotalKilled);
|
||||
|
||||
(*
|
||||
Reset (LastFile);
|
||||
While Not Eof(LastFile) Do Begin
|
||||
Read (LastFile, Last);
|
||||
If (Last.LastRead > TotalMsgs) And Not LimitKill Then Begin
|
||||
Dec (Last.LastRead);
|
||||
Seek (LastFile, FilePos(LastFile) - 1);
|
||||
Write (LastFile, Last);
|
||||
End;
|
||||
End;
|
||||
Close (LastFile);
|
||||
*)
|
||||
If HaveHdr And (MsgHdr.ReplyFirst <> 0) Then Begin
|
||||
Assign (TmpHdrFile, BasePath + '.jhr');
|
||||
Reset (TmpHdrFile, 1);
|
||||
|
||||
BlockRead (TmpHdrFile, TmpSigHdr, SizeOf(TmpSigHdr));
|
||||
|
||||
While Not Eof(TmpHdrFile) Do Begin
|
||||
BlockRead (TmpHdrFile, TmpMsgHdr, SizeOf(TmpMsgHdr));
|
||||
|
||||
If TmpMsgHdr.ReplyTo = MsgHdr.MsgNumber Then Begin
|
||||
TmpMsgHdr.ReplyTo := 0;
|
||||
Seek (TmpHdrFile, FilePos(TmpHdrFile) - SizeOf(TmpMsgHdr));
|
||||
BlockWrite (TmpHdrFile, TmpMsgHdr, SizeOf(TmpMsgHdr));
|
||||
End;
|
||||
|
||||
Seek (TmpHdrFile, FilePos(TmpHdrFile) + TmpMsgHdr.SubFieldLen);
|
||||
End;
|
||||
Close (TmpHdrFile);
|
||||
End;
|
||||
|
||||
End Else Begin
|
||||
Inc (TotalMsgs);
|
||||
|
||||
If TotalKilled > 0 Then Begin
|
||||
Reset (LastFile);
|
||||
While Not Eof(LastFile) Do Begin
|
||||
Read (LastFile, Last);
|
||||
If Last.LastRead = MsgHdr.MsgNumber Then Begin
|
||||
Last.LastRead := TotalMsgs;
|
||||
Seek (LastFile, FilePos(LastFile) - 1);
|
||||
Write (LastFile, Last);
|
||||
End;
|
||||
End;
|
||||
Close (LastFile);
|
||||
End;
|
||||
|
||||
If (TotalKilled > 0) and (MsgHdr.ReplyFirst <> 0) Then Begin
|
||||
Assign (TmpHdrFile, BasePath + '.jhr');
|
||||
Reset (TmpHdrFile, 1);
|
||||
|
||||
BlockRead (TmpHdrFile, TmpSigHdr, SizeOf(TmpSigHdr));
|
||||
|
||||
While Not Eof(TmpHdrFile) Do Begin
|
||||
BlockRead (TmpHdrFile, TmpMsgHdr, SizeOf(TmpMsgHdr));
|
||||
|
||||
If TmpMsgHdr.ReplyTo = MsgHdr.MsgNumber Then Begin
|
||||
TmpMsgHdr.ReplyTo := TotalMsgs;
|
||||
Seek (TmpHdrFile, FilePos(TmpHdrFile) - SizeOf(TmpMsgHdr));
|
||||
BlockWrite (TmpHdrFile, TmpMsgHdr, SizeOf(TmpMsgHdr));
|
||||
End;
|
||||
|
||||
Seek (TmpHdrFile, FilePos(TmpHdrFile) + TmpMsgHdr.SubFieldLen);
|
||||
End;
|
||||
Close (TmpHdrFile);
|
||||
End;
|
||||
|
||||
If (TotalKilled > 0) and (MsgHdr.ReplyTo <> 0) Then Begin
|
||||
Assign (TmpHdrFile, BasePath + '._hr');
|
||||
Reset (TmpHdrFile, 1);
|
||||
|
||||
BlockRead (TmpHdrFile, TmpSigHdr, SizeOf(TmpSigHdr));
|
||||
|
||||
While Not Eof(TmpHdrFile) Do Begin
|
||||
BlockRead (TmpHdrFile, TmpMsgHdr, SizeOf(TmpMsgHdr));
|
||||
|
||||
If TmpMsgHdr.ReplyFirst = MsgHdr.MsgNumber Then Begin
|
||||
TmpMsgHdr.ReplyFirst := TotalMsgs;
|
||||
Seek (TmpHdrFile, FilePos(TmpHdrFile) - SizeOf(TmpMsgHdr));
|
||||
BlockWrite (TmpHdrFile, TmpMsgHdr, SizeOf(TmpMsgHdr));
|
||||
End;
|
||||
|
||||
Seek (TmpHdrFile, FilePos(TmpHdrFile) + TmpMsgHdr.SubFieldLen);
|
||||
End;
|
||||
Close (TmpHdrFile);
|
||||
End;
|
||||
|
||||
MsgHdr.MsgNumber := TotalMsgs;
|
||||
MsgIdx.HdrLoc := FilePos(NewHdrFile);
|
||||
|
||||
(* write text from old file to new file *)
|
||||
|
||||
If MsgHdr.TextLen > 65000 Then MsgHdr.TextLen := 65000;
|
||||
// Why did I put this limitation here? Prob should be removed
|
||||
|
||||
Seek (OldTxtFile, MsgHdr.TextOfs);
|
||||
BlockRead (OldTxtFile, TxtBuf^, MsgHdr.TextLen);
|
||||
|
||||
MsgHdr.TextOfs := FileSize(NewTxtFile);
|
||||
|
||||
BlockWrite (NewTxtFile, TxtBuf^, MsgHdr.TextLen);
|
||||
|
||||
(* write header from old to new file *)
|
||||
|
||||
BlockWrite (NewHdrFile, MsgHdr, SizeOf(MsgHdr));
|
||||
|
||||
(* write subfield data if it exists *)
|
||||
|
||||
If MsgHdr.SubFieldLen > 0 Then Begin
|
||||
Count := 1;
|
||||
|
||||
While (Count <= MsgHdr.SubFieldLen) Do Begin
|
||||
BlockRead (OldHdrFile, SubField, 8);
|
||||
BlockRead (OldHdrFile, SubField.Data, SubField.DataLen);
|
||||
BlockWrite (NewHdrFile, SubField, 8);
|
||||
BlockWrite (NewHdrFile, SubField.Data, SubField.DataLen);
|
||||
|
||||
Inc (Count, 8 + SubField.DataLen);
|
||||
End;
|
||||
End;
|
||||
|
||||
(* write new index to index file *)
|
||||
|
||||
Write (NewIdxFile, MsgIdx);
|
||||
End;
|
||||
End;
|
||||
|
||||
Dispose (TxtBuf);
|
||||
|
||||
SigHdr.ActiveMsgs := TotalMsgs;
|
||||
SigHdr.BaseMsgNum := 1;
|
||||
|
||||
Reset (NewHdrFile, 1);
|
||||
BlockWrite (NewHdrFile, SigHdr, SizeOf(SigHdr));
|
||||
|
||||
SavedBytes := (FileSize(OldHdrFile) - FileSize(NewHdrFile)) +
|
||||
(FileSize(OldTxtFile) - FileSize(NewTxtFile)) +
|
||||
((FileSize(OldIdxFile) - FileSize(NewIdxFile)) * SizeOf(MsgIdx));
|
||||
|
||||
Close (OldHdrFile);
|
||||
Close (OldTxtFile);
|
||||
Close (OldIdxFile);
|
||||
Close (NewHdrFile);
|
||||
Close (NewTxtFile);
|
||||
Close (NewIdxFile);
|
||||
|
||||
Erase (OldHdrFile);
|
||||
Erase (OldTxtFile);
|
||||
Erase (OldIdxFile);
|
||||
|
||||
ReName (NewHdrFile, BasePath + '.jhr');
|
||||
ReName (NewTxtFile, BasePath + '.jdt');
|
||||
ReName (NewIdxFile, BasePath + '.jdx');
|
||||
|
||||
If TotalKilled > 0 Then Begin
|
||||
Reset (LastFile);
|
||||
While Not Eof(LastFile) Do Begin
|
||||
Read (LastFile, Last);
|
||||
If Last.LastRead > TotalMsgs Then Last.LastRead := TotalMsgs;
|
||||
If Last.HighRead > Last.LastRead Then Last.HighRead := Last.LastRead;
|
||||
Seek (LastFile, FilePos(LastFile) - 1);
|
||||
Write (LastFile, Last);
|
||||
End;
|
||||
Close (LastFile);
|
||||
End;
|
||||
End;
|
||||
|
||||
Procedure ShowHelp;
|
||||
Begin
|
||||
WriteLn ('Invalid command line options');
|
||||
WriteLn;
|
||||
WriteLn ('-PACK : Pack all jam message bases');
|
||||
WriteLn ('-SKIPFIRST : Skips the first message of each local message base');
|
||||
WriteLn;
|
||||
PWriteLn ('|12NOTE: This program can sometimes crash if users are online.|07');
|
||||
Halt(1);
|
||||
End;
|
||||
|
||||
Var
|
||||
TotalMsgs : LongInt;
|
||||
TotalBytes : LongInt;
|
||||
Msgs : LongInt;
|
||||
Bytes : LongInt;
|
||||
Count : Byte;
|
||||
Str : String;
|
||||
Begin
|
||||
FileMode := 66;
|
||||
|
||||
ClrScr;
|
||||
PWriteLn ('|08-> |15MYSTPACK ' + PackVer + ' : JAM message base packer');
|
||||
PWriteLn ('|08-> |07Compatible with Mystic BBS software v' + mysVersion);
|
||||
PWriteLn ('|08ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ|07');
|
||||
WriteLn;
|
||||
|
||||
Window (1, 5, 80, 24);
|
||||
|
||||
If ParamCount = 0 Then ShowHelp;
|
||||
|
||||
For Count := 1 to ParamCount Do Begin
|
||||
Str := strUpper(ParamStr(Count));
|
||||
|
||||
If Str = '-PACK' Then
|
||||
PackMsgs := True
|
||||
Else
|
||||
If Str = '-SKIPFIRST' Then
|
||||
SkipFirst := True
|
||||
Else
|
||||
ShowHelp;
|
||||
End;
|
||||
|
||||
Assign (ConfigFile, 'mystic.dat');
|
||||
{$I-} Reset (ConfigFile); {$I+}
|
||||
If IoResult <> 0 Then Begin
|
||||
WriteLn ('ERROR: Unable to read MYSTIC.DAT. Run from root Mystic directory');
|
||||
Halt(1);
|
||||
End;
|
||||
Read (ConfigFile, Config);
|
||||
Close (ConfigFile);
|
||||
|
||||
If Config.DataChanged <> mysDataChanged Then Begin
|
||||
WriteLn('ERROR: Data files are not current and must be upgraded.');
|
||||
Halt(1);
|
||||
End;
|
||||
|
||||
Assign (MBaseFile, Config.DataPath + 'mbases.dat');
|
||||
{$I-} Reset(MBaseFile); {$I+}
|
||||
If IoResult <> 0 Then Begin
|
||||
WriteLn ('ERROR: Unable to read message area data');
|
||||
Halt(1);
|
||||
End;
|
||||
|
||||
While Not Eof(MBaseFile) Do Begin
|
||||
Read (MBaseFile, MBase);
|
||||
|
||||
If MBase.BaseType = 0 Then Begin
|
||||
PackJAMBase(Msgs, Bytes);
|
||||
WriteLn (#8 + 'Killed ', Msgs, '; ', Bytes, ' bytes');
|
||||
|
||||
Inc (TotalMsgs, Msgs);
|
||||
Inc (TotalBytes, Bytes);
|
||||
End;
|
||||
End;
|
||||
|
||||
Close (MBaseFile);
|
||||
|
||||
WriteLn;
|
||||
PWriteLn ('|08[|07-|08] |07Killed |15' + strI2S(TotalMsgs) + '|07 Msgs; Removed |15' + strI2S(TotalBytes) + '|07 bytes');
|
||||
|
||||
Window (1, 1, 80, 25);
|
||||
End.
|
|
@ -0,0 +1,697 @@
|
|||
{
|
||||
===========================================================================
|
||||
Mystic BBS Software Copyright (C) 1997-2012 By James Coyle
|
||||
===========================================================================
|
||||
File | RECORDS.PAS
|
||||
Desc | This file holds the data file records for all data files used
|
||||
within Mystic BBS software. Mystic BBS is compiled with the
|
||||
latest version of Free Pascal for all platforms.
|
||||
===========================================================================
|
||||
}
|
||||
|
||||
Const
|
||||
mysSoftwareID = 'Mystic';
|
||||
mysCopyYear = '1997-2012';
|
||||
mysVersion = '1.10 A11';
|
||||
mysDataChanged = '1.10 A11';
|
||||
|
||||
{$IFDEF WIN32}
|
||||
PathChar = '\';
|
||||
LineTerm = #13#10;
|
||||
OSID = 'Windows';
|
||||
OSType = 0;
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF LINUX}
|
||||
PathChar = '/';
|
||||
LineTerm = #10;
|
||||
OSID = 'Linux';
|
||||
OSType = 1;
|
||||
{$ENDIF}
|
||||
|
||||
{$IFDEF DARWIN}
|
||||
PathChar = '/';
|
||||
LineTerm = #10;
|
||||
OSID = 'OSX';
|
||||
OSType = 2;
|
||||
{$ENDIF}
|
||||
|
||||
mysMaxAcsSize = 30; // Max ACS string size
|
||||
mysMaxPathSize = 80;
|
||||
mysMaxMsgLines = 500; // Max message base lines
|
||||
mysMaxInputHistory = 5; // Input history stack size
|
||||
mysMaxFileDescLen = 50;
|
||||
mysMaxBatchQueue = 50;
|
||||
mysMaxVoteQuestion = 20; { Max number of voting questions }
|
||||
mysMaxMenuNameLen = 20;
|
||||
mysMaxMenuCmds = 75; { Maximum menu commands per menu }
|
||||
mysMaxLanguageStr = 478; { Total # of strings in language file }
|
||||
|
||||
Type
|
||||
SmallWord = System.Word;
|
||||
Integer = SmallInt; { force Integer to be a 2-byte signed }
|
||||
Word = SmallWord;
|
||||
|
||||
RecMessageText = Array[1..mysMaxMsgLines] of String[79];
|
||||
|
||||
AccessFlagType = Set of 1..25; { flags A to Z }
|
||||
|
||||
RecEchoMailAddr = Record { FidoNet-style network address }
|
||||
Zone,
|
||||
Net,
|
||||
Node,
|
||||
Point : Word;
|
||||
End;
|
||||
|
||||
RecUserOptionalField = Record
|
||||
Ask : Boolean;
|
||||
Desc : String[12];
|
||||
iType : Byte;
|
||||
iField : Byte;
|
||||
iMax : Byte;
|
||||
End;
|
||||
|
||||
RecConfig = Record // MYSTIC.DAT
|
||||
// INTERNALS
|
||||
DataChanged : String[8]; // Version of last data change
|
||||
SystemCalls : LongInt; // system caller number
|
||||
UserIdxPos : LongInt; // permanent user # position
|
||||
// SYSTEM PATHS
|
||||
SystemPath : String[mysMaxPathSize];
|
||||
DataPath : String[mysMaxPathSize];
|
||||
LogsPath : String[mysMaxPathSize];
|
||||
MsgsPath : String[mysMaxPathSize];
|
||||
AttachPath : String[mysMaxPathSize];
|
||||
ScriptPath : String[mysMaxPathSize];
|
||||
QwkPath : String[mysMaxPathSize];
|
||||
SemaPath : String[mysMaxPathSize];
|
||||
TemplatePath : String[mysMaxPathSize];
|
||||
MenuPath : String[mysMaxPathsize];
|
||||
TextPath : String[mysMaxPathSize];
|
||||
WebPath : String[mysMaxPathSize];
|
||||
// GENERAL SETTINGS
|
||||
BBSName : String[30];
|
||||
SysopName : String[30];
|
||||
SysopPW : String[15];
|
||||
SystemPW : String[15];
|
||||
FeedbackTo : String[30];
|
||||
Inactivity : Word;
|
||||
LoginTime : Byte;
|
||||
LoginAttempts : Byte;
|
||||
PWAttempts : Byte;
|
||||
PWChange : Word;
|
||||
PWInquiry : Boolean;
|
||||
DefStartMenu : String[20];
|
||||
DefFallMenu : String[20];
|
||||
DefThemeFile : String[20];
|
||||
DefTermMode : Byte;
|
||||
DefScreenSize : Byte;
|
||||
DefScreenCols : Byte;
|
||||
UseMatrix : Boolean;
|
||||
MatrixMenu : String[20];
|
||||
MatrixPW : String[15];
|
||||
MatrixAcs : String[mysMaxAcsSize];
|
||||
AcsSysop : String[mysMaxAcsSize];
|
||||
AcsInvisLogin : String[mysMaxAcsSize];
|
||||
AcsSeeInvis : String[mysMaxAcsSize];
|
||||
AcsMultiLogin : String[mysMaxAcsSize];
|
||||
SysopMacro : Array[1..4] of String[80]; // Sysop Macros
|
||||
ChatStart : SmallInt; // Chat hour start
|
||||
ChatEnd : SmallInt; // Chat hour end: mins since midnight
|
||||
ChatFeedback : Boolean; // E-mail sysop if page isn't answered
|
||||
ChatLogging : Boolean; // Record SysOp chat to CHAT.LOG?
|
||||
UseStatusBar : Boolean;
|
||||
StatusColor1 : Byte;
|
||||
StatusColor2 : Byte;
|
||||
StatusColor3 : Byte;
|
||||
// NEW USER SETTINGS
|
||||
AllowNewUsers : Boolean;
|
||||
NewUserSec : SmallInt;
|
||||
NewUserPW : String[15];
|
||||
NewUserEMail : Boolean;
|
||||
StartMGroup : Word;
|
||||
StartFGroup : Word;
|
||||
UseUSAPhone : Boolean;
|
||||
UserNameFormat : Byte;
|
||||
UserDateType : Byte; // 1=MM/DD/YY 2=DD/MM/YY 3=YY/DD/MM 4=Ask
|
||||
UserEditorType : Byte; // 0=Line 1=Full 2=Ask
|
||||
UserHotKeys : Byte; // 0=no 1=yes 2=ask
|
||||
UserFullChat : Byte; // 0=no 1=yes 2=ask
|
||||
UserFileList : Byte; // 0=Normal 1=Lightbar 2=Ask
|
||||
UserReadType : Byte; // 0=normal 1=ansi 2=ask
|
||||
UserMailIndex : Byte;
|
||||
UserReadIndex : Byte;
|
||||
UserQuoteWin : Byte;
|
||||
AskTheme : Boolean;
|
||||
AskRealName : Boolean;
|
||||
AskAlias : Boolean;
|
||||
AskStreet : Boolean;
|
||||
AskCityState : Boolean;
|
||||
AskZipCode : Boolean;
|
||||
AskHomePhone : Boolean;
|
||||
AskDataPhone : Boolean;
|
||||
AskBirthdate : Boolean;
|
||||
AskGender : Boolean;
|
||||
AskEmail : Boolean;
|
||||
AskUserNote : Boolean;
|
||||
AskScreenSize : Boolean;
|
||||
AskScreenCols : Boolean;
|
||||
OptionalField : Array[1..10] of RecUserOptionalField;
|
||||
// MESSAGE BASE SETTINGS
|
||||
MCompress : Boolean;
|
||||
MColumns : Byte;
|
||||
MShowHeader : Boolean; // re-show msg header after pause
|
||||
MShowBases : Boolean;
|
||||
MaxAutoSig : Byte;
|
||||
qwkMaxBase : SmallInt;
|
||||
qwkMaxPacket : SmallInt;
|
||||
qwkArchive : String[4];
|
||||
qwkBBSID : String[8];
|
||||
qwkWelcome : String[mysMaxPathSize];
|
||||
qwkNews : String[mysMaxPathSize];
|
||||
qwkGoodbye : String[mysMaxPathSize];
|
||||
Origin : String[50]; // Default origin line
|
||||
NetAddress : Array[1..30] of RecEchoMailAddr; // echomail addresses
|
||||
NetDesc : Array[1..30] of String[20]; // echomail network description
|
||||
NetCrash : Boolean;
|
||||
NetHold : Boolean;
|
||||
NetKillSent : Boolean;
|
||||
ColorQuote : Byte;
|
||||
ColorText : Byte;
|
||||
ColorTear : Byte;
|
||||
ColorOrigin : Byte;
|
||||
ColorKludge : Byte;
|
||||
AcsCrossPost : String[mysMaxAcsSize];
|
||||
AcsFileAttach : String[mysMaxAcsSize];
|
||||
AcsNodeLookup : String[mysMaxAcsSize];
|
||||
FSEditor : Boolean;
|
||||
FSCommand : String[60];
|
||||
// FILE BASE SETTINGS
|
||||
FCompress : Boolean;
|
||||
FColumns : Byte;
|
||||
FShowHeader : Boolean;
|
||||
FShowBases : Boolean;
|
||||
FDupeScan : Byte; // 0=no 1=yes 2=global
|
||||
UploadBase : Word; // Default upload file base
|
||||
ImportDIZ : Boolean;
|
||||
FreeUL : LongInt;
|
||||
FreeCDROM : LongInt;
|
||||
MaxFileDesc : Byte;
|
||||
FCommentLines : Byte;
|
||||
FCommentLen : Byte;
|
||||
TestUploads : Boolean;
|
||||
TestPassLevel : Byte;
|
||||
TestCmdLine : String[mysMaxPathSize];
|
||||
AcsValidate : String[mysMaxAcsSize];
|
||||
AcsSeeUnvalid : String[mysMaxAcsSize];
|
||||
AcsDLUnvalid : String[mysMaxAcsSize];
|
||||
AcsSeeFailed : String[mysMaxAcsSize];
|
||||
AcsDLFailed : String[mysMaxAcsSize];
|
||||
// INTERNET SERVER SETTINGS
|
||||
inetDomain : String[25];
|
||||
inetIPBlocking : Boolean;
|
||||
inetIPLogging : Boolean;
|
||||
inetSMTPUse : Boolean;
|
||||
inetSMTPPort : Word;
|
||||
inetSMTPMax : Word;
|
||||
inetSMTPDupes : Byte;
|
||||
inetPOP3Use : Boolean;
|
||||
inetPOP3Port : Word;
|
||||
inetPOP3Max : Word;
|
||||
inetPOP3Dupes : Byte;
|
||||
inetTNUse : Boolean;
|
||||
inetTNPort : Word;
|
||||
inetTNMax : Byte;
|
||||
inetTNDupes : Byte;
|
||||
inetFTPUse : Boolean;
|
||||
inetFTPPort : Word;
|
||||
inetFTPMax : Word;
|
||||
inetFTPDupes : Byte;
|
||||
inetFTPPortMin : Word;
|
||||
inetFTPPortMax : Word;
|
||||
inetFTPAnon : Boolean;
|
||||
inetFTPTimeout : Word;
|
||||
inetNNTPUse : Boolean;
|
||||
inetNNTPPort : Word;
|
||||
inetNNTPMax : Word;
|
||||
inetNNTPDupes : Byte;
|
||||
// UNSORTED
|
||||
Reserved : Array[1..491] of Char;
|
||||
End;
|
||||
|
||||
Const
|
||||
UserLockedOut = $01;
|
||||
UserNoRatio = $02;
|
||||
UserDeleted = $04;
|
||||
UserNoKill = $08;
|
||||
UserNoCaller = $10;
|
||||
UserNoPWChange = $20;
|
||||
|
||||
//FUTURE DATA FILE UPDATES NEEDED
|
||||
//LASTON needs optional1-10 compare to Mystic2
|
||||
//FBASE
|
||||
// ACS to comment on file
|
||||
//FDIR
|
||||
// pointer to comments record
|
||||
// rating moved here from comment record
|
||||
// file deletes and mbbsutil need updating to deal with comments
|
||||
//MBASES
|
||||
// expand header filename[20]
|
||||
// add template[20]
|
||||
// add msgbase sponser[30]
|
||||
// add newsname[80]
|
||||
// add colorkludge[b]
|
||||
// add flags[l] merge in useReal
|
||||
// flags:
|
||||
// userealname, forced, allow autosig, allow attachments, kludge filter
|
||||
// remove password?
|
||||
// ACS to s[30]
|
||||
//MENUS
|
||||
// remove fallback?
|
||||
// (flags)
|
||||
// menu descriptions
|
||||
// node action
|
||||
// command timer
|
||||
// input chars
|
||||
// (commands)
|
||||
// TBD compare to mystic 2
|
||||
// VOTING: expand ACS to s[30]
|
||||
// LANGREC
|
||||
// example path sizes
|
||||
// add script path?
|
||||
// compare to mystic 2 for fallback stuff?
|
||||
// rename to THEME
|
||||
|
||||
Type
|
||||
RecUser = Record { USERS.DAT }
|
||||
PermIdx : LongInt; // permanent user number
|
||||
Flags : Byte; { User Flags }
|
||||
Handle : String[30]; { Handle }
|
||||
RealName : String[30]; { Real Name }
|
||||
Password : String[15]; { Password }
|
||||
Address : String[30]; { Address }
|
||||
City : String[25]; { City }
|
||||
ZipCode : String[9]; { Zipcode }
|
||||
HomePhone : String[15]; { Home Phone }
|
||||
DataPhone : String[15]; { Data Phone }
|
||||
Birthday : LongInt;
|
||||
Gender : Char; { M> Male F> Female }
|
||||
Email : String[60]; { email address }
|
||||
Optional : Array[1..10] of String[60];
|
||||
UserInfo : String[30]; { user comment field }
|
||||
Theme : String[20]; { user's language file }
|
||||
AF1 : AccessFlagType;
|
||||
AF2 : AccessFlagType; { access flags set #2 }
|
||||
Security : SmallInt; { Security Level }
|
||||
Expires : String[8];
|
||||
ExpiresTo : Byte;
|
||||
LastPWChange : String[8];
|
||||
StartMenu : String[20]; { Start menu for user }
|
||||
Archive : String[4]; { default archive extension }
|
||||
QwkFiles : Boolean; { Include new files in QWK? }
|
||||
DateType : Byte; { Date format (see above) }
|
||||
ScreenSize : Byte; { user's screen length }
|
||||
ScreenCols : Byte;
|
||||
PeerIP : String[20];
|
||||
PeerName : String[50];
|
||||
FirstOn : LongInt; { Date/Time of First Call }
|
||||
LastOn : LongInt; { Date/Time of Last Call }
|
||||
Calls : LongInt; { Number of calls to BBS }
|
||||
CallsToday : SmallInt; { Number of calls today }
|
||||
DLs : SmallInt; { # of downloads }
|
||||
DLsToday : SmallInt; { # of downloads today }
|
||||
DLk : LongInt; { # of downloads in K }
|
||||
DLkToday : LongInt; { # of downloaded K today }
|
||||
ULs : LongInt; { total number of uploads }
|
||||
ULk : LongInt; { total number of uploaded K }
|
||||
Posts : LongInt; { total number of msg posts }
|
||||
Emails : LongInt; { total number of sent email }
|
||||
TimeLeft : LongInt; { time left online for today }
|
||||
TimeBank : SmallInt; { number of mins in timebank }
|
||||
FileRatings : LongInt;
|
||||
FileComment : LongInt;
|
||||
LastFBase : Word; { Last file base }
|
||||
LastMBase : Word; { Last message base }
|
||||
LastMGroup : Word; { Last group accessed }
|
||||
LastFGroup : Word; { Last file group accessed }
|
||||
Vote : Array[1..mysMaxVoteQuestion] of Byte; { Voting booth data }
|
||||
EditType : Byte; { 0 = Line, 1 = Full, 2 = Ask }
|
||||
FileList : Byte; { 0 = Normal, 1 = Lightbar }
|
||||
SigUse : Boolean; { Use auto-signature? }
|
||||
SigOffset : LongInt; { offset to sig in AUTOSIG.DAT }
|
||||
SigLength : Byte; { number of lines in sig }
|
||||
HotKeys : Boolean; { does user have hotkeys on? }
|
||||
MReadType : Byte; { 0 = line 1 = full 2 = ask }
|
||||
UseLBIndex : Boolean; { use lightbar index? }
|
||||
UseLBQuote : Boolean; { use lightbar quote mode }
|
||||
UseLBMIdx : Boolean; { use lightbar index in email? }
|
||||
UseFullChat : Boolean; { use full screen teleconference }
|
||||
Credits : LongInt;
|
||||
Reserved : Array[1..393] of Byte;
|
||||
End;
|
||||
|
||||
EventRec = Record { EVENTS.DAT }
|
||||
Active : Boolean; { Is event active? }
|
||||
Name : String[30]; { Event Name }
|
||||
Forced : Boolean; { Is this a forced event }
|
||||
ErrLevel : Byte; { Errorlevel to Exit }
|
||||
ExecTime : SmallInt; { Minutes after midnight }
|
||||
Warning : Byte; { Warn user before the event }
|
||||
Offhook : Boolean; { Offhook modem for event? }
|
||||
Node : Byte; { Node number. 0 = all }
|
||||
LastRan : LongInt; { Last time event was ran }
|
||||
End;
|
||||
|
||||
(* SECURITY.DAT in the data directory holds 255 records, one for each *)
|
||||
(* possible security level. *)
|
||||
|
||||
RecSecurity = Record { SECURITY.DAT }
|
||||
Desc : String[30]; { Description of security level }
|
||||
Time : SmallInt; { Time online (mins) per day }
|
||||
MaxCalls : SmallInt; { Max calls per day }
|
||||
MaxDLs : SmallInt; { Max downloads per day }
|
||||
MaxDLk : SmallInt; { Max download kilobytes per day }
|
||||
MaxTB : SmallInt; { Max mins allowed in time bank }
|
||||
DLRatio : Byte; { Download ratio (# of DLs per UL) }
|
||||
DLKRatio : SmallInt; { DL K ratio (# of DLed K per UL K }
|
||||
AF1 : AccessFlagType; { Access flags for this level A-Z }
|
||||
AF2 : AccessFlagType; { Access flags #2 for this level }
|
||||
Hard : Boolean; { Do a hard AF upgrade? }
|
||||
StartMenu : String[20]; { Start Menu for this level }
|
||||
PCRatio : SmallInt; { Post / Call ratio per 100 calls }
|
||||
Expires : Word;
|
||||
ExpiresTo : Word;
|
||||
Posts : Word;
|
||||
PostsTo : Word;
|
||||
Download : Word;
|
||||
DownloadTo : Word;
|
||||
Upload : Word;
|
||||
UploadTo : Word;
|
||||
Calls : Word;
|
||||
CallsTo : Word;
|
||||
Reserved : Array[1..64] of Byte;
|
||||
End;
|
||||
|
||||
RecArchive = Record { ARCHIVE.DAT }
|
||||
OSType : Byte;
|
||||
Active : Boolean;
|
||||
Desc : String[30];
|
||||
Ext : String[4];
|
||||
Pack : String[80];
|
||||
Unpack : String[80];
|
||||
View : String[80];
|
||||
End;
|
||||
|
||||
MScanRec = Record { <Message Base Path> *.SCN }
|
||||
NewScan : Byte; { Include this base in new scan? }
|
||||
QwkScan : Byte; { Include this base in qwk scan? }
|
||||
End;
|
||||
|
||||
MBaseRec = Record { MBASES.DAT }
|
||||
Name : String[40]; { Message base name }
|
||||
QWKName : String[13]; { QWK (short) message base name }
|
||||
FileName : String[40]; { Message base file name }
|
||||
Path : String[40]; { Path where files are stored }
|
||||
BaseType : Byte; { 0 = JAM, 1 = Squish }
|
||||
NetType : Byte; { 0 = Local 1 = EchoMail }
|
||||
{ 2 = UseNet 3 = NetMail }
|
||||
PostType : Byte; { 0 = Public 1 = Private }
|
||||
ACS, { ACS required to see this base }
|
||||
ReadACS, { ACS required to read messages }
|
||||
PostACS, { ACS required to post messages }
|
||||
SysopACS : String[20]; { ACS required for sysop options }
|
||||
Password : String[15]; { Password for this message base }
|
||||
ColQuote : Byte; { Quote text color }
|
||||
ColText : Byte; { Text color }
|
||||
ColTear : Byte; { Tear line color }
|
||||
ColOrigin: Byte; { Origin line color }
|
||||
NetAddr : Byte; { Net AKA to use for this base }
|
||||
Origin : String[50]; { Net origin line for this base }
|
||||
UseReal : Boolean; { Use real names? }
|
||||
DefNScan : Byte; { 0 = off, 1 = on, 2 = always }
|
||||
DefQScan : Byte; { 0 = off, 1 = on, 2 = always }
|
||||
MaxMsgs : Word; { Max messages to allow }
|
||||
MaxAge : Word; { Max age of messages before purge }
|
||||
Header : String[8]; { Display Header file name }
|
||||
Index : SmallInt; { QWK index - NEVER CHANGE THIS }
|
||||
End;
|
||||
|
||||
FScanRec = Record { <Data Path> *.SCN }
|
||||
NewScan : Byte; { Include this base in new scan? }
|
||||
LastNew : LongInt; { Last file scan (packed datetime)}
|
||||
End;
|
||||
|
||||
FBaseRec = Record { FBASES.DAT }
|
||||
Name : String[40]; { File base name }
|
||||
FtpName : String[60]; { FTP directory name }
|
||||
Filename : String[40]; { File name }
|
||||
DispFile : String[20]; { Pre-list display file name }
|
||||
Template : String[20]; { ansi file list template }
|
||||
ListACS, { ACS required to see this base }
|
||||
FtpACS, { ACS to see in FTP directory }
|
||||
SysopACS, { ACS required for SysOp functions}
|
||||
ULACS, { ACS required to upload files }
|
||||
DLACS : String[mysMaxAcsSize]; { ACS required to download files }
|
||||
Path : String[120]; { Path where files are stored }
|
||||
Password : String[20]; { Password to access this base }
|
||||
DefScan : Byte; { Default New Scan Setting }
|
||||
ShowUL : Boolean;
|
||||
IsCDROM : Boolean;
|
||||
IsFREE : Boolean;
|
||||
End;
|
||||
// make flags and merge in shouul, iscdrom,isfree, etc
|
||||
|
||||
(* The file directory listing are stored as <FBaseRec.FileName>.DIR in *)
|
||||
(* the data directory. Each record stores the info on one file. File *)
|
||||
(* descriptions are stored in <FBaseRec.FileName>.DES in the data *)
|
||||
(* directory. FDirRec.Pointer points to the file position in the .DES *)
|
||||
(* file where the file description for the file begins. FDirRec.Lines is *)
|
||||
(* the number of lines in the file description. Each line is stored as a *)
|
||||
(* Pascal-like string (ie the first byte is the length of the string, *)
|
||||
(* followed by text which is the length of the first byte *)
|
||||
|
||||
Const
|
||||
FDirOffline = $01;
|
||||
FDirInvalid = $02;
|
||||
FDirDeleted = $04;
|
||||
FDirFailed = $08;
|
||||
FDirFree = $10;
|
||||
|
||||
Type
|
||||
FDirRec = Record { *.DIR }
|
||||
FileName : String[70]; { File name }
|
||||
Size : LongInt; { File size (in bytes) }
|
||||
DateTime : LongInt; { Date and time of upload }
|
||||
Uploader : String[30]; { User name who uploaded the file }
|
||||
Flags : Byte; { Set of FDIRFLAGS (see above) }
|
||||
Pointer : LongInt; { Pointer to file description }
|
||||
Lines : Byte; { Number of description lines }
|
||||
DLs : Word; { # of times this file was downloaded}
|
||||
End;
|
||||
|
||||
FDirCommentRec = Record { .FCI and .FCT in DATA directory }
|
||||
UserName : String[30];
|
||||
Rating : Byte;
|
||||
Date : LongInt;
|
||||
Lines : Word;
|
||||
End;
|
||||
|
||||
RecGroup = Record { GROUP_*.DAT }
|
||||
Name : String[30]; { Group name }
|
||||
ACS : String[30]; { ACS required to access group }
|
||||
Hidden : Boolean;
|
||||
End;
|
||||
|
||||
(* Mystic BBS stores it's menu files as text files. They *)
|
||||
(* have been stored this way to make it possible to edit them with a text *)
|
||||
(* editor (which is sometimes easier then using the menu editor). The *)
|
||||
(* following records do not need to be used, but provide one way of *)
|
||||
(* reading a menu into a record. *)
|
||||
|
||||
MenuRec = Record
|
||||
Header : String[255];
|
||||
Prompt : String[255];
|
||||
DispCols : Byte;
|
||||
ACS : String[20];
|
||||
Password : String[15];
|
||||
TextFile : String[8];
|
||||
FallBack : String[8];
|
||||
MenuType : Byte; { 0 = standard, 1 = lightbar, 2 = lightbar grid }
|
||||
InputType : Byte; { 0 = user setting, 1 = longkey, 2 = hotkey }
|
||||
DoneX : Byte;
|
||||
DoneY : Byte;
|
||||
Global : Byte; { 0 = no, 1 = yes }
|
||||
End;
|
||||
|
||||
MenuCmdRec = Record
|
||||
Text : String[79];
|
||||
HotKey : String[8];
|
||||
LongKey : String[8];
|
||||
ACS : string[20];
|
||||
Command : String[2];
|
||||
Data : String[79];
|
||||
X : Byte;
|
||||
Y : Byte;
|
||||
cUp : Byte;
|
||||
cDown : Byte;
|
||||
cLeft : Byte;
|
||||
cRight : Byte;
|
||||
LText : String[79];
|
||||
LHText : String[79];
|
||||
End;
|
||||
|
||||
PercentRec = Record // percentage bar record
|
||||
BarLen : Byte;
|
||||
LoChar : Char;
|
||||
LoAttr : Byte;
|
||||
HiChar : Char;
|
||||
HiAttr : Byte;
|
||||
End;
|
||||
|
||||
LangRec = Record { LANGUAGE.DAT }
|
||||
FileName : String[8]; { Language file name }
|
||||
Desc : String[30]; { Language description }
|
||||
TextPath : String[40]; { Path where text files are stored }
|
||||
MenuPath : String[40]; { Path where menu files are stored }
|
||||
okASCII : Boolean; { Allow ASCII }
|
||||
okANSI : Boolean; { Allow ANSI }
|
||||
BarYN : Boolean; { Use Lightbar Y/N with this lang }
|
||||
FieldCol1 : Byte; { Field input color }
|
||||
FieldCol2 : Byte;
|
||||
FieldChar : Char;
|
||||
EchoCh : Char; { Password echo character }
|
||||
QuoteColor : Byte; { Color for quote lightbar }
|
||||
TagCh : Char; { File Tagged Char }
|
||||
FileHi : Byte; { Color of file search highlight }
|
||||
FileLo : Byte; { Non lightbar description color }
|
||||
NewMsgChar : Char; { Lightbar Msg Index New Msg Char }
|
||||
VotingBar : PercentRec; { voting booth bar }
|
||||
FileBar : PercentRec; { file list bar }
|
||||
MsgBar : PercentRec; { lightbar msg reader bar }
|
||||
GalleryBar : PercentRec;
|
||||
Reserved : Array[1..95] of Byte; { RESERVED }
|
||||
End;
|
||||
|
||||
BBSListRec = Record
|
||||
cType : Byte;
|
||||
Phone : String[15];
|
||||
Telnet : String[40];
|
||||
BBSName : String[30];
|
||||
Location : String[25];
|
||||
SysopName : String[30];
|
||||
BaudRate : String[6];
|
||||
Software : String[10];
|
||||
Deleted : Boolean;
|
||||
AddedBy : String[30];
|
||||
Verified : LongInt;
|
||||
Res : Array[1..6] of Byte;
|
||||
End;
|
||||
|
||||
(* ONELINERS.DAT found in the data directory. This file contains all the
|
||||
one-liner data. It can be any number of records in size. *)
|
||||
|
||||
OneLineRec = Record
|
||||
Text : String[79];
|
||||
From : String[30];
|
||||
End;
|
||||
|
||||
(* Each record of VOTES.DAT is one question. Mystic only allows for up *)
|
||||
(* to 20 questions. *)
|
||||
|
||||
VoteRec = Record { VOTES.DAT in DATA directory }
|
||||
Votes : SmallInt; { Total votes for this question }
|
||||
AnsNum : Byte; { Total # of Answers }
|
||||
User : String[30]; { User name who added question }
|
||||
ACS : String[20]; { ACS to see this question }
|
||||
AddACS : String[20]; { ACS to add an answer }
|
||||
ForceACS : String[20]; { ACS to force voting of question }
|
||||
Question : String[79]; { Question text }
|
||||
Answer : Array[1..15] of Record { Array[1..15] of Answer data }
|
||||
Text : String[40]; { Answer text }
|
||||
Votes : SmallInt; { Votes for this answer }
|
||||
End;
|
||||
End;
|
||||
|
||||
(* CHATx.DAT is created upon startup, where X is the node number being *)
|
||||
(* loaded. These files are used to store all the user information for a *)
|
||||
(* node. *)
|
||||
|
||||
ChatRec = Record { CHATx.DAT }
|
||||
Active : Boolean; { Is there a user on this node? }
|
||||
Name : String[30]; { User's name on this node }
|
||||
Action : String[40]; { User's action on this node }
|
||||
Location : String[30]; { User's City/State on this node }
|
||||
Gender : Char; { User's gender }
|
||||
Age : Byte; { User's age }
|
||||
Baud : String[6]; { User's baud rate }
|
||||
Invisible : Boolean; { Is node invisible? }
|
||||
Available : Boolean; { Is node available? }
|
||||
InChat : Boolean; { Is user in multi-node chat? }
|
||||
Room : Byte; { Chat room }
|
||||
End;
|
||||
|
||||
(* Chat room record - partially used by the multi node chat functions *)
|
||||
|
||||
RoomRec = Record
|
||||
Name : String[40]; { Channel Name }
|
||||
Reserved : Array[1..128] of Byte; { RESERVED }
|
||||
End;
|
||||
|
||||
(* CALLERS.DAT holds information on the last ten callers to the BBS. This *)
|
||||
(* file is always 10 records long with the most recent caller being the *)
|
||||
(* 10th record. *)
|
||||
|
||||
LastOnRec = Record { CALLERS.DAT }
|
||||
Handle : String[30]; { User's Name }
|
||||
City : String[25]; { City/State }
|
||||
Address : String[30]; { user's address }
|
||||
Baud : String[6]; { Baud Rate }
|
||||
DateTime : LongInt; { Date & Time (UNIX) }
|
||||
Node : Byte; { Node number of login }
|
||||
CallNum : LongInt; { Caller Number }
|
||||
EmailAddr : String[35]; { email address }
|
||||
UserInfo : String[30]; { user info field }
|
||||
Option1 : String[35]; { optional data 1 }
|
||||
Option2 : String[35]; { " " 2 }
|
||||
Option3 : String[35]; { " " 3 }
|
||||
End;
|
||||
|
||||
HistoryRec = Record
|
||||
Date : LongInt;
|
||||
Emails : Word;
|
||||
Posts : Word;
|
||||
Downloads : Word;
|
||||
Uploads : Word;
|
||||
DownloadKB : LongInt;
|
||||
UploadKB : LongInt;
|
||||
Calls : LongInt;
|
||||
NewUsers : Word;
|
||||
End;
|
||||
|
||||
RecProtocol = Record
|
||||
OSType : Byte;
|
||||
Active : Boolean;
|
||||
Batch : Boolean;
|
||||
Key : Char;
|
||||
Desc : String[40];
|
||||
SendCmd : String[60];
|
||||
RecvCmd : String[60];
|
||||
End;
|
||||
|
||||
PromptRec = String[255];
|
||||
|
||||
NodeMsgRec = Record
|
||||
FromNode : Byte;
|
||||
FromWho : String[30];
|
||||
ToWho : String[30];
|
||||
Message : String[250];
|
||||
MsgType : Byte;
|
||||
{ 1 = Chat Pub and broadcast }
|
||||
{ 2 = System message }
|
||||
{ 3 = User message }
|
||||
{ 4 = Chat Private }
|
||||
{ 5 = chat status note }
|
||||
{ 6 = chat action }
|
||||
{ 7 = chat topic update }
|
||||
Room : Byte; { Chat room number. 0 = chat broadcast }
|
||||
End;
|
Loading…
Reference in New Issue