Skip to content

Commit

Permalink
Add -DBREBUILD Command (#611)
Browse files Browse the repository at this point in the history
* Add -DBREBUILD Command

- Add `-DBREBUILD` command line argument
- Add support for rebuilding `BBSUSR.DAT/DB` from the internal MBBSEmu Database

* Refactor and Cleanup

- Move Resetting `BBSUSR` to after loading and verifying internal user records
- Refactor `UserAccount` to add constructor to handle data casting, cleans up code
  • Loading branch information
enusbaum authored Dec 29, 2023
1 parent 1faca83 commit a2eedf8
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 18 deletions.
12 changes: 2 additions & 10 deletions MBBSEmu/HostProcess/GlobalRoutines/SysopGlobal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,11 +246,7 @@ private void RemoveAccount(IReadOnlyList<string> commandSequence)
//Remove the User from the BBSUSR Database
var accountBtrieve = _globalCache.Get<BtrieveFileProcessor>("ACCBB-PROCESSOR");

var result = accountBtrieve.PerformOperation(0, new Span<byte>(new UserAccount
{
userid = Encoding.ASCII.GetBytes(userAccount.userName.ToUpper()),
psword = Encoding.ASCII.GetBytes("<<HASHED>>")
}.Data).Slice(0, 55), EnumBtrieveOperationCodes.AcquireEqual);
var result = accountBtrieve.PerformOperation(0, new Span<byte>(new UserAccount(userAccount.userName.ToUpper()).Data)[..55], EnumBtrieveOperationCodes.AcquireEqual);

if (result)
accountBtrieve.Delete();
Expand Down Expand Up @@ -287,11 +283,7 @@ private void ChangeSex(IReadOnlyList<string> commandSequence)
//Remove the User from the BBSUSR.db Database
var accountBtrieve = _globalCache.Get<BtrieveFileProcessor>("ACCBB-PROCESSOR");

var result = accountBtrieve.PerformOperation(0, new Span<byte>(new UserAccount
{
userid = Encoding.ASCII.GetBytes(userName.ToUpper()),
psword = Encoding.ASCII.GetBytes("<<HASHED>>")
}.Data).Slice(0, 55), EnumBtrieveOperationCodes.AcquireEqual);
var result = accountBtrieve.PerformOperation(0, new Span<byte>(new UserAccount(userName.ToUpper()).Data)[..55], EnumBtrieveOperationCodes.AcquireEqual);

if (!result)
{
Expand Down
8 changes: 2 additions & 6 deletions MBBSEmu/HostProcess/HostRoutines/MenuRoutines.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,7 @@ private void LoginPasswordInput(SessionBase session)
//Lookup User in BBSUSR.db
var accountBtrieve = _globalCache.Get<BtrieveFileProcessor>("ACCBB-PROCESSOR");

var result = accountBtrieve.PerformOperation(0, new Span<byte>(new UserAccount
{
userid = Encoding.ASCII.GetBytes(session.Username.ToUpper()),
psword = Encoding.ASCII.GetBytes("<<HASHED>>")
}.Data).Slice(0, 55), EnumBtrieveOperationCodes.AcquireEqual);
var result = accountBtrieve.PerformOperation(0, new Span<byte>(new UserAccount(session.Username.ToUpper()).Data)[..55], EnumBtrieveOperationCodes.AcquireEqual);

if (!result)
{
Expand Down Expand Up @@ -605,7 +601,7 @@ private void SignupGenderInput(SessionBase session)

//Add The User to the BBS Btrieve User Database
var _accountBtrieve = _globalCache.Get<BtrieveFileProcessor>("ACCBB-PROCESSOR");
_accountBtrieve.Insert(new UserAccount { userid = Encoding.ASCII.GetBytes(session.Username), psword = Encoding.ASCII.GetBytes("<<HASHED>>"), sex = session.UsrAcc.sex }.Data, LogLevel.Error);
_accountBtrieve.Insert(new UserAccount(session.Username, (char)session.UsrAcc.sex).Data, LogLevel.Error);

session.SessionState = EnumSessionState.LoginRoutines;
session.InputBuffer.SetLength(0);
Expand Down
22 changes: 22 additions & 0 deletions MBBSEmu/HostProcess/Structs/UserAccount.cs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,28 @@ public byte[] birthd

public const ushort Size = 338;

/// <summary>
/// Constructor for UserAccount where you can specify the User's UserName and Sex via constructor parameters
/// </summary>
/// <param name="userName">Username the user will use to log into the system</param>
/// <param name="userSex">Sex/Gender of the User (Only M/F supported)</param>
public UserAccount(string userName, char userSex = 'M') : this()
{
//Verify Input Parameters
if (userName.Length > UIDSIZ - 1)
throw new ArgumentOutOfRangeException(nameof(userName), $"Username must be {UIDSIZ - 1} characters or less");

if (userSex != 'M' && userSex != 'F')
throw new ArgumentOutOfRangeException(nameof(userSex), "Only M or F are supported for userSex in The MajorBBS/Worldgroup");

userid = Encoding.ASCII.GetBytes(userName + "\0");
psword = Encoding.ASCII.GetBytes("<<HASHED>>"); //Password is always hashed in the internal database, so we don't store it here as the hashed value would be too long
sex = (byte)userSex;
}

/// <summary>
/// Default Constructor for UserAccount
/// </summary>
public UserAccount()
{
flags = 1; //Set everyone to having "MASTER" key
Expand Down
84 changes: 82 additions & 2 deletions MBBSEmu/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public class Program
/// </summary>
private string _newSysopPassword;

/// <summary>
/// Specified if the -DBREBUILD Command Line Argument was passed
/// </summary>
private bool _doDatabaseRebuild;

/// <summary>
/// Database File to be Rebuilt (if able)
/// </summary>
private string _databaseRebuildFileName;

/// <summary>
/// Specified if the -CONSOLE Command Line Argument was passed
/// </summary>
Expand Down Expand Up @@ -177,6 +187,18 @@ private void Run(string[] args)

break;
}
case "-DBREBUILD":
{
_doDatabaseRebuild = true;
if (i + 1 < args.Length && args[i + 1][0] != '-')
{
_databaseRebuildFileName = args[i + 1];
i++;
}

_databaseRebuildFileName = _databaseRebuildFileName.ToUpperInvariant();
break;
}
case "-APIREPORT":
_doApiReport = true;
break;
Expand Down Expand Up @@ -352,6 +374,20 @@ private void Run(string[] args)
DatabaseReset();
}

//Database Rebuild
if (_doDatabaseRebuild)
{
switch (_databaseRebuildFileName)
{
case "BBSUSR":
RebuildAccDb();
break;
default:
_logger.Error($"Unknown Database to rebuild: {_databaseRebuildFileName}");
break;
}
}

//Setup Modules
if (!string.IsNullOrEmpty(_moduleIdentifier))
{
Expand Down Expand Up @@ -571,8 +607,8 @@ private void DatabaseReset()
//Insert Into BBS Account Btrieve File
var _accountBtrieve = _serviceResolver.GetService<IGlobalCache>().Get<BtrieveFileProcessor>("ACCBB-PROCESSOR");
_accountBtrieve.DeleteAll();
_accountBtrieve.Insert(new UserAccount { userid = Encoding.ASCII.GetBytes("sysop"), psword = Encoding.ASCII.GetBytes("<<HASHED>>"), sex = (byte)'M' }.Data, LogLevel.Error);
_accountBtrieve.Insert(new UserAccount { userid = Encoding.ASCII.GetBytes("guest"), psword = Encoding.ASCII.GetBytes("<<HASHED>>"), sex = (byte)'M' }.Data, LogLevel.Error);
_accountBtrieve.Insert(new UserAccount("sysop").Data, LogLevel.Error);
_accountBtrieve.Insert(new UserAccount("guest").Data, LogLevel.Error);

//Reset BBSGEN
var _genbbBtrieve = _serviceResolver.GetService<IGlobalCache>().Get<BtrieveFileProcessor>("GENBB-PROCESSOR");
Expand Down Expand Up @@ -620,5 +656,49 @@ private void PasswordReset()
_logger.Info("Sysop Password Reset!");
_doResetPassword = false;
}

/// <summary>
/// Rebuilds the internal MajorBBS/WG Account Database (BBSUSR.DAT) using the current SQLite Database
/// and users that are already created. This is useful if you have a corrupted or missing BBSUSR.DB.
///
/// The BBSUSR.DAT file (ACCDB) is used by MajorBBS/WG to store user accounts. It is referenced by several
/// internal API calls and is required for the system to function properly. Because of this, we only store the
/// bare minimum amount of inofrmation required for this file to exist and be valid. Full user account information
/// is stored within the internal MBBSEmu SQLite Database.
///
/// This might seem a little confusing, but internally in the MajorBBS code this database is referenced
/// as "ACCDB" but the actual file name is BBSUSR.DAT.
/// </summary>
private void RebuildAccDb()
{
_logger.Info("Rebuilding BBSUSR.DAT...");

//Get Internal MBBSEmu User Account Database
var acct = _serviceResolver.GetService<IAccountRepository>();
var accounts = acct.GetAccounts();

//Verify there are valid accounts in the MBBSEmu Accounts Database
if (!accounts.Any())
{
_logger.Error("No Accounts Found in MBBSEmu Database, skipping rebuild of BBSUSR.DAT");
_logger.Error("Please consider using the -DBRESET command line argument to reset the internal databases to their default state");
return;
}

//Get BBSUSR.DAT and clear out existing records
var _accountBtrieve = _serviceResolver.GetService<IGlobalCache>().Get<BtrieveFileProcessor>("ACCBB-PROCESSOR");
_accountBtrieve.DeleteAll();

//Insert each record into BBSUSR.DAT
foreach (var a in accounts)
_accountBtrieve.Insert(new UserAccount(a.userName).Data, LogLevel.Error);

//Verify the Counts are Equal
if (accounts.Count() != _accountBtrieve.GetRecordCount())
_logger.Warn($"MBBSEmu Database Account Count ({accounts.Count()}) does not match BBSUSR.DAT Account Count ({_accountBtrieve.GetRecordCount()})");

_logger.Info("BBSUSR.DAT (BBSUSR.DB) Rebuilt!");
_logger.Info($"{accounts.Count()} Accounts Inserted");
}
}
}

0 comments on commit a2eedf8

Please sign in to comment.