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