[Rules] Add rule to allow players to permanently save chat channels to database, up to a limit. (#2706)

* Initial code

* Tweak

* Rule description tweak

* More channel work

* More adjustments

* Auto-join saved permanent player channels

* Fix UCS crash if player has no channels to load from table.

* Implemented channel blocking feature

* Update database when player channel's owner or password change

* First round of requested changes.

* Logic tweak to ensure player channels are sets to permanent when appropraite

* name_filter table integration and some refactoring

* Use new `reserved_channel_names` table to block specific channel names.

* Remove some legacy channel block code

* Setup required SQL update to create  `reserved_channel_names`  table.

* Update db_update_manifest.txt

* Update db_update_manifest.txt

* Update chatchannel.cpp

* Code review

* Database to UCSDatabase

* Repository SaveChatChannel

* CurrentPlayerChannelCount repository

* Cleanup name filter

* CreateChannel

* Update websocketpp

* Increment CURRENT_BINARY_DATABASE_VERSION

Set to 9216

* Minor tweaks to blocked channel name checks & other related areas.

- Enforce blocked channel names on channel creation.
- Also enforce blocked channel names on channel join.
- Add channel status check to Debug logging.
- Minor formatting adjustments.
- Add single quotes to column name value in query.

* Minor log change

* Increment DB Version

* Formatting Tweaks

- Made formatting adjustments consistent with KinglyKrab's recommended changes.
- This compiles successfully with these changes, but unable to test the changes until this weekend.

Co-authored-by: Akkadius <akkadius1@gmail.com>
This commit is contained in:
Vayle
2023-01-18 23:42:09 -05:00
committed by GitHub
parent 03a27b02ff
commit 29473aa7f5
16 changed files with 1409 additions and 286 deletions
+132 -92
View File
@@ -48,8 +48,10 @@ int LookupCommand(const char *ChatCommand) {
for (int i = 0; i < CommandEndOfList; i++) {
if (!strcasecmp(Commands[i].CommandString, ChatCommand))
if (!strcasecmp(Commands[i].CommandString, ChatCommand)) {
return Commands[i].CommandCode;
}
}
return -1;
@@ -594,6 +596,28 @@ void Clientlist::CheckForStaleConnections(Client *c) {
}
}
std::string RemoveDuplicateChannels(const std::string& in_channels) {
// Split the string by ", " and store the names in a vector
std::vector<std::string> channel_names = Strings::Split(in_channels, ", ");
// Remove duplicates by inserting the names of the channels into an unordered set
// and then copying the unique elements back into the original vector
std::unordered_set<std::string> unique_channels;
channel_names.erase(
std::remove_if(
channel_names.begin(), channel_names.end(),
[&unique_channels](const std::string &channel) {
return !unique_channels.insert(channel).second;
}
), channel_names.end()
);
// Concatenate the names of the unique channels into a single string
std::string unique_channels_string = Strings::Implode(", ", channel_names);
return unique_channels_string;
}
void Clientlist::Process()
{
auto it = ClientChatConnections.begin();
@@ -682,10 +706,18 @@ void Clientlist::Process()
CheckForStaleConnections((*it));
break;
}
case OP_Mail: {
std::string CommandString = (const char *)app->pBuffer + 1;
ProcessOPMailCommand((*it), CommandString);
std::string command_string = (const char *)app->pBuffer + 1;
bool command_directed = false;
if (command_string.empty()) {
break;
}
if (Strings::Contains(Strings::ToLower(command_string), "leave")) {
command_directed = true;
}
ProcessOPMailCommand((*it), command_string, command_directed);
break;
}
@@ -716,106 +748,112 @@ void Clientlist::Process()
}
}
void Clientlist::ProcessOPMailCommand(Client *c, std::string CommandString)
void Clientlist::ProcessOPMailCommand(Client *c, std::string command_string, bool command_directed)
{
if (CommandString.length() == 0)
if (command_string.length() == 0)
return;
if (isdigit(CommandString[0]))
if (isdigit(command_string[0]))
{
c->SendChannelMessageByNumber(CommandString);
c->SendChannelMessageByNumber(command_string);
return;
}
if (CommandString[0] == '#') {
if (command_string[0] == '#') {
c->SendChannelMessage(CommandString);
c->SendChannelMessage(command_string);
return;
}
std::string Command, Parameters;
std::string command, parameters;
std::string::size_type Space = CommandString.find_first_of(" ");
std::string::size_type Space = command_string.find_first_of(" ");
if (Space != std::string::npos) {
Command = CommandString.substr(0, Space);
command = command_string.substr(0, Space);
std::string::size_type ParametersStart = CommandString.find_first_not_of(" ", Space);
std::string::size_type parameters_start = command_string.find_first_not_of(" ", Space);
if (ParametersStart != std::string::npos)
Parameters = CommandString.substr(ParametersStart);
if (parameters_start != std::string::npos)
parameters = command_string.substr(parameters_start);
}
else {
command = command_string;
}
else
Command = CommandString;
int CommandCode = LookupCommand(Command.c_str());
switch (CommandCode) {
auto command_code = LookupCommand(command.c_str());
switch (command_code) {
case CommandJoin:
c->JoinChannels(Parameters);
if (!command_directed) {
//Append saved channels to params
parameters = parameters + ", " + database.CurrentPlayerChannels(c->GetName());
parameters = RemoveDuplicateChannels(parameters);
}
c->JoinChannels(parameters, command_directed);
break;
case CommandLeaveAll:
c->LeaveAllChannels();
c->LeaveAllChannels(true, true);
break;
case CommandLeave:
c->LeaveChannels(Parameters);
c->LeaveChannels(parameters, command_directed);
break;
case CommandListAll:
ChannelList->SendAllChannels(c);
break;
case CommandList:
c->ProcessChannelList(Parameters);
c->ProcessChannelList(parameters);
break;
case CommandSet:
c->LeaveAllChannels(false);
c->JoinChannels(Parameters);
c->JoinChannels(parameters, command_directed);
break;
case CommandAnnounce:
c->ToggleAnnounce(Parameters);
c->ToggleAnnounce(parameters);
break;
case CommandSetOwner:
c->SetChannelOwner(Parameters);
c->SetChannelOwner(parameters);
break;
case CommandOPList:
c->OPList(Parameters);
c->OPList(parameters);
break;
case CommandInvite:
c->ChannelInvite(Parameters);
c->ChannelInvite(parameters);
break;
case CommandGrant:
c->ChannelGrantModerator(Parameters);
c->ChannelGrantModerator(parameters);
break;
case CommandModerate:
c->ChannelModerate(Parameters);
c->ChannelModerate(parameters);
break;
case CommandVoice:
c->ChannelGrantVoice(Parameters);
c->ChannelGrantVoice(parameters);
break;
case CommandKick:
c->ChannelKick(Parameters);
c->ChannelKick(parameters);
break;
case CommandPassword:
c->SetChannelPassword(Parameters);
c->SetChannelPassword(parameters);
break;
case CommandToggleInvites:
@@ -834,43 +872,44 @@ void Clientlist::ProcessOPMailCommand(Client *c, std::string CommandString)
break;
case CommandGetBody:
database.SendBody(c, atoi(Parameters.c_str()));
database.SendBody(c, atoi(parameters.c_str()));
break;
case CommandMailTo:
ProcessMailTo(c, Parameters);
ProcessMailTo(c, parameters);
break;
case CommandSetMessageStatus:
LogInfo("Set Message Status, Params: [{}]", Parameters.c_str());
ProcessSetMessageStatus(Parameters);
LogInfo("Set Message Status, Params: [{}]", parameters.c_str());
ProcessSetMessageStatus(parameters);
break;
case CommandSelectMailBox:
{
std::string::size_type NumStart = Parameters.find_first_of("0123456789");
c->ChangeMailBox(atoi(Parameters.substr(NumStart).c_str()));
std::string::size_type NumStart = parameters.find_first_of("0123456789");
c->ChangeMailBox(atoi(parameters.substr(NumStart).c_str()));
break;
}
case CommandSetMailForwarding:
break;
case CommandBuddy:
RemoveApostrophes(Parameters);
ProcessCommandBuddy(c, Parameters);
RemoveApostrophes(parameters);
ProcessCommandBuddy(c, parameters);
break;
case CommandIgnorePlayer:
RemoveApostrophes(Parameters);
ProcessCommandIgnore(c, Parameters);
RemoveApostrophes(parameters);
ProcessCommandIgnore(c, parameters);
break;
default:
c->SendHelp();
LogInfo("Unhandled OP_Mail command: [{}]", CommandString.c_str());
LogInfo("Unhandled OP_Mail command: [{}]", command_string.c_str());
}
}
void Clientlist::CloseAllConnections() {
@@ -992,51 +1031,51 @@ int Client::ChannelCount() {
}
void Client::JoinChannels(std::string ChannelNameList) {
void Client::JoinChannels(std::string& channel_name_list, bool command_directed) {
for (auto &elem : ChannelNameList) {
for (auto &elem : channel_name_list) {
if (elem == '%') {
elem = '/';
}
}
LogInfo("Client: [{}] joining channels [{}]", GetName().c_str(), ChannelNameList.c_str());
LogInfo("Client: [{}] joining channels [{}]", GetName().c_str(), channel_name_list.c_str());
int NumberOfChannels = ChannelCount();
auto number_of_channels = ChannelCount();
std::string::size_type CurrentPos = ChannelNameList.find_first_not_of(" ");
auto current_pos = channel_name_list.find_first_not_of(" ");
while (CurrentPos != std::string::npos) {
while (current_pos != std::string::npos) {
if (NumberOfChannels == MAX_JOINED_CHANNELS) {
if (number_of_channels == MAX_JOINED_CHANNELS) {
GeneralChannelMessage("You have joined the maximum number of channels. /leave one before trying to join another.");
break;
}
std::string::size_type Comma = ChannelNameList.find_first_of(", ", CurrentPos);
auto comma = channel_name_list.find_first_of(", ", current_pos);
if (Comma == std::string::npos) {
if (comma == std::string::npos) {
auto* joined_channel = ChannelList->AddClientToChannel(channel_name_list.substr(current_pos), this, command_directed);
ChatChannel* JoinedChannel = ChannelList->AddClientToChannel(ChannelNameList.substr(CurrentPos), this);
if (JoinedChannel)
AddToChannelList(JoinedChannel);
if (joined_channel) {
AddToChannelList(joined_channel);
}
break;
}
ChatChannel* JoinedChannel = ChannelList->AddClientToChannel(ChannelNameList.substr(CurrentPos, Comma - CurrentPos), this);
auto* joined_channel = ChannelList->AddClientToChannel(channel_name_list.substr(current_pos, comma - current_pos), this, command_directed);
if (JoinedChannel) {
if (joined_channel) {
AddToChannelList(JoinedChannel);
AddToChannelList(joined_channel);
NumberOfChannels++;
number_of_channels++;
}
CurrentPos = ChannelNameList.find_first_not_of(", ", Comma);
current_pos = channel_name_list.find_first_not_of(", ", comma);
}
std::string JoinedChannelsList, ChannelMessage;
@@ -1097,37 +1136,36 @@ void Client::JoinChannels(std::string ChannelNameList) {
safe_delete(outapp);
}
void Client::LeaveChannels(std::string ChannelNameList) {
void Client::LeaveChannels(std::string& channel_name_list, bool command_directed) {
LogInfo("Client: [{}] leaving channels [{}]", GetName().c_str(), channel_name_list.c_str());
LogInfo("Client: [{}] leaving channels [{}]", GetName().c_str(), ChannelNameList.c_str());
auto current_pos = 0;
std::string::size_type CurrentPos = 0;
while (current_pos != std::string::npos) {
while (CurrentPos != std::string::npos) {
std::string::size_type Comma = ChannelNameList.find_first_of(", ", CurrentPos);
std::string::size_type Comma = channel_name_list.find_first_of(", ", current_pos);
if (Comma == std::string::npos) {
ChatChannel* JoinedChannel = ChannelList->RemoveClientFromChannel(ChannelNameList.substr(CurrentPos), this);
auto* joined_channel = ChannelList->RemoveClientFromChannel(channel_name_list.substr(current_pos), this, command_directed);
if (JoinedChannel)
RemoveFromChannelList(JoinedChannel);
if (joined_channel)
RemoveFromChannelList(joined_channel);
break;
}
ChatChannel* JoinedChannel = ChannelList->RemoveClientFromChannel(ChannelNameList.substr(CurrentPos, Comma - CurrentPos), this);
auto* joined_channel = ChannelList->RemoveClientFromChannel(channel_name_list.substr(current_pos, Comma - current_pos), this, command_directed);
if (JoinedChannel)
RemoveFromChannelList(JoinedChannel);
if (joined_channel)
RemoveFromChannelList(joined_channel);
CurrentPos = ChannelNameList.find_first_not_of(", ", Comma);
current_pos = channel_name_list.find_first_not_of(", ", Comma);
}
std::string JoinedChannelsList, ChannelMessage;
std::string joined_channels_list, channel_message;
ChannelMessage = "Channels: ";
channel_message = "Channels: ";
char tmp[200];
@@ -1139,26 +1177,26 @@ void Client::LeaveChannels(std::string ChannelNameList) {
if (ChannelCount) {
JoinedChannelsList = JoinedChannelsList + ",";
joined_channels_list = joined_channels_list + ",";
ChannelMessage = ChannelMessage + ",";
channel_message = channel_message + ",";
}
JoinedChannelsList = JoinedChannelsList + JoinedChannels[i]->GetName();
joined_channels_list = joined_channels_list + JoinedChannels[i]->GetName();
sprintf(tmp, "%i=%s(%i)", i + 1, JoinedChannels[i]->GetName().c_str(), JoinedChannels[i]->MemberCount(Status));
ChannelMessage += tmp;
channel_message += tmp;
ChannelCount++;
}
}
auto outapp = new EQApplicationPacket(OP_Mail, JoinedChannelsList.length() + 1);
auto outapp = new EQApplicationPacket(OP_Mail, joined_channels_list.length() + 1);
char *PacketBuffer = (char *)outapp->pBuffer;
sprintf(PacketBuffer, "%s", JoinedChannelsList.c_str());
sprintf(PacketBuffer, "%s", joined_channels_list.c_str());
QueuePacket(outapp);
@@ -1166,15 +1204,15 @@ void Client::LeaveChannels(std::string ChannelNameList) {
safe_delete(outapp);
if (ChannelCount == 0)
ChannelMessage = "You are not on any channels.";
channel_message = "You are not on any channels.";
outapp = new EQApplicationPacket(OP_ChannelMessage, ChannelMessage.length() + 3);
outapp = new EQApplicationPacket(OP_ChannelMessage, channel_message.length() + 3);
PacketBuffer = (char *)outapp->pBuffer;
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x00);
VARSTRUCT_ENCODE_TYPE(uint8, PacketBuffer, 0x00);
VARSTRUCT_ENCODE_STRING(PacketBuffer, ChannelMessage.c_str());
VARSTRUCT_ENCODE_STRING(PacketBuffer, channel_message.c_str());
QueuePacket(outapp);
@@ -1182,19 +1220,19 @@ void Client::LeaveChannels(std::string ChannelNameList) {
safe_delete(outapp);
}
void Client::LeaveAllChannels(bool SendUpdatedChannelList) {
void Client::LeaveAllChannels(bool send_updated_channel_list, bool command_directed) {
for (auto &elem : JoinedChannels) {
if (elem) {
ChannelList->RemoveClientFromChannel(elem->GetName(), this);
ChannelList->RemoveClientFromChannel(elem->GetName(), this, command_directed);
elem = nullptr;
}
}
if (SendUpdatedChannelList)
if (send_updated_channel_list)
SendChannelList();
}
@@ -1643,6 +1681,7 @@ void Client::SetChannelPassword(std::string ChannelPassword) {
}
RequiredChannel->SetPassword(Password);
database.SaveChatChannel(RequiredChannel->GetName(), RequiredChannel->GetOwnerName(), Password, RequiredChannel->GetMinStatus()); // Update DB with new password
GeneralChannelMessage(Message);
@@ -1703,6 +1742,7 @@ void Client::SetChannelOwner(std::string CommandString) {
}
RequiredChannel->SetOwner(NewOwner);
database.SaveChatChannel(RequiredChannel->GetName(), NewOwner, RequiredChannel->GetPassword(), RequiredChannel->GetMinStatus()); // Update DB with new owner
if (RequiredChannel->IsModerator(NewOwner))
RequiredChannel->RemoveModerator(NewOwner);
@@ -2121,7 +2161,7 @@ void Client::ChannelKick(std::string CommandString) {
GeneralChannelMessage("Kicked " + Kickee + " from channel " + ChannelName);
RequiredClient->LeaveChannels(ChannelName);
RequiredClient->LeaveChannels(ChannelName, false);
}
void Client::ToggleInvites() {