mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-11 21:01:29 +00:00
965 lines
25 KiB
C++
965 lines
25 KiB
C++
/* EQEMu: Everquest Server Emulator
|
|
Copyright (C) 2001-2008 EQEMu Development Team (http://eqemulator.net)
|
|
|
|
This program 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; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY except by those people which sell it, which
|
|
are required to give you total support for your newly bought product;
|
|
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 this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
#include "../common/eqemu_logsys.h"
|
|
#include "../common/strings.h"
|
|
#include "chatchannel.h"
|
|
#include "clientlist.h"
|
|
#include "database.h"
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
|
|
extern UCSDatabase database;
|
|
extern uint32 ChatMessagesSent;
|
|
|
|
void ServerToClient45SayLink(std::string& clientSayLink, const std::string& serverSayLink);
|
|
void ServerToClient50SayLink(std::string& clientSayLink, const std::string& serverSayLink);
|
|
void ServerToClient55SayLink(std::string& clientSayLink, const std::string& serverSayLink);
|
|
|
|
ChatChannel::ChatChannel(const std::string& inName, const std::string& inOwner, const std::string& inPassword, bool inPermanent, int inMinimumStatus) :
|
|
m_delete_timer(0) {
|
|
|
|
m_name = inName;
|
|
|
|
m_owner = inOwner;
|
|
|
|
m_password = inPassword;
|
|
|
|
m_permanent = inPermanent;
|
|
|
|
m_minimum_status = inMinimumStatus;
|
|
|
|
m_moderated = false;
|
|
|
|
LogDebug(
|
|
"New ChatChannel created: Name: [{}] Owner: [{}] Password: [{}] MinStatus: [{}]",
|
|
m_name,
|
|
m_owner,
|
|
m_password,
|
|
m_minimum_status
|
|
);
|
|
|
|
}
|
|
|
|
ChatChannel::~ChatChannel() {
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements())
|
|
iterator.RemoveCurrent(false);
|
|
}
|
|
|
|
ChatChannel *ChatChannelList::CreateChannel(
|
|
const std::string& name,
|
|
const std::string& owner,
|
|
const std::string& password,
|
|
bool permanent,
|
|
int minimum_status,
|
|
bool save_to_db
|
|
)
|
|
{
|
|
uint8 max_perm_player_channels = RuleI(Chat, MaxPermanentPlayerChannels);
|
|
|
|
if (!RuleB(Chat, ChannelsIgnoreNameFilter) && !database.CheckChannelNameFilter(name)) {
|
|
if (!(owner == SYSTEM_OWNER)) {
|
|
return nullptr;
|
|
}
|
|
else {
|
|
LogDebug("Ignoring Name Filter as channel is owned by System...");
|
|
}
|
|
}
|
|
|
|
if (IsOnChannelBlockList(name)) {
|
|
if (!(owner == SYSTEM_OWNER)) {
|
|
LogInfo("Channel name [{}] is a reserved/blocked channel name. Channel creation canceled.", name);
|
|
return nullptr;
|
|
}
|
|
else {
|
|
LogInfo("Ignoring reserved/blocked channel name [{}] as channel is owned by System...", name);
|
|
}
|
|
}
|
|
else {
|
|
LogDebug("Channel name [{}] passed the reserved/blocked channel name check...", name);
|
|
}
|
|
|
|
|
|
auto *new_channel = new ChatChannel(CapitaliseName(name), owner, password, permanent, minimum_status);
|
|
|
|
ChatChannels.Insert(new_channel);
|
|
|
|
if (owner == SYSTEM_OWNER) {
|
|
save_to_db = false;
|
|
}
|
|
|
|
// If permanent player channels are enabled (and not a system channel)
|
|
// save channel to database if not exceeding limit.
|
|
bool can_save_channel = (max_perm_player_channels > 0) && !(owner == SYSTEM_OWNER) && save_to_db;
|
|
if (can_save_channel) {
|
|
|
|
// Ensure there is room to save another chat channel to the database.
|
|
bool player_under_channel_limit = database.CurrentPlayerChannelCount(owner) + 1 <= max_perm_player_channels;
|
|
if (player_under_channel_limit) {
|
|
database.SaveChatChannel(
|
|
CapitaliseName(name),
|
|
owner,
|
|
password,
|
|
minimum_status
|
|
);
|
|
}
|
|
else {
|
|
LogDebug(
|
|
"Maximum number of channels [{}] reached for player [{}], channel [{}] save to database aborted.",
|
|
max_perm_player_channels,
|
|
owner,
|
|
CapitaliseName(name)
|
|
);
|
|
}
|
|
}
|
|
|
|
return new_channel;
|
|
}
|
|
|
|
ChatChannel* ChatChannelList::FindChannel(const std::string& Name) {
|
|
|
|
std::string normalized_name = CapitaliseName(Name);
|
|
|
|
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
auto *current_channel = iterator.GetData();
|
|
|
|
if(current_channel && (current_channel->m_name == normalized_name))
|
|
return iterator.GetData();
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void ChatChannelList::SendAllChannels(Client *c) {
|
|
|
|
if(!c) return;
|
|
|
|
if(!c->CanListAllChannels()) {
|
|
c->GeneralChannelMessage("You do not have permission to list all the channels.");
|
|
return;
|
|
}
|
|
|
|
c->GeneralChannelMessage("All current channels:");
|
|
|
|
int ChannelsInLine = 0;
|
|
|
|
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
|
|
|
iterator.Reset();
|
|
|
|
std::string Message;
|
|
|
|
char CountString[10];
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
ChatChannel *CurrentChannel = iterator.GetData();
|
|
|
|
if(!CurrentChannel || (CurrentChannel->GetMinStatus() > c->GetAccountStatus())) {
|
|
|
|
iterator.Advance();
|
|
|
|
continue;
|
|
}
|
|
|
|
if(ChannelsInLine > 0)
|
|
Message += ", ";
|
|
|
|
sprintf(CountString, "(%i)", CurrentChannel->MemberCount(c->GetAccountStatus()));
|
|
|
|
Message += CurrentChannel->GetName();
|
|
|
|
Message += CountString;
|
|
|
|
ChannelsInLine++;
|
|
|
|
if(ChannelsInLine == 6) {
|
|
|
|
c->GeneralChannelMessage(Message);
|
|
|
|
ChannelsInLine = 0;
|
|
|
|
Message.clear();
|
|
}
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
if(ChannelsInLine > 0)
|
|
c->GeneralChannelMessage(Message);
|
|
|
|
}
|
|
|
|
void ChatChannelList::RemoveChannel(ChatChannel *Channel) {
|
|
|
|
LogDebug("Remove channel [{}]", Channel->GetName().c_str());
|
|
|
|
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
if(iterator.GetData() == Channel) {
|
|
|
|
iterator.RemoveCurrent();
|
|
|
|
return;
|
|
}
|
|
|
|
iterator.Advance();
|
|
}
|
|
}
|
|
|
|
void ChatChannelList::RemoveAllChannels() {
|
|
|
|
LogDebug("RemoveAllChannels");
|
|
|
|
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements())
|
|
iterator.RemoveCurrent();
|
|
}
|
|
|
|
int ChatChannel::MemberCount(int Status) {
|
|
|
|
int Count = 0;
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
Client *ChannelClient = iterator.GetData();
|
|
|
|
if(ChannelClient && (!ChannelClient->GetHideMe() || (ChannelClient->GetAccountStatus() < Status)))
|
|
Count++;
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
return Count;
|
|
}
|
|
|
|
void ChatChannel::SetPassword(const std::string& in_password) {
|
|
|
|
m_password = in_password;
|
|
|
|
if(m_permanent)
|
|
{
|
|
RemoveApostrophes(m_password);
|
|
database.SetChannelPassword(m_name, m_password);
|
|
}
|
|
}
|
|
|
|
void ChatChannel::SetOwner(const std::string& in_owner) {
|
|
|
|
m_owner = in_owner;
|
|
|
|
if(m_permanent)
|
|
database.SetChannelOwner(m_name, m_owner);
|
|
}
|
|
|
|
// Returns the owner's name in type std::string()
|
|
std::string& ChatChannel::GetOwnerName() {
|
|
return m_owner;
|
|
}
|
|
|
|
void ChatChannel::SetTemporary() {
|
|
m_permanent = false;
|
|
}
|
|
|
|
void ChatChannel::SetPermanent() {
|
|
m_permanent = true;
|
|
}
|
|
|
|
void ChatChannel::AddClient(Client *c) {
|
|
|
|
if(!c) return;
|
|
|
|
m_delete_timer.Disable();
|
|
|
|
if(IsClientInChannel(c)) {
|
|
|
|
LogInfo("Client [{}] already in channel [{}]", c->GetName().c_str(), GetName().c_str());
|
|
|
|
return;
|
|
}
|
|
|
|
bool HideMe = c->GetHideMe();
|
|
|
|
int AccountStatus = c->GetAccountStatus();
|
|
|
|
LogDebug("Adding [{}] to channel [{}]", c->GetName().c_str(), m_name.c_str());
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
Client *CurrentClient = iterator.GetData();
|
|
|
|
if(CurrentClient && CurrentClient->IsAnnounceOn())
|
|
if(!HideMe || (CurrentClient->GetAccountStatus() > AccountStatus))
|
|
CurrentClient->AnnounceJoin(this, c);
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
m_clients_in_channel.Insert(c);
|
|
|
|
}
|
|
|
|
bool ChatChannel::RemoveClient(Client *c) {
|
|
|
|
if(!c) return false;
|
|
|
|
LogDebug("Remove client [{}] from channel [{}]", c->GetName().c_str(), GetName().c_str());
|
|
|
|
bool hide_me = c->GetHideMe();
|
|
|
|
int account_status = c->GetAccountStatus();
|
|
|
|
int players_in_channel = 0;
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
auto *current_client = iterator.GetData();
|
|
|
|
if(current_client == c) {
|
|
iterator.RemoveCurrent(false);
|
|
}
|
|
else if(current_client) {
|
|
|
|
players_in_channel++;
|
|
|
|
if(current_client->IsAnnounceOn())
|
|
if(!hide_me || (current_client->GetAccountStatus() > account_status))
|
|
current_client->AnnounceLeave(this, c);
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
}
|
|
|
|
if((players_in_channel == 0) && !m_permanent) {
|
|
|
|
if((m_password.length() == 0) || (RuleI(Channels, DeleteTimer) == 0))
|
|
return false;
|
|
|
|
LogDebug("Starting delete timer for empty password protected channel [{}]", m_name.c_str());
|
|
|
|
m_delete_timer.Start(RuleI(Channels, DeleteTimer) * 60000);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ChatChannel::SendOPList(Client *c)
|
|
{
|
|
if (!c) {
|
|
return;
|
|
}
|
|
|
|
c->GeneralChannelMessage("Channel " + m_name + " op-list: (Owner=" + m_owner + ")");
|
|
|
|
for (auto &&m : m_moderators) {
|
|
c->GeneralChannelMessage(m);
|
|
}
|
|
}
|
|
|
|
void ChatChannel::SendChannelMembers(Client *c) {
|
|
|
|
if(!c) return;
|
|
|
|
char CountString[10];
|
|
|
|
sprintf(CountString, "(%i)", MemberCount(c->GetAccountStatus()));
|
|
|
|
std::string Message = "Channel " + GetName();
|
|
|
|
Message += CountString;
|
|
|
|
Message += " members:";
|
|
|
|
c->GeneralChannelMessage(Message);
|
|
|
|
int AccountStatus = c->GetAccountStatus();
|
|
|
|
Message.clear();
|
|
|
|
int MembersInLine = 0;
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
Client *ChannelClient = iterator.GetData();
|
|
|
|
// Don't list hidden characters with status higher or equal than the character requesting the list.
|
|
//
|
|
if(!ChannelClient || (ChannelClient->GetHideMe() && (ChannelClient->GetAccountStatus() >= AccountStatus))) {
|
|
iterator.Advance();
|
|
continue;
|
|
}
|
|
|
|
if(MembersInLine > 0)
|
|
Message += ", ";
|
|
|
|
Message += ChannelClient->GetName();
|
|
|
|
MembersInLine++;
|
|
|
|
if(MembersInLine == 6) {
|
|
|
|
c->GeneralChannelMessage(Message);
|
|
|
|
MembersInLine = 0;
|
|
|
|
Message.clear();
|
|
}
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
if(MembersInLine > 0)
|
|
c->GeneralChannelMessage(Message);
|
|
|
|
}
|
|
|
|
void ChatChannel::SendMessageToChannel(const std::string& Message, Client* Sender) {
|
|
|
|
if(!Sender) return;
|
|
|
|
std::string cv_messages[EQ::versions::ClientVersionCount];
|
|
|
|
ChatMessagesSent++;
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
auto *channel_client = iterator.GetData();
|
|
|
|
if(channel_client)
|
|
{
|
|
LogDebug("Sending message to [{}] from [{}]",
|
|
channel_client->GetName().c_str(), Sender->GetName().c_str());
|
|
|
|
if (cv_messages[static_cast<uint32>(channel_client->GetClientVersion())].length() == 0) {
|
|
switch (channel_client->GetClientVersion()) {
|
|
case EQ::versions::ClientVersion::Titanium:
|
|
ServerToClient45SayLink(cv_messages[static_cast<uint32>(channel_client->GetClientVersion())], Message);
|
|
break;
|
|
case EQ::versions::ClientVersion::SoF:
|
|
case EQ::versions::ClientVersion::SoD:
|
|
case EQ::versions::ClientVersion::UF:
|
|
ServerToClient50SayLink(cv_messages[static_cast<uint32>(channel_client->GetClientVersion())], Message);
|
|
break;
|
|
case EQ::versions::ClientVersion::RoF:
|
|
ServerToClient55SayLink(cv_messages[static_cast<uint32>(channel_client->GetClientVersion())], Message);
|
|
break;
|
|
case EQ::versions::ClientVersion::RoF2:
|
|
default:
|
|
cv_messages[static_cast<uint32>(channel_client->GetClientVersion())] = Message;
|
|
break;
|
|
}
|
|
}
|
|
|
|
channel_client->SendChannelMessage(m_name, cv_messages[static_cast<uint32>(channel_client->GetClientVersion())], Sender);
|
|
}
|
|
|
|
iterator.Advance();
|
|
}
|
|
}
|
|
|
|
void ChatChannel::SetModerated(bool inModerated) {
|
|
|
|
m_moderated = inModerated;
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
Client *ChannelClient = iterator.GetData();
|
|
|
|
if(ChannelClient) {
|
|
|
|
if(m_moderated)
|
|
ChannelClient->GeneralChannelMessage("Channel " + m_name + " is now moderated.");
|
|
else
|
|
ChannelClient->GeneralChannelMessage("Channel " + m_name + " is no longer moderated.");
|
|
}
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
}
|
|
bool ChatChannel::IsClientInChannel(Client *c) {
|
|
|
|
if(!c) return false;
|
|
|
|
LinkedListIterator<Client*> iterator(m_clients_in_channel);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
if(iterator.GetData() == c)
|
|
return true;
|
|
|
|
iterator.Advance();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
ChatChannel *ChatChannelList::AddClientToChannel(std::string channel_name, Client *c, bool command_directed) {
|
|
|
|
if(!c) return nullptr;
|
|
|
|
if ((channel_name.length() > 0) && (isdigit(channel_name[0]))) { // Ensure channel name does not start with a number
|
|
c->GeneralChannelMessage("The channel name can not begin with a number.");
|
|
return nullptr;
|
|
}
|
|
else if (channel_name.empty()) { // Ensure channel name is not empty
|
|
return nullptr;
|
|
}
|
|
|
|
std::string normalized_name, password;
|
|
|
|
std::string::size_type Colon = channel_name.find_first_of(":");
|
|
|
|
if(Colon == std::string::npos)
|
|
normalized_name = CapitaliseName(channel_name);
|
|
else {
|
|
normalized_name = CapitaliseName(channel_name.substr(0, Colon));
|
|
|
|
password = channel_name.substr(Colon + 1);
|
|
}
|
|
|
|
if((normalized_name.length() > 64) || (password.length() > 64)) {
|
|
|
|
c->GeneralChannelMessage("The channel name or password cannot exceed 64 characters.");
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
ChatChannel *RequiredChannel = FindChannel(normalized_name);
|
|
|
|
if (RequiredChannel) {
|
|
if (IsOnChannelBlockList(channel_name)) { // Ensure channel name is not blocked
|
|
if (!(RequiredChannel->GetOwnerName() == SYSTEM_OWNER)) {
|
|
c->GeneralChannelMessage("That channel name is blocked by the server operator.");
|
|
return nullptr;
|
|
}
|
|
else {
|
|
LogDebug("Reserved/blocked channel name check for [{}] ignored due to channel being owned by System...", normalized_name);
|
|
}
|
|
}
|
|
}
|
|
|
|
const std::string& channel_owner = c->GetName();
|
|
|
|
bool permanent = false;
|
|
if (command_directed && RuleI(Chat, MaxPermanentPlayerChannels) > 0) {
|
|
permanent = true;
|
|
}
|
|
|
|
if (!RequiredChannel) {
|
|
RequiredChannel = CreateChannel(normalized_name, channel_owner, password, permanent, 0, command_directed);
|
|
if (RequiredChannel == nullptr) {
|
|
LogDebug("Failed to create new channel with name: {}. Possible blocked or reserved channel name.", normalized_name);
|
|
c->GeneralChannelMessage("Failed to create new channel with provided name. Possible blocked or reserved channel name.");
|
|
return nullptr;
|
|
}
|
|
LogDebug("Created and added Client to channel [{}] with password [{}]. Owner: {}. Command Directed: {}", normalized_name.c_str(), password.c_str(), channel_owner, command_directed);
|
|
}
|
|
|
|
LogDebug("Checking status requirement of channel: {}. Channel status required: {}, player status: {}.", normalized_name, std::to_string(RequiredChannel->GetMinStatus()), std::to_string(c->GetAccountStatus()));
|
|
if (RequiredChannel->GetMinStatus() > c->GetAccountStatus()) {
|
|
std::string Message = "You do not have the required account status to join channel " + normalized_name;
|
|
|
|
c->GeneralChannelMessage(Message);
|
|
LogInfo("Client [{}] connection to channel [{}] refused due to insufficient status.", c->GetName(), normalized_name);
|
|
return nullptr;
|
|
}
|
|
|
|
if (RequiredChannel->IsClientInChannel(c)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if(RequiredChannel->IsInvitee(c->GetName())) {
|
|
|
|
RequiredChannel->AddClient(c);
|
|
|
|
RequiredChannel->RemoveInvitee(c->GetName());
|
|
|
|
return RequiredChannel;
|
|
}
|
|
|
|
if(RequiredChannel->CheckPassword(password) || RequiredChannel->IsOwner(c->GetName()) || RequiredChannel->IsModerator(c->GetName()) ||
|
|
c->IsChannelAdmin()) {
|
|
|
|
RequiredChannel->AddClient(c);
|
|
|
|
return RequiredChannel;
|
|
}
|
|
|
|
c->GeneralChannelMessage("Incorrect password for channel " + (normalized_name));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
ChatChannel *ChatChannelList::RemoveClientFromChannel(const std::string& in_channel_name, Client *c, bool command_directed) {
|
|
if(!c) return nullptr;
|
|
|
|
std::string channel_name = in_channel_name;
|
|
|
|
if (in_channel_name.length() > 0 && isdigit(channel_name[0])) {
|
|
channel_name = c->ChannelSlotName(Strings::ToInt(in_channel_name));
|
|
}
|
|
|
|
auto *required_channel = FindChannel(channel_name);
|
|
|
|
if (!required_channel) {
|
|
return nullptr;
|
|
}
|
|
|
|
LogDebug("Client [{}] removed from channel [{}]. Channel is owned by {}. Command directed: {}", c->GetName(), channel_name, required_channel->GetOwnerName(), command_directed);
|
|
if (c->GetName() == required_channel->GetOwnerName() && command_directed) { // Check if the client that is leaving is the channel owner
|
|
LogDebug("Owner left the channel [{}], removing channel from database...", channel_name);
|
|
database.DeleteChatChannel(channel_name); // Remove the channel from the database.
|
|
LogDebug("Flagging [{}] channel as temporary...", channel_name);
|
|
required_channel->SetTemporary();
|
|
}
|
|
|
|
// RemoveClient will return false if there is no-one left in the channel, and the channel is not permanent and has
|
|
// no password.
|
|
if (!required_channel->RemoveClient(c)) {
|
|
LogDebug("Noone left in the temporary channel [{}] and no password is set; removing temporary channel.", channel_name);
|
|
RemoveChannel(required_channel);
|
|
}
|
|
|
|
return required_channel;
|
|
}
|
|
|
|
void ChatChannelList::Process() {
|
|
|
|
LinkedListIterator<ChatChannel*> iterator(ChatChannels);
|
|
|
|
iterator.Reset();
|
|
|
|
while(iterator.MoreElements()) {
|
|
|
|
ChatChannel *CurrentChannel = iterator.GetData();
|
|
|
|
if(CurrentChannel && CurrentChannel->ReadyToDelete()) {
|
|
|
|
LogDebug("Empty temporary password protected channel [{}] being destroyed",
|
|
CurrentChannel->GetName().c_str());
|
|
|
|
iterator.RemoveCurrent();
|
|
}
|
|
else {
|
|
iterator.Advance();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ChatChannel::AddInvitee(const std::string &Invitee)
|
|
{
|
|
if (!IsInvitee(Invitee)) {
|
|
m_invitees.push_back(Invitee);
|
|
|
|
LogDebug("Added [{}] as invitee to channel [{}]", Invitee.c_str(), m_name.c_str());
|
|
}
|
|
|
|
}
|
|
|
|
void ChatChannel::RemoveInvitee(std::string Invitee)
|
|
{
|
|
auto it = std::find(std::begin(m_invitees), std::end(m_invitees), Invitee);
|
|
|
|
if(it != std::end(m_invitees)) {
|
|
m_invitees.erase(it);
|
|
LogDebug("Removed [{}] as invitee to channel [{}]", Invitee.c_str(), m_name.c_str());
|
|
}
|
|
}
|
|
|
|
bool ChatChannel::IsInvitee(std::string Invitee)
|
|
{
|
|
return std::find(std::begin(m_invitees), std::end(m_invitees), Invitee) != std::end(m_invitees);
|
|
}
|
|
|
|
void ChatChannel::AddModerator(const std::string &Moderator)
|
|
{
|
|
if (!IsModerator(Moderator)) {
|
|
m_moderators.push_back(Moderator);
|
|
|
|
LogInfo("Added [{}] as moderator to channel [{}]", Moderator.c_str(), m_name.c_str());
|
|
}
|
|
|
|
}
|
|
|
|
void ChatChannel::RemoveModerator(const std::string &Moderator)
|
|
{
|
|
auto it = std::find(std::begin(m_moderators), std::end(m_moderators), Moderator);
|
|
|
|
if (it != std::end(m_moderators)) {
|
|
m_moderators.erase(it);
|
|
LogInfo("Removed [{}] as moderator to channel [{}]", Moderator.c_str(), m_name.c_str());
|
|
}
|
|
}
|
|
|
|
bool ChatChannel::IsModerator(std::string Moderator)
|
|
{
|
|
return std::find(std::begin(m_moderators), std::end(m_moderators), Moderator) != std::end(m_moderators);
|
|
}
|
|
|
|
void ChatChannel::AddVoice(const std::string &inVoiced)
|
|
{
|
|
if (!HasVoice(inVoiced)) {
|
|
m_voiced.push_back(inVoiced);
|
|
|
|
LogInfo("Added [{}] as voiced to channel [{}]", inVoiced.c_str(), m_name.c_str());
|
|
}
|
|
}
|
|
|
|
void ChatChannel::RemoveVoice(const std::string &inVoiced)
|
|
{
|
|
auto it = std::find(std::begin(m_voiced), std::end(m_voiced), inVoiced);
|
|
|
|
if (it != std::end(m_voiced)) {
|
|
m_voiced.erase(it);
|
|
|
|
LogInfo("Removed [{}] as voiced to channel [{}]", inVoiced.c_str(), m_name.c_str());
|
|
}
|
|
}
|
|
|
|
bool ChatChannel::HasVoice(std::string inVoiced)
|
|
{
|
|
return std::find(std::begin(m_voiced), std::end(m_voiced), inVoiced) != std::end(m_voiced);
|
|
}
|
|
|
|
std::string CapitaliseName(const std::string& inString) {
|
|
|
|
std::string NormalisedName = inString;
|
|
|
|
for(unsigned int i = 0; i < NormalisedName.length(); i++) {
|
|
|
|
if(i == 0)
|
|
NormalisedName[i] = toupper(NormalisedName[i]);
|
|
else
|
|
NormalisedName[i] = tolower(NormalisedName[i]);
|
|
}
|
|
|
|
return NormalisedName;
|
|
}
|
|
|
|
bool ChatChannelList::IsOnChannelBlockList(const std::string& channel_name) {
|
|
if (channel_name.empty()) {
|
|
return false;
|
|
}
|
|
|
|
// Check if channel_name is already in the BlockedChannelNames vector
|
|
return Strings::Contains(GetBlockedChannelNames(), channel_name);
|
|
}
|
|
|
|
bool ChatChannelList::IsOnFilteredNameList(const std::string& name) {
|
|
if (name.empty()) {
|
|
return false;
|
|
}
|
|
|
|
// Check if name is already in the filtered name vector
|
|
return Strings::Contains(GetFilteredNames(), name);
|
|
}
|
|
|
|
|
|
void ChatChannelList::AddToChannelBlockList(const std::string& channel_name) {
|
|
if (channel_name.empty()) {
|
|
return;
|
|
}
|
|
|
|
// Check if channelName is already in the BlockedChannelNames vector
|
|
bool is_found = Strings::Contains(ChatChannelList::GetBlockedChannelNames(), channel_name);
|
|
|
|
// Add channelName to the BlockedChannelNames vector if it is not already present
|
|
if (!is_found) {
|
|
auto blocked_channel_names = GetBlockedChannelNames(); // Get current blocked list
|
|
blocked_channel_names.push_back(channel_name); // Add new name to local blocked list
|
|
SetChannelBlockList(blocked_channel_names); // Set blocked list to match local blocked list
|
|
}
|
|
}
|
|
|
|
void ChatChannelList::AddToFilteredNames(const std::string& name) {
|
|
if (name.empty()) {
|
|
return;
|
|
}
|
|
|
|
// Add name to the filtered names vector if it is not already present
|
|
if (!Strings::Contains(ChatChannelList::GetFilteredNames(), name)) {
|
|
auto filtered_names = GetFilteredNames(); // Get current filter name list
|
|
filtered_names.push_back(name); // Add new name to local filtered names list
|
|
SetFilteredNameList(filtered_names); // Set filtered names list to match local filtered names list
|
|
}
|
|
}
|
|
|
|
void ServerToClient45SayLink(std::string& clientSayLink, const std::string& serverSayLink) {
|
|
if (serverSayLink.find('\x12') == std::string::npos) {
|
|
clientSayLink = serverSayLink;
|
|
return;
|
|
}
|
|
|
|
auto segments = Strings::Split(serverSayLink, '\x12');
|
|
|
|
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
|
if (segment_iter & 1) {
|
|
if (segments[segment_iter].length() <= 56) {
|
|
clientSayLink.append(segments[segment_iter]);
|
|
// TODO: log size mismatch error
|
|
continue;
|
|
}
|
|
|
|
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
|
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
|
// 6.2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXXXXX (45)
|
|
// Diff: ^^^^^ ^ ^^^^^
|
|
|
|
clientSayLink.push_back('\x12');
|
|
clientSayLink.append(segments[segment_iter].substr(0, 31));
|
|
clientSayLink.append(segments[segment_iter].substr(36, 5));
|
|
|
|
if (segments[segment_iter][41] == '0')
|
|
clientSayLink.push_back(segments[segment_iter][42]);
|
|
else
|
|
clientSayLink.push_back('F');
|
|
|
|
clientSayLink.append(segments[segment_iter].substr(48));
|
|
clientSayLink.push_back('\x12');
|
|
}
|
|
else {
|
|
clientSayLink.append(segments[segment_iter]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServerToClient50SayLink(std::string& clientSayLink, const std::string& serverSayLink) {
|
|
if (serverSayLink.find('\x12') == std::string::npos) {
|
|
clientSayLink = serverSayLink;
|
|
return;
|
|
}
|
|
|
|
auto segments = Strings::Split(serverSayLink, '\x12');
|
|
|
|
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
|
if (segment_iter & 1) {
|
|
if (segments[segment_iter].length() <= 56) {
|
|
clientSayLink.append(segments[segment_iter]);
|
|
// TODO: log size mismatch error
|
|
continue;
|
|
}
|
|
|
|
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
|
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
|
// SoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (50)
|
|
// Diff: ^^^^^ ^
|
|
|
|
clientSayLink.push_back('\x12');
|
|
clientSayLink.append(segments[segment_iter].substr(0, 31));
|
|
clientSayLink.append(segments[segment_iter].substr(36, 5));
|
|
|
|
if (segments[segment_iter][41] == '0')
|
|
clientSayLink.push_back(segments[segment_iter][42]);
|
|
else
|
|
clientSayLink.push_back('F');
|
|
|
|
clientSayLink.append(segments[segment_iter].substr(43));
|
|
clientSayLink.push_back('\x12');
|
|
}
|
|
else {
|
|
clientSayLink.append(segments[segment_iter]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ServerToClient55SayLink(std::string& clientSayLink, const std::string& serverSayLink) {
|
|
if (serverSayLink.find('\x12') == std::string::npos) {
|
|
clientSayLink = serverSayLink;
|
|
return;
|
|
}
|
|
|
|
auto segments = Strings::Split(serverSayLink, '\x12');
|
|
|
|
for (size_t segment_iter = 0; segment_iter < segments.size(); ++segment_iter) {
|
|
if (segment_iter & 1) {
|
|
if (segments[segment_iter].length() <= 56) {
|
|
clientSayLink.append(segments[segment_iter]);
|
|
// TODO: log size mismatch error
|
|
continue;
|
|
}
|
|
|
|
// Idx: 0 1 6 11 16 21 26 31 36 37 41 43 48 (Source)
|
|
// RoF2: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX XX XXXXX XXXXXXXX (56)
|
|
// RoF: X XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX XXXXX X XXXX X XXXXX XXXXXXXX (55)
|
|
// Diff: ^
|
|
|
|
clientSayLink.push_back('\x12');
|
|
clientSayLink.append(segments[segment_iter].substr(0, 41));
|
|
|
|
if (segments[segment_iter][41] == '0')
|
|
clientSayLink.push_back(segments[segment_iter][42]);
|
|
else
|
|
clientSayLink.push_back('F');
|
|
|
|
clientSayLink.append(segments[segment_iter].substr(43));
|
|
clientSayLink.push_back('\x12');
|
|
}
|
|
else {
|
|
clientSayLink.append(segments[segment_iter]);
|
|
}
|
|
}
|
|
}
|