// ==================================================================== // Mystic BBS Software Copyright 1997-2012 By James Coyle // ==================================================================== // // This file is part of Mystic BBS. // // Mystic BBS is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Mystic BBS is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Mystic BBS. If not, see . // // ==================================================================== Program MBBSUTIL; // post a text file to msg base? // auto mass upload // export AREAS.BBS? // import FIDONET.NA // .TIC stuff? {$I M_OPS.PAS} Uses CRT, DOS, m_DateTime, m_Strings, m_QuickSort, m_FileIO, bbs_MsgBase_ABS, bbs_MsgBase_JAM, bbs_MsgBase_Squish; {$I RECORDS.PAS} Const FilePack : Boolean = False; FileSort : Boolean = False; FileCheck : Boolean = False; FileUpload : Boolean = False; BBSPack : Boolean = False; BBSSort : Boolean = False; BBSKill : Boolean = False; UserKill : Boolean = False; UserPack : Boolean = False; MsgTrash : Boolean = False; NodeCheck : Boolean = True; AreasOut : Boolean = False; UserKillDays : Integer = 0; BBSSortID : String = ''; BBSSortType : Byte = 0; BBSKillID : String = ''; BBSKillDays : Integer = 0; TrashFile : String = ''; TempPath : String = ''; AreasFile : String = ''; Var ConfigFile : File of RecConfig; Config : RecConfig; Type JamLastType = Record NameCrc : LongInt; UserNum : LongInt; LastRead : LongInt; HighRead : LongInt; End; SquLastType = LongInt; Function ShellDOS (ExecPath: String; Command: String) : LongInt; Begin // needs to save/restore screen If ExecPath <> '' Then DirChange(ExecPath); {$IFDEF UNIX} Result := Shell (Command); {$ENDIF} {$IFDEF WINDOWS} If Command <> '' Then Command := '/C' + Command; Exec (GetEnv('COMSPEC'), Command); Result := DosExitCode; {$ENDIF} DirChange(Config.SystemPath); End; Procedure ExecuteArchive (FName: String; Temp: String; Mask: String; Mode: Byte); {mode: 1 = pack, 2 = unpack} Var A : Byte; Temp2 : String[60]; ArcFile : File of RecArchive; Arc : RecArchive; Begin Temp := strUpper(JustFileExt(FName)); Assign (ArcFile, Config.DataPath + 'archive.dat'); {$I-} Reset (ArcFile); {$I+} If IoResult <> 0 Then Exit; Repeat If Eof(ArcFile) Then Begin Close (ArcFile); Exit; End; Read (ArcFile, Arc); If (Not Arc.Active) or (Arc.OSType <> OSType) Then Continue; If strUpper(Arc.Ext) = Temp Then Break; Until False; Close (ArcFile); Case Mode of 1 : Temp2 := Arc.Pack; 2 : Temp2 := Arc.Unpack; End; If Temp2 = '' Then Exit; Temp := ''; A := 1; While A <= Length(Temp2) Do Begin If Temp2[A] = '%' Then Begin Inc(A); If Temp2[A] = '1' Then Temp := Temp + FName Else If Temp2[A] = '2' Then Temp := Temp + Mask Else If Temp2[A] = '3' Then Temp := Temp + TempPath; End Else Temp := Temp + Temp2[A]; Inc(A); End; ShellDOS ('', Temp); End; Function strAddr2Str (Addr : RecEchoMailAddr) : String; Var Temp : String[20]; Begin Temp := strI2S(Addr.Zone) + ':' + strI2S(Addr.Net) + '/' + strI2S(Addr.Node); If Addr.Point <> 0 Then Temp := Temp + '.' + strI2S(Addr.Point); Result := Temp; End; Procedure Update_Status (Str: String); Begin GotoXY (44, WhereY); Write (strPadR(Str, 35, ' ')); End; Procedure Update_Bar (Cur, Total: Integer); Var Percent : Byte; Begin Percent := Round(Cur / Total * 100 / 10); GotoXY (24, WhereY); Write (strRep(#178, Percent)); Write (strRep(#176, 10 - Percent)); Write (strPadL(strI2S(Percent * 10) + '%', 5, ' ')); End; Procedure Show_Help; Begin WriteLn ('Usage: MBBSUTIL '); WriteLn; WriteLn ('The following command line options are available:'); WriteLn; WriteLn ('-AREAOUT Export AREAS.BBS format file in '); WriteLn ('-BKILL Delete BBSes which haven''t been verified in '); WriteLn ('-BPACK Pack all BBS lists'); WriteLn ('-BSORT Sorts and packs BBS list by '); WriteLn ('-FCHECK Checks file entries for correct size and status'); WriteLn ('-FPACK Pack file bases'); WriteLn ('-FSORT Sort file base entries by filename'); WriteLn ('-FUPLOAD Mass upload all files into filebases'); WriteLn ('-MTRASH Delete messages to/from users listed in '); WriteLn ('-NOCHECK Bypass online user check at startup'); WriteLn ('-UKILL Delete users who have not called in '); WriteLn ('-UPACK Pack user database'); End; (***************************************************************************) (***************************************************************************) (***************************************************************************) Procedure Sort_File_Bases; Var SortList : TQuickSort; FBaseFile : File of RecFileBase; FBase : RecFileBase; FDirFile : File of RecFileList; TFDirFile : File of RecFileList; FDir : RecFileList; A : Word; Begin Write ('Sorting File Bases : '); Assign (FBaseFile, Config.DataPath + 'fbases.dat'); {$I-} Reset (FBaseFile); {$I+} If IoResult <> 0 Then Exit; While Not Eof(FBaseFile) Do Begin Read (FBaseFile, FBase); Update_Bar (FilePos(FBaseFile), FileSize(FBaseFile)); Update_Status (strStripMCI(FBase.Name)); If FileRename (Config.DataPath + FBase.FileName + '.dir', Config.DataPath + FBase.FileName + '.dib') Then Begin Assign (FDirFile, Config.DataPath + FBase.FileName + '.dib'); Reset (FDirFile); Assign (TFDirFile, Config.DataPath + FBase.FileName + '.dir'); ReWrite (TFDirFile); SortList := TQuickSort.Create; While Not Eof(FDirFile) Do Begin Read (FDirFile, FDir); If (FDir.Flags AND FDirDeleted = 0) Then {$IFDEF FS_SENSITIVE} SortList.Add(FDir.FileName, FilePos(FDirFile) - 1); {$ELSE} SortList.Add(strUpper(FDir.FileName), FilePos(FDirFile) - 1); {$ENDIF} End; SortList.Sort(1, SortList.Total, qAscending); For A := 1 to SortList.Total Do Begin Seek (FDirFile, SortList.Data[A]^.Ptr); Read (FDirFile, FDir); Write (TFDirFile, FDir); End; SortList.Free; Close (FDirFile); Erase (FDirFile); Close (TFDirFile); End; End; Close (FBaseFile); Update_Status ('Completed'); WriteLn; End; Procedure Pack_File_Bases; Var A : Byte; Temp : String[50]; FDirFile : File of RecFileList; TFDirFile : File of RecFileList; FDir : RecFileList; DataFile : File; TDataFile : File; FBaseFile : File of RecFileBase; FBase : RecFileBase; Begin Write ('Packing File Bases : '); Assign (FBaseFile, Config.DataPath + 'fbases.dat'); {$I-} Reset (FBaseFile); {$I+} If IoResult <> 0 Then Exit; While Not Eof(FBaseFile) Do Begin Read (FBaseFile, FBase); Update_Bar (FilePos(FBaseFile), FileSize(FBaseFile)); Update_Status (strStripPipe(FBase.Name)); If FileRename (Config.DataPath + FBase.FileName + '.dir', Config.DataPath + FBase.FileName + '.dib') Then Begin Assign (FDirFile, Config.DataPath + FBase.FileName + '.dib'); Reset (FDirFile); Assign (TFDirFile, Config.DataPath + FBase.FileName + '.dir'); ReWrite (TFDirFile); If FileRename (Config.DataPath + FBase.FileName + '.des', Config.DataPath + FBase.FileName + '.deb') Then Begin Assign (TDataFile, Config.DataPath + FBase.FileName + '.deb'); Reset (TDataFile, 1); Assign (DataFile, Config.DataPath + FBase.FileName + '.des'); ReWrite (DataFile, 1); While Not Eof(FDirFile) Do Begin Read (FDirFile, FDir); If FDir.Flags AND FDirDeleted = 0 Then Begin Seek (TDataFile, FDir.DescPtr); FDir.DescPtr := FilePos(DataFile); For A := 1 to FDir.DescLines Do Begin BlockRead (TDataFile, Temp[0], 1); BlockRead (TDataFile, Temp[1], Ord(Temp[0])); BlockWrite (DataFile, Temp[0], 1); BlockWrite (DataFile, Temp[1], Ord(Temp[0])); End; Write (TFDirFile, FDir); End; End; Close (TDataFile); Erase (TDataFile); {delete backup file} Close (DataFile); End; Close (FDirFile); Erase (FDirFile); {delete backup file} Close (TFDirFile); End; End; Close (FBaseFile); Update_Status ('Completed'); WriteLn; End; Procedure Check_File_Bases; Var FBaseFile : File of RecFileBase; FBase : RecFileBase; FDirFile : File of RecFileList; FDir : RecFileList; TFDirFile : File of RecFileList; DF : File of Byte; Begin Write ('Checking File Bases : '); Assign (FBaseFile, Config.DataPath + 'fbases.dat'); {$I-} Reset (FBaseFile); {$I+} If IoResult <> 0 Then Exit; While Not Eof(FBaseFile) Do Begin Read (FBaseFile, FBase); Update_Bar (FilePos(FBaseFile), FileSize(FBaseFile)); Update_Status (strStripPipe(FBase.Name)); If FileRename (Config.DataPath + FBase.FileName + '.dir', Config.DataPath + FBase.FileName + '.dib') Then Begin Assign (FDirFile, Config.DataPath + FBase.FileName + '.dib'); Reset (FDirFile); Assign (TFDirFile, Config.DataPath + FBase.FileName + '.dir'); ReWrite (TFDirFile); While Not Eof(FDirFile) Do Begin Read (FDirFile, FDir); If FDir.Flags And FDirDeleted = 0 Then Begin Assign (DF, FBase.Path + FDir.FileName); {$I-} Reset (DF); {$I+} If IoResult <> 0 Then FDir.Flags := FDir.Flags AND FDirOffline Else Begin FDir.Size := FileSize(DF); If FDir.Size = 0 Then FDir.Flags := FDir.Flags OR FDirOffline Else FDir.Flags := FDir.Flags AND NOT FDirOffline; Close (DF); End; Write (TFDirFile, FDir); End; End; Close (FDirFile); {delete backup file} Erase (FDirFile); Close (TFDirFile); End; End; Close (FBaseFile); Update_Status ('Completed'); WriteLn; End; Procedure Pack_BBS_List; Var TBBSFile : File of BBSListRec; BBSFile : File of BBSListRec; BBSList : BBSListRec; Dir : SearchRec; D : DirStr; N : NameStr; E : ExtStr; Begin Write ('Packing BBS File :'); FindFirst (Config.DataPath + '*.bbi', AnyFile - Directory, Dir); While DosError = 0 Do Begin FSplit (Dir.Name, D, N, E); If FileRename (Config.DataPath + Dir.Name, Config.DataPath + N + '.bbz') Then Begin Assign (TBBSFile, Config.DataPath + N + '.bbz'); Reset (TBBSFile); Assign (BBSFile, Config.DataPath + Dir.Name); ReWrite (BBSFile); While Not Eof(TBBSFile) Do Begin Read (TBBSFile, BBSList); If Not BBSList.Deleted Then Write (BBSFile, BBSList); Update_Bar (FilePos(TBBSFile), FileSize(TBBSFile)); Update_Status (BBSList.BBSName); End; Close (TBBSFile); Erase (TBBSFile); Close (BBSFile); End; FindNext(Dir); End; FindClose(Dir); Update_Status ('Completed'); WriteLn; End; Procedure Sort_BBS_List; Procedure SortList; Var TBBSFile, BBSFile : File of BBSListRec; BBS : BBSListRec; SortList : TQuickSort; Str : String; A : Word; Begin If FileRename (Config.DataPath + BBSSortID + '.bbi', Config.DataPath + BBSSortID + '.bbz') Then Begin Update_Status (BBSSortID); Assign (TBBSFile, Config.DataPath + BBSSortID + '.bbz'); Reset (TBBSFile); Assign (BBSFile, Config.DataPath + BBSSortID + '.bbi'); ReWrite (BBSFile); SortList := TQuickSort.Create; While Not Eof(TBBSFile) Do Begin Read (TBBSFile, BBS); Update_Bar (FilePos(TBBSFile), FileSize(TBBSFile)); If Not BBS.Deleted Then Begin Case BBSSortType of 0 : Str := strUpper(BBS.Phone); 1 : Str := strUpper(BBS.Telnet); 2 : Str := strUpper(BBS.BBSName); 3 : Str := strUpper(BBS.Location); End; SortList.Add(Str, FilePos(TBBSFile) - 1); End; End; SortList.Sort(1, SortList.Total, qAscending); For A := 1 to SortList.Total Do Begin Seek (TBBSFile, SortList.Data[A]^.Ptr); Read (TBBSFile, BBS); Write (BBSFile, BBS); End; SortList.Free; Close (TBBSFile); Erase (TBBSFile); Close (BBSFile); End; End; Var D : DirStr; N : NameStr; E : ExtStr; Dir : SearchRec; Begin Write ('Sorting BBS File :'); If strUpper(BBSSortID) = 'ALL' Then Begin FindFirst (Config.DataPath + '*.bbi', AnyFile - Directory, Dir); While DosError = 0 Do Begin FSplit (Dir.Name, D, N, E); BBSSortID := N; SortList; FindNext(Dir); End; FindClose(Dir); End Else SortList; Update_Status ('Completed'); WriteLn; End; Procedure Kill_BBS_List; Procedure PackFile; Var TBBSFile : File of BBSListRec; BBSFile : File of BBSListRec; BBS : BBSListRec; Begin If FileRename (Config.DataPath + BBSKillID + '.bbi', Config.DataPath + BBSKillID + '.bbb') Then Begin Assign (TBBSFile, Config.DataPath + BBSKillID + '.bbb'); Reset (TBBSFile); Assign (BBSFile, Config.DataPath + BBSKillID + '.bbi'); ReWrite (BBSFile); While Not Eof(TBBSFile) Do Begin Read (TBBSFile, BBS); Update_Bar (FilePos(TBBSFile), FileSize(TBBSFile)); If DaysAgo(BBS.Verified) >= BBSKillDays Then Begin BBS.Deleted := True; BBSPack := True; Update_Status ('Killing ' + BBS.BBSName); End; Write (BBSFile, BBS); End; Close (BBSFile); Close (TBBSFile); Erase (TBBSFile); End; End; Var D : DirStr; N : NameStr; E : ExtStr; Dir : SearchRec; Begin Write ('Killing BBS List :'); If strUpper(BBSKillID) = 'ALL' Then Begin FindFirst (Config.DataPath + '*.bbi', AnyFile - Directory, Dir); While DosError = 0 Do Begin FSplit (Dir.Name, D, N, E); BBSKillID := N; PackFile; FindNext(Dir); End; FindClose(Dir); End Else PackFile; Update_Status ('Completed'); WriteLn; End; Procedure Kill_User_File; Var tUserFile, UserFile : File of RecUser; User : RecUser; Begin Write ('Killing User File :'); If FileRename (Config.DataPath + 'users.dat', Config.DataPath + 'users.dab') Then Begin Assign (TUserFile, Config.DataPath + 'users.dab'); Reset (TUserFile); Assign (UserFile, Config.DataPath + 'users.dat'); ReWrite (UserFile); While Not Eof(TUserFile) Do Begin Read (TUserFile, User); Update_Bar (FilePos(TUserFile), FileSize(TUserFile)); If (DaysAgo(User.LastOn) >= UserKillDays) And (User.Flags AND UserNoKill = 0) Then Begin User.Flags := User.Flags OR UserDeleted; Update_Status ('Killing ' + User.Handle); UserPack := True; End; Write (UserFile, User); End; Close (UserFile); Close (tUserFile); Erase (tUserFile); End; Update_Status ('Completed'); WriteLn; End; Procedure Pack_User_File; Var SquLRFile : File of SquLastType; SquLR : SquLastType; UserFile : File of RecUser; TUserFile : File of RecUser; User : RecUser; MBaseFile : File of RecMessageBase; MBase : RecMessageBase; MScanFile : File of MScanRec; MScan : MScanRec; FBaseFile : File of RecFileBase; FBase : RecFileBase; FScanFile : File of FScanRec; FScan : FScanRec; JamLRFile : File of JamLastType; TJamLRFile : File of JamLastType; JamLR : JamLastType; Deleted : LongInt; Count : LongInt; MsgBase : PMsgBaseABS; Begin Write ('Packing User File :'); If FileRename (Config.DataPath + 'users.dat', Config.DataPath + 'users.dab') Then Begin Assign (TUserFile, Config.DataPath + 'users.dab'); Reset (TUserFile); Assign (UserFile, Config.DataPath + 'users.dat'); ReWrite (UserFile); Deleted := 0; While Not Eof(TUserFile) Do Begin Read (TUserFile, User); Update_Bar (FilePos(TUserFile), FileSize(TUserFile)); If (User.Flags AND UserDeleted <> 0) And (User.Flags AND UserNoKill = 0) Then Begin Update_Status ('Deleted ' + User.Handle); { DELETE MESSAGES FROM ANY PRIVATE MSG BASE } Assign (MBaseFile, Config.DataPath + 'mbases.dat'); {$I-} Reset (MBaseFile); {$I+} If IoResult = 0 Then Begin While Not Eof(MBaseFile) Do Begin Read (MBaseFile, MBase); If MBase.Flags And MBPrivate = 0 Then Continue; Case MBase.BaseType of 0 : MsgBase := New(PMsgBaseJAM, Init); 1 : MsgBase := New(PMsgBaseSquish, Init); End; MsgBase^.SetMsgPath (MBase.Path + MBase.FileName); If Not MsgBase^.OpenMsgBase Then Begin Dispose (MsgBase, Done); Continue; End; MsgBase^.SeekFirst(1); While MsgBase^.SeekFound Do Begin MsgBase^.MsgStartUp; If (strUpper(MsgBase^.GetFrom) = strUpper(User.RealName)) or (strUpper(MsgBase^.GetFrom) = strUpper(User.Handle)) or (strUpper(MsgBase^.GetTo) = strUpper(User.RealName)) or (strUpper(MsgBase^.GetTo) = strUpper(User.Handle)) Then MsgBase^.DeleteMsg; MsgBase^.SeekNext; End; MsgBase^.CloseMsgBase; Dispose(MsgBase, Done); End; Close (MBaseFile); End; { DELETE LASTREAD AND SCAN SETTINGS FOR MESSAGE BASES } Assign (MBaseFile, Config.DataPath + 'mbases.dat'); {$I-} Reset (MBaseFile); {$I+} If IoResult = 0 Then Begin While Not Eof(MBaseFile) Do Begin Read (MBaseFile, MBase); Case MBase.BaseType of 0 : Begin { DELETE JAM LASTREAD RECORDS } If FileRename (MBase.Path + MBase.FileName + '.jlr', MBase.Path + MBase.FileName + '.jlb') Then Begin Assign (TJamLRFile, MBase.Path + MBase.FileName + '.jlb'); Reset (TJamLRFile); Assign (JamLRFile, MBase.Path + MBase.FileName + '.jlr'); ReWrite (JamLRFile); Count := FilePos(TUserFile); While Not Eof(TJamLRFile) Do Begin Read (TJamLRFile, JamLR); If JamLR.UserNum = Count - Deleted Then Continue; If JamLR.UserNum > Count - Deleted Then Dec(JamLR.UserNum); Write (JamLRFile, JamLR); End; Close (TJamLRFile); Erase (TJamLRFile); Close (JamLRFile); End; End; 1 : Begin { DELETE SQUISH LASTREAD RECORDS } Assign (SquLRFile, Config.MsgsPath + MBase.FileName + '.sql'); {$I-} Reset (SquLRFile); {$I+} If IoResult = 0 Then Begin If FilePos(TUserFile) - 1 <= FileSize(SquLRFile) Then Begin For Count := FilePos(TUserFile) - 1 to FileSize(SquLRFile) - 2 Do Begin Seek (SquLRFile, Count + 1); Read (SquLRFile, SquLR); Seek (SquLRFile, Count); Write (SquLRFile, SquLR); End; Seek (SquLRFile, FileSize(SquLRFile) - 1); Truncate (SquLRFile); End; Close (SquLRFile); End; End; End; { DELETE MSCAN RECORDS } Assign (MScanFile, Config.MsgsPath + MBase.FileName + '.scn'); {$I-} Reset (MScanFile); {$I+} If IoResult = 0 Then Begin If FilePos(TUserFile) - 1 - Deleted <{=} FileSize(MScanFile) Then Begin For Count := FilePos(TUserFile) - 1 - Deleted to FileSize(MScanFile) - 2 Do Begin Seek (MScanFile, Count + 1); Read (MScanFile, MScan); Seek (MScanFile, Count); Write (MScanFile, MScan); End; Seek (MScanFile, FileSize(MScanFile) - 1); Truncate (MScanFile); End; Close (MScanFile); End; End; Close (MBaseFile); End; { DELETE FSCAN RECORDS } Assign (FBaseFile, Config.DataPath + 'fbases.dat'); {$I-} Reset (FBaseFile); {$I+} If IoResult = 0 Then Begin While Not Eof(FBaseFile) Do Begin Read (FBaseFile, FBase); Assign (FScanFile, Config.DataPath + FBase.FileName + '.scn'); {$I-} Reset (FScanFile); {$I+} If IoResult = 0 Then Begin If FilePos(TUserFile) - 1 - Deleted <{=} FileSize(FScanFile) Then Begin For Count := FilePos(TUserFile) - 1 - Deleted to FileSize(FScanFile) - 2 Do Begin Seek (FScanFile, Count + 1); Read (FScanFile, FScan); Seek (FScanFile, Count); Write (FScanFile, FScan); End; Seek (FScanFile, FileSize(FScanFile) - 1); Truncate (FScanFile); End; Close (FScanFile); End; End; Close (FBaseFile); End; Inc (Deleted); End Else Write (UserFile, User); End; Close (TUserFile); Erase (TUserFile); Close (UserFile); End; Update_Status ('Completed'); WriteLn; End; Procedure MsgBase_Trash; Var TF : Text; BadName : String; MBaseFile : File of RecMessageBase; MBase : RecMessageBase; MsgBase : PMsgBaseABS; Begin Write ('Trashing Messages :'); Assign (TF, TrashFile); {$I-} Reset(TF); {$I+} If IoResult = 0 Then Begin While Not Eof(TF) Do Begin ReadLn(TF, BadName); BadName := strUpper(strStripB(BadName, ' ')); If BadName = '' Then Continue; Update_Status(BadName); Assign (MBaseFile, Config.DataPath + 'mbases.dat'); {$I-} Reset(MBaseFile); {$I+} If IoResult <> 0 Then Continue; Read (MBaseFile, MBase); While Not Eof(MBaseFile) Do Begin Read (MBaseFile, MBase); Update_Bar(FilePos(MBaseFile), FileSize(MBaseFile)); Case MBase.BaseType of 0 : MsgBase := New(PMsgBaseJAM, Init); 1 : MsgBase := New(PMsgBaseSquish, Init); End; MsgBase^.SetMsgPath (MBase.Path + MBase.FileName); If Not MsgBase^.OpenMsgBase Then Begin Dispose (MsgBase, Done); Continue; End; MsgBase^.SeekFirst(1); While MsgBase^.SeekFound Do Begin MsgBase^.MsgStartUp; If (strUpper(MsgBase^.GetFrom) = BadName) or (strUpper(MsgBase^.GetTo) = BadName) Then MsgBase^.DeleteMsg; MsgBase^.SeekNext; End; MsgBase^.CloseMsgBase; Dispose(MsgBase, Done); End; Close (MBaseFile); End; Close (TF); End; Update_Bar(100, 100); Update_Status('Completed'); WriteLn; End; Procedure Upload_File_Bases; Const NoDescStr = 'No Description'; Var BaseFile : File of RecFileBase; ListFile : File of RecFileList; DescFile : File; DizFile : Text; Base : RecFileBase; List : RecFileList; DirInfo : SearchRec; Found : Boolean; Desc : Array[1..99] of String[50]; Count : Integer; Procedure RemoveDesc (Num: Byte); Var A : Byte; Begin For A := Num To List.DescLines - 1 Do Desc[A] := Desc[A + 1]; Desc[List.DescLines] := ''; Dec (List.DescLines); End; Begin Write ('Mass Upload Files :'); Assign (BaseFile, Config.DataPath + 'fbases.dat'); {$I-} Reset (BaseFile); {$I+} If IoResult = 0 Then Begin While Not Eof(BaseFile) Do Begin Read (BaseFile, Base); Update_Status (strStripPipe(Base.Name)); Update_Bar (FilePos(BaseFile), FileSize(BaseFile)); If Not FileDirExists(Base.Path) Then Continue; FindFirst (Base.Path + '*', AnyFile, DirInfo); While DosError = 0 Do Begin If (DirInfo.Attr And Directory <> 0) or (Length(DirInfo.Name) > 70) Then Begin FindNext(DirInfo); Continue; End; // should technically rename the file like Mystic does if > 70 chars Assign (ListFile, Config.DataPath + Base.FileName + '.dir'); If FileExist(Config.DataPath + Base.FileName + '.dir') Then ioReset (ListFile, SizeOf(RecFileList), fmRWDN) Else ReWrite (ListFile); Found := False; While Not Eof(ListFile) And Not Found Do Begin Read (ListFile, List); If List.Flags and FDirDeleted <> 0 Then Continue; {$IFDEF FS_SENSITIVE} Found := List.FileName = DirInfo.Name; {$ELSE} Found := strUpper(List.FileName) = strUpper(DirInfo.Name); {$ENDIF} End; If Not Found Then Begin Seek (ListFile, FileSize(ListFile)); List.FileName := DirInfo.Name; List.Size := DirInfo.Size; List.DateTime := CurDateDos; List.Uploader := 'MBBSUTIL'; List.Flags := 0; List.Downloads := 0; List.Rating := 0; ExecuteArchive (Base.Path + List.FileName, '', 'file_id.diz', 2); Assign (DizFile, TempPath + 'file_id.diz'); {$I-} Reset (DizFile); {$I+} If IoResult = 0 Then Begin List.DescLines := 0; While Not Eof(DizFile) Do Begin Inc (List.DescLines); ReadLn (DizFile, Desc[List.DescLines]); Desc[List.DescLines] := strStripLOW(Desc[List.DescLines]); If Length(Desc[List.DescLines]) > mysMaxFileDescLen Then Desc[List.DescLines][0] := Chr(mysMaxFileDescLen); If List.DescLines = Config.MaxFileDesc Then Break; End; Close (DizFile); While (Desc[1] = '') and (List.DescLines > 0) Do RemoveDesc(1); While (Desc[List.DescLines] = '') And (List.DescLines > 0) Do Dec (List.DescLines); End Else Begin List.DescLines := 1; Desc[1] := NoDescStr; End; FileErase (TempPath + 'file_id.diz'); Assign (DescFile, Config.DataPath + Base.FileName + '.des'); If FileExist(Config.DataPath + Base.FileName + '.des') Then Reset (DescFile, 1) Else ReWrite (DescFile, 1); List.DescPtr := FileSize(DescFile); Seek (DescFile, List.DescPtr); For Count := 1 to List.DescLines Do BlockWrite (DescFile, Desc[Count][0], Length(Desc[Count]) + 1); Close (DescFile); Write (ListFile, List); End; Close (ListFile); FindNext(DirInfo); End; FindClose(DirInfo); End; Close (BaseFile); End; Update_Bar (100, 100); Update_Status ('Completed'); WriteLn; End; Procedure ExportAreasBBS; Var MBaseFile : TBufFile; MBase : RecMessageBase; OutFile : Text; Begin Write ('Exporting AREAS.BBS : '); Assign (OutFile, AreasFile); {$I-} ReWrite(OutFile); {$I+} If IoResult <> 0 Then Exit; MBaseFile := TBufFile.Create(8192); If MBaseFile.Open(Config.DataPath + 'mbases.dat', fmOpen, fmRWDN, SizeOf(RecMessageBase)) Then Begin MBaseFile.Read(MBase); While Not MBaseFile.EOF Do Begin MBaseFile.Read(MBase); Update_Bar (MBaseFile.FilePos, MBaseFile.FileSize); Update_Status (strStripPipe(MBase.Name)); If MBase.NetType <> 1 Then Continue; WriteLn (OutFile, '!' + Config.DataPath + MBase.FileName + ' ' + MBase.FileName + ' ' + strAddr2Str(Config.NetUplink[MBase.NetAddr])); End; End; Close (OutFile); MBaseFile.Free; Update_Status ('Completed'); WriteLn; End; Var A : Byte; Temp : String; ChatFile : File of ChatRec; Chat : ChatRec; Begin TextAttr := 7; WriteLn; WriteLn ('MBBSUTIL: ', mysSoftwareID, ' BBS Utilities Version ', mysVersion, ' (', OSID, ')'); WriteLn ('Copyright (C) ', mysCopyYear, ' By James Coyle. All Rights Reserved.'); WriteLn; FileMode := 66; Assign (ConfigFile, 'mystic.dat'); {$I-} Reset(ConfigFile); {$I+} If IoResult <> 0 Then Begin WriteLn ('Error reading MYSTIC.DAT. Run MBBSUTIL from the main BBS directory.'); Halt(1); End; Read (ConfigFile, Config); Close (ConfigFile); If Config.DataChanged <> mysDataChanged Then Begin WriteLn('ERROR: Data files are not current and must be upgraded.'); Halt(1); End; If ParamCount = 0 Then Begin Show_Help; Exit; End; A := 1; While (A <= ParamCount) Do Begin Temp := strUpper(ParamStr(A)); If Temp = '-AREASOUT' Then Begin AreasFile := ParamStr(A+1); Inc(A); AreasOut := True; If AreasFile = '' Then Begin WriteLn('Missing parameter'); Halt(1); End; End; If Temp = '-BKILL' Then Begin BBSKillID := ParamStr(A+1); BBSKillDays := strS2I(ParamStr(A+2)); Inc(A, 2); If (strUpper(BBSKillID) <> 'ALL') And Not FileExist(Config.DataPath + BBSKillID + '.bbi') Then Begin WriteLn ('ERROR: -BKILL: List ID (' + BBSKillID + ') does not exist.'); Halt(1); End Else If BBSKillDays < 1 Then Begin WriteLn ('ERROR: -BKILL days must be set to a LEAST 1.'); Halt(1); End Else BBSKill := True; End; If Temp = '-BPACK' Then BBSPack := True; If Temp = '-BSORT' Then Begin BBSSortID := ParamStr(A+1); Temp := strUpper(ParamStr(A+2)); Inc (A, 2); If Temp = 'PHONE' Then BBSSortType := 0 Else If Temp = 'TELNET' Then BBSSortType := 1 Else If Temp = 'BBSNAME' Then BBSSortType := 2 Else If Temp = 'LOCATION' Then BBSSortType := 3 Else Begin WriteLn ('ERROR: -BSORT: Invalid sort type.'); Halt(1); End; If (strUpper(BBSSortID) <> 'ALL') And Not FileExist(Config.DataPath + BBSSortID + '.bbi') Then Begin WriteLn ('ERROR: -BSORT: List ID (' + BBSSortID + ') does not exist.'); Halt(1); End Else BBSSort := True; End; If Temp = '-FCHECK' Then FileCheck := True; If Temp = '-FPACK' Then FilePack := True; If Temp = '-FSORT' Then FileSort := True; If Temp = '-FUPLOAD' Then FileUpload := True; If Temp = '-UKILL' Then Begin UserKill := True; Inc(A); UserKillDays := strS2I(ParamStr(A)); If UserKillDays < 5 Then Begin WriteLn ('ERROR: -UKILL days must be set to at LEAST 5.'); Halt(1); End; End; If Temp = '-MTRASH' Then Begin Inc(A); MsgTrash := True; TrashFile := strStripB(ParamStr(A), ' '); If (TrashFile <> '') And Not FileExist(TrashFile) Then Begin WriteLn('ERROR: Trash file does not exist.'); Halt(1); End; If TrashFile = '' Then TrashFile := Config.DataPath + 'trashcan.dat'; End; If Temp = '-UPACK' Then UserPack := True; Inc (A); End; If NodeCheck Then For A := 1 to Config.INetTNNodes Do Begin Assign (ChatFile, Config.DataPath + 'chat' + strI2S(A) + '.dat'); {$I-} Reset (ChatFile); {$I+} If IoResult = 0 Then Begin Read (ChatFile, Chat); If Chat.Active Then Begin WriteLn ('ERROR: MBBSUTIL has detected that a user is online at this time.'); WriteLn (' In order to prevent corruption of the system data files,'); WriteLn (' this program should only be ran when there are NO users'); WriteLn (' logged in to the BBS system.'); WriteLn (''); WriteLn ('Create a system event to log off all users before running this program.'); WriteLn; WriteLn ('If there are NO users online and MBBSUTIL detects that there are, try'); WriteLn ('changing to the data directory and deleting "chat*.dat" then re-run'); WriteLn ('MBBSUTIL'); WriteLn; WriteLn ('Using the -NOCHECK option will bypass this check'); Halt(1); End; End; End; {$I-} MkDir (Config.SystemPath + 'temp0'); If IoResult <> 0 Then; {$I+} TempPath := Config.SystemPath + 'temp0' + PathChar; DirClean (TempPath, ''); If FileUpload Then Upload_File_Bases; If FileSort Then Sort_File_Bases; If FileCheck Then Check_File_Bases; If FilePack Then Pack_File_Bases; If BBSKill Then Kill_BBS_List; If BBSPack Then Pack_BBS_List; If BBSSort Then Sort_BBS_List; If UserKill Then Kill_User_File; If UserPack Then Pack_User_File; If MsgTrash Then MsgBase_Trash; If AreasOut Then ExportAreasBBS; End.