mysticbbs/mystic/bbs_msgbase.pas

4795 lines
132 KiB
ObjectPascal

Unit bbs_MsgBase;
// ====================================================================
// Mystic BBS Software Copyright 1997-2013 By James Coyle
// ====================================================================
//
// This file is part of Mystic BBS.
//
// Mystic BBS is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Mystic BBS is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Mystic BBS. If not, see <http://www.gnu.org/licenses/>.
//
// ====================================================================
{$I M_OPS.PAS}
Interface
Uses
m_FileIO,
m_DateTime,
BBS_Records,
BBS_Common,
bbs_General,
bbs_MsgBase_ABS,
bbs_MsgBase_JAM,
bbs_MsgBase_Squish,
bbs_Edit_ANSI;
Type
TMsgBase = Class
MBaseFile : File of RecMessageBase;
MScanFile : File of MScanRec;
GroupFile : File of RecGroup;
TotalMsgs : Integer;
TotalConf : Integer;
MsgBase : PMsgBaseABS;
MBase : RecMessageBase;
MScan : MScanRec;
Group : RecGroup;
MsgText : RecMessageText;
MsgTextSize : SmallInt;
WereMsgs : Boolean;
Reading : Boolean;
Constructor Create (Var Owner: Pointer);
Destructor Destroy; Override;
Function IsQuotedText (Str: String) : Boolean;
Procedure ExportQuoteData (Var Msg: PMsgBaseABS);
Procedure AppendMessageText (Var Msg: PMsgBaseABS; Lines: Integer; ReplyID: String);
Procedure AssignMessageData (Var Msg: PMsgBaseABS; Var TempBase: RecMessageBase);
Function GetBaseByNum (Num: LongInt; Var TempBase: RecMessageBase) : Boolean;
Function GetBaseCompressed (Num: LongInt; Var TempBase: RecMessageBase) : Boolean;
Function GetMessageStats (List, ShowPrompt, ShowYou: Boolean; Var ListPtr: LongInt; Var TempBase: RecMessageBase; NoFrom, NoRead: Boolean; Var Total, New, Yours: LongInt) : Boolean;
Procedure GetMailStats (Var Total, UnRead: LongInt);
Function GetMatchedAddress (Orig, Dest: RecEchoMailAddr) : RecEchoMailAddr;
Function GetTotalBases (Compressed: Boolean) : LongInt;
Function GetTotalMessages (Var TempBase: RecMessageBase) : LongInt;
Procedure PostTextFile (Data: String; AllowCodes: Boolean);
Function SaveMessage (mArea: RecMessageBase; mFrom, mTo, mSubj: String; mAddr: RecEchoMailAddr; mLines: Integer) : Boolean;
Function NetmailLookup (FromMenu: Boolean; MsgTo, DefAddr: String) : String;
Function ListAreas (Compress: Boolean) : Integer;
Procedure ChangeArea (Data: String);
Procedure SetMessageScan;
Procedure GetMessageScan;
Procedure SendMassEmail;
Procedure ReplyMessage (Email: Boolean; ListMode: Byte; ReplyID: String);
Procedure EditMessage;
Function ReadMessages (Mode: Char; CmdData, SearchStr: String) : Boolean;
Procedure ToggleNewScan (QWK: Boolean; Data: String);
Procedure MessageGroupChange (Ops: String; FirstBase, Intro : Boolean);
Procedure PostMessage (Email: Boolean; Data: String);
Procedure CheckEMail (CmdData: String);
Procedure MessageNewScan (Data: String);
Procedure MessageQuickScan (Data: String);
Procedure GlobalMessageSearch (Mode: Char);
Procedure SetMessagePointers (ForceGlobal: Boolean);
Procedure ViewSentEmail;
Function ResolveOrigin (Var mArea: RecMessageBase) : String;
// QWK and QWKE goodies
Procedure DownloadQWK (Extended: Boolean; Data: String);
Procedure UploadREP;
Procedure WriteCONTROLDAT (Extended: Boolean);
Procedure WriteTOREADEREXT;
Procedure WriteDOORID (Extended: Boolean);
Function WriteMSGDAT (Extended: Boolean) : LongInt;
End;
Implementation
Uses
m_Strings,
BBS_DataBase,
BBS_Core,
BBS_User,
BBS_NodeInfo,
BBS_NodeList,
BBS_cfg_UserEdit;
Const
QwkControlName = 'MYSTICQWK';
Type
BSingle = Array [0..3] of Byte;
QwkNdxHdr = Record
MsgPos : BSingle;
Junk : Byte;
End;
QwkDATHdr = Record {128 bytes}
Status : Char;
MSGNum : Array [1..7] of Char;
Date : Array [1..8] of Char;
Time : Array [1..5] of Char;
UpTO : Array [1..25] of Char;
UpFROM : Array [1..25] of Char;
Subject : Array [1..25] of Char;
PassWord : Array [1..12] of Char;
ReferNum : Array [1..8] of Char;
NumChunk : Array [1..6] of Char;
Active : Char; {225 active, 226 killed}
ConfNum : Word;
Junk : Word;
NetTag : Char;
End;
Constructor TMsgBase.Create (Var Owner: Pointer);
Begin
Inherited Create;
MBase.Name := 'None';
Group.Name := 'None';
WereMsgs := False;
Reading := False;
MsgTextSize := 0;
End;
Destructor TMsgBase.Destroy;
Begin
Inherited Destroy;
End;
Procedure TMsgBase.ExportQuoteData (Var Msg: PMsgBaseABS);
Var
QuoteFile : Text;
Initials : String[4];
TempStr : String;
WrapData : String;
DoWrap : Boolean = True;
Begin
Assign (QuoteFile, Session.TempPath + 'msgtmp');
{$I-} ReWrite (QuoteFile); {$I+}
If IoResult = 0 Then Begin
Initials := strInitials(MsgBase^.GetFrom) + '> ';
TempStr := Session.GetPrompt(464);
TempStr := strReplace(TempStr, '|&1', MsgBase^.GetDate);
TempStr := strReplace(TempStr, '|&2', MsgBase^.GetFrom);
TempStr := strReplace(TempStr, '|&3', Initials);
WriteLn (QuoteFile, TempStr);
WriteLn (QuoteFile, ' ');
MsgBase^.MsgTxtStartUp;
WrapData := '';
While Not MsgBase^.EOM Do Begin
TempStr := MsgBase^.GetString(79);
If TempStr[1] = #1 Then Continue;
DoWrap := Not IsQuotedText(TempStr);
If DoWrap Then Begin
If WrapData <> '' Then Begin
If TempStr = '' Then Begin
WriteLn (QuoteFile, ' ' + Initials + strStripB(WrapData, ' '));
WriteLn (QuoteFile, ' ' + Initials);
WrapData := '';
Continue;
End;
TempStr := strStripB(WrapData, ' ') + ' ' + strStripL(TempStr, ' ');
End;
strWrap (TempStr, WrapData, 74);
WriteLn (QuoteFile, ' ' + Initials + Copy(TempStr, 1, 75));
End Else
WriteLn (QuoteFile, ' ' + Initials + Copy(TempStr, 1, 75));
End;
Close (QuoteFile);
End;
End;
Function TMsgBase.GetMatchedAddress (Orig, Dest: RecEchoMailAddr) : RecEchoMailAddr;
Var
Count : Byte;
Begin
Result := Orig;
If Orig.Zone = Dest.Zone Then Exit;
For Count := 1 to 30 Do
If bbsCfg.NetAddress[Count].Zone = Dest.Zone Then Begin
Result := bbsCfg.NetAddress[Count];
Exit;
End;
End;
Function TMsgBase.NetmailLookup (FromMenu: Boolean; MsgTo, DefAddr: String) : String;
Procedure ShowNode (ShowType: Byte; NodeData: RecNodeSearch; Ext: Boolean);
Var
Str : String;
Begin
Case ShowType of
0 : Str := Addr2Str(NodeData.Address);
1,
2 : If NodeData.Keyword = 'ZONE' Then
Str := 'ZONE' + strPadL(strI2S(NodeData.Address.Zone), 8, ' ')
Else
If NodeData.Keyword = 'REGION' Then
Str := 'REGION' + strPadL(strI2S(NodeData.Address.Net), 6, ' ')
Else
If NodeData.Keyword = 'HOST' Then
Str := 'NET' + strPadL(strI2S(NodeData.Address.Net), 9, ' ');
End;
Session.io.PromptInfo[1] := Str;
Session.io.PromptInfo[2] := NodeData.BBSName;
Session.io.PromptInfo[3] := NodeData.Location;
Session.io.PromptInfo[4] := NodeData.SysopName;
Session.io.PromptInfo[5] := NodeData.Phone;
Session.io.PromptInfo[6] := NodeData.Internet;
If Ext Then
Session.io.OutFullLn(Session.GetPrompt(500))
Else
Session.io.OutFullLn(Session.GetPrompt(499));
End;
Var
NodeList : TNodeListSearch;
FirstNode : RecNodeSearch;
NodeData : RecNodeSearch;
Listed : LongInt;
ListType : Byte;
HasList : Boolean;
Addr : RecEchoMailAddr;
Begin
HasList := FileExist(bbsCfg.DataPath + 'nodelist.txt');
NodeList := TNodeListSearch.Create;
If HasList Then
Session.io.OutFile ('nodesearch', False, 0);
Repeat
If FromMenu Then
Session.io.OutFull (Session.GetPrompt(497))
Else
If HasList Then
Session.io.OutFull (Session.GetPrompt(496))
Else
Session.io.OutFull (Session.GetPrompt(342));
Result := strUpper(Session.io.GetInput(25, 25, 11, DefAddr));
If Result = '' Then Break;
If (Result = '?') and HasList Then Begin
Session.io.OutFile('nodesearch', False, 0);
Continue;
End;
If Not HasList Then Break;
ListType := 0;
If Pos('LIST ZONE', Result) > 0 Then Begin
ListType := 1;
Result := '?:?/?';
End;
If Pos('LIST NET', Result) > 0 Then Begin
ListType := 2;
Result := strWordGet(3, Result, ' ') + ':?/?';
End;
Listed := 0;
Session.io.PausePtr := 1;
Session.io.AllowPause := True;
NodeList.ResetSearch (bbsCfg.DataPath + 'nodelist.txt', Result);
While NodeList.FindNext(NodeData) Do Begin
Case ListType of
0 : If Not FromMenu and (NodeData.Address.Net = 0) Then Continue;
1 : If NodeData.Keyword <> 'ZONE' Then Continue;
2 : If (NodeData.Keyword <> 'ZONE') and (NodeData.Keyword <> 'REGION') and (NodeData.Keyword <> 'HOST') Then Continue;
End;
Inc (Listed);
If Listed = 1 Then
FirstNode := NodeData
Else Begin
If Listed = 2 Then Begin
Session.io.OutFullLn (Session.GetPrompt(498));
ShowNode (ListType, FirstNode, False);
End;
ShowNode (ListType, NodeData, False);
End;
If (Session.io.PausePtr >= Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then
Case Session.io.MorePrompt of
'N' : Break;
'C' : Session.io.AllowPause := False;
End;
End;
If (Listed = 1) and (ListType = 0) Then Begin
ShowNode(ListType, FirstNode, True);
If FromMenu Then Continue;
Session.io.PromptInfo[7] := MsgTo;
If Session.io.GetYN(Session.GetPrompt(502), True) Then Begin
Result := Addr2Str(NodeData.Address);
Break;
End;
End Else
If (Listed = 0) And Not FromMenu And Not bbsCfg.ForceNodelist Then Begin
If Str2Addr(Result, Addr) Then Begin
Session.io.PromptInfo[1] := Addr2Str(Addr);
Session.io.PromptInfo[7] := MsgTo;
If Session.io.GetYN(Session.GetPrompt(502), True) Then Begin
Result := Addr2Str(Addr);
Break;
End;
End;
End Else Begin
Session.io.PromptInfo[1] := strComma(Listed);
Session.io.OutFullLn(Session.GetPrompt(501));
End;
Until False;
NodeList.Free;
End;
Function TMsgBase.IsQuotedText (Str: String) : Boolean;
Var
Temp : Byte;
Begin
Temp := Pos('>', Str);
// Temp := Pos('>', strStripL(Str, ' '));
Result := (Temp > 0) and (Temp < 5);
End;
(*
Function TMsgBase.OpenCreateBase (Var Msg: PMsgBaseABS; Var Area: RecMessageBase) : Boolean;
Begin
Result := False;
Case Area.BaseType of
0 : Msg := New(PMsgBaseJAM, Init);
1 : Msg := New(PMsgBaseSquish, Init);
End;
Msg^.SetMsgPath (Area.Path + Area.FileName);
Msg^.SetTempFile (Session.TempPath + 'msgbuf.');
If Not Msg^.OpenMsgBase Then
If Not Msg^.CreateMsgBase (Area.MaxMsgs, Area.MaxAge) Then Begin
Dispose (Msg, Done);
Exit;
End Else
If Not Msg^.OpenMsgBase Then Begin
Dispose (Msg, Done);
Exit;
End;
Result := True;
End;
*)
Function TMsgBase.GetBaseByNum (Num: LongInt; Var TempBase: RecMessageBase) : Boolean;
Var
F : File;
Begin
Result := False;
Assign (F, bbsCfg.DataPath + 'mbases.dat');
If Not ioReset(F, SizeOf(RecMessageBase), fmRWDN) Then Exit;
If ioSeek(F, Num) And (ioRead(F, TempBase)) Then
Result := True;
Close (F);
End;
Function TMsgBase.GetBaseCompressed (Num: LongInt; Var TempBase: RecMessageBase) : Boolean;
Var
F : File;
Count : LongInt;
Begin
If Not bbsCfg.MCompress Then Begin
Result := GetBaseByNum(Num, TempBase);
Exit;
End;
Result := False;
Assign (F, bbsCfg.DataPath + 'mbases.dat');
If Not ioReset(F, SizeOf(RecMessageBase), fmRWDN) Then Exit;
Count := 0;
While Not Eof(F) And (Count <> Num) Do Begin
ioRead (F, TempBase);
If Session.User.Access(TempBase.ListACS) Then Inc(Count);
End;
Close (F);
Result := Count = Num;
End;
(*
Function TMsgBase.GetBaseByIndex (Num: LongInt; Var TempBase: RecMessageBase) : Boolean;
Var
F : File;
Begin
Result := False;
Assign (F, bbsCfg.DataPath + 'mbases.dat');
If Not ioReset(F, SizeOf(RecMessageBase), fmRWDN) Then Exit;
While Not Eof(F) Do Begin
ioRead (F, TempBase);
If TempBase.Index = Num Then Begin
Result := True;
Break;
End;
End;
Close (F);
End;
*)
Function TMsgBase.GetTotalBases (Compressed: Boolean) : LongInt;
Var
F : File;
TempBase : RecMessageBase;
Begin
Result := 0;
Assign (F, bbsCfg.DataPath + 'mbases.dat');
If Not ioReset(F, SizeOf(RecMessageBase), fmRWDN) Then Exit;
If Not Compressed Then
Result := FileSize(F)
Else Begin
While Not Eof(F) Do Begin
ioRead (F, TempBase);
If Session.User.Access(TempBase.ListACS) Then
Inc (Result);
End;
End;
Close (F);
End;
Function TMsgBase.GetTotalMessages (Var TempBase: RecMessageBase) : LongInt;
Var
TempMsg : PMsgBaseABS;
Begin
Result := 0;
If TempBase.Name = 'None' Then Exit;
If MBaseOpenCreate(TempMsg, TempBase, Session.TempPath) Then Begin
Result := TempMsg^.NumberOfMsgs;
TempMsg^.CloseMsgBase;
Dispose (TempMsg, Done);
End;
End;
Function TMsgBase.GetMessageStats (List, ShowPrompt, ShowYou: Boolean; Var ListPtr: LongInt; Var TempBase: RecMessageBase; NoFrom, NoRead: Boolean; Var Total, New, Yours: LongInt) : Boolean;
Var
TempMsg : PMsgBaseABS;
Begin
Total := 0;
New := 0;
Yours := 0;
Result := False;
If TempBase.Name = 'None' Then Exit;
If MBaseOpenCreate(TempMsg, TempBase, Session.TempPath) Then Begin
Total := TempMsg^.NumberOfMsgs;
TempMsg^.SeekFirst(TempMsg^.GetLastRead(Session.User.UserNum) + 1);
While TempMsg^.SeekFound Do Begin
TempMsg^.MsgStartUp;
If NoFrom And Session.User.IsThisUser(TempMsg^.GetFrom) Then Begin
TempMsg^.SeekNext;
Continue;
End;
If (TempBase.Flags AND MBPrivate <> 0) And Not Session.User.IsThisUser(TempMsg^.GetTo) Then Begin
TempMsg^.SeekNext;
Continue;
End;
If TempMsg^.IsPriv And Not Session.User.IsThisUser(TempMsg^.GetTo) Then Begin
TempMsg^.SeekNext;
Continue;
End;
If NoRead And Session.User.IsThisUser(TempMsg^.GetTo) And TempMsg^.IsRcvd Then Begin
TempMsg^.SeekNext;
Continue;
End;
If List Then Begin
If (ShowYou And Not Session.User.IsThisUser(TempMsg^.GetTo)) Then Begin
TempMsg^.SeekNext;
Continue;
End;
If ShowPrompt Then
Session.io.OutBS(Console.CursorX, True);
Inc (ListPtr);
Session.io.PromptInfo[1] := strI2S(ListPtr);
Session.io.PromptInfo[2] := TempBase.Name;
Session.io.PromptInfo[3] := TempMsg^.GetFrom;
Session.io.PromptInfo[4] := TempMsg^.GetTo;
Session.io.PromptInfo[5] := TempMsg^.GetSubj;
Session.io.PromptInfo[6] := DateDos2Str(DateStr2Dos(TempMsg^.GetDate), Session.User.ThisUser.DateType);
If ListPtr = 1 Then
Session.io.OutFullLn(Session.GetPrompt(506));
Session.io.OutFullLn(Session.GetPrompt(507));
//write('ptr:', session.io.pauseptr, ' size:', session.user.thisuser.screensize, ' allow:', session.io.allowpause);session.io.getkey;
If (Session.io.PausePtr >= Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then
Case Session.io.MorePrompt of
'N' : Begin
Result := True;
Break;
End;
'C' : Session.io.AllowPause := False;
End;
// If ShowPrompt Then
// Session.io.OutFull(Session.GetPrompt(487));
Session.io.BufFlush;
End;
Inc (New);
If Session.User.IsThisUser(TempMsg^.GetTo) Then
Inc(Yours);
TempMsg^.SeekNext;
End;
TempMsg^.CloseMsgBase;
Dispose (TempMsg, Done);
End;
End;
Procedure TMsgBase.GetMailStats (Var Total, UnRead: LongInt);
Var
TempMsg : PMsgBaseABS;
TempBase : RecMessageBase;
Begin
Total := 0;
UnRead := 0;
FileMode := 66;
Reset (MBaseFile);
Read (MBaseFile, TempBase);
Close (MBaseFile);
If MBaseOpenCreate (TempMsg, TempBase, Session.TempPath) Then Begin
TempMsg^.SeekFirst (1);
While TempMsg^.SeekFound Do Begin
TempMsg^.MsgStartUp;
If Session.User.IsThisUser(TempMsg^.GetTo) Then Begin
Inc (Total);
If Not TempMsg^.IsRcvd Then Inc (UnRead);
End;
TempMsg^.SeekNext;
End;
TempMsg^.CloseMsgBase;
Dispose (TempMsg, Done);
End;
End;
Procedure TMsgBase.SetMessageScan;
Var
Count : Integer;
Temp : MScanRec;
Begin
Temp.NewScan := MBase.DefNScan;
Temp.QwkScan := MBase.DefQScan;
Assign (MScanFile, MBase.Path + MBase.FileName + '.scn');
{$I-} Reset (MScanFile); {$I+}
If IoResult <> 0 Then ReWrite (MScanFile);
If FileSize(MScanFile) < Session.User.UserNum - 1 Then Begin
Seek (MScanFile, FileSize(MScanFile));
For Count := FileSize(MScanFile) to Session.User.UserNum - 1 Do
Write (MScanFile, Temp);
End;
Seek (MScanFile, Session.User.UserNum - 1);
Write (MScanFile, MScan);
Close (MScanFile);
End;
Procedure TMsgBase.GetMessageScan;
Begin
MScan.NewScan := MBase.DefNScan;
MScan.QwkScan := MBase.DefQScan;
FileMode := 66;
Assign (MScanFile, MBase.Path + MBase.FileName + '.scn');
{$I-} Reset (MScanFile); {$I+}
If IoResult <> 0 Then Exit;
If FileSize(MScanFile) >= Session.User.UserNum Then Begin {filesize and usernum are }
Seek (MScanFile, Session.User.UserNum - 1); {not zero based }
Read (MScanFile, MScan);
{ added security measure for forced reading bases }
If MBase.DefNScan = 2 Then MScan.NewScan := 2;
If MBase.DefQScan = 2 Then MScan.QwkScan := 2;
End;
Close (MScanFile);
End;
Procedure TMsgBase.AppendMessageText (Var Msg: PMsgBaseABS; Lines: Integer; ReplyID: String);
Var
DF : File;
S : String;
A : SmallInt;
Begin
If (MBase.NetType > 0) and (MBase.QwkNetID = 0) Then Begin
Msg^.DoStringLn (#1 + 'MSGID: ' + Addr2Str(Msg^.GetOrigAddr) + ' ' + strI2H(CurDateDos, 8));
//Msg^.DoStringLn (#1 + 'MSGID: ' + Addr2Str(bbsCfg.NetAddress[MBase.NetAddr]) + ' ' + strI2H(CurDateDos, 8));
If ReplyID <> '' Then
Msg^.DoStringLn (#1 + 'REPLY: ' + ReplyID);
End;
For A := 1 to Lines Do
Msg^.DoStringLn(MsgText[A]);
If (MBase.Flags AND MBAutoSigs <> 0) and Session.User.ThisUser.SigUse and (Session.User.ThisUser.SigLength > 0) Then Begin
Assign (DF, bbsCfg.DataPath + 'autosig.dat');
Reset (DF, 1);
Seek (DF, Session.User.ThisUser.SigOffset);
Msg^.DoStringLn('');
For A := 1 to Session.User.ThisUser.SigLength Do Begin
BlockRead (DF, S[0], 1);
BlockRead (DF, S[1], Ord(S[0]));
Msg^.DoStringLn(S);
End;
Close (DF);
End;
If MBase.NetType > 0 Then Begin
Msg^.DoStringLn (#13 + '--- ' + mysSoftwareID + ' v' + mysVersion + ' (' + OSID + ')');
S := ' * Origin: ' + ResolveOrigin(MBase);
If MBase.QwkNetID = 0 Then
S := S + ' (' + Addr2Str(Msg^.GetOrigAddr) + ')';
Msg^.DoStringLn (S);
End;
End;
Procedure TMsgBase.AssignMessageData (Var Msg: PMsgBaseABS; Var TempBase: RecMessageBase);
Var
SemFile : Text;
Begin
Msg^.StartNewMsg;
If TempBase.Flags And MBRealNames <> 0 Then
Msg^.SetFrom(Session.User.ThisUser.RealName)
Else
Msg^.SetFrom(Session.User.ThisUser.Handle);
Msg^.SetLocal (True);
If TempBase.NetType > 0 Then Begin
If TempBase.NetType = 3 Then
Msg^.SetMailType(mmtNetMail)
Else
Msg^.SetMailType(mmtEchoMail);
Msg^.SetOrig(bbsCfg.NetAddress[TempBase.NetAddr]);
Case TempBase.NetType of
1 : Begin
If TempBase.QwkConfID = 0 Then
Assign (SemFile, bbsCfg.SemaPath + fn_SemFileEchoOut)
Else
Assign (SemFile, bbsCfg.SemaPath + fn_SemFileQwk);
If Session.ExitLevel > 5 Then Session.ExitLevel := 7 Else Session.ExitLevel := 5;
End;
2 : Begin
Assign (SemFile, bbsCfg.SemaPath + fn_SemFileNews);
If Session.ExitLevel > 5 Then Session.ExitLevel := 7 Else Session.ExitLevel := 5;
End;
3 : Begin
Assign (SemFile, bbsCfg.SemaPath + fn_SemFileNet);
If Session.ExitLevel = 5 Then Session.ExitLevel := 7 Else Session.ExitLevel := 6;
End;
End;
ReWrite (SemFile);
Close (SemFile);
End Else
Msg^.SetMailType(mmtNormal);
Msg^.SetPriv (TempBase.Flags and MBPrivate <> 0);
Msg^.SetDate (DateDos2Str(CurDateDos, 1));
Msg^.SetTime (TimeDos2Str(CurDateDos, 0));
End;
Procedure TMsgBase.ChangeArea (Data: String);
Var
Count : LongInt;
Total : Word;
TempBase : RecMessageBase;
Begin
If (Data = '+') or (Data = '-') Then Begin
Count := Session.User.ThisUser.LastMBase;
Repeat
Case Data[1] of
'+' : Inc(Count);
'-' : Dec(Count);
End;
If Not GetBaseByNum(Count, TempBase) Then Exit;
If Session.User.Access(TempBase.ListACS) Then Begin
Session.User.ThisUser.LastMBase := Count;
MBase := TempBase;
Exit;
End;
Until False;
End;
Count := strS2I(Data);
If Count > 0 Then Begin
If GetBaseByNum (Count, TempBase) Then
If Session.User.Access(TempBase.ListACS) Then Begin
Session.User.ThisUser.LastMBase := Count;
MBase := TempBase;
End;
Exit;
End;
If Pos('NOLIST', strUpper(Data)) > 0 Then
Total := GetTotalBases(bbsCfg.MCompress)
Else
Total := ListAreas(bbsCfg.MCompress);
If Total = 0 Then Begin
Session.io.OutFullLn (Session.GetPrompt(94));
Exit;
End;
Repeat
Session.io.OutFull (Session.GetPrompt(102));
Case Session.io.OneKeyRange(#13 + '?Q', 1, Total) of
#13,
'Q': Exit;
'?': Total := ListAreas(bbsCfg.MCompress);
Else
Break;
End;
Until False;
Count := Session.io.RangeValue;
If GetBaseCompressed(Count, TempBase) Then
If Session.User.Access(MBase.ListACS) Then Begin
MBase := TempBase;
Session.User.ThisUser.LastMBase := Count;
End;
End;
Procedure TMsgBase.ToggleNewScan (QWK: Boolean; Data: String);
Var
Total : LongInt;
QwkNet : Boolean;
Procedure List_Bases;
Begin
Session.io.PausePtr := 1;
Session.io.AllowPause := True;
If QWK Then
Session.io.OutFullLn (Session.GetPrompt(90))
Else
Session.io.OutFullLn (Session.GetPrompt(91));
Session.io.OutFullLn (Session.GetPrompt(92));
Total := 0;
FileMode := 66;
Reset (MBaseFile);
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If QwkNet And (MBase.QwkNetID <> Session.User.ThisUser.QwkNetwork) Then Continue;
If Session.User.Access(MBase.ListACS) Then Begin
Inc (Total);
Session.io.PromptInfo[1] := strI2S(Total);
Session.io.PromptInfo[2] := MBase.Name;
GetMessageScan;
If ((MScan.NewScan > 0) And Not QWK) or ((MScan.QwkScan > 0) And QWK) Then
Session.io.PromptInfo[3] := 'Yes' {++lang++}
Else
Session.io.PromptInfo[3] := 'No'; {++lang++}
Session.io.OutFull (Session.GetPrompt(93));
If (Total MOD bbsCfg.MColumns = 0) And (Total > 0) Then Session.io.OutRawLn('');
End;
If EOF(MBaseFile) and (Total MOD bbsCfg.MColumns <> 0) Then Session.io.OutRawLn('');
If (Session.io.PausePtr = Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then
Case Session.io.MorePrompt of
'N' : Break;
'C' : Session.io.AllowPause := False;
End;
End;
Close (MBaseFile);
Session.io.OutFull (Session.GetPrompt(430));
End;
Procedure ToggleCurrent (Forced: LongInt);
Begin
GetMessageScan;
Session.io.PromptInfo[1] := MBase.Name;
If QWK Then Begin
Case MScan.QwkScan of
0 : Begin
If Forced <> -1 Then
MScan.QwkScan := Forced
Else Begin
MScan.QwkScan := 1;
Session.io.OutFullLn (Session.GetPrompt(97));
End;
End;
1 : Begin
If Forced <> -1 Then
MScan.QwkScan := Forced
Else Begin
MScan.QwkScan := 0;
Session.io.OutFullLn (Session.GetPrompt(96));
End;
End;
2 : If Forced <> -1 Then
Session.io.OutFullLn (Session.GetPrompt(302));
End;
End Else Begin
Case MScan.NewScan of
0 : Begin
If Forced <> -1 Then
MScan.NewScan := Forced
Else Begin
MScan.NewScan := 1;
Session.io.OutFullLn (Session.GetPrompt(99));
End;
End;
1 : Begin
If Forced <> -1 Then
MScan.NewScan := Forced
Else Begin
MScan.NewScan := 0;
Session.io.OutFullLn (Session.GetPrompt(98));
End;
End;
2 : If Forced <> -1 Then
Session.io.OutFullLn (Session.GetPrompt(302));
End;
End;
SetMessageScan;
End;
Procedure ToggleAll (Value: Byte);
Begin
Reset (MBaseFile);
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If Session.User.Access(MBase.ListACS) Then
ToggleCurrent(Value);
End;
Close (MBaseFile);
End;
Procedure ToggleByNumber (BaseNumber: LongInt);
Begin
If (BaseNumber > 0) And GetBaseCompressed(BaseNumber, MBase) Then
ToggleCurrent(-1);
End;
Var
Old : RecMessageBase;
Temp : String[40];
Count1 : LongInt;
Count2 : LongInt;
Num1 : String[40];
Num2 : String[40];
Begin
Old := MBase;
FileMode := 66;
Session.User.IgnoreGroup := Pos('/ALLGROUP', strUpper(Data)) > 0;
QwkNet := Pos('/QWKNET', strUpper(Data)) > 0;
List_Bases;
If Total = 0 Then Begin
Session.io.OutFullLn (Session.GetPrompt(94));
MBase := Old;
Session.User.IgnoreGroup := False;
Exit;
End;
Repeat
Session.io.OutFull (Session.GetPrompt(95));
Temp := Session.io.GetInput(10, 40, 12, '');
If (Temp = '') or (Temp = 'Q') Then Break;
If Temp = 'A' Then
ToggleAll(1)
Else
If Temp = 'R' Then
ToggleAll(0)
Else
If Temp = '?' Then
// do nothing
Else Begin
Num1 := '';
Num2 := '';
For Count1 := 1 to Length(Temp) Do Begin
If Temp[Count1] = ' ' Then Continue;
If Temp[Count1] = ',' Then Begin
If Num2 <> '' Then Begin
For Count2 := strS2I(Num2) to strS2I(Num1) Do
ToggleByNumber(Count2);
End Else
ToggleByNumber(strS2I(Num1));
Num1 := '';
Num2 := '';
End Else
If Temp[Count1] = '-' Then Begin
Num2 := Num1;
Num1 := '';
End Else
Num1 := Num1 + Temp[Count1];
End;
If Num2 <> '' Then Begin
For Count1 := strS2I(Num2) to strS2I(Num1) Do
ToggleByNumber(Count1);
End Else
ToggleByNumber(strS2I(Num1));
End;
List_Bases;
Until False;
MBase := Old;
Session.User.IgnoreGroup := False;
End;
Procedure TMsgBase.MessageGroupChange (Ops : String; FirstBase, Intro : Boolean);
Var
Count : Word;
Total : Word;
tGroup : RecGroup;
tMBase : RecMessageBase;
tLast : Word;
Areas : Word;
Data : Word;
Begin
tGroup := Group;
If (Ops = '+') or (Ops = '-') Then Begin
Reset (GroupFile);
Count := Session.User.ThisUser.LastMGroup - 1;
Repeat
Case Ops[1] of
'+' : Inc(Count);
'-' : Dec(Count);
End;
{$I-}
Seek (GroupFile, Count);
Read (GroupFile, Group);
{$I+}
If IoResult <> 0 Then Break;
If Session.User.Access(Group.ACS) Then Begin
Session.User.ThisUser.LastMGroup := FilePos(GroupFile);
Close (GroupFile);
If Intro Then Session.io.OutFile ('group' + strI2S(Session.User.ThisUser.LastMGroup), True, 0);
If FirstBase Then Begin
Session.User.ThisUser.LastMBase := 0;
ChangeArea('+');
End;
Exit;
End;
Until False;
Close (GroupFile);
Group := tGroup;
Exit;
End;
Data := strS2I(Ops);
Reset (GroupFile);
If Data > 0 Then Begin
If Data > FileSize(GroupFile) Then Begin
Close (GroupFile);
Exit;
End;
Seek (GroupFile, Data - 1);
Read (GroupFile, Group);
If Session.User.Access(Group.ACS) Then Begin
Session.User.ThisUser.LastMGroup := FilePos(GroupFile);
If Intro Then
Session.io.OutFile ('group' + strI2S(Data), True, 0);
End Else
Group := tGroup;
Close (GroupFile);
If FirstBase Then Begin
Session.User.ThisUser.LastMBase := 1;
ChangeArea('+');
End;
Exit;
End;
Session.io.PausePtr := 1;
Session.io.AllowPause := True;
Session.io.OutFullLn (Session.GetPrompt(174)); { was after reset(groupfile) }
tLast := Session.User.ThisUser.LastMGroup;
Total := 0;
While Not Eof(GroupFile) Do Begin
Read (GroupFile, Group);
If Not Group.Hidden And Session.User.Access(Group.ACS) Then Begin
Areas := 0;
Session.User.ThisUser.LastMGroup := FilePos(GroupFile);
// use gettotalbases(true) here!?
If bbsCfg.MShowBases Then Begin
Reset (MBaseFile);
Read (MBaseFile, tMBase); { Skip EMAIL base }
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, tMBase);
If Session.User.Access(tMBase.ListACS) Then Inc(Areas);
End;
Close (MBaseFile);
End;
Inc (Total);
Session.io.PromptInfo[1] := strI2S(Total);
Session.io.PromptInfo[2] := Group.Name;
Session.io.PromptInfo[3] := strI2S(Areas);
Session.io.OutFullLn (Session.GetPrompt(175));
If (Session.io.PausePtr = Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then
Case Session.io.MorePrompt of
'N' : Break;
'C' : Session.io.AllowPause := False;
End;
End;
End;
Session.User.ThisUser.LastMGroup := tLast;
If Total = 0 Then
Session.io.OutFullLn (Session.GetPrompt(176))
Else Begin
Session.io.OutFull (Session.GetPrompt(177));
Session.io.OneKeyRange(#13 + 'Q', 1, Total);
Count := Session.io.RangeValue;
If (Count > 0) and (Count <= Total) Then Begin
Total := 0;
Reset (GroupFile);
Repeat
Read (GroupFile, Group);
If Not Group.Hidden And Session.User.Access(Group.ACS) Then Inc(Total);
If Count = Total Then Break;
Until False;
Session.User.ThisUser.LastMGroup := FilePos(GroupFile);
If Intro Then Session.io.OutFile ('group' + strI2S(Session.User.ThisUser.LastMGroup), True, 0);
Session.User.ThisUser.LastMBase := 1;
ChangeArea('+');
End Else
Group := tGroup;
End;
Close (GroupFile);
End;
Function TMsgBase.ListAreas (Compress: Boolean) : Integer;
Var
Total : LongInt = 0;
Listed : LongInt = 0;
TempBase : RecMessageBase;
TempFile : File;
Begin
Result := 1;
Assign (TempFile, bbsCfg.DataPath + 'mbases.dat');
If Not ioReset(TempFile, SizeOf(RecMessageBase), fmRWDN) Then Exit;
Session.io.PausePtr := 1;
Session.io.AllowPause := True;
While Not Eof(TempFile) Do Begin
ioRead (TempFile, TempBase);
If Session.User.Access(TempBase.ListACS) Then Begin
Inc (Listed);
If Listed = 1 Then
Session.io.OutFullLn(Session.GetPrompt(100));
If Compress Then
Inc (Total)
Else
Total := FilePos(TempFile);
Session.io.PromptInfo[1] := strI2S(Total);
Session.io.PromptInfo[2] := TempBase.Name;
Session.io.PromptInfo[3] := strI2S(GetTotalMessages(TempBase));
Session.io.OutFull (Session.GetPrompt(101));
If (Listed MOD bbsCfg.MColumns = 0) and (Listed > 0) Then Session.io.OutRawLn('');
End;
If Eof(TempFile) and (Listed MOD bbsCfg.MColumns <> 0) Then Session.io.OutRawLn('');
If (Session.io.PausePtr = Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then
Case Session.io.MorePrompt of
'N' : Begin
Total := FileSize(TempFile);
Break;
End;
'C' : Session.io.AllowPause := False;
End;
End;
Close (TempFile);
Result := Total;
End;
Procedure TMsgBase.ReplyMessage (Email: Boolean; ListMode: Byte; ReplyID: String);
Var
ToWho : String[30];
Subj : String[60];
Addr : RecEchomailAddr;
MsgNew : PMsgBaseABS;
TempStr : String;
Lines : SmallInt;
Total : LongInt;
ReplyBase : RecMessageBase;
IsPrivate : Boolean;
IsIgnore : Boolean;
Begin
ReplyBase := MBase;
If Not Email And Session.User.Access(bbsCfg.AcsExtReply) Then Begin
Session.io.PromptInfo[1] := MBase.Name;
Session.io.PromptInfo[2] := MsgBase^.GetFrom;
Session.io.PromptInfo[3] := MsgBase^.GetSubj;
If ListMode = 0 Then
Session.io.OutFull(Session.GetPrompt(509))
Else
Session.io.OutFull(Session.GetPrompt(510));
Case Session.io.OneKey (#13#27 + 'QBE', True) of
'Q',
#27 : Exit;
'B' : Begin
IsIgnore := Session.User.IgnoreGroup;
Session.User.IgnoreGroup := True;
Total := ListAreas(bbsCfg.MCompress);
Repeat
Session.io.OutFull(Session.GetPrompt(511));
Case Session.io.OneKeyRange(#13 + '?Q', 1, Total) of
#13,
'Q': Begin
Session.User.IgnoreGroup := IsIgnore;
Exit;
End;
'?': Total := ListAreas(bbsCfg.MCompress);
Else
Break;
End;
Until False;
If Not GetBaseCompressed(Session.io.RangeValue, ReplyBase) Then Begin
Session.User.IgnoreGroup := IsIgnore;
Exit;
End;
Session.User.IgnoreGroup := IsIgnore;
End;
'E' : Begin
Reset (MBaseFile);
Read (MBaseFile, ReplyBase);
Close (MBaseFile);
Email := True;
End;
End;
End;
Session.io.PromptInfo[1] := ReplyBase.Name;
Session.io.OutFullLn(Session.GetPrompt(512));
If Not Session.User.Access(ReplyBase.PostACS) Then Begin
Session.io.OutFullLn (Session.GetPrompt(105));
Exit;
End;
Set_Node_Action (Session.GetPrompt(349));
IsPrivate := (ReplyBase.Flags AND MBPrivate <> 0) or (ReplyBase.NetType = 3);
If (ReplyBase.Flags AND MBPrivate = 0) AND (ReplyBase.Flags AND MBPrivReply <> 0) Then
IsPrivate := Session.io.GetYN(Session.GetPrompt(514), False);
Repeat
If ListMode = 0 Then
Session.io.OutFull (Session.GetPrompt(407))
Else
Session.io.OutFull (Session.GetPrompt(408));
ToWho := Session.io.GetInput(30, 30, 11, MsgBase^.GetFrom);
If ToWho = '' Then Exit;
If (ReplyBase.NetType = 3) Or Not (Email or IsPrivate) Then Break;
If Not Session.User.FindUser(ToWho, False) Then Begin
Session.io.PromptInfo[1] := ToWho;
Session.io.OutFullLn (Session.GetPrompt(161));
ToWho := MsgBase^.GetFrom;
End Else
Break;
Until False;
If ReplyBase.NetType = 3 Then Begin
// If ReplyID <> '' Then
If Not Str2Addr(strWordGet(1, ReplyID, ' '), Addr) Then
MsgBase^.GetOrig(Addr);
TempStr := NetmailLookup(False, ToWho, Addr2Str(Addr));
If Not Str2Addr (TempStr, Addr) Then Exit;
End;
Subj := MsgBase^.GetSubj;
If Pos ('Re:', Subj) = 0 Then Subj := 'Re: ' + Subj;
Session.io.OutFull (Session.GetPrompt(451));
Subj := Session.io.GetInput (60, 60, 11, Subj);
If Subj = '' Then Exit;
ExportQuoteData(MsgBase);
Lines := 0;
Session.io.PromptInfo[1] := ToWho;
If Editor(Lines, ColumnValue[Session.Theme.ColumnSize] - 2, mysMaxMsgLines, False, fn_tplMsgEdit, Subj) Then Begin
Session.io.OutFull (Session.GetPrompt(107));
If Not MBaseOpenCreate(MsgNew, ReplyBase, Session.TempPath) Then Exit;
AssignMessageData(MsgNew, ReplyBase);
Case ReplyBase.NetType of
2 : MsgNew^.SetTo('All'); //Lang++
3 : Begin
MsgNew^.SetDest (Addr);
MsgNew^.SetOrig (GetMatchedAddress(bbsCfg.NetAddress[ReplyBase.NetAddr], Addr));
MsgNew^.SetCrash (bbsCfg.netCrash);
MsgNew^.SetHold (bbsCfg.netHold);
MsgNew^.SetKillSent (bbsCfg.netKillSent);
MsgNew^.SetTo (ToWho);
End;
Else
MsgNew^.SetTo (ToWho);
End;
MsgNew^.SetSubj (Subj);
MsgNew^.SetRefer (MsgBase^.GetMsgNum);
MsgNew^.SetPriv (IsPrivate);
AppendMessageText (MsgNew, Lines, ReplyID);
MsgNew^.WriteMsg;
MsgNew^.CloseMsgBase;
If MsgBase^.GetSeeAlso = 0 Then Begin
MsgBase^.MsgStartUp;
MsgBase^.SetSeeAlso(MsgNew^.GetMsgNum);
MsgBase^.ReWriteHdr;
End;
If Email Then Begin
Session.SystemLog ('Sent Email to ' + MsgNew^.GetTo);
Inc (Session.User.ThisUser.Emails);
Inc (Session.HistoryEmails);
End Else Begin
Session.SystemLog ('Posted #' + strI2S(MsgNew^.GetMsgNum) + ': "' + Subj + '" to ' + strStripMCI(ReplyBase.Name));
Inc (Session.User.ThisUser.Posts);
Inc (Session.HistoryPosts);
End;
Dispose (MsgNew, Done);
Session.io.OutFullLn (Session.GetPrompt(122));
End Else
Session.io.OutFullLn (Session.GetPrompt(109));
DirClean (Session.TempPath, '');
End;
Procedure TMsgBase.EditMessage;
Var
Lines : Integer;
Procedure ReadText;
Begin
MsgBase^.MsgTxtStartUp;
Lines := 0;
While Not MsgBase^.EOM and (Lines < mysMaxMsgLines) Do Begin
Inc (Lines);
MsgText[Lines] := MsgBase^.GetString(79);
End;
If Lines < mysMaxMsgLines Then Begin
Inc (Lines);
MsgText[Lines] := '';
End;
End;
Var
Count : LongInt;
TempStr : String;
DestAddr : RecEchoMailAddr;
Begin
If MsgBase^.GetRefer > 0 Then Begin
Count := MsgBase^.GetMsgNum;
MsgBase^.SeekFirst(MsgBase^.GetRefer);
If MsgBase^.SeekFound Then Begin
MsgBase^.MsgStartUp;
ExportQuoteData(MsgBase);
End;
MsgBase^.SeekFirst(Count);
MsgBase^.MsgStartUp;
End;
ReadText;
Repeat
Session.io.PromptInfo[1] := MsgBase^.GetTo;
Session.io.PromptInfo[2] := MsgBase^.GetSubj;
Session.io.PromptInfo[3] := Session.io.OutYN(MsgBase^.IsSent);
If MBase.NetType = 3 Then Begin
MsgBase^.GetDest(DestAddr);
Session.io.PromptInfo[1] := Session.io.PromptInfo[1] + ' (' + Addr2Str(DestAddr) + ')';
End;
Session.io.OutFull (Session.GetPrompt(296));
Case Session.io.OneKey('ABCQ!', True) of
'A' : Begin
Session.io.OutFull (Session.GetPrompt(297));
If MBase.NetType = 3 Then Begin
TempStr := Session.io.GetInput(30, 30, 11, MsgBase^.GetTo);
Session.io.OutFull (Session.GetPrompt(298));
If Str2Addr(Session.io.GetInput(20, 20, 12, Addr2Str(DestAddr)), DestAddr) Then Begin
MsgBase^.SetTo(TempStr);
MsgBase^.SetDest(DestAddr)
End;
End Else
If MBase.Flags And MBPrivate <> 0 Then Begin
TempStr := Session.io.GetInput (30, 30, 11, MsgBase^.GetTo);
If Session.User.SearchUser(TempStr, MBase.Flags and MBRealNames <> 0) Then
MsgBase^.SetTo(TempStr);
End Else
MsgBase^.SetTo(Session.io.GetInput(30, 30, 11, MsgBase^.GetTo));
End;
'B' : Begin
Session.io.OutFull (Session.GetPrompt(299));
MsgBase^.SetSubj(Session.io.GetInput(50, 50, 11, MsgBase^.GetSubj));
End;
'C' : MsgBase^.SetSent(NOT MsgBase^.IsSent);
'!' : Begin
TempStr := MsgBase^.GetSubj;
If Editor(Lines, ColumnValue[Session.Theme.ColumnSize] - 2, mysMaxMsgLines, False, fn_tplMsgEdit, TempStr) Then
MsgBase^.SetSubj(TempStr)
Else
ReadText;
End;
'Q' : Begin
If Session.io.GetYN(Session.GetPrompt(300), True) Then Begin
MsgBase^.EditMsgInit;
For Count := 1 to Lines Do
MsgBase^.DoStringLn(MsgText[Count]);
MsgBase^.EditMsgSave;
End;
Break;
End;
End;
Until False;
DirClean (Session.TempPath, '');
End;
(*
Procedure TMsgBase.MessageUpload (Var CurLine: SmallInt);
Var
FN : String[100];
TF : Text;
T1 : String[30];
T2 : String[60];
OK : Boolean;
Begin
OK := False;
T1 := Session.io.PromptInfo[1];
T2 := Session.io.PromptInfo[2];
Session.io.OutFull (Session.GetPrompt(352));
If Session.LocalMode Then Begin
FN := Session.io.GetInput(70, 70, 11, '');
If FN = '' Then Exit;
OK := FileExist(FN);
End Else Begin
FN := Session.TempPath + Session.io.GetInput(70, 70, 11, '');
If Session.FileBase.SelectProtocol(True, False) = 'Q' Then Exit;
Session.FileBase.ExecuteProtocol(1, FN);
OK := Session.FileBase.dszSearch(JustFile(FN));
End;
If OK Then Begin
Assign (TF, FN);
Reset (TF);
While Not Eof(TF) and (CurLine < mysMaxMsgLines) Do Begin
ReadLn (TF, MsgText[CurLine]);
Inc (CurLine);
End;
Close (TF);
End;
If Not Session.LocalMode Then FileErase(FN);
DirClean (Session.TempPath, 'msgtmp');
Session.io.PromptInfo[1] := T1;
Session.io.PromptInfo[2] := T2;
End;
*)
Function TMsgBase.ReadMessages (Mode: Char; CmdData, SearchStr: String) : Boolean;
Var
ReadRes : Boolean;
NoFrom : Boolean;
NoRead : Boolean;
ScanMode : Byte;
ValidKeys : String;
HelpFile : String[8];
LastRead : LongInt;
ListMode : Byte;
ReplyID : String[60];
TempStr : String;
Procedure SetMessageSecurity;
Begin
If Mode = 'E' Then Begin
ValidKeys := 'ADJLNPQRX?'#13;
HelpFile := 'emailhlp';
End Else
If Session.User.Access(MBase.SysopACS) or Session.User.IsThisUser(MsgBase^.GetFrom) Then Begin
ValidKeys := 'ADEFGHIJLMNPQRTX[]?'#13;
HelpFile := 'readshlp';
End Else Begin
ValidKeys := 'AGHIJLNPQRTX[]?'#13;
HelpFile := 'readhlp';
End;
End;
Function MoveMessage (IsCopy: Boolean) : Boolean;
Var
Total : LongInt;
TempBase : RecMessageBase;
MsgNew : PMsgBaseABS;
Str : String;
Addr : RecEchoMailAddr;
Ignore : Boolean;
Begin
Result := False;
Ignore := Session.User.IgnoreGroup;
Session.User.IgnoreGroup := True;
Repeat
Total := ListAreas(bbsCfg.MCompress);
If IsCopy Then
Session.io.OutFull (Session.GetPrompt(492))
Else
Session.io.OutFull (Session.GetPrompt(282));
Case Session.io.OneKeyRange('Q?', 1, Total) of
#00: If GetBaseCompressed(Session.io.RangeValue, TempBase) Then Begin
If Not Session.User.Access(TempBase.PostACS) Then Begin
Session.io.OutFullLn (Session.GetPrompt(105));
Break;
End;
Session.io.PromptInfo[1] := TempBase.Name;
Session.io.OutFullLn (Session.GetPrompt(318));
If Not MBaseOpenCreate(MsgNew, TempBase, Session.TempPath) Then Break;
MsgNew^.StartNewMsg;
MsgNew^.SetFrom (MsgBase^.GetFrom);
MsgNew^.SetLocal (True);
Case TempBase.NetType of
0 : MsgNew^.SetMailType(mmtNormal);
3 : MsgNew^.SetMailType(mmtNetMail);
Else
MsgNew^.SetMailType(mmtEchoMail);
End;
MsgBase^.GetOrig (Addr);
MsgNew^.SetOrig (Addr);
MsgNew^.SetPriv (MsgBase^.IsPriv);
MsgNew^.SetDate (MsgBase^.GetDate);
MsgNew^.SetTime (MsgBase^.GetTime);
MsgNew^.SetTo (MsgBase^.GetTo);
MsgNew^.SetSubj (MsgBase^.GetSubj);
MsgBase^.MsgTxtStartUp;
While Not MsgBase^.EOM Do Begin
Str := MsgBase^.GetString(79);
MsgNew^.DoStringLn(Str);
End;
MsgNew^.WriteMsg;
MsgNew^.CloseMsgBase;
Dispose (MsgNew, Done);
If IsCopy Then
Session.SystemLog('Forward msg to ' + strStripMCI(TempBase.Name))
Else Begin
Session.SystemLog('Moved msg to ' + strStripMCI(TempBase.Name));
MsgBase^.DeleteMsg;
End;
Result := True;
Break;
End;
#13,
'Q': Break;
End;
Until False;
Session.User.IgnoreGroup := Ignore;
End;
Procedure ExportMessage;
Var
FN : String;
Temp : String;
TF : Text;
Begin
If Session.LocalMode Then Begin
If ListMode = 0 Then
Session.io.OutFull (Session.GetPrompt(363))
Else
Session.io.OutFull (Session.GetPrompt(415));
FN := Session.io.GetInput(70, 70, 11, '');
End Else Begin
If ListMode = 0 Then
Session.io.OutFull (Session.GetPrompt(326))
Else
Session.io.OutFull (Session.GetPrompt(414));
FN := Session.TempPath + Session.io.GetInput(70, 70, 11, '');
End;
If FN = '' Then Exit;
Session.io.PromptInfo[1] := JustFile(FN);
Assign (TF, FN);
{$I-} ReWrite (TF); {$I+}
If IoResult = 0 Then Begin
WriteLn (TF, 'From: ' + MsgBase^.GetFrom);
WriteLn (TF, ' To: ' + MsgBase^.GetTo);
WriteLn (TF, 'Subj: ' + MsgBase^.GetSubj);
WriteLn (TF, 'Date: ' + MsgBase^.GetDate + ' ' + MsgBase^.GetTime);
WriteLn (TF, 'Base: ' + MBase.Name);
WriteLn (TF, '');
MsgBase^.MsgTxtStartUp;
While Not MsgBase^.EOM Do Begin
Temp := MsgBase^.GetString(79);
If Temp[1] <> #1 Then WriteLn (TF, Temp);
End;
Close (TF);
Session.io.OutFullLn (Session.GetPrompt(327));
If Not Session.LocalMode Then Begin
Session.FileBase.SendFile(FN);
FileErase(FN);
End;
End;
End;
Function SeekNextMsg (First, Back: Boolean): Boolean;
Var
Res : Boolean;
Str : String;
Begin
Res := False;
If (ScanMode = 3) and First Then Begin
If Mode = 'S' Then Session.io.OutRawLn('');
Session.io.OutFull (Session.GetPrompt(130));
Session.io.BufFlush;
End;
If Not First Then
If Back Then
MsgBase^.SeekPrior
Else
MsgBase^.SeekNext;
While Not Res And MsgBase^.SeekFound Do Begin
MsgBase^.MsgStartUp;
Case ScanMode of
0 : If MsgBase^.IsPriv Then
Res := Session.User.IsThisUser(MsgBase^.GetTo) or Session.User.IsThisUser(MsgBase^.GetFrom)
Else
Res := True;
1 : Res := Session.User.IsThisUser(MsgBase^.GetTo);
2 : Res := Session.User.IsThisUser(MsgBase^.GetTo) or Session.User.IsThisUser(MsgBase^.GetFrom);
(*
3 : Begin
Res := (Pos(SearchStr, strUpper(MsgBase^.GetTo)) > 0) or (Pos(SearchStr, strUpper(MsgBase^.GetFrom)) > 0) or
(Pos(SearchStr, strUpper(MsgBase^.GetSubj)) > 0);
If Not Res Then Begin
MsgBase^.MsgTxtStartUp;
While Not Res And Not MsgBase^.EOM Do Begin
Str := strUpper(MsgBase^.GetString(79));
Res := Pos(SearchStr, Str) > 0;
End;
End;
End;
*)
4 : Res := Session.User.IsThisUser(MsgBase^.GetFrom);
End;
If (SearchStr <> '') And (((ScanMode = 2) And Res) Or (ScanMode = 3)) Then Begin
Res := (Pos(SearchStr, strUpper(MsgBase^.GetTo)) > 0) or (Pos(SearchStr, strUpper(MsgBase^.GetFrom)) > 0) or
(Pos(SearchStr, strUpper(MsgBase^.GetSubj)) > 0);
If Not Res Then Begin
MsgBase^.MsgTxtStartUp;
While Not Res And Not MsgBase^.EOM Do Begin
Str := strUpper(MsgBase^.GetString(79));
Res := Pos(SearchStr, Str) > 0;
End;
End;
End;
If NoFrom And Session.User.IsThisUser(MsgBase^.GetFrom) Then
Res := False;
If NoRead And Session.User.IsThisUser(MsgBase^.GetTo) And MsgBase^.IsRcvd Then
Res := False;
If Not Res Then
If Back Then
MsgBase^.SeekPrior
Else
MsgBase^.SeekNext;
End;
If (ScanMode = 3) And First Then
Session.io.OutBS (Console.CursorX, True);
If Not WereMsgs Then WereMsgs := Res;
SeekNextMsg := Res;
End;
Procedure AssignHeaderInfo;
Var
NetAddr : RecEchoMailAddr;
Begin
FillChar (Session.io.PromptInfo, SizeOf(Session.io.PromptInfo), 0);
Session.io.PromptInfo[1] := MsgBase^.GetFrom;
If MBase.NetType = 3 Then Begin
MsgBase^.GetOrig(NetAddr);
Session.io.PromptInfo[1] := Session.io.PromptInfo[1] + ' (' + Addr2Str(NetAddr) + ')';
End;
Session.io.PromptInfo[2] := MsgBase^.GetTo;
If MBase.NetType = 3 Then Begin
MsgBase^.GetDest(NetAddr);
Session.io.PromptInfo[2] := Session.io.PromptInfo[2] + ' (' + Addr2Str(NetAddr) + ')';
End;
Session.io.PromptInfo[3] := MsgBase^.GetSubj;
Session.io.PromptInfo[4] := DateDos2Str(DateStr2Dos(MsgBase^.GetDate), Session.User.ThisUser.DateType);
Session.io.PromptInfo[10] := MsgBase^.GetTime;
Session.io.PromptInfo[5] := strI2S(MsgBase^.GetMsgNum);
Session.io.PromptInfo[6] := strI2S(MsgBase^.GetHighMsgNum);
Session.io.PromptInfo[7] := strI2S(MsgBase^.GetRefer);
Session.io.PromptInfo[8] := strI2S(MsgBase^.GetSeeAlso);
TempStr := Session.GetPrompt(490);
If MsgBase^.IsLocal Then Session.io.PromptInfo[9] := strWordGet(1, TempStr, ',');
If MsgBase^.IsEchoed Then Session.io.PromptInfo[9] := Session.io.PromptInfo[9] + ' ' + strWordGet(2, TempStr, ',');
If MsgBase^.IsPriv Then Session.io.PromptInfo[9] := Session.io.PromptInfo[9] + ' ' + strWordGet(3, TempStr, ',');
If MsgBase^.IsSent Then Session.io.PromptInfo[9] := Session.io.PromptInfo[9] + ' ' + strWordGet(4, TempStr, ',');
If MsgBase^.IsRcvd Then Session.io.PromptInfo[9] := Session.io.PromptInfo[9] + ' ' + strWordGet(6, TempStr, ',');
If MsgBase^.IsDeleted Then Session.io.PromptInfo[9] := Session.io.PromptInfo[9] + ' ' + strWordGet(5, TempStr, ',');
Session.io.PromptInfo[9] := strStripB(Session.io.PromptInfo[9], ' ');
End;
Procedure Send_Msg_Text (Str: String);
Begin
If IsQuotedText(Str) Then Begin
Session.io.AnsiColor (MBase.ColQuote);
Session.io.OutPipe (Str);
Session.io.AnsiColor (MBase.ColText);
End Else
If Copy(Str, 1, 4) = '--- ' Then Begin
Session.io.AnsiColor (MBase.ColTear);
Session.io.OutPipe (Str);
Session.io.AnsiColor (MBase.ColText);
End Else
If Copy(Str, 1, 2) = ' *' Then Begin
Session.io.AnsiColor (MBase.ColOrigin);
Session.io.OutPipe (Str);
Session.io.AnsiColor (MBase.ColText);
End Else
Session.io.OutPipe(Str);
If ListMode = 1 Then
Session.io.AnsiClrEOL;
Session.io.OutRawLn('');
End;
Procedure RemoveNewScan (PromptNumber: SmallInt);
Begin
GetMessageScan;
If MScan.NewScan = 1 Then
If Session.io.GetYN(Session.GetPrompt(PromptNumber), False) Then Begin
MScan.NewScan := 0;
SetMessageScan;
End;
End;
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
Function Ansi_View_Message : Boolean;
Var
Lines : SmallInt;
PageSize : SmallInt;
PageStart : SmallInt;
PageEnd : SmallInt;
Procedure Draw_Msg_Text;
Var
A : SmallInt;
Temp : String;
Begin
PageEnd := PageStart;
Session.io.AnsiGotoXY (1, Session.io.ScreenInfo[1].Y);
Session.io.AnsiColor (MBase.ColText);
For A := 1 to PageSize Do
If PageEnd <= Lines Then Begin
Send_Msg_Text(MsgText[PageEnd]);
Inc (PageEnd);
End Else Begin
Session.io.AnsiClrEOL;
Session.io.OutRawLn ('');
End;
Temp := Session.io.DrawPercent(Session.Theme.MsgBar, PageEnd - 1, Lines, A);
If Session.io.ScreenInfo[4].Y <> 0 Then Begin
Session.io.AnsiGotoXY (Session.io.ScreenInfo[4].X, Session.io.ScreenInfo[4].Y);
Session.io.AnsiColor (Session.io.ScreenInfo[4].A);
Session.io.OutRaw (strPadL(strI2S(A), 3, ' '));
End;
If Session.io.ScreenInfo[5].Y <> 0 Then Begin
Session.io.AnsiGotoXY (Session.io.ScreenInfo[5].X, Session.io.ScreenInfo[5].Y);
Session.io.OutFull (Temp);
End;
End;
Var
Ch : Char;
CurMsg : LongInt;
Begin
Result := False;
Repeat
Set_Node_Action (Session.GetPrompt(348));
SetMessageSecurity;
If Session.User.IsThisUser(MsgBase^.GetTo) And Not MsgBase^.IsRcvd Then Begin
MsgBase^.SetRcvd(True);
MsgBase^.ReWriteHDR;
End;
CurMsg := MsgBase^.GetMsgNum;
Lines := 0;
PageStart := 1;
ReplyID := '';
If CurMsg > LastRead Then LastRead := CurMsg;
Session.io.AllowArrow := True;
// create ReadMessageText function? This can also be used in the
// ASCII reader and in fact should be used, because if a more prompt
// is interrupted, its possible for a ReplyID to not be set. RepID
// is also not nulled prior to loading a new message.
MsgBase^.MsgTxtStartUp;
While Not MsgBase^.EOM And (Lines < mysMaxMsgLines) Do Begin
Inc (Lines);
MsgText[Lines] := MsgBase^.GetString(79);
If MsgText[Lines][1] = #1 Then Begin
If Copy(MsgText[Lines], 2, 5) = 'MSGID' Then
ReplyID := Copy(MsgText[Lines], 9, Length(MsgText[Lines]));
Dec (Lines);
End;
End;
AssignHeaderInfo;
Session.io.ScreenInfo[4].Y := 0;
Session.io.ScreenInfo[5].Y := 0;
Session.io.OutFile (MBase.RTemplate, True, 0);
PageSize := Session.io.ScreenInfo[2].Y - Session.io.ScreenInfo[1].Y + 1;
Draw_Msg_Text;
Repeat
Session.io.PurgeInputBuffer;
Repeat
Ch := UpCase(Session.io.GetKey);
Until (Pos(Ch, #27 + ValidKeys) > 0) or Session.io.IsArrow;
If Session.io.IsArrow Then Begin
Case Ch of
#71 : If PageStart > 1 Then Begin
PageStart := 1;
Draw_Msg_Text;
End;
#72 : If PageStart > 1 Then Begin
Dec (PageStart);
Draw_Msg_Text;
End;
#73 : If PageStart > 1 Then Begin
If PageStart - PageSize > 0 Then
Dec (PageStart, PageSize)
Else
PageStart := 1;
Draw_Msg_Text;
End;
#75 : If SeekNextMsg(False, True) Then
Break
Else Begin
MsgBase^.SeekFirst(CurMsg);
SeekNextMsg(True, False);
End;
#77 : If SeekNextMsg(False, False) Then
Break
Else Begin
MsgBase^.SeekFirst(CurMsg);
SeekNextMsg(True, False);
End;
#79 : Begin
PageStart := Lines - PageSize + 1;
If PageStart < 1 Then PageStart := 1;
Draw_Msg_Text;
End;
#80 : If PageEnd <= Lines Then Begin
Inc (PageStart);
Draw_Msg_Text;
End;
#81 : If (Lines > PageSize) and (PageEnd <= Lines) Then Begin
If PageStart + PageSize <= Lines - PageSize Then
Inc (PageStart, PageSize)
Else
PageStart := Lines - PageSize + 1;
Draw_Msg_Text;
End;
End;
End Else
Case Ch of
'A' : Break;
'D' : Begin
If Session.io.GetYN(Session.GetPrompt(402), True) Then Begin
MsgBase^.DeleteMsg;
If Not SeekNextMsg(False, False) Then Begin
Ansi_View_Message := True;
Exit;
End;
End Else
MsgBase^.SeekFirst(CurMsg);
Break;
End;
'E' : Begin
EditMessage;
Break;
End;
'F' : Begin
MoveMessage(True);
Break;
End;
'G' : Begin
Ansi_View_Message := True;
Exit;
End;
'H' : Begin
LastRead := CurMsg - 1;
Session.io.PromptInfo[1] := strI2S(LastRead);
Session.io.OutFullLn(Session.GetPrompt(504));
Break;
End;
'I' : Begin
LastRead := MsgBase^.GetHighMsgNum;
Result := True;
RemoveNewScan(495);
Exit;
End;
'J' : Begin
Session.io.PromptInfo[1] := strI2S(CurMsg);
Session.io.PromptInfo[2] := strI2S(MsgBase^.GetHighMsgNum);
Session.io.OutFull (Session.GetPrompt(403));
If Session.io.OneKeyRange(#13 + 'Q', 1, MsgBase^.GetHighMsgNum) = #0 Then Begin
MsgBase^.SeekFirst(Session.io.RangeValue);
If Not SeekNextMsg(True, False) Then Begin
MsgBase^.SeekFirst(CurMsg);
SeekNextMsg(True, False);
End;
End;
Break;
End;
'L' : Exit;
'M' : Begin
If MoveMessage(False) Then
If Not SeekNextMsg(False, False) Then Begin
Ansi_View_Message := True;
Exit;
End;
Break;
End;
#13 : If (Lines > PageSize) and (PageEnd <= Lines) Then Begin
If PageStart + PageSize <= Lines - PageSize Then
Inc (PageStart, PageSize)
Else
PageStart := Lines - PageSize + 1;
Draw_Msg_Text;
End Else Begin
If SeekNextMsg(False, False) Then
Break
Else Begin
Ansi_View_Message := True;
Exit;
End;
End;
'N' : If SeekNextMsg(False, False) Then
Break
Else Begin
Ansi_View_Message := True;
Exit;
End;
'P' : If SeekNextMsg(False, True) Then
Break
Else Begin
MsgBase^.SeekFirst(CurMsg);
SeekNextMsg(True, False);
End;
#27,
'Q' : Begin
GetMessageScan;
If MScan.NewScan = 2 Then
Session.io.OutFullLn(Session.GetPrompt(406))
Else Begin
ReadRes := False;
Ansi_View_Message := True;
Exit;
End;
End;
'R' : Begin
ReplyMessage (Mode = 'E', ListMode, ReplyID);
Break;
End;
'T' : Begin
Session.io.PromptInfo[1] := MBase.Name;
GetMessageScan;
Case MScan.NewScan of
0 : Begin
MScan.NewScan := 1;
Session.io.OutFull (Session.GetPrompt(405));
End;
1 : Begin
MScan.NewScan := 0;
Session.io.OutFull (Session.GetPrompt(404));
End;
2 : Session.io.OutFull (Session.GetPrompt(406));
End;
SetMessageScan;
Break;
End;
'X' : Begin
ExportMessage;
Break;
End;
'[' : If MsgBase^.GetRefer > 0 Then Begin
MsgBase^.SeekFirst(MsgBase^.GetRefer);
MsgBase^.MsgStartUp;
Break;
End;
']' : If MsgBase^.GetSeeAlso > 0 Then Begin
MsgBase^.SeekFirst(MsgBase^.GetSeeAlso);
MsgBase^.MsgStartUp;
Break;
End;
'?' : Begin
Session.io.OutFile ('amsghlp2', True, 0);
Break;
End;
End;
Until False;
Until False;
End;
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
Procedure Ansi_Read_Messages;
Type
MsgInfoRec = Record
Num : LongInt;
MsgFrom : String[30];
MsgTo : String[30];
Subj : String[60];
NewMsgs : Boolean;
End;
Var
PageSize : SmallInt;
PagePos : SmallInt;
PageTotal : SmallInt;
CurPage : Word;
MsgInfo : Array[1..24] of MsgInfoRec;
FirstPage : Boolean;
AskRemove : Boolean;
Procedure DrawPage;
Var
A : SmallInt;
Begin
Session.io.AnsiGotoXY (1, Session.io.ScreenInfo[1].Y);
For A := 1 to PageSize Do
If A <= PageTotal Then Begin
With MsgInfo[A] Do Begin
Session.io.PromptInfo[1] := strI2S(Num);
Session.io.PromptInfo[2] := Subj;
Session.io.PromptInfo[3] := MsgFrom;
Session.io.PromptInfo[4] := MsgTo;
If NewMsgs Then
Session.io.PromptInfo[5] := Session.Theme.NewMsgChar
Else
Session.io.PromptInfo[5] := ' ';
End;
Session.io.OutFull (Session.GetPrompt(399));
Session.io.AnsiClrEOL;
Session.io.OutRawLn('');
End Else Begin
Session.io.AnsiClrEOL;
Session.io.OutRawLn('');
End;
End;
Procedure FullReDraw;
Begin
Session.io.OutFile (MBase.ITemplate, True, 0);
PageSize := Session.io.ScreenInfo[2].Y - Session.io.ScreenInfo[1].Y + 1;
End;
Function Read_Page (First, Back, NoDraw : Boolean) : Boolean;
Var
A : SmallInt;
B : SmallInt;
Temp : MsgInfoRec;
Begin
Read_Page := False;
FirstPage := False;
If SeekNextMsg(First, Back) Then Begin
If First Then Begin
FullReDraw;
CurPage := 0;
End;
// add scanning prompt here
//if (scanmode=3) then begin
// Session.io.AnsiGotoXY(32, 11);
// Session.io.OutFull ('|08.---------------.');
// Session.io.AnsiGotoXY(32, 12);
// Session.io.OutFull ('| |07searching ... |08|');
// Session.io.AnsiGotoXY(32, 13);
// Session.io.OutFull ('`---------------''');
//end;
PageTotal := 0;
Read_Page := True;
Repeat
Inc (PageTotal);
MsgInfo[PageTotal].Num := MsgBase^.GetMsgNum;
MsgInfo[PageTotal].MsgFrom := MsgBase^.GetFrom;
MsgInfo[PageTotal].MsgTo := MsgBase^.GetTo;
MsgInfo[PageTotal].Subj := MsgBase^.GetSubj;
MsgInfo[PageTotal].NewMsgs := MsgBase^.GetMsgNum > LastRead;
Until (PageTotal = PageSize) or (Not SeekNextMsg(False, Back));
If Back Then Begin { reverse message order }
Dec (CurPage);
B := PageTotal;
For A := 1 to PageTotal DIV 2 Do Begin
Temp := MsgInfo[A];
MsgInfo[A] := MsgInfo[B];
MsgInfo[B] := Temp;
Dec (B);
End;
// if backwards and page is not filled, fill it going foward.
If PageTotal < PageSize Then Begin
FirstPage := True;
MsgBase^.SeekFirst(MsgInfo[PageTotal].Num);
While SeekNextMsg(False, False) and (PageTotal < PageSize) Do Begin
Inc (PageTotal);
MsgInfo[PageTotal].Num := MsgBase^.GetMsgNum;
MsgInfo[PageTotal].MsgFrom := MsgBase^.GetFrom;
MsgInfo[PageTotal].MsgTo := MsgBase^.GetTo;
MsgInfo[PageTotal].Subj := MsgBase^.GetSubj;
MsgInfo[PageTotal].NewMsgs := MsgBase^.GetMsgNum > LastRead;
End;
Read_Page := False;
End;
End Else Begin
Inc (CurPage);
Read_Page := True;
End;
If Not NoDraw Then DrawPage;
End;
End;
Procedure UpdateBar (On : Boolean);
Begin
If PageTotal = 0 Then Exit;
Session.io.PromptInfo[1] := strI2S(MsgInfo[PagePos].Num);
Session.io.PromptInfo[2] := MsgInfo[PagePos].Subj;
Session.io.PromptInfo[3] := MsgInfo[PagePos].MsgFrom;
Session.io.PromptInfo[4] := MsgInfo[PagePos].MsgTo;
If MsgInfo[PagePos].NewMsgs Then
Session.io.PromptInfo[5] := Session.Theme.NewMsgChar
Else
Session.io.PromptInfo[5] := ' ';
Session.io.AnsiGotoXY (1, Session.io.ScreenInfo[1].Y + PagePos - 1);
If On Then
Session.io.OutFull (Session.GetPrompt(400))
Else
Session.io.OutFull (Session.GetPrompt(401));
End;
Procedure Ansi_Message_Index;
Var
Ch : Char;
SN : LongInt;
A : Byte;
Begin
AskRemove := False;
If Read_Page (True, False, False) Then Begin
WereMsgs := True;
PagePos := 1;
Repeat
Session.io.AllowArrow := True;
UpdateBar(True);
Session.io.PurgeInputBuffer;
Ch := UpCase(Session.io.GetKey);
If Session.io.IsArrow Then Begin
Case Ch of
#71 : Begin
UpdateBar(False);
While Read_Page(False, True, True) Do;
PagePos := 1;
DrawPage;
End;
#72 : Begin
UpdateBar(False);
If PagePos > 1 Then
Dec (PagePos)
Else Begin
SN := MsgInfo[PagePos].Num;
MsgBase^.SeekFirst(MsgInfo[1].Num);
If Not Read_Page(False, True, False) Then
PagePos := 1
Else
If Not FirstPage Then
PagePos := PageTotal
Else Begin
For A := 1 to PageTotal Do
If MsgInfo[A].Num = SN Then Begin
PagePos := A - 1;
Break;
End;
If PagePos < 1 Then PagePos := 1;
End;
End;
End;
#73,
#75 : Begin
UpdateBar(False);
MsgBase^.SeekFirst(MsgInfo[1].Num);
If Not Read_Page(False, True, False) Then
PagePos := 1
Else
If PagePos > PageTotal Then PagePos := PageTotal;
End;
#80 : Begin
UpdateBar(False);
If PagePos < PageTotal Then
Inc (PagePos)
Else Begin
MsgBase^.SeekFirst(MsgInfo[PageTotal].Num);
If Read_Page(False, False, False) Then PagePos := 1;
End;
End;
#77,
#81 : Begin
MsgBase^.SeekFirst(MsgInfo[PageTotal].Num);
If Read_Page(False, False, False) Then Begin
If PagePos > PageTotal Then PagePos := PageTotal;
End Else Begin
UpdateBar(False);
PagePos := PageTotal;
End;
End;
#79 : Begin
UpdateBar(False);
While Read_Page(False, False, True) Do;
PagePos := PageTotal;
DrawPage;
End;
End;
End Else
Case Ch of
#13 : Begin
MsgBase^.SeekFirst(MsgInfo[PagePos].Num);
SeekNextMsg (True, False);
If Ansi_View_Message Then Break;
MsgBase^.SeekFirst(MsgInfo[1].Num);
If Not Read_Page(True, False, False) Then Begin
PageTotal := 0;
FullReDraw;
DrawPage;
End;
End;
'Q',
#27 : Begin
GetMessageScan;
If MScan.NewScan = 2 Then
Session.io.OutFullLn(Session.GetPrompt(406))
Else Begin
ReadRes := False;
Break;
End;
End;
'G' : Break;
'I' : Begin
LastRead := MsgBase^.GetHighMsgNum;
AskRemove := True;
Break;
End;
'?' : Begin
Session.io.OutFile('amsghlp1', True, 0);
FullReDraw;
DrawPage;
End;
End;
Until False;
End;
Session.io.AllowArrow := False;
If WereMsgs Then Begin
Session.io.AnsiGotoXY (1, Session.io.ScreenInfo[3].Y);
Session.io.OutRawLn('');
If AskRemove Then
RemoveNewScan(495);
End;
End;
Begin
If ((Mode = 'E') and Session.User.ThisUser.UseLBMIdx) or ((Mode <> 'E') and Session.User.ThisUser.UseLBIndex) Then
Ansi_Message_Index
Else Begin
If SeekNextMsg(True, False) Then
If Not Ansi_View_Message Then
Ansi_Message_Index;
End;
End;
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
Procedure Ascii_Read_Messages;
Procedure Display_Header;
Begin
Session.io.PausePtr := 1;
Session.io.OutFile (MBase.Header, True, 0);
If Session.io.NoFile Then Begin
Session.io.OutFullLn ('|CL|03From : |14|$R40|&1 |03Msg # : |14|&5 |03of |14|&6');
Session.io.OutFullLn ('|03To : |10|$R40|&2 |03Date : |11|&4 |&0');
Session.io.OutFullLn ('|03Subj : |12|$R40|&3 |03Refer to : |10|&7');
Session.io.OutFullLn ('|03Stat : |13|$R40|&9 |03See Also : |12|&8');
(*
Session.io.OutFullLn ('|03To : |10|$R40|&2 |03Refer to : |10|&7');
Session.io.OutFullLn ('|03Subj : |12|$R40|&3 |03See Also : |12|&8');
Session.io.OutFullLn ('|03Stat : |13|$R40|&9 |03Date : |11|&4 |&0');
*)
Session.io.OutFullLn ('|03Base : |14|MB|CR');
End;
Session.io.AnsiColor (MBase.ColText);
End;
Var
Str : String;
A : LongInt;
B : LongInt;
Begin
If SeekNextMsg(True, False) Then
Repeat
// Set_Node_Action (Session.GetPrompt(348));
If MsgBase^.GetMsgNum > LastRead Then LastRead := MsgBase^.GetMsgNum;
If Session.User.IsThisUser(MsgBase^.GetTo) And Not MsgBase^.IsRcvd Then Begin
MsgBase^.SetRcvd(True);
MsgBase^.ReWriteHDR;
End;
SetMessageSecurity;
AssignHeaderInfo;
Display_Header;
MsgBase^.MsgTxtStartUp;
WereMsgs := True;
Session.io.AllowPause := True;
// should be entirely read in and then filtered for kludge
// then displayed based on what was read in. replyID should
// be reset here
While Not MsgBase^.EOM Do Begin
Str := MsgBase^.GetString(79);
If Str[1] = #1 Then Begin
If Copy(Str, 2, 5) = 'MSGID' Then
ReplyID := Copy(Str, 9, Length(Str));
End Else
Send_Msg_Text (Str);
If (Session.io.PausePtr = Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then Begin
Case Session.io.MorePrompt of
'N' : Break;
'C' : Session.io.AllowPause := False;
End;
If bbsCfg.MShowHeader Then Display_Header;
End;
End;
Session.io.AllowPause := False;
Repeat
Session.io.PromptInfo[1] := strI2S(MsgBase^.GetMsgNum);
Session.io.PromptInfo[2] := strI2S(MsgBase^.GetHighMsgNum);
If Mode = 'E' Then
Session.io.OutFull (Session.GetPrompt(115))
Else
If Session.User.Access(MBase.SysopACS) or Session.User.IsThisUser(MsgBase^.GetFrom) Then
Session.io.OutFull (Session.GetPrompt(213))
Else
Session.io.OutFull (Session.GetPrompt(116));
Str := Session.io.OneKeyRange(ValidKeys, 1, MsgBase^.GetHighMsgNum);
Case Str[1] of
#00 : Begin
B := MsgBase^.GetMsgNum;
MsgBase^.SeekFirst(Session.io.RangeValue);
If Not SeekNextMsg(True, False) Then Begin
MsgBase^.SeekFirst(B);
SeekNextMsg(True, False);
End;
Break;
End;
'A' : Break;
'D' : If Session.io.GetYN (Session.GetPrompt(117), True) Then Begin {Delete E-mail}
MsgBase^.DeleteMsg;
If Not SeekNextMsg(False, False) Then Exit;
Break;
End;
'E' : Begin
EditMessage;
Break;
End;
'F' : Begin
MoveMessage(True);
Break;
End;
'G' : Exit;
'H' : Begin
LastRead := MsgBase^.GetMsgNum - 1;
Session.io.PromptInfo[1] := strI2S(LastRead);
Session.io.OutFullLn(Session.GetPrompt(505));
Break;
End;
'I' : Begin
LastRead := MsgBase^.GetHighMsgNum;
RemoveNewScan(494);
Exit;
End;
'J' : Begin
B := MsgBase^.GetMsgNum;
Session.io.OutFull (Session.GetPrompt(334));
If Session.io.OneKeyRange(#13 + 'Q', 1, MsgBase^.GetHighMsgNum) = #0 Then Begin
MsgBase^.SeekFirst(Session.io.RangeValue);
If Not SeekNextMsg(True, False) Then Begin
MsgBase^.SeekFirst(B);
SeekNextMsg(True, False);
End;
End;
Break;
End;
'L' : Begin
Session.io.PausePtr := 1;
Session.io.AllowPause := True;
A := MsgBase^.GetMsgNum;
Session.io.OutFullLn(Session.GetPrompt(411));
While SeekNextMsg(False, False) Do Begin
AssignHeaderInfo;
Session.io.OutFullLn (Session.GetPrompt(412));
If (Session.io.PausePtr = Session.User.ThisUser.ScreenSize) and (Session.io.AllowPause) Then
Case Session.io.MorePrompt of
'N' : Break;
'C' : Session.io.AllowPause := False;
End;
End;
Session.io.OutFull (Session.GetPrompt(413));
MsgBase^.SeekFirst(A);
MsgBase^.MsgStartup;
Session.io.PromptInfo[1] := strI2S(MsgBase^.GetMsgNum);
Session.io.PromptInfo[2] := strI2S(MsgBase^.GetHighMsgNum);
End;
'M' : Begin
If MoveMessage(False) Then
If Not SeekNextMsg(False, False) Then Exit;
Break;
End;
#13,
'N' : If SeekNextMsg(False, False) Then Break Else Exit;
'P' : Begin
If Not SeekNextMsg(False, True) Then Begin
MsgBase^.SeekFirst(MsgBase^.GetMsgNum);
SeekNextMsg(True, False);
End;
Break;
End;
'Q' : Begin
GetMessageScan;
If MScan.NewScan = 2 Then
Session.io.OutFullLn(Session.GetPrompt(302))
Else Begin
ReadRes := False;
Exit;
End;
End;
'R' : Begin
ReplyMessage (Mode = 'E', ListMode, ReplyID);
Break;
End;
'T' : Begin
Session.io.PromptInfo[1] := MBase.Name;
GetMessageScan;
Case MScan.NewScan of
0 : Begin
MScan.NewScan := 1;
Session.io.OutFull (Session.GetPrompt(99));
End;
1 : Begin
MScan.NewScan := 0;
Session.io.OutFull (Session.GetPrompt(98));
End;
2 : Session.io.OutFull (Session.GetPrompt(302));
End;
SetMessageScan;
End;
'X' : ExportMessage;
'?' : Session.io.OutFile(HelpFile, True, 0);
'[' : If MsgBase^.GetRefer > 0 Then Begin
MsgBase^.SeekFirst(MsgBase^.GetRefer);
MsgBase^.MsgStartUp;
Break;
End Else
Session.io.OutFullLn (Session.GetPrompt(128));
']' : If MsgBase^.GetSeeAlso > 0 Then Begin
MsgBase^.SeekFirst(MsgBase^.GetSeeAlso);
MsgBase^.MsgStartUp;
Break;
End Else
Session.io.OutFullLn (Session.GetPrompt(199));
End;
Until False;
Until False;
End;
(**************************************************************************)
(**************************************************************************)
(**************************************************************************)
{ F = Forward S = Search E = Electronic Mail
N = New messages Y = Your messages G = Global scan
P = Global personal scan B = By You T = Global text search }
Var
MsgNum : LongInt;
NoLastRead : Boolean;
Begin
ReadMessages := True;
ReadRes := True;
WereMsgs := False;
ReplyID := '';
NoLastRead := Pos('/NOLR', strUpper(CmdData)) > 0;
NoFrom := Pos('/NOFROM', strUpper(CmdData)) > 0;
NoRead := Pos('/NOREAD', strUpper(CmdData)) > 0;
If MBase.FileName = '' Then Begin
Session.io.OutFullLn (Session.GetPrompt(110));
Exit;
End;
If Not Session.User.Access(MBase.ReadACS) Then Begin
If Not (Mode in ['G', 'P', 'T']) Then Session.io.OutFullLn (Session.GetPrompt(111));
Exit;
End;
If Not (Mode in ['B', 'T', 'S', 'E', 'F', 'G', 'N', 'P', 'Y']) Then Begin
Session.io.OutFull (Session.GetPrompt(112));
Mode := Session.io.OneKey(#13 + 'BFNSYQ', True);
End;
Case Mode of
#13 : Mode := 'F';
'Q' : Exit;
'S' : If SearchStr = '' Then Begin
Session.io.OutFull (Session.GetPrompt(396));
SearchStr := Session.io.GetInput(50, 50, 12, '');
If SearchStr = '' Then Exit;
End;
End;
{ start here opencreate... }
Case MBase.BaseType of
0 : MsgBase := New(PMsgBaseJAM, Init);
1 : MsgBase := New(PMsgBaseSquish, Init);
End;
MsgBase^.SetMsgPath (MBase.Path + MBase.FileName);
MsgBase^.SetTempFile (Session.TempPath + 'msgbuf.');
If Not MsgBase^.OpenMsgBase Then Begin
If Mode = 'E' Then
Session.io.OutFullLn (Session.GetPrompt(124))
Else
If Not (Mode in ['G', 'P', 'T']) Then Session.io.OutFullLn (Session.GetPrompt(114));
Dispose (MsgBase, Done);
Exit;
End;
{end here }
If Mode = 'E' Then
ScanMode := 1
Else
If (MBase.Flags and MBPrivate <> 0) or (Mode = 'Y') or (Mode = 'P') Then
ScanMode := 2
Else
If (Mode = 'S') or (Mode = 'T') Then
ScanMode := 3
Else
If Mode = 'B' Then
ScanMode := 4
Else
ScanMode := 0;
// session.io.outfull('read ' + mbase.filename + ' ' + mode + ' ' + searchstr + ' ' + stri2s(scanmode) + '|PN');
// session.io.bufflush;
LastRead := MsgBase^.GetLastRead(Session.User.UserNum);
MsgNum := 1;
If Mode = 'F' Then Begin
Session.io.PromptInfo[1] := strI2S(MsgBase^.GetHighMsgNum);
If Session.io.PromptInfo[1] = '0' Then Begin
Session.io.OutFullLn(Session.GetPrompt(114));
MsgBase^.CloseMsgBase;
Dispose (MsgBase, Done);
Exit;
End;
Session.io.OutFull (Session.GetPrompt(338));
Session.io.OneKeyRange(#13, 1, MsgBase^.GetHighMsgNum);
MsgNum := Session.io.RangeValue;
End;
Set_Node_Action (Session.GetPrompt(348));
If Mode in ['B', 'S', 'T', 'Y', 'E', 'F'] Then
MsgBase^.SeekFirst(MsgNum)
Else
MsgBase^.SeekFirst(LastRead + 1);
SetMessageSecurity;
Reading := True;
If (Session.User.ThisUser.MReadType = 1) and (Session.io.Graphics > 0) Then Begin
ListMode := 1;
Ansi_Read_Messages;
End Else Begin
ListMode := 0;
Ascii_Read_Messages;
End;
If Not (Mode in ['E', 'S', 'T']) And Not NoLastRead Then
MsgBase^.SetLastRead (Session.User.UserNum, LastRead);
MsgBase^.CloseMsgBase;
Dispose (MsgBase, Done);
Reading := False;
If WereMsgs Then Begin
If Not (Mode in ['B', 'E', 'P']) And ReadRes Then
If ListMode = 0 Then Begin
Session.io.OutFull('|CR');
If Session.io.GetYN(Session.GetPrompt(383), False) Then
PostMessage (False, '');
End Else
If Session.io.GetYN(Session.GetPrompt(438), False) Then
PostMessage (False, '');
End Else
Case Mode of
'S' : Session.io.OutFullLn (Session.GetPrompt(113));
'B',
'Y',
'N' : Session.io.OutFullLn ('|CR' + Session.GetPrompt(113));
End;
Result := ReadRes;
End;
Procedure TMsgBase.PostMessage (Email: Boolean; Data: String);
Var
MsgTo : String[30];
MsgSubj : String[60];
MsgAddr : String[20];
TempStr : String;
DestAddr : RecEchoMailAddr;
A : Integer;
Lines : Integer;
Forced : Boolean;
Old : RecMessageBase;
SaveGroup : Boolean;
IsPrivate : Boolean;
Begin
Old := MBase;
SaveGroup := Session.User.IgnoreGroup;
If Email Then Begin
Reset (MBaseFile);
Read (MBaseFile, MBase);
Close (MBaseFile);
Session.User.IgnoreGroup := True;
End;
If MBase.FileName = '' Then Begin
Session.io.OutFullLn (Session.GetPrompt(110));
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
If Not Session.User.Access(MBase.PostACS) Then Begin
Session.io.OutFullLn (Session.GetPrompt(105));
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
Set_Node_Action (Session.GetPrompt(349));
MsgTo := '';
MsgSubj := '';
MsgAddr := '';
Forced := False;
IsPrivate := MBase.Flags AND MBPrivate <> 0;
If (MBase.Flags AND MBPrivate = 0) AND (MBase.Flags AND MBPrivReply <> 0) Then
IsPrivate := Session.io.GetYN(Session.GetPrompt(513), False);
For A := 1 to strWordCount(Data, ' ') Do Begin
TempStr := strWordGet(A, Data, ' ');
If Pos ('/F', strUpper(TempStr)) > 0 Then
Forced := True
Else
If Pos ('/TO:', strUpper(TempStr)) > 0 Then
MsgTo := strReplace(Copy(TempStr, Pos('/TO:', strUpper(TempStr)) + 4, Length(TempStr)), '_', ' ')
Else
If Pos ('/SUBJ:', strUpper(TempStr)) > 0 Then
MsgSubj := strReplace(Copy(TempStr, Pos('/SUBJ:', strUpper(TempStr)) + 6, Length(TempStr)), '_', ' ')
Else
If Pos('/ADDR:', strUpper(TempStr)) > 0 Then Begin
MsgAddr := strReplace(Copy(TempStr, Pos('/ADDR:', strUpper(TempStr)) + 6, Length(TempStr)), '_', ' ');
If Not Str2Addr(MsgAddr, DestAddr) Then MsgAddr := '';
End;
End;
If MBase.NetType = 2 Then { UseNet Base: To = "All" }
MsgTo := 'All'
Else
If MBase.NetType = 3 Then Begin { NetMail Base: Get To *and* Address }
If MsgTo = '' Then Begin
Session.io.OutFull (Session.GetPrompt(119));
MsgTo := Session.io.GetInput (30, 30, 18, '');
End;
If MsgTo <> '' Then
If MsgAddr = '' Then Begin
MsgAddr := NetmailLookup(False, MsgTo, '');
If Not Str2Addr(MsgAddr, DestAddr) Then MsgTo := '';
End;
End Else
If IsPrivate Then Begin
If MsgTo = '' Then Begin
Session.io.OutFull (Session.GetPrompt(450));
MsgTo := Session.io.GetInput (30, 30, 18, '');
If Not Session.User.SearchUser(MsgTo, MBase.Flags and MBRealNames <> 0) Then MsgTo := '';
End Else
If strUpper(MsgTo) = 'SYSOP' Then MsgTo := bbsCfg.SysopName;
If Session.User.FindUser(MsgTo, False) Then Begin
Session.io.PromptInfo[1] := MsgTo;
Session.io.OutFullLn (Session.GetPrompt(108));
End Else
MsgTo := '';
End Else Begin
Session.io.OutFull (Session.GetPrompt(119));
MsgTo := Session.io.GetInput (30, 30, 18, 'All');
End;
If MsgTo = '' Then Begin
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
If MsgSubj = '' Then
Repeat
Session.io.OutFull (Session.GetPrompt(120));
MsgSubj := Session.io.GetInput (60, 60, 11, '');
If MsgSubj = '' Then
If Forced Then
Session.io.OutFull (Session.GetPrompt(307))
Else Begin
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
Until MsgSubj <> '';
Lines := 0;
Session.io.PromptInfo[1] := MsgTo;
// Session.io.PromptInfo[2] := MsgSubj;
If Editor(Lines, ColumnValue[Session.Theme.ColumnSize] - 2, mysMaxMsgLines, Forced, fn_tplMsgEdit, MsgSubj) Then Begin
Session.io.OutFull (Session.GetPrompt(107));
{ all of this below should be replaced with a SaveMessage function }
{ the same should be used for Replying and also for TextFile post }
{ and then the automated e-mails can be added where mystic will send }
{ notifications out to the sysop for various things (configurable) }
{ also could be used in mass email rewrite and qwk .REP rewrite }
If Not MBaseOpenCreate(MsgBase, MBase, Session.TempPath) Then Begin
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
Exit;
End;
AssignMessageData(MsgBase, MBase);
MsgBase^.SetTo (MsgTo);
MsgBase^.SetSubj (MsgSubj);
MsgBase^.SetPriv (IsPrivate);
If MBase.NetType = 3 Then Begin
MsgBase^.SetDest (DestAddr);
MsgBase^.SetCrash (bbsCfg.netCrash);
MsgBase^.SetHold (bbsCfg.netHold);
MsgBase^.SetKillSent (bbsCfg.netKillSent);
MsgBase^.SetOrig (GetMatchedAddress(bbsCfg.NetAddress[MBase.NetAddr], DestAddr));
End;
AppendMessageText (MsgBase, Lines, '');
MsgBase^.WriteMsg;
MsgBase^.CloseMsgBase;
If Email Then Begin
Session.SystemLog ('Sent Email to ' + MsgTo);
Inc (Session.User.ThisUser.Emails);
Inc (Session.HistoryEmails);
A := IsUserOnline(MsgTo);
If A <> 0 Then Begin
TempStr := Session.GetPrompt(465);
TempStr := strReplace(TempStr, '|&1', Session.User.ThisUser.Handle);
TempStr := strReplace(TempStr, '|&2', MsgSubj);
Send_Node_Message(2, strI2S(A) + ';' + TempStr, 0);
End;
End Else Begin
Session.SystemLog ('Posted #' + strI2S(MsgBase^.GetMsgNum) + ': "' + MsgSubj + '" to ' + strStripMCI(MBase.Name));
Inc (Session.User.ThisUser.Posts);
Inc (Session.HistoryPosts);
End;
Dispose (MsgBase, Done);
Session.io.OutFullLn (Session.GetPrompt(122));
End Else
Session.io.OutFullLn (Session.GetPrompt(109));
MBase := Old;
Session.User.IgnoreGroup := SaveGroup;
End;
Procedure TMsgBase.CheckEMail (CmdData: String);
Var
TempMsg : PMsgBaseABS;
TempBase : RecMessageBase;
Total : Integer;
UnRead : Integer;
Begin
TempBase := MBase;
Total := 0;
UnRead := 0;
FileMode := 66;
Session.io.OutFull (Session.GetPrompt(123));
Session.io.BufFlush;
Reset (MBaseFile);
Read (MBaseFile, MBase);
Close (MBaseFile);
If Pos('/NOLIST', strUpper(CmdData)) > 0 Then Begin
ReadMessages('E', '', '');
Session.io.OutFullLn (Session.GetPrompt(118));
MBase := TempBase;
Exit;
End;
If MBaseOpenCreate (TempMsg, MBase, Session.TempPath) Then Begin
TempMsg^.SeekFirst (1);
While TempMsg^.SeekFound Do Begin
TempMsg^.MsgStartUp;
If Session.User.IsThisUser(TempMsg^.GetTo) Then Begin
Inc (Total);
If Not TempMsg^.IsRcvd Then Inc (UnRead);
If Total = 1 Then
Session.io.OutFullLn (Session.GetPrompt(125));
Session.io.PromptInfo[1] := strI2S(Total);
Session.io.PromptInfo[2] := TempMsg^.GetFrom;
Session.io.PromptInfo[3] := TempMsg^.GetSubj;
Session.io.PromptInfo[4] := TempMsg^.GetDate;
Session.io.OutFullLn (Session.GetPrompt(126));
End;
TempMsg^.SeekNext;
End;
TempMsg^.CloseMsgBase;
Dispose (TempMsg, Done);
End;
Session.LastScanHadNew := UnRead > 0;
If Total = 0 Then
Session.io.OutFullLn (Session.GetPrompt(124))
Else Begin
Session.io.PromptInfo[1] := strI2S(Total);
Session.io.PromptInfo[2] := strI2S(UnRead);
If Session.io.GetYN (Session.GetPrompt(127), UnRead > 0) Then Begin
ReadMessages('E', '', '');
Session.io.OutFullLn (Session.GetPrompt(118));
End;
End;
MBase := TempBase;
End;
Procedure TMsgBase.SetMessagePointers (ForceGlobal: Boolean);
Var
NewDate : LongInt;
TempBase : RecMessageBase;
Procedure UpdateBase;
Var
Found : Boolean;
Begin
Found := False;
If MBaseOpenCreate (MsgBase, TempBase, Session.TempPath) Then Begin
MsgBase^.SeekFirst(1);
While MsgBase^.SeekFound Do Begin
MsgBase^.MsgStartUp;
If DateStr2Dos(MsgBase^.GetDate) >= NewDate Then Begin
MsgBase^.SetLastRead(Session.User.UserNum, MsgBase^.GetMsgNum - 1);
Found := True;
Break;
End;
MsgBase^.SeekNext;
End;
If Not Found Then
MsgBase^.SetLastRead(Session.User.UserNum, MsgBase^.GetHighMsgNum);
MsgBase^.CloseMsgBase;
End;
Dispose (MsgBase, Done);
End;
Var
InDate : String[8];
Begin
Session.io.OutFull (Session.GetPrompt(458));
InDate := Session.io.GetInput(8, 8, 15, DateDos2Str(CurDateDos, Session.User.ThisUser.DateType));
If Not DateValid(InDate) Then Exit;
NewDate := DateStr2Dos(InDate);
If Not ForceGlobal Then
ForceGlobal := Session.io.GetYN(Session.GetPrompt(459), False);
Session.io.OutFullLn (Session.GetPrompt(460));
If ForceGlobal Then Begin
ioReset (MBaseFile, SizeOf(RecMessageBase), fmRWDN);
ioRead (MBaseFile, TempBase);
While Not Eof(MBaseFile) Do Begin
ioRead (MBaseFile, TempBase);
UpdateBase;
End;
Close (MBaseFile);
End Else Begin
TempBase := MBase;
UpdateBase;
End;
End;
Procedure TMsgBase.MessageNewScan (Data: String);
{ menu data commands: }
{ /P : scan for personal mail in all bases }
{ /M : scan only mandatory bases }
{ /G : scan all bases in all groups }
Var
Old : RecMessageBase;
Mode : Char;
Mand : Boolean;
CmdData : String;
Begin
Old := MBase;
Mand := False;
FileMode := 66;
Reset (MBaseFile);
If Pos ('/P', Data) > 0 Then Begin
Mode := 'P';
Session.SystemLog ('Scan for personal messages');
End Else Begin
Mand := Pos('/M', Data) > 0;
Mode := 'G';
Read (MBaseFile, MBase);
Session.SystemLog ('Scan for new messages');
End;
Session.User.IgnoreGroup := Pos('/G', Data) > 0;
WereMsgs := False;
CmdData := '';
If Pos('/NOLR', Data) > 0 Then CmdData := '/NOLR';
If Pos('/NOFROM', Data) > 0 Then CmdData := CmdData + '/NOFROM';
If Pos('/NOREAD', Data) > 0 Then CmdData := CmdData + '/NOREAD';
Session.io.OutRawLn ('');
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If Session.User.Access(MBase.ReadACS) Then Begin
GetMessageScan;
If ((Mand) and (MBase.DefNScan = 2)) or ((Not Mand) and (MScan.NewScan > 0)) Then Begin
Session.io.OutBS (Console.CursorX, True);
Session.io.OutFull (Session.GetPrompt(130));
Session.io.BufFlush;
If Not ReadMessages(Mode, CmdData, '') Then Begin
Session.io.OutRawLn('');
Break;
End;
If WereMsgs Then Session.io.OutRawLn('');
End;
End;
End;
If Not WereMsgs Then Session.io.OutFullLn('|CR');
Session.io.OutFull (Session.GetPrompt(131));
Close (MBaseFile);
Session.User.IgnoreGroup := False;
MBase := OLD;
End;
Procedure TMsgBase.GlobalMessageSearch (Mode : Char);
{ C = current area }
{ G = all areas in group }
{ A = all areas in all groups }
Var
SearchStr : String;
SavedIgnore : Boolean;
Old : RecMessageBase;
Begin
If Not (Mode in ['A', 'C', 'G']) Then Mode := 'G';
Session.io.OutFull (Session.GetPrompt(310));
SearchStr := Session.io.GetInput(50, 50, 12, '');
If SearchStr = '' Then Exit;
OLD := MBase;
WereMsgs := False;
SavedIgnore := Session.User.IgnoreGroup;
Session.User.IgnoreGroup := Mode = 'A';
If Mode = 'C' Then
ReadMessages('S', '', SearchStr)
Else Begin
Session.io.OutRawLn ('');
Reset (MBaseFile);
Read (MBaseFile, MBase);
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If Session.User.Access(MBase.ReadACS) Then Begin
GetMessageScan;
If MScan.NewScan > 0 Then Begin
If Not ReadMessages('T', '', SearchStr) Then Begin
Session.io.OutRawLn('');
Break;
End;
If WereMsgs Then Session.io.OutRawLn('');
End;
End;
End;
Session.io.OutFull (Session.GetPrompt(311));
Close (MBaseFile);
End;
Session.User.IgnoreGroup := SavedIgnore;
MBase := OLD;
End;
Procedure TMsgBase.SendMassEmail;
Var
Mode : Char;
Names : Array[1..25] of String[35];
NamePos : SmallInt;
ACS : String[20];
Str : String[30];
A : SmallInt;
MsgFrom : String[30];
MsgTo : String[30];
MsgSubj : String[60];
Lines : Integer;
Old : RecMessageBase;
OldUser : RecUser;
Procedure Write_Mass_Msg;
Begin
Session.SystemLog ('Sending mass mail to ' + MsgTo);
AssignMessageData (MsgBase, MBase);
MsgBase^.SetFrom (MsgFrom);
MsgBase^.SetTo (MsgTo);
MsgBase^.SetSubj (MsgSubj);
AppendMessageText (MsgBase, Lines, '');
MsgBase^.WriteMsg;
End;
Begin
MsgFrom := Session.User.ThisUser.Handle;
Session.io.OutFull (Session.GetPrompt(387));
Mode := Session.io.OneKey('123Q', True);
Case Mode of
'1' : Begin
Session.io.OutFull (Session.GetPrompt(388));
ACS := Session.io.GetInput(20, 20, 11, '');
If ACS = '' Then Exit;
Session.io.OutFullLn (Session.GetPrompt(391));
OldUser := Session.User.ThisUser;
Reset (Session.User.UserFile);
While Not Eof(Session.User.UserFile) Do Begin
Read (Session.User.UserFile, Session.User.ThisUser);
If (Session.User.ThisUser.Flags AND UserDeleted = 0) and
(Session.User.ThisUser.Flags AND UserQWKNetwork = 0) and
Session.User.Access(ACS) Then Begin
Session.io.PromptInfo[1] := Session.User.ThisUser.Handle;
Session.io.OutFullLn (Session.GetPrompt(392));
End;
End;
Close (Session.User.UserFile);
Session.User.ThisUser := OldUser;
If Not Session.io.GetYN(Session.GetPrompt(393), True) Then
Exit;
End;
'2' : Begin
NamePos := 0;
Session.io.OutFull (Session.GetPrompt(389));
While NamePos < 25 Do Begin
Session.io.PromptInfo[1] := strI2S(NamePos);
Session.io.OutFull (Session.GetPrompt(390));
Str := Session.io.GetInput (30, 30, 18, '');
If Str <> '' Then Begin
If Session.User.SearchUser(Str, MBase.Flags And MBRealNames <> 0) Then Begin
Inc (NamePos);
Names[NamePos] := Str;
End;
End Else
If NamePos = 0 Then
Exit
Else
Break;
End;
Session.io.OutFullLn (Session.GetPrompt(391));
For A := 1 to NamePos Do Begin
Session.io.PromptInfo[1] := Names[A];
Session.io.OutFullLn (Session.GetPrompt(392));
End;
If Not Session.io.GetYN(Session.GetPrompt(393), True) Then
Exit;
End;
'3' : Begin
Mode := '1';
ACS := '^';
End;
'Q' : Exit;
End;
Session.io.OutFull (Session.GetPrompt(416));
MsgSubj := Session.io.GetInput (60, 60, 11, '');
If MsgSubj = '' Then Exit;
Session.io.PromptInfo[1] := 'Mass Mail';
Session.io.PromptInfo[2] := MsgSubj;
Lines := 0;
If Editor(Lines, ColumnValue[Session.Theme.ColumnSize] - 2, mysMaxMsgLines, False, fn_tplMsgEdit, MsgSubj) Then Begin
Session.io.OutFullLn (Session.GetPrompt(394));
OLD := MBase;
Reset (MBaseFile);
Read (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);
MBase := Old;
Exit;
End Else
If Not MsgBase^.OpenMsgBase Then Begin
Dispose (MsgBase, Done);
MBase := Old;
Exit;
End;
Case Mode of
'1' : Begin
OldUser := Session.User.ThisUser;
Reset (Session.User.UserFile);
While Not Eof(Session.User.UserFile) Do Begin
Read (Session.User.UserFile, Session.User.ThisUser);
If (Session.User.ThisUser.Flags AND UserDeleted = 0) and Session.User.Access(ACS) Then Begin
MsgTo := Session.User.ThisUser.Handle;
Session.User.ThisUser := OldUser;
Write_Mass_Msg;
{// appends wrong autosig so we add thisuser := olduser?}
// shitty kludge all of these var swaps should be
// rewritten.. probably do away with global MBAse records
End;
End;
Close (Session.User.UserFile);
Session.User.ThisUser := OldUser;
End;
'2' : For A := 1 to NamePos Do Begin
MsgTo := Names[A];
Write_Mass_Msg;
End;
End;
MsgBase^.CloseMsgBase;
Dispose (MsgBase, Done);
End;
End;
Procedure TMsgBase.ViewSentEmail;
Var
Old : RecMessageBase;
Begin
Old := MBase;
Reset (MBaseFile);
Read (MBaseFile, MBase);
Close (MBaseFile);
ReadMessages('B', '', '');
MBase := Old;
End;
Procedure TMsgBase.MessageQuickScan (Data: String);
// Defaults to ALL groups/bases
// /CURRENT = scan only current message base
// /GROUP = scan only current group bases
// other options:
// /LIST = List messages
// /NEW = only show/list if base has new or msg is new
// /YOU = only show/list if base has your msgs or is your msg
// /NOFOOT = dont show footer prompt
// /NOSCAN = do not show "scanning" prompt
// /NOFROM = bypass messages posted FROM the user
// /NOREAD = bypass messages addressed to, and read by, the user
Var
Aborted : Boolean;
NoFrom : Boolean;
NoRead : Boolean;
ShowIfNew : Boolean;
ShowIfYou : Boolean;
ShowScanPrompt : Boolean;
ShowFootPrompt : Boolean;
ShowMessage : Boolean;
ShowMessagePTR : LongInt;
Global_CurBase : LongInt;
Global_TotalBases : LongInt;
Global_TotalMsgs : LongInt;
Global_NewMsgs : LongInt;
Global_YourMsgs : LongInt;
Mode : Char;
Procedure ScanBase;
Var
NewMsgs : LongInt;
YourMsgs : LongInt;
TotalMsgs : LongInt;
Begin
Session.io.PromptInfo[1] := MBase.Name;
Session.io.PromptInfo[2] := strI2S(Global_CurBase);
Session.io.PromptInfo[3] := strI2S(Global_TotalBases);
NewMsgs := 0;
YourMsgs := 0;
TotalMsgs := 0;
If ShowScanPrompt Then Begin
Session.io.OutFull(Session.GetPrompt(487));
Session.io.BufFlush;
End;
Aborted := GetMessageStats(ShowMessage, ShowScanPrompt, ShowIfYou, ShowMessagePTR, MBase, NoFrom, NoRead, TotalMsgs, NewMsgs, YourMsgs);
If ShowMessage And Aborted Then Exit;
Inc (Global_TotalMsgs, TotalMsgs);
Inc (Global_NewMsgs, NewMsgs);
Inc (Global_YourMsgs, YourMsgs);
Session.io.PromptInfo[4] := strI2S(TotalMsgs);
Session.io.PromptInfo[5] := strI2S(NewMsgs);
Session.io.PromptInfo[6] := strI2S(YourMsgs);
Session.io.PromptInfo[7] := strI2S(Global_TotalMsgs);
Session.io.PromptInfo[8] := strI2S(Global_NewMsgs);
Session.io.PromptInfo[9] := strI2S(Global_YourMsgs);
If ShowScanPrompt Then
Session.io.OutBS(Console.CursorX, True);
If Not ShowMessage Then
If (ShowIfNew And (NewMsgs > 0)) or (ShowIfYou And (YourMsgs > 0)) or (Not ShowIfNew And Not ShowIfYou) Then Begin
Session.io.OutFullLn(Session.GetPrompt(488));
Session.io.BufFlush;
End;
End;
Var
Old : RecMessageBase;
Begin
Session.io.AllowPause := True;
Session.io.PausePtr := 1;
Session.LastScanHadNew := False;
Session.LastScanHadYou := False;
Global_CurBase := 1;
Global_TotalBases := 1;
Global_TotalMsgs := 0;
Global_NewMsgs := 0;
Global_YourMsgs := 0;
ShowMessagePTR := 0;
Mode := 'A';
FillChar(Session.io.PromptInfo, SizeOf(Session.io.PromptInfo), 0);
If Pos('/GROUP', Data) > 0 Then Mode := 'G';
If Pos('/CURRENT', Data) > 0 Then Mode := 'C';
ShowMessage := Pos('/LIST', Data) > 0;
ShowFootPrompt := Pos('/NOFOOT', Data) = 0;
ShowScanPrompt := Pos('/NOSCAN', Data) = 0;
ShowIfNew := Pos('/NEW', Data) > 0;
ShowIfYou := Pos('/YOU', Data) > 0;
NoFrom := Pos('/NOFROM', Data) > 0;
NoRead := Pos('/NOREAD', Data) > 0;
Old := MBase;
Session.User.IgnoreGroup := Mode = 'A';
FileMode := 66;
If Mode = 'C' Then
ScanBase
Else Begin
Reset (MBaseFile);
Global_TotalBases := FileSize(MBaseFile);
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
Global_CurBase := FilePos(MBaseFile);
If Session.User.Access(MBase.ReadACS) Then Begin
GetMessageScan;
If MScan.NewScan > 0 Then ScanBase;
If ShowMessage And Aborted Then Break;
End;
End;
Close (MBaseFile);
End;
Session.LastScanHadNew := Global_NewMsgs > 0;
Session.LastScanHadYou := Global_YourMsgs > 0;
Session.io.PromptInfo[1] := strComma(Global_TotalMsgs);
Session.io.PromptInfo[2] := strComma(Global_NewMsgs);
Session.io.PromptInfo[3] := strComma(Global_YourMsgs);
If ShowMessagePTR > 0 Then
Session.io.OutFull(Session.GetPrompt(508));
If ShowFootPrompt Then
Session.io.OutFullLn(Session.GetPrompt(489));
Session.User.IgnoreGroup := False;
MBase := Old;
End;
Function TMsgBase.SaveMessage (mArea: RecMessageBase; mFrom, mTo, mSubj: String; mAddr: RecEchoMailAddr; mLines: Integer) : Boolean;
Var
SemFile : File;
Count : SmallInt;
Msg : PMsgBaseABS;
Begin
// things to do:
// 2) see if we can use assignmessagedata, etc
// 3) add autosig? if we cannot use the assignmsgdata things
Result := False;
If Not MBaseOpenCreate(Msg, mArea, Session.TempPath) Then Exit;
Msg^.StartNewMsg;
Msg^.SetLocal (True);
If mArea.NetType > 0 Then Begin
If mArea.NetType = 3 Then Begin
Msg^.SetMailType (mmtNetMail);
Msg^.SetCrash (bbsCfg.netCrash);
Msg^.SetHold (bbsCfg.netHold);
Msg^.SetKillSent (bbsCfg.netKillSent);
Msg^.SetDest (mAddr);
End Else
Msg^.SetMailType (mmtEchoMail);
Msg^.SetOrig (GetMatchedAddress(bbsCfg.NetAddress[mArea.NetAddr], mAddr));
Case mArea.NetType of
1 : If mArea.QwkConfID = 0 Then
Assign (SemFile, bbsCfg.SemaPath + fn_SemFileEchoOut)
Else
Assign (SemFile, bbsCfg.SemaPath + fn_SemFileQwk);
2 : Assign (SemFile, bbsCfg.SemaPath + fn_SemFileNews);
3 : Assign (SemFile, bbsCfg.SemaPath + fn_SemFileNet);
End;
ReWrite (SemFile);
Close (SemFile);
End Else
Msg^.SetMailType (mmtNormal);
Msg^.SetPriv (mArea.Flags And MBPrivate <> 0);
Msg^.SetDate (DateDos2Str(CurDateDos, 1));
Msg^.SetTime (TimeDos2Str(CurDateDos, 0));
Msg^.SetFrom (mFrom);
Msg^.SetTo (mTo);
Msg^.SetSubj (mSubj);
For Count := 1 to mLines Do
Msg^.DoStringLn(MsgText[Count]);
If mArea.NetType > 0 Then Begin
Msg^.DoStringLn (#13 + '--- ' + mysSoftwareID + ' v' + mysVersion + ' (' + OSID + ')');
Msg^.DoStringLn (' * Origin: ' + ResolveOrigin(mArea) + ' (' + Addr2Str(Msg^.GetOrigAddr) + ')');
End;
Msg^.WriteMsg;
Msg^.CloseMsgBase;
Dispose (Msg, Done);
Result := True;
End;
Procedure TMsgBase.PostTextFile (Data: String; AllowCodes: Boolean);
Const
MaxLines = 10000;
Var
MBFile : File;
mName : String;
mArea : Word;
mFrom : String;
mTo : String;
mSubj : String;
mAddr : RecEchoMailAddr;
mLines : Integer;
InFile : Text;
TextBuf : Array[1..2048] of Char;
Buffer : Array[1..MaxLines] of ^String;
Str : String[79];
Lines : Integer;
Pages : Integer;
Count : Integer;
Offset : Integer;
TempBase : RecMessageBase;
Begin
mName := strWordGet(1, Data, ';');
mArea := strS2I(strWordGet(2, Data, ';'));
mFrom := strWordGet(3, Data, ';');
mTo := strWordGet(4, Data, ';');
mSubj := strWordGet(5, Data, ';');
Str := strWordGet(6, Data, ';');
If (Str = '') Then Str := '0:0/0';
Str2Addr (Str, mAddr);
If FileExist(bbsCfg.DataPath + mName) Then
mName := bbsCfg.DataPath + mName
Else
If Not FileExist(mName) Then Begin
Session.SystemLog('AutoPost: ' + mName + ' not found');
Exit;
End;
Assign (MBFile, bbsCfg.DataPath + 'mbases.dat');
ioReset (MBFile, SizeOf(RecMessageBase), fmRWDN);
If Not ioSeek (MBFile, mArea) Then Begin
Close (MBFile);
Exit;
End;
If Not ioRead (MBFile, TempBase) Then Begin
Close (MBFile);
Exit;
End;
Close (MBFile);
Assign (InFile, mName);
SetTextBuf (InFile, TextBuf, SizeOf(TextBuf));
Reset (InFile);
Lines := 0;
While Not Eof(InFile) And (Lines < MaxLines) Do Begin
ReadLn (InFile, Str);
If AllowCodes Then Str := Session.io.StrMci(Str);
Inc (Lines);
New (Buffer[Lines]);
Buffer[Lines]^ := Str;
End;
Close (InFile);
Pages := Lines DIV mysMaxMsgLines + 1;
If (Lines MOD mysMaxMsgLines = 0) Then Dec(Pages);
For Count := 1 to Pages Do Begin
Offset := mysMaxMsgLines * Pred(Count);
mLines := 0;
While (Offset < Lines) and (mLines < mysMaxMsgLines) Do Begin
Inc (mLines);
Inc (Offset);
MsgText[mLines] := Buffer[Offset]^;
End;
If Pages > 1 Then
Str := mSubj + ' (' + strI2S(Count) + '/' + strI2S(Pages) + ')'
Else
Str := mSubj;
If Not SaveMessage (TempBase, mFrom, mTo, Str, mAddr, mLines) Then Break;
End;
While Lines > 0 Do Begin
Dispose (Buffer[Lines]);
Dec (Lines);
End;
End;
Function TMsgBase.ResolveOrigin (Var mArea: RecMessageBase) : String;
Var
Loc : Byte;
FN : String;
TF : Text;
Buf : Array[1..2048] of Char;
Str : String;
Count : LongInt;
Pick : LongInt;
Begin
Result := '';
Loc := Pos('@RANDOM=', strUpper(mArea.Origin));
If Loc > 0 Then Begin
FN := strStripB(Copy(mArea.Origin, Loc + 8, 255), ' ');
If Pos(PathChar, FN) = 0 Then FN := bbsCfg.DataPath + FN;
FileMode := 66;
Assign (TF, FN);
SetTextBuf (TF, Buf, SizeOf(Buf));
{$I-} Reset (TF); {$I+}
If IoResult <> 0 Then Exit;
Count := 0;
While Not Eof(TF) Do Begin
ReadLn (TF, Str);
If strStripB(Str, ' ') = '' Then Continue;
Inc (Count);
End;
If Count = 0 Then Begin
Close (TF);
Exit;
End;
Pick := Random(Count) + 1;
Reset (TF);
Count := 0;
While Not Eof(TF) Do Begin
ReadLn (TF, Str);
If strStripB(Str, ' ') = '' Then Continue;
Inc (Count);
If Count = Pick Then Begin
Result := Str;
Break;
End;
End;
Close (TF);
End Else
Result := mArea.Origin;
End;
// ==========================================================================
// QWK/QWKE OPTIONS
// ==========================================================================
Procedure TMsgBase.WriteDOORID (Extended: Boolean);
Const
CRLF = #13#10;
Var
tFile : Text;
Begin
Assign (tFile, Session.TempPath + 'door.id');
ReWrite (tFile);
Write (tFile, 'DOOR = ' + mysSoftwareID + CRLF);
Write (tFile, 'VERSION = ' + mysVersion + CRLF);
Write (tFile, 'SYSTEM = ' + mysSoftwareID + ' ' + mysVersion + CRLF);
Write (tFile, 'CONTROLNAME = ' + qwkControlName + CRLF);
Write (tFile, 'CONTROLTYPE = ADD' + CRLF);
Write (tFile, 'CONTROLTYPE = DROP' + CRLF);
Close (tFile);
End;
Procedure TMsgBase.WriteTOREADEREXT;
Const
CRLF = #13#10;
Var
tFile : Text;
Flags : String;
Begin
Assign (tFile, Session.TempPath + 'toreader.ext');
ReWrite (tFile);
Write (tFile, 'ALIAS ' + Session.User.ThisUser.Handle + CRLF);
Reset (MBaseFile);
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If Session.User.Access(MBase.ReadACS) Then Begin
Flags := ' ';
If MBase.Flags AND MBPrivate = 0 Then
Flags := Flags + 'aO'
Else
Flags := Flags + 'pP';
If MBase.Flags AND MBRealNames = 0 Then
Flags := Flags + 'H';
If Not Session.User.Access(MBase.PostACS) Then
Flags := Flags + 'BRZ';
Case MBase.NetType of
0 : Flags := Flags + 'L';
1 : Flags := Flags + 'E';
2 : Flags := Flags + 'U';
3 : Flags := Flags + 'N';
End;
If MBase.DefQScan = 2 Then
Flags := Flags + 'F';
Write (tFile, 'AREA ' + strI2S(MBase.Index) + Flags, CRLF);
End;
End;
Close (MBaseFile);
Close (tFile);
End;
Procedure TMsgBase.WriteCONTROLDAT (Extended: Boolean);
Const
CRLF = #13#10; { for eventually having option for linux OR dos text files }
Var
tFile : Text;
Begin
Assign (tFile, Session.TempPath + 'control.dat');
ReWrite (tFile);
Write (tFile, bbsCfg.BBSName + CRLF);
Write (tFile, CRLF);
Write (tFile, CRLF);
Write (tFile, bbsCfg.SysopName + CRLF);
Write (tFile, '0,' + bbsCfg.qwkBBSID + CRLF);
Write (tFile, DateDos2Str(CurDateDos, 1), ',', TimeDos2Str(CurDateDos, 0) + CRLF);
Write (tFile, Session.User.ThisUser.Handle + CRLF);
Write (tFile, CRLF);
Write (tFile, '0' + CRLF);
Write (tFile, TotalMsgs, CRLF); {TOTAL MSG IN PACKET}
Write (tFile, TotalConf - 1, CRLF); {TOTAL CONF - 1}
Reset (MBaseFile);
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If Session.User.Access(MBase.ReadACS) Then Begin
Write (tFile, MBase.Index, CRLF); {conf #}
If Extended Then
Write (tFile, strStripMCI(MBase.Name) + CRLF)
Else
Write (tFile, MBase.QwkName + CRLF);
End;
End;
Close (MBaseFile);
Write (tFile, JustFile(bbsCfg.qwkWelcome) + CRLF);
Write (tFile, JustFile(bbsCfg.qwkNews) + CRLF);
Write (tFile, JustFile(bbsCfg.qwkGoodbye) + CRLF);
Close (tFile);
End;
{ converts TP real to Microsoft 4 bytes single }
{ what kind of stupid standard uses this var type!? }
Procedure Long2msb (Index : LongInt; Var MS : BSingle);
Var
Exp : Byte;
Begin
If Index <> 0 Then Begin
Exp := 0;
While Index And $800000 = 0 Do Begin
Inc (Exp);
Index := Index SHL 1
End;
Index := Index And $7FFFFF;
End Else
Exp := 152;
MS[0] := Index AND $FF;
MS[1] := (Index SHR 8) AND $FF;
MS[2] := (Index SHR 16) AND $FF;
MS[3] := 152 - Exp;
End;
Function TMsgBase.WriteMSGDAT (Extended: Boolean) : LongInt;
Var
DataFile : File;
NdxFile : File of QwkNdxHdr;
NdxHdr : QwkNdxHdr;
Header : String[128];
Chunks : Word;
BufStr : String[128];
MsgAdded : Integer;
LastRead : LongInt;
QwkIndex : LongInt;
TooBig : Boolean;
Procedure DoString (Str: String);
Var
Count : SmallInt;
Begin
For Count := 1 to Length(Str) Do Begin
BufStr := BufStr + Str[Count];
If BufStr[0] = #128 Then Begin
BlockWrite (DataFile, BufStr[1], 128);
BufStr := '';
End;
End;
End;
Var
TempStr : String;
Begin
MsgAdded := 0;
If Not MBaseOpenCreate(MsgBase, MBase, Session.TempPath) Then Exit;
Session.io.OutFull (Session.GetPrompt(231));
Assign (DataFile, Session.TempPath + 'messages.dat');
Reset (DataFile, 1);
Seek (DataFile, FileSize(DataFile));
LastRead := MsgBase^.GetLastRead(Session.User.UserNum) + 1;
MsgBase^.SeekFirst (LastRead);
While MsgBase^.SeekFound Do Begin
If ((bbsCfg.QwkMaxBase > 0) and (MsgAdded = bbsCfg.QwkMaxBase)) or
((bbsCfg.QwkMaxPacket > 0) and (TotalMsgs = bbsCfg.QwkMaxPacket)) Then Break;
MsgBase^.MsgStartUp;
If MsgBase^.IsPriv And Not Session.User.IsThisUser(MsgBase^.GetTo) Then Begin
MsgBase^.SeekNext;
Continue;
End;
Inc (MsgAdded);
Inc (TotalMsgs);
LastRead := MsgBase^.GetMsgNum;
Chunks := 0;
BufStr := '';
TooBig := False;
QwkIndex := FileSize(DataFile) DIV 128 + 1;
MsgBase^.MsgTxtStartUp;
While Not MsgBase^.EOM Do Begin
TempStr := MsgBase^.GetString(79);
If TempStr[1] = #1 Then Continue;
Inc (Chunks, Length(TempStr));
End;
If Chunks MOD 128 = 0 Then
Chunks := Chunks DIV 128 + 1
Else
Chunks := Chunks DIV 128 + 2;
Header :=
' ' +
strPadR(strI2S(MsgBase^.GetMsgNum), 7, ' ') +
MsgBase^.GetDate +
MsgBase^.GetTime +
strPadR(MsgBase^.GetTo, 25, ' ') +
strPadR(MsgBase^.GetFrom, 25, ' ') +
strPadR(MsgBase^.GetSubj, 25, ' ') +
strPadR('', 12, ' ') +
strPadR(strI2S(MsgBase^.GetRefer), 8, ' ') +
strPadR(strI2S(Chunks), 6, ' ') +
#255 +
' ' +
' ' +
' ';
If MsgAdded = 1 Then Begin
Assign (NdxFile, Session.TempPath + strPadL(strI2S(MBase.Index), 3, '0') + '.ndx');
ReWrite (NdxFile);
End;
LONG2MSB (QwkIndex, NdxHdr.MsgPos);
Write (NdxFile, NdxHdr);
BlockWrite (DataFile, Header[1], 128);
If Extended Then Begin
If Length(MsgBase^.GetFrom) > 25 Then Begin
DoString('From: ' + MsgBase^.GetFrom + #227);
TooBig := True;
End;
If Length(MsgBase^.GetTo) > 25 Then Begin
DoString('To: ' + MsgBase^.GetTo + #227);
TooBig := True;
End;
If Length(MsgBase^.GetSubj) > 25 Then Begin
DoString('Subject: ' + MsgBase^.GetSubj + #227);
TooBig := True;
End;
If TooBig Then DoString(#227);
End;
MsgBase^.MsgTxtStartUp;
While Not MsgBase^.EOM Do Begin
TempStr := MsgBase^.GetString(79) + #227;
If TempStr[1] = #1 Then Continue;
DoString (TempStr);
End;
If BufStr <> '' Then Begin
BufStr := strPadR (BufStr, 128, ' ');
BlockWrite (DataFile, BufStr[1], 128);
End;
MsgBase^.SeekNext;
End;
Close (DataFile);
If MsgAdded > 0 Then Close (NdxFile);
Session.io.PromptInfo[1] := strI2S(MBase.Index);
Session.io.PromptInfo[2] := MBase.Name;
Session.io.PromptInfo[3] := MBase.QwkName;
Session.io.PromptInfo[4] := strI2S(MsgBase^.NumberOfMsgs);
Session.io.PromptInfo[5] := strI2S(MsgAdded);
MsgBase^.CloseMsgBase;
Dispose (MsgBase, Done);
Session.io.OutBS (Console.CursorX, True);
Session.io.OutFullLn (Session.GetPrompt(232));
Result := LastRead;
End;
Procedure TMsgBase.DownloadQWK (Extended: Boolean; Data: String);
Type
QwkLRRec = Record
Base : Word;
Pos : LongInt;
End;
Var
Old : RecMessageBase;
DataFile : File;
Temp : String;
QwkLR : QwkLRRec;
QwkLRFile : File of QwkLRRec;
Begin
If Session.User.ThisUser.QwkFiles Then
Session.FileBase.ExportFileList(True, True);
FileMode := 66;
Old := MBase;
Temp := strPadR('Produced By ' + mysSoftwareID + ' v' + mysVersion + '. ' + mysCopyNotice, 128, ' ');
Assign (DataFile, Session.TempPath + 'messages.dat');
ReWrite (DataFile, 1);
BlockWrite (DataFile, Temp[1], 128);
Close (DataFile);
Assign (QwkLRFile, Session.TempPath + 'qlr.dat');
ReWrite (QwkLRFile);
Reset (MBaseFile);
Session.io.OutFullLn (Session.GetPrompt(230));
TotalMsgs := 0;
TotalConf := 0;
Session.User.IgnoreGroup := Pos('/ALLGROUP', strUpper(Data)) > 0;
While Not Eof(MBaseFile) Do Begin
Read (MBaseFile, MBase);
If Session.User.Access(MBase.ReadACS) Then Begin
Inc (TotalConf);
GetMessageScan;
If MScan.QwkScan > 0 Then Begin
QwkLR.Base := FilePos(MBaseFile);
QwkLR.Pos := WriteMsgDAT(Extended);
Write (QwkLRFile, QwkLR);
End;
End;
End;
Close (QwkLRFile);
WriteControlDAT (Extended);
WriteDOORID (Extended);
If Extended Then WriteTOREADEREXT;
If TotalMsgs > 0 Then Begin
Session.io.PromptInfo[1] := strI2S(TotalMsgs);
Session.io.PromptInfo[2] := strI2S(TotalConf);
Session.io.OutFullLn (Session.GetPrompt(233));
Temp := bbsCfg.qwkBBSID + '.qwk';
Session.io.OutFullLn (Session.GetPrompt(234));
Session.io.PromptInfo[1] := Temp;
If FileExist(bbsCfg.QwkWelcome) Then FileCopy(bbsCfg.qwkWelcome, Session.TempPath + JustFile(bbsCfg.qwkWelcome));
If FileExist(bbsCfg.QwkNews) Then FileCopy(bbsCfg.qwkNews, Session.TempPath + JustFile(bbsCfg.qwkNews));
If FileExist(bbsCfg.QwkGoodbye) Then FileCopy(bbsCfg.qwkGoodbye, Session.TempPath + JustFile(bbsCfg.qwkGoodbye));
// Session.SystemLog('DEBUG: Archiving QWK packet');
If Session.LocalMode Then Begin
FileErase (bbsCfg.QWKPath + Temp);
Session.FileBase.ExecuteArchive (bbsCfg.QWKPath + Temp, Session.User.ThisUser.Archive, Session.TempPath + '*', 1);
Session.io.OutFullLn (Session.GetPrompt(235));
End Else Begin
Session.FileBase.ExecuteArchive (Session.TempPath + Temp, Session.User.ThisUser.Archive, Session.TempPath + '*', 1);
Session.FileBase.SendFile (Session.TempPath + Temp);
End;
If Session.io.GetYN (Session.GetPrompt(236), True) Then Begin
Reset (MBaseFile);
Reset (QwkLRFile);
While Not Eof(QwkLRFile) Do Begin
Read (QwkLRFile, QwkLR);
Seek (MBaseFile, QwkLR.Base - 1);
Read (MBaseFile, MBase);
Case MBase.BaseType of
0 : MsgBase := New(PMsgBaseJAM, Init);
1 : MsgBase := New(PMsgBaseSquish, Init);
End;
MsgBase^.SetMsgPath (MBase.Path + MBase.FileName);
If MsgBase^.OpenMsgBase Then Begin
MsgBase^.SetLastRead (Session.User.UserNum, QwkLR.Pos);
MsgBase^.CloseMsgBase;
End;
Dispose(MsgBase, Done);
End;
Close (QwkLRFile);
Close (MBaseFile);
End;
End Else
Session.io.OutFullLn (Session.GetPrompt(228));
Session.User.IgnoreGroup := False;
// Close (MBaseFile);
MBase := Old;
DirClean (Session.TempPath, '');
End;
Procedure TMsgBase.UploadREP;
Var
DataFile : File;
TempBase : RecMessageBase;
OldBase : RecMessageBase;
QwkHeader : QwkDATHdr;
QwkBlock : String[128];
Line : String;
A : SmallInt;
B : SmallInt;
Chunks : SmallInt;
LineCount : SmallInt;
IsControl : Boolean;
GotControl : Boolean;
ExtFile : Text;
StatOK : LongInt = 0;
StatFailed : LongInt = 0;
StatBaseAdd : LongInt = 0;
StatBaseDel : LongInt = 0;
Procedure QwkControl (Idx: LongInt; Mode: Byte);
Begin
OldBase := MBase;
If GetMBaseByIndex(Idx, MBase) Then Begin
GetMessageScan;
MScan.QwkScan := Mode;
If Mode = 0 Then Inc (StatBaseDel);
If Mode = 1 Then Inc (StatBaseAdd);
SetMessageScan;
End;
MBase := OldBase;
End;
Begin
If Session.LocalMode Then
Session.FileBase.ExecuteArchive (bbsCfg.QWKPath + bbsCfg.qwkBBSID + '.rep', Session.User.ThisUser.Archive, '*', 2)
Else Begin
If Session.FileBase.SelectProtocol(True, False) = 'Q' Then Exit;
Session.FileBase.ExecuteProtocol(1, Session.TempPath + bbsCfg.qwkBBSID + '.rep');
If Not Session.FileBase.DszSearch(bbsCfg.qwkBBSID + '.rep') Then Begin
Session.io.PromptInfo[1] := bbsCfg.qwkBBSID + '.rep';
Session.io.OutFullLn (Session.GetPrompt(84));
Exit;
End;
Session.FileBase.ExecuteArchive (Session.TempPath + bbsCfg.qwkBBSID + '.rep', Session.User.ThisUser.Archive, '*', 2)
End;
Assign (DataFile, FileFind(Session.TempPath + bbsCfg.qwkBBSID + '.msg'));
If Not ioReset(DataFile, 1, fmRWDN) Then Begin
Session.io.OutFull (Session.GetPrompt(238));
DirClean (Session.TempPath, '');
Exit;
End;
BlockRead (DataFile, QwkBlock[1], 128);
QwkBlock[0] := #128;
If Pos(strUpper(bbsCfg.qwkBBSID), strUpper(QwkBlock)) = 0 Then Begin
Session.io.OutFullLn (Session.GetPrompt(239));
Close (DataFile);
DirClean(Session.TempPath, '');
Exit;
End;
Session.io.OutFull (Session.GetPrompt(240));
While Not Eof(DataFile) Do Begin
BlockRead (DataFile, QwkHeader, SizeOf(QwkHeader));
Move (QwkHeader.MsgNum, QwkBlock[1], 7);
QwkBlock[0] := #7;
If GetMBaseByIndex(strS2I(QwkBlock), TempBase) Then Begin
If MBaseOpenCreate(MsgBase, TempBase, Session.TempPath) Then Begin
AssignMessageData(MsgBase, TempBase);
QwkBlock[0] := #25;
Move (QwkHeader.UpTo, QwkBlock[1], 25);
MsgBase^.SetTo(strStripR(QwkBlock, ' '));
Move (QwkHeader.Subject, QwkBlock[1], 25);
MsgBase^.SetSubj(strStripR(QwkBlock, ' '));
Move (QwkHeader.ReferNum, QwkBlock[1], 6);
QwkBlock[0] := #6;
MsgBase^.SetRefer(strS2I(strStripR(QwkBlock, ' ')));
Move(QwkHeader.NumChunk, QwkBlock[1], 6);
Chunks := strS2I(QwkBlock) - 1;
Line := '';
LineCount := 0;
IsControl := MsgBase^.GetTo = qwkControlName;
GotControl := False;
If IsControl And ((MsgBase^.GetSubj = 'ADD') or (MsgBase^.GetSubj = 'DROP')) Then
QwkControl (TempBase.Index, Ord(MsgBase^.GetSubj = 'ADD'));
For A := 1 to Chunks Do Begin
BlockRead (DataFile, QwkBlock[1], 128);
QwkBlock[0] := #128;
QwkBlock := strStripR(QwkBlock, ' ');
For B := 1 to Length(QwkBlock) Do Begin
If QwkBlock[B] = #227 Then Begin
Inc (LineCount);
If (LineCount < 4) and (Copy(Line, 1, 5) = 'From:') Then
GotControl := True
// Mystic uses the username of the person who uploaded the
// reply package, based on the alias/realname setting of the
// base itself. This prevents people from spoofing "From"
// fields.
// If QWK networking will need to allow this of course
Else
If (LineCount < 4) and (Copy(Line, 1, 3) = 'To:') Then Begin
MsgBase^.SetTo(strStripB(Copy(Line, 4, Length(Line)), ' '));
GotControl := True;
End Else
If (LineCount < 4) and (Copy(Line, 1, 8) = 'Subject:') Then Begin
MsgBase^.SetSubj(strStripB(Copy(Line, 9, Length(Line)), ' '));
GotControl := True;
End Else
If GotControl And (Line = '') Then
GotControl := False
Else
MsgBase^.DoStringLn(Line);
Line := '';
End Else
Line := Line + QwkBlock[B];
End;
End;
If Line <> '' Then MsgBase^.DoStringLn(Line);
If TempBase.NetType > 0 Then Begin
MsgBase^.DoStringLn (#13 + '--- ' + mysSoftwareID + '/QWK v' + mysVersion + ' (' + OSID + ')');
Line := ' * Origin: ' + ResolveOrigin(MBase);
If MBase.QwkNetID = 0 Then
Line := Line + ' (' + Addr2Str(MsgBase^.GetOrigAddr) + ')';
MsgBase^.DoStringLn (Line);
End;
If Not IsControl Then Begin
MsgBase^.WriteMsg;
Inc (StatOK);
Inc (Session.User.ThisUser.Posts);
Inc (Session.HistoryPosts);
End;
MsgBase^.CloseMsgBase;
Dispose (MsgBase, Done);
End Else
Inc (StatFailed);
End Else
Inc (StatFailed);
End;
Close (DataFile);
Assign (ExtFile, FileFind(Session.TempPath + 'todoor.ext'));
{$I-} Reset (ExtFile); {$I+}
If IoResult = 0 Then Begin
While Not Eof(ExtFile) Do Begin
ReadLn (ExtFile, Line);
If strWordGet(1, Line, ' ') = 'AREA' Then Begin
QwkBlock := strWordGet(3, Line, ' ');
If Pos('a', QwkBlock) > 0 Then QwkControl(strS2I(strWordGet(2, Line, ' ')), 1);
If Pos('D', QwkBlock) > 0 Then QwkControl(strS2I(strWordGet(2, Line, ' ')), 0);
End;
End;
Close (ExtFile);
End;
DirClean (Session.TempPath, '');
Session.io.PromptInfo[1] := strI2S(StatOK);
Session.io.PromptInfo[2] := strI2S(StatFailed);
Session.io.PromptInfo[3] := strI2S(StatBaseAdd);
Session.io.PromptInfo[4] := strI2S(StatBaseDel);
Session.io.OutFullLn(Session.GetPrompt(503));
End;
End.