Files
src-1.2/engine/server/application/ChatServer/src/shared/ChatServer.cpp
T

3080 lines
101 KiB
C++
Executable File

// ChatServer.cpp
// Copyright 2000-02, Sony Online Entertainment Inc., all rights reserved.
// Author: Justin Randall
//-----------------------------------------------------------------------
#include "FirstChatServer.h"
#include "ChatServer.h"
#include "CentralServerConnection.h"
#include "ChatInterface.h"
#include "ChatServerMetricsData.h"
#include "ConfigChatServer.h"
#include "ConnectionServerConnection.h"
#include "CustomerServiceServerConnection.h"
#include "GameServerConnection.h"
#include "PlanetServerConnection.h"
#include "UnicodeUtils.h"
#include "serverMetrics/MetricsManager.h"
#include "serverNetworkMessages/ChatConnectAvatar.h"
#include "serverNetworkMessages/ChatServerOnline.h"
#include "serverNetworkMessages/EnumerateServers.h"
#include "serverNetworkMessages/TransferCharacterData.h"
#include "serverUtility/ChatLogManager.h"
#include "sharedDebug/DebugFlags.h"
#include "sharedDebug/Profiler.h"
#include "sharedFoundation/Clock.h"
#include "sharedFoundation/ConfigFile.h"
#include "sharedFoundation/NetworkIdArchive.h"
#include "sharedFoundation/Os.h"
#include "sharedLog/Log.h"
#include "sharedLog/SetupSharedLog.h"
#include "sharedMessageDispatch/Transceiver.h"
#include "sharedNetwork/ConfigSharedNetwork.h"
#include "sharedNetwork/NetworkSetupData.h"
#include "sharedNetwork/Service.h"
#include "sharedNetworkMessages/ChatAvatarId.h"
#include "sharedNetworkMessages/ChatInstantMessageToClient.h"
#include "sharedNetworkMessages/ChatOnAddModeratorToRoom.h"
#include "sharedNetworkMessages/ChatOnBanAvatarFromRoom.h"
#include "sharedNetworkMessages/ChatOnCreateRoom.h"
#include "sharedNetworkMessages/ChatOnDestroyRoom.h"
#include "sharedNetworkMessages/ChatOnEnteredRoom.h"
#include "sharedNetworkMessages/ChatOnGetFriendsList.h"
#include "sharedNetworkMessages/ChatOnGetIgnoreList.h"
#include "sharedNetworkMessages/ChatOnInviteToRoom.h"
#include "sharedNetworkMessages/ChatOnInviteGroupToRoom.h"
#include "sharedNetworkMessages/ChatOnKickAvatarFromRoom.h"
#include "sharedNetworkMessages/ChatOnLeaveRoom.h"
#include "sharedNetworkMessages/ChatOnRemoveModeratorFromRoom.h"
#include "sharedNetworkMessages/ChatOnRequestLog.h"
#include "sharedNetworkMessages/ChatOnSendInstantMessage.h"
#include "sharedNetworkMessages/ChatOnSendRoomMessage.h"
#include "sharedNetworkMessages/ChatOnUnbanAvatarFromRoom.h"
#include "sharedNetworkMessages/ChatOnUninviteFromRoom.h"
#include "sharedNetworkMessages/ChatSystemMessage.h"
#include "sharedNetworkMessages/GenericValueTypeMessage.h"
#include "sharedNetworkMessages/VoiceChatMiscMessages.h"
#include "serverUtility/ConfigServerUtility.h"
#include "ChatAPI/ChatAPI.h"
#include "VChatInterface.h"
#include <list>
#include <sstream>
//-----------------------------------------------------------------------
namespace ChatServerNamespace
{
ChatServerMetricsData * s_chatServerMetricsData = 0;
typedef std::list<std::pair<int, time_t> > MessageList;
typedef std::unordered_map<Unicode::String, MessageList> PlayerMessageList;
PlayerMessageList s_playerMessageList;
void cleanChatLog();
time_t const chatMessageCleanTime = 60;
time_t chatMessageCleanTimer = 0;
Unicode::String const s_channelTell = Unicode::narrowToWide("tell");
Unicode::String const s_channelEmail = Unicode::narrowToWide("email");
bool s_loggingEnabled = false;
std::set<std::pair<std::string, ChatAvatarId> > s_pendingEntersByName;
std::set<std::pair<NetworkId, std::pair<unsigned int, unsigned int> > > s_pendingEntersById;
Unicode::String getRoomAddress(const std::string & roomName)
{
std::string fullName = roomName;
size_t dotPos = 0;
while(dotPos != std::string::npos)
{
dotPos = fullName.find('.');
if(dotPos != std::string::npos)
{
fullName[dotPos] = '+';
}
}
if(fullName.find(ConfigChatServer::getClusterName()) == std::string::npos)
{
fullName = ConfigChatServer::getClusterName() + '+' + fullName;
}
if(fullName.find(ConfigChatServer::getGameCode()) == std::string::npos)
{
fullName = ConfigChatServer::getGameCode() + '+' + fullName;
}
if(fullName.find("SOE") == std::string::npos)
{
fullName = "SOE+" + fullName;
}
return Unicode::narrowToWide(fullName);
}
ChatUnicodeString makeChatUnicodeString(const Unicode::String & source)
{
return ChatUnicodeString(source.c_str(), source.length());
}
std::set<NetworkId> s_godClients;
std::set<NetworkId> s_notSubscribedClients;
// Control log output for chat room related methods
bool const s_enableChatRoomLogs = false;
}
using namespace ChatServerNamespace;
//-----------------------------------------------------------------------
void ChatServerNamespace::cleanChatLog()
{
PlayerMessageList::iterator iterPlayerMessageList = s_playerMessageList.begin();
time_t const spatialChatLogTime = static_cast<time_t>(ConfigServerUtility::getChatLogMinutes() * 60);
time_t const currentTime = Os::getRealSystemTime();
for (; iterPlayerMessageList != s_playerMessageList.end(); ++iterPlayerMessageList)
{
MessageList &messageList = iterPlayerMessageList->second;
int chatLogCount = static_cast<int>(messageList.size());
MessageList::iterator iterMessageList = messageList.begin();
while (!messageList.empty())
{
time_t const messageTime = iterMessageList->second;
if (messageTime < (currentTime - spatialChatLogTime) || (chatLogCount > ConfigServerUtility::getPlayerMaxChatLogLines()))
{
iterMessageList = messageList.erase(iterMessageList);
--chatLogCount;
}
else
{
break;
}
}
}
}
//-----------------------------------------------------------------------
ChatServer *ChatServer::m_instance = NULL;
#include <stdio.h>
void splitRoomName(std::string roomName, Unicode::String &name, Unicode::String &address);
//-----------------------------------------------------------------------
std::string toLower(const std::string & source)
{
std::string lower;
size_t i;
for(i = 0; i < source.length(); ++i)
{
char a = static_cast<char>(tolower(source[i]));
lower += a;
}
return lower;
}
//-----------------------------------------------------------------------
std::string toUpper(const std::string & source)
{
std::string upper;
size_t i;
for(i = 0; i < source.length(); ++i)
{
char a = static_cast<char>(toupper(source[i]));
upper += a;
}
return upper;
}
//-----------------------------------------------------------------------
void ChatServer::update()
{
PROFILER_BLOCK_DEFINE(profileBlockMainLoop, "main loop");
PROFILER_BLOCK_ENTER(profileBlockMainLoop);
static unsigned int lastTime = 0;
unsigned int t1 = Clock::timeMs();
NetworkHandler::update();
unsigned int t2 = Clock::timeMs();
chatInterface->checkQueuedLogins();
chatInterface->sendQueuedHeadersToClient();
if ((t2 - t1) > (1000 * 5))
{
DEBUG_WARNING(true, ("\n\n\n\n\nNetworkHandler::update() took %i ms\n\n\n\n\n", (t2 - t1)));
}
NetworkHandler::dispatch();
unsigned int t3 = Clock::timeMs();
if ((t3 - t2) > (1000 * 5))
{
DEBUG_WARNING(true, ("\n\n\n\n\nNetworkHandler::dispatch() took %i ms\n\n\n\n\n", (t3 - t2)));
}
if (lastTime != 0)
{
unsigned int time = Clock::timeMs();
if ((time - lastTime) > (1000))
{
//DEBUG_WARNING(true, ("\n\n\n\n\n\nLong Chat Frame (%i ms)\n\n\n\n", (time - lastTime)));
}
}
lastTime = Clock::timeMs();
chatInterface->Process();
voiceChatInterface->Process();
PROFILER_BLOCK_LEAVE(profileBlockMainLoop);
if (!Os::update())
done = true;
Os::sleep(1);
static int i = 0;
if (i % 600 == 0)
{
instance().chatInterface->updateRooms();
}
if (i % 6000 == 0)
{
static Unicode::String wideSWG = Unicode::narrowToWide("SOE+SWG");
static Unicode::String wideFilter = Unicode::narrowToWide("");
static ChatUnicodeString swgNode(wideSWG.data(), wideSWG.size());
static ChatUnicodeString filter(wideFilter.data(), wideFilter.size());
instance().chatInterface->RequestGetRoomSummaries(swgNode, filter, NULL);
}
++i;
NetworkHandler::clearBytesThisFrame();
if(s_chatServerMetricsData)
MetricsManager::update(Clock::frameTime() * 1000);
// Clear the chat log every once in a while
if ((chatMessageCleanTimer + chatMessageCleanTime) > Os::getRealSystemTime())
{
chatMessageCleanTimer = Os::getRealSystemTime();
cleanChatLog();
}
}
//-----------------------------------------------------------------------
ChatServer::ChatServer() :
pendingRequests(),
callback(new MessageDispatch::Callback),
centralServerConnection(new CentralServerConnection(ConfigChatServer::getCentralServerAddress(), ConfigChatServer::getCentralServerPort())),
chatAvatars(),
chatInterface(0),
voiceChatInterface(0),
clientMap(),
gameServerConnectionMap(),
connectionServerConnections(),
done(false),
gameService(0),
planetService(),
ownerSystem(0),
systemAvatarId("SWG", ConfigChatServer::getClusterName(), "SYSTEM"),
customerServiceServerConnection(NULL),
m_gameServerConnectionRegistry(),
m_voiceChatIdMap()
{
s_loggingEnabled = ConfigChatServer::isLoggingEnabled();
DebugFlags::registerFlag(s_loggingEnabled, "ChatServer", "loggingEnabled");
SetupSharedLog::install("SwgChatServer");
NetworkSetupData setup;
setup.maxConnections = 100;
setup.port = 0;
setup.bindInterface = ConfigChatServer::getGameServiceBindInterface();
gameService = new Service(ConnectionAllocator<GameServerConnection>(), setup);
setup.bindInterface = ConfigChatServer::getPlanetServiceBindInterface();
planetService = new Service(ConnectionAllocator<PlanetServerConnection>(), setup);
const std::string getGameCode = ConfigChatServer::getGameCode();
const std::string getGatewayServerIP = ConfigChatServer::getGatewayServerIP();
chatInterface = new ChatInterface(getGameCode, getGatewayServerIP, ConfigChatServer::getGatewayServerPort(), ConfigChatServer::getRegistrarHost(), static_cast<unsigned short>(ConfigChatServer::getRegistrarPort()));
std::string vChatHost;
int numConnectionStrings = ConfigChatServer::getNumberOfVoiceChatGateways();
for(int i = 0; i < numConnectionStrings; ++i)
{
if(i != 0)
{
vChatHost += " ";
}
vChatHost += ConfigChatServer::getVoiceChatGateway(i);
}
voiceChatInterface = new VChatInterface(vChatHost.c_str());
callback->connect(*this, &ChatServer::onEnumerateServers); //lint !e1025 !e1703 !e1514 !e64 !e1058 !e118 // jrandall lint is confused, the compiler resolves this just fine //lint !e1703 // jrandall, really, this is fine!
ChatServer::fileLog(true, "ChatServer", "ChatServer() VChat host: %s", vChatHost.c_str());
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigChatServer::getCentralServerAddress() %s", ConfigChatServer::getCentralServerAddress());
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigChatServer::getCentralServerPort() %d", ConfigChatServer::getCentralServerPort());
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getReportUdpDisconnects() %s", ConfigSharedNetwork::getReportUdpDisconnects() ? "yes" : "no");
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getReportTcpDisconnects() %s", ConfigSharedNetwork::getReportTcpDisconnects() ? "yes" : "no");
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionConstructionDestruction() %s", ConfigSharedNetwork::getLogConnectionConstructionDestruction() ? "yes" : "no");
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionOpenedClosed() %s", ConfigSharedNetwork::getLogConnectionOpenedClosed() ? "yes" : "no");
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionDeferredMessagesWarning() %s", ConfigSharedNetwork::getLogConnectionDeferredMessagesWarning() ? "yes" : "no");
ChatServer::fileLog(true, "ChatServer", "ChatServer() ConfigSharedNetwork::getLogConnectionDeferredMessagesWarningInterval() %d", ConfigSharedNetwork::getLogConnectionDeferredMessagesWarningInterval());
s_chatServerMetricsData = new ChatServerMetricsData();
MetricsManager::install(s_chatServerMetricsData, false, "ChatServer" , "", 0);
// ownerSystem = new ChatAvatar("SWG", ConfigChatServer::getClusterName(), "SYSTEM");
}
//-----------------------------------------------------------------------
ChatServer::~ChatServer()
{
std::set<ConnectionServerConnection *>::const_iterator i;
for(i = connectionServerConnections.begin(); i != connectionServerConnections.end(); ++i)
{
ConnectionServerConnection * c = (*i);
delete c;
}
if(centralServerConnection)
centralServerConnection->disconnect();
// need to delete these before NetworkHandler::remove() is called in ::run()
//delete gameService;
//delete planetService;
delete callback;
delete voiceChatInterface;
delete chatInterface;
ownerSystem = 0; //lint !e423 deletion is taken care of in the OnDestroy
delete s_chatServerMetricsData;
MetricsManager::remove();
}
//-----------------------------------------------------------------------
bool ChatServer::getChatLog(Unicode::String const &player, std::vector<ChatLogEntry> &chatLog)
{
Unicode::String const lowerPlayer(Unicode::toLower(player));
ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() player(%s)", Unicode::wideToNarrow(lowerPlayer).c_str());
bool result = false;
PlayerMessageList::const_iterator iterPlayerMessageList = s_playerMessageList.find(lowerPlayer);
if (iterPlayerMessageList != s_playerMessageList.end())
{
result = true;
cleanChatLog();
MessageList::const_iterator iterMessageList = iterPlayerMessageList->second.begin();
chatLog.clear();
for (; iterMessageList != iterPlayerMessageList->second.end(); ++iterMessageList)
{
int const messageIndex = iterMessageList->first;
ChatLogEntry chatLogEntry;
if (ChatLogManager::getChatMessage(messageIndex, chatLogEntry.m_from, chatLogEntry.m_to, chatLogEntry.m_message, chatLogEntry.m_channel, chatLogEntry.m_time))
{
chatLog.push_back(chatLogEntry);
}
else
{
DEBUG_WARNING(true, ("Unable to find chat log message(%d)", messageIndex));
}
}
}
ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() Found %u chat log messages for player(%s)", chatLog.size(), Unicode::wideToNarrow(lowerPlayer).c_str());
if (s_loggingEnabled)
{
ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() -- BEGIN Player List --");
iterPlayerMessageList = s_playerMessageList.begin();
int count = 0;
for (; iterPlayerMessageList != s_playerMessageList.end(); ++iterPlayerMessageList)
{
ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() [%d] player(%s)", ++count, Unicode::wideToNarrow(iterPlayerMessageList->first).c_str());
}
ChatServer::fileLog(false, "ChatServer", "ChatServer::getChatLog() -- END Player List --");
}
return result;
}
//-----------------------------------------------------------------------
void ChatServer::deferChatMessageFor(const NetworkId & id, const Archive::ByteStream & bs)
{
instance().chatInterface->deferChatMessageFor(id, bs);
}
//-----------------------------------------------------------------------
void ChatServer::sendToClient(const NetworkId & id, const GameNetworkMessage & message)
{
ChatServer::fileLog(false, "ChatServer", "sendToClient() id(%s) message(%s)", id.getValueString().c_str(), message.getCmdName().c_str());
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::const_iterator f = instance().clientMap.find(id);
if(f != instance().clientMap.end())
{
(*f).second->sendToClient(id, message);
}
}
//-----------------------------------------------------------------------
void ChatServer::setOwnerSystem(const ChatAvatar * o)
{
ChatServer::fileLog(false, "ChatServer", "setOwnerSystem() ");
instance().ownerSystem = o; //lint !e423 deletion is taken care of in the OnDestroy
const Service * s = getGameService();
if(s)
{
ChatServerOnline cso(s->getBindAddress(), s->getBindPort());
Archive::ByteStream bs;
cso.pack(bs);
Connection *connection = safe_cast<Connection *>(instance().centralServerConnection);
if (connection != NULL)
{
connection->send(bs, true);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::onEnumerateServers(const EnumerateServers & e)
{
if(e.getAdd())
{
switch(e.getServerType())
{
case EnumerateServers::CONNECTION_SERVER:
{
//printf("!!!adding connection server, chat was told to connect to port %i!!!!\n",
// e.getPort());
static int count = 0;
++count;
ConnectionServerConnection * c = new ConnectionServerConnection(e.getAddress(), e.getPort());
if ( !e.getAddress().empty()
&& (e.getPort() != 0))
{
ChatServer::fileLog(true, "ChatServer", "onEnumerateServers() count(%d) address(%s)", count, getConnectionAddress(c).c_str());
IGNORE_RETURN(connectionServerConnections.insert(c));
s_chatServerMetricsData->setConnectionServerConnectionCount(instance().connectionServerConnections.size());
}
else
{
ChatServer::fileLog(true, "ChatServer", "onEnumerateServers() count(%d) Empty server address", count);
}
}//lint !e429 Custodial pointer 'c' (line 232) has not been freed or returned //jrandall tracked by connectionServerConnections
break;
default:
break;
}
}
else
{
// remove the server
}
}
//-----------------------------------------------------------------------
ChatServer & ChatServer::instance()
{
static ChatServer s;
m_instance = &s;
return *m_instance;
}
//-----------------------------------------------------------------------
void ChatServer::quit()
{
instance().done = true;
}
//-----------------------------------------------------------------------
void ChatServer::reconnectToCentralServer()
{
ChatServer::fileLog(true, "ChatServer", "reconnectToCentralServer()");
if (instance().centralServerConnection)
instance().centralServerConnection->disconnect();
instance().centralServerConnection = new CentralServerConnection(ConfigChatServer::getCentralServerAddress(), ConfigChatServer::getCentralServerPort());
}
//-----------------------------------------------------------------------
void ChatServer::onCentralServerConnectionClosed()
{
instance().centralServerConnection = 0;
}
//-----------------------------------------------------------------------
const ChatAvatarId & ChatServer::getSystemAvatarId()
{
return instance().systemAvatarId;
}
//-----------------------------------------------------------------------
const Service * ChatServer::getGameService()
{
return instance().gameService;
}
//-----------------------------------------------------------------------
void ChatServer::run()
{
NetworkHandler::install();
Clock::setFrameRateLimit(20.0f);
// create default rooms
NetworkId id = NetworkId::cms_invalid;
// LOG("ServerStartup",("ChatServer starting"));
int const numberOfCreateRooms = ConfigChatServer::getNumberOfCreateRooms();
for (int i = 0; i < numberOfCreateRooms; ++i)
{
char const * const p = ConfigChatServer::getCreateRoom(i);
if (p)
{
createRoom(id, 0, std::string(p), false, true, "");
}
}
while(! instance().done)
{
instance().update();
}
instance().removeServices();
NetworkHandler::remove();
}
void ChatServer::removeServices()
{
delete gameService;
gameService = 0;
delete planetService;
planetService = 0;
}
//-----------------------------------------------------------------------
ChatAvatarId ChatServer::getAvatarIdForTrackId(unsigned trackId)
{
ChatServer & server = instance();
std::unordered_map<unsigned, NetworkId>::iterator f = server.pendingRequests.find(trackId);
if(f != server.pendingRequests.end())
{
const ChatAvatar *avatar = getAvatarByNetworkId((*f).second);
if (avatar)
{
ChatAvatarId avatarId;
makeAvatarId(*avatar, avatarId);
return avatarId;
}
server.pendingRequests.erase(f);
}
static const ChatAvatarId badId;
return badId;
}
//-----------------------------------------------------------------------
const ChatAvatar * ChatServer::getAvatarByNetworkId(const NetworkId & id)
{
if (id.getValue() == 0)
{
return NULL;
}
const ChatAvatar * result = 0;
ChatAvatarList::const_iterator f = instance().chatAvatars.find(id);
if(f != instance().chatAvatars.end())
{
result = &((*f).second.chatAvatar);
}
return result;
}
//-----------------------------------------------------------------------
ChatServer::AvatarExtendedData * ChatServer::getAvatarExtendedDataByNetworkId(const NetworkId & id)
{
if (id.getValue() == 0)
{
return NULL;
}
ChatServer::AvatarExtendedData * result = 0;
ChatAvatarList::iterator f = instance().chatAvatars.find(id);
if(f != instance().chatAvatars.end())
{
result = &((*f).second);
}
return result;
}
//-----------------------------------------------------------------------
const NetworkId & ChatServer::getNetworkIdByAvatarId(const ChatAvatarId & id)
{
PROFILER_AUTO_BLOCK_DEFINE("ChatServer - getNetworkIdByAvatarId");
/*ChatAvatarList::const_iterator f;
for (f = instance().chatAvatars.begin(); f != instance().chatAvatars.end(); ++f)
{
ChatAvatarId av;
makeAvatarId((*f).second.chatAvatar, av);
if (av == id)
{
return f->first;
}
}
static NetworkId badId;
return badId;
*/
return instance().chatInterface->getNetworkIdByAvatarId(id);
}
//-----------------------------------------------------------------------
NetworkId ChatServer::sendResponseForTrackId(unsigned trackId, const GameNetworkMessage & response)
{
NetworkId id;
ChatServer & server = instance();
std::unordered_map<unsigned, NetworkId>::iterator f = server.pendingRequests.find(trackId);
if(f != server.pendingRequests.end())
{
id = (*f).second;
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::const_iterator c = server.clientMap.find((*f).second);
if(c != server.clientMap.end())
{
ConnectionServerConnection * conn = (*c).second;
conn->sendToClient((*f).second, response);
}
server.pendingRequests.erase(f);
}
return id;
}
//-----------------------------------------------------------------------
GameServerConnection *ChatServer::getGameServerConnection(unsigned int sequence)
{
GameServerConnection * result = 0;
std::unordered_map<unsigned int, GameServerConnection *>::iterator f = instance().gameServerConnectionMap.find(sequence);
if(f != instance().gameServerConnectionMap.end())
{
result = (*f).second;
instance().gameServerConnectionMap.erase(f);
}
return result;
}
//-----------------------------------------------------------------------
void ChatServer::addGameServerConnection(unsigned int sequence, GameServerConnection *connection)
{
IGNORE_RETURN(instance().gameServerConnectionMap.insert(std::make_pair(sequence, connection)));
s_chatServerMetricsData->setGameServerConnectionCount(instance().gameServerConnectionMap.size());
}
//-----------------------------------------------------------------------
void ChatServer::clearGameServerConnection(const GameServerConnection *connection)
{
std::vector<unsigned int> removeKeyList;
std::unordered_map<unsigned int, GameServerConnection *>::const_iterator i;
for(i = instance().gameServerConnectionMap.begin(); i != instance().gameServerConnectionMap.end(); ++i)
{
if ((*i).second == connection)
{
removeKeyList.push_back((*i).first);
}
}
std::vector<unsigned int>::const_iterator j;
for (j = removeKeyList.begin(); j != removeKeyList.end(); ++j)
{
IGNORE_RETURN(instance().gameServerConnectionMap.erase((*j)));
}
s_chatServerMetricsData->setGameServerConnectionCount(instance().gameServerConnectionMap.size());
}
//-----------------------------------------------------------------------
ConnectionServerConnection * ChatServer::getConnectionForCharacter(const NetworkId & characterId)
{
ConnectionServerConnection * result = 0;
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::iterator f = instance().clientMap.find(characterId);
if(f != instance().clientMap.end())
{
result = (*f).second;
}
return result;
}
//-----------------------------------------------------------------------
void splitChatAvatarId(const ChatAvatarId &id, Unicode::String &name, Unicode::String &address)
{
name = Unicode::narrowToWide(id.name);
address = Unicode::narrowToWide("SOE+" + id.gameCode + "+" + id.cluster);
}
//-----------------------------------------------------------------------
void canonicalizeAvatarId(const ChatAvatarId &id)
{
ChatAvatarId &hack = const_cast<ChatAvatarId &>(id);
hack.gameCode = toUpper(hack.gameCode);
hack.name = toLower(hack.name);
}
//-----------------------------------------------------------------------
void ChatServer::addFriend(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & friendId)
{
UNREF(sequence);
ChatServer::fileLog(false, "ChatServer", "addFriend() id(%s) sequence(%u) friendId(%s)", id.getValueString().c_str(), sequence, friendId.getFullName().c_str());
const ChatAvatar * from = getAvatarByNetworkId(id);
if(from)
{
Unicode::String friendName;
Unicode::String friendAddress;
canonicalizeAvatarId(friendId);
splitChatAvatarId(friendId, friendName, friendAddress);
unsigned track = instance().chatInterface->RequestAddFriend(from, ChatUnicodeString(friendName.data(), friendName.length()),
ChatUnicodeString(friendAddress.data(), friendAddress.length()),
false, NULL);
instance().pendingRequests[track] = id;
}
else
{
ChatServer::fileLog(true, "ChatServer", "addFriend() ERROR: avatar not found(%s)", id.getValueString().c_str());
}
}
//-----------------------------------------------------------------------
void ChatServer::removeFriend(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & friendId)
{
UNREF(sequence);
ChatServer::fileLog(false, "ChatServer", "removeFriend() id(%s) sequence(%u) friendId(%s)", id.getValueString().c_str(), sequence, friendId.getFullName().c_str());
const ChatAvatar * from = getAvatarByNetworkId(id);
if(from)
{
Unicode::String friendName;
Unicode::String friendAddress;
canonicalizeAvatarId(friendId);
splitChatAvatarId(friendId, friendName, friendAddress);
unsigned track = instance().chatInterface->RequestRemoveFriend(from, ChatUnicodeString(friendName.data(), friendName.length()),
ChatUnicodeString(friendAddress.data(), friendAddress.length()), NULL);
instance().pendingRequests[track] = id;
}
else
{
ChatServer::fileLog(true, "ChatServer", "removeFriend() ERROR: avatar not found(%s)", id.getValueString().c_str());
}
}
//-----------------------------------------------------------------------
void ChatServer::getFriendsList(const ChatAvatarId &characterName)
{
ChatServer::fileLog(false, "ChatServer", "getFriendsList() characterName(%s)", characterName.getFullName().c_str());
const NetworkId &id = getNetworkIdByAvatarId(characterName);
const ChatAvatar *avatar = getAvatarByNetworkId(id);
if (avatar)
{
unsigned track = instance().chatInterface->RequestFriendStatus(avatar, NULL);
instance().pendingRequests[track] = id;
}
else
{
ChatServer::fileLog(true, "ChatServer", "getFriendsList() ERROR: avatar not found(%s)", characterName.getFullName().c_str());
}
}
//-----------------------------------------------------------------------
void ChatServer::addIgnore(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & ignoreId)
{
UNREF(sequence);
ChatServer::fileLog(false, "ChatServer", "addIgnore() id(%s) sequence(%u) ignoreId(%s)", id.getValueString().c_str(), sequence, ignoreId.getFullName().c_str());
const ChatAvatar * from = getAvatarByNetworkId(id);
if(from)
{
Unicode::String ignoreName;
Unicode::String ignoreAddress;
canonicalizeAvatarId(ignoreId);
splitChatAvatarId(ignoreId, ignoreName, ignoreAddress);
unsigned track = instance().chatInterface->RequestAddIgnore(from, ChatUnicodeString(ignoreName.data(), ignoreName.length()),
ChatUnicodeString(ignoreAddress.data(), ignoreAddress.length()),
NULL);
instance().pendingRequests[track] = id;
}
else
{
ChatServer::fileLog(true, "ChatServer", "addIgnore() ERROR: avatar not found(%s)", id.getValueString().c_str());
}
}
//-----------------------------------------------------------------------
void ChatServer::removeIgnore(const NetworkId & id, const unsigned int sequence, const ChatAvatarId & ignoreId)
{
UNREF(sequence);
ChatServer::fileLog(false, "ChatServer", "removeIgnore() id(%s) sequence(%u) ignoreId(%s)", id.getValueString().c_str(), sequence, ignoreId.getFullName().c_str());
const ChatAvatar * from = getAvatarByNetworkId(id);
if(from)
{
Unicode::String ignoreName;
Unicode::String ignoreAddress;
canonicalizeAvatarId(ignoreId);
splitChatAvatarId(ignoreId, ignoreName, ignoreAddress);
unsigned track = instance().chatInterface->RequestRemoveIgnore(from, ChatUnicodeString(ignoreName.data(), ignoreName.length()),
ChatUnicodeString(ignoreAddress.data(), ignoreAddress.length()), NULL);
instance().pendingRequests[track] = id;
}
else
{
ChatServer::fileLog(true, "ChatServer", "removeIgnore() ERROR: avatar not found(%s)", id.getValueString().c_str());
}
}
//-----------------------------------------------------------------------
void ChatServer::getIgnoreList(const ChatAvatarId &characterName)
{
canonicalizeAvatarId(characterName);
ChatServer::fileLog(false, "ChatServer", "getIgnoreList() characterName(%s)", characterName.getFullName().c_str());
const NetworkId &id = getNetworkIdByAvatarId(characterName);
const ChatAvatar *avatar = getAvatarByNetworkId(id);
if (avatar)
{
unsigned track = instance().chatInterface->RequestIgnoreStatus(avatar, NULL);
instance().pendingRequests[track] = id;
}
else
{
ChatServer::fileLog(true, "ChatServer", "getIgnoreList() ERROR: avatar not found(%s)", characterName.getFullName().c_str());
}
}
//-----------------------------------------------------------------------
void ChatServer::addModeratorToRoom(const unsigned int sequenceId, const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName)
{
canonicalizeAvatarId(avatarId);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "addModeratorToRoom() sequenceId(%u) id(%s) avatarId(%s) roomName(%s)", sequenceId, id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str());
const ChatAvatar * from = getAvatarByNetworkId(id);
if(from)
{
unsigned errorCode = CHATRESULT_SUCCESS;
const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
Unicode::String moderatorName;
Unicode::String moderatorAddress;
splitChatAvatarId(avatarId, moderatorName, moderatorAddress);
// Remove the avatar from the ban list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequenceId, avatarId);
instance().chatInterface->RequestRemoveBan(from, moderatorName, moderatorAddress, roomOwner->getAddress(), (void *)pair);
}
// Try to make the avatar a moderator
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequenceId, avatarId);
unsigned track = instance().chatInterface->RequestAddModerator(from, moderatorName, moderatorAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = id;
}
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId fromId;
makeAvatarId(*from, fromId);
ChatOnAddModeratorToRoom msg(errorCode, sequenceId, fromId, avatarId, roomName);
instance().chatInterface->sendMessageToAvatar(fromId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::removeModeratorFromRoom(const unsigned int sequenceId, const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName)
{
canonicalizeAvatarId(avatarId);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeModeratorFromRoom() sequenceId(%u) id(%s) avatarId(%s) roomName(%s)", sequenceId, id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str());
const ChatAvatar * from = getAvatarByNetworkId(id);
if(from)
{
unsigned errorCode = CHATRESULT_SUCCESS;
const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
Unicode::String moderatorName;
Unicode::String moderatorAddress;
splitChatAvatarId(avatarId, moderatorName, moderatorAddress);
// User data so that we remember who is being removed as a moderator
AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequenceId, avatarId);
unsigned track = instance().chatInterface->RequestRemoveModerator(from, moderatorName, moderatorAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = id;
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId fromId;
makeAvatarId(*from, fromId);
ChatOnRemoveModeratorFromRoom msg(errorCode, sequenceId, fromId, avatarId, roomName);
instance().chatInterface->sendMessageToAvatar(fromId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::chatConnectedAvatar(const NetworkId & id, const ChatAvatar & newAvatar)
{
ChatServer::fileLog(false, "ChatServer", "chatConnectedAvatar() id(%s) newAvatar(%s)", id.getValueString().c_str(), getFullChatAvatarName(&newAvatar).c_str());
AvatarExtendedData aed;
aed.chatAvatar = newAvatar;
aed.isSubscribed = (s_notSubscribedClients.count(id) == 0);
aed.spatialCharCount = 0;
aed.nonSpatialCharCount = 0;
aed.chatSpamTimeEndInterval = 0;
aed.chatSpamNextTimeToSyncWithGameServer = 0;
aed.chatSpamNextTimeToNotifyPlayerWhenLimited = 0;
aed.unsquelchTime = 0;
IGNORE_RETURN(instance().chatAvatars.insert(std::make_pair(id, aed)));
}
//-----------------------------------------------------------------------
void ChatServer::connectPlayer(ConnectionServerConnection * connection, const unsigned int suid, const std::string & characterName, const NetworkId & networkId, bool isSecure, bool isSubscribed)
{
ChatServer::fileLog(false, "ChatServer", "connectPlayer() address(%s) suid(%u) characterName(%s) networkId(%s)", getConnectionAddress(connection).c_str(), suid, characterName.c_str(), networkId.getValueString().c_str());
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::iterator cf = instance().clientMap.find(networkId);
if (cf != instance().clientMap.end())
{
DEBUG_WARNING(true, ("We received a chat login attempt for a player (%s) that we think is already logged in. We're going to try to log out the old avatar then log in the new one.", characterName.c_str()));
//instance().disconnectPlayer(networkId);
instance().clientMap[networkId] = connection;
return;
}
IGNORE_RETURN(instance().clientMap.insert(std::make_pair(networkId, connection)));
instance().chatInterface->ConnectPlayer(suid, toLower(characterName), networkId);
uint32 voiceStatus = VoiceChatStatus::SC_VoiceStatusUnknown;
if(isSubscribed || isSecure)
{
getVChatInterface()->requestConnectPlayer(suid, characterName, networkId);
voiceStatus = VoiceChatStatus::SC_VoiceEnabled;
}
else
{
voiceStatus = VoiceChatStatus::SC_VoiceClientIsTrial;
}
VoiceChatStatus msg(voiceStatus);
sendToClient(networkId, msg);
s_chatServerMetricsData->setClientCount(instance().clientMap.size());
if(isSecure)
{
s_godClients.insert(networkId);
}
if (!isSubscribed)
{
s_notSubscribedClients.insert(networkId);
}
}
int countDots(const std::string &str)
{
int num = 0;
for (unsigned i = 0; i < str.length(); ++i)
{
if (str[i] == '.')
{
++num;
}
}
return num;
}
//-----------------------------------------------------------------------
void ChatServer::createRoom(const NetworkId & id, const unsigned int sequence, const std::string & roomName, const bool isModerated, const bool isPublic, const std::string & title)
{
if(roomName.empty())
return;
if(roomName.find("..") != std::string::npos ||
roomName.find(" ") != std::string::npos ||
roomName[0] == '.')
{
return;
}
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "createRoom() id(%s) sequence(%u) roomName(%s) isModerated(%s) isPublic(%s) title(%s)", id.getValueString().c_str(), sequence, roomName.c_str(), isModerated ? "yes" : "no", isPublic ? "yes" : "no", title.c_str());
RoomParams roomParams;
std::string baseName = std::string("SWG.") + ConfigChatServer::getClusterName();
if (roomName == baseName || roomName == toLower(baseName))
{
return;
}
if(toLower(roomName).find(toLower(baseName)) != 0)
return;
int numDots = countDots(roomName);
if (numDots > 1)
{
size_t lastDot = roomName.rfind('.');
if (lastDot != std::string::npos)
{
std::string parent = roomName.substr(0, lastDot);
const ChatServerRoomOwner *room =
instance().chatInterface->getRoomOwner(parent);
if (!room)
{
//REPORT_LOG(true, ("Creating parent room %s\n", parent.c_str()));
createRoom(id, 0, parent, isModerated, isPublic, "");
}
}
}
//printf("Creating room %s\n", roomName.c_str());
unsigned roomAttr = 0;
static Archive::ByteStream a;
const ChatAvatar * owner = 0;
bool isSystemOwner = false;
//REPORT_LOG(true, ("createRoom(%s, %s)\n", id.getValueString().c_str(), roomName.c_str()));
if(id != NetworkId::cms_invalid)
{
owner = getAvatarByNetworkId(id);
}
else
{
isSystemOwner = true;
owner = instance().ownerSystem;
//REPORT_LOG(true, ("System is creating a room: %s\n", roomName.c_str()));
}
if (!owner)
{
return;
}
if (isModerated)
{
roomAttr |= ROOMATTR_MODERATED;
}
if (!isPublic)
{
roomAttr |= ROOMATTR_PRIVATE;
}
if (isSystemOwner && (strstr(roomName.c_str(), "system") != NULL))
{
roomAttr |= ROOMATTR_PERSISTENT;
}
std::string tmpRoomName = roomName;
Unicode::String wideRoomName;
Unicode::String wideRoomAddress;
splitRoomName(tmpRoomName, wideRoomName, wideRoomAddress);
Unicode::String wideTitle = Unicode::narrowToWide(title);
roomParams.setRoomName(ChatUnicodeString(wideRoomName.data(), wideRoomName.size()));
roomParams.setRoomTopic(ChatUnicodeString(wideTitle.data(), wideTitle.size()));
roomParams.setRoomAttributes(roomAttr);
//instance().voiceChatInterface->GetChannel(narrowRoomAddress,narrowRoomName,"text","",0,false,0);
unsigned track = instance().chatInterface->RequestCreateRoom(owner, roomParams, ChatUnicodeString(wideRoomAddress.data(), wideRoomAddress.size()), (void *)sequence); //lint !e641 Converting enum 'ChatRoomType' to int
if(id != NetworkId::cms_invalid)
instance().pendingRequests[track] = id;
}
//-----------------------------------------------------------------------
void ChatServer::deleteAllPersistentMessages(const NetworkId &sourceNetworkId, const NetworkId &targetNetworkId)
{
ChatServer::fileLog(false, "ChatServer", "deleteAllPersistentMessages() sourceNetworkId(%s) targetNetworkId(%s)", sourceNetworkId.getValueString().c_str(), targetNetworkId.getValueString().c_str());
ChatAvatar const *avatar = getAvatarByNetworkId(targetNetworkId);
if (avatar != NULL)
{
{
NetworkId *tmpNetworkId = new NetworkId(sourceNetworkId);
instance().chatInterface->RequestUpdatePersistentMessages(avatar, PERSISTENT_NEW, PERSISTENT_DELETED, reinterpret_cast<void *>(tmpNetworkId));
}
{
NetworkId *tmpNetworkId = new NetworkId(sourceNetworkId);
instance().chatInterface->RequestUpdatePersistentMessages(avatar, PERSISTENT_UNREAD, PERSISTENT_DELETED, reinterpret_cast<void *>(tmpNetworkId));
}
{
NetworkId *tmpNetworkId = new NetworkId(sourceNetworkId);
instance().chatInterface->RequestUpdatePersistentMessages(avatar, PERSISTENT_READ, PERSISTENT_DELETED, reinterpret_cast<void *>(tmpNetworkId));
}
}
else
{
DEBUG_REPORT_LOG(true, ("ChatServer::deleteAllPersistentMessages() Unable to resolve target avatar.\n"));
}
}
//-----------------------------------------------------------------------
void ChatServer::deletePersistentMessage(const NetworkId &id, const unsigned int messageId)
{
ChatServer::fileLog(false, "ChatServer", "deletePersistentMessage() id(%s) messageId(%u)", id.getValueString().c_str(), messageId);
const ChatAvatar *avatar = getAvatarByNetworkId(id);
if (avatar)
{
instance().chatInterface->RequestUpdatePersistentMessage(avatar, messageId, PERSISTENT_DELETED, NULL);
}
}
//-----------------------------------------------------------------------
ChatInterface *ChatServer::getChatInterface()
{
return instance().chatInterface;
}
//-----------------------------------------------------------------------
void ChatServer::destroyRoom(const NetworkId & id, const unsigned int sequence, const unsigned int roomId)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "destroyRoom() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId);
/* const ChatAvatar * avatar = getAvatarByNetworkId(id);
if(avatar)
{
ChatAvatarId destroyer(avatar->GetGameCode(), avatar->GetGameServerName(), avatar->GetCharacterName());
// can this avatar destroy the room?
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator i;
for(i = instance().chatInterface->getRoomList().begin(); i != instance().chatInterface->getRoomList().end(); ++i)
{
if((*i).second.getRoomData().id == roomId)
{
bool removeRoom = false;
if((*i).second.getRoomData().owner == destroyer)
removeRoom = true;
else if((*i).second.getRoomData().creator == destroyer)
removeRoom = true;
if(removeRoom)
{
std::string track = instance().chatInterface->DestroyRoom(sequence, roomId, avatar->GetCharacterName(), avatar->GetGameServerName(), avatar->GetGameCode());
instance().pendingRequests[track] = id;
}
else
{
ChatOnDestroyRoom destroy(sequence, CHAT_RESULT_FAIL_INSUFFICIENT_PRIVILEGES, roomId, destroyer); //lint !e641 enum to int
sendToClient(id, destroy);
}
break;
}
}
}*/
const ChatServerRoomOwner *owner = instance().chatInterface->getRoomOwner(roomId);
const ChatAvatar *avatar = getAvatarByNetworkId(id);
if (avatar && owner)
{
RoomOwnerSequencePair *pair = new RoomOwnerSequencePair(sequence, owner);
unsigned track = instance().chatInterface->RequestDestroyRoom(avatar, owner->getAddress(), (void *)pair);
instance().pendingRequests[track] = id;
}
}
//-----------------------------------------------------------------------
void ChatServer::destroyRoom(const std::string & roomName)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "destroyRoom() roomName(%s)", roomName.c_str());
if ((strstr(roomName.c_str(), ConfigChatServer::getClusterName()) != NULL) ||
(strstr(roomName.c_str(), toLower(std::string(ConfigChatServer::getClusterName() ) ).c_str() ) ))
{
if ((strstr(roomName.c_str(), "GroupChat") != NULL) || (strstr(roomName.c_str(), "groupchat") != NULL))
{
size_t pos = roomName.rfind(".");
if (pos != roomName.npos)
{
std::string tmpRoomName = roomName.substr(0, pos);
char lastChar = tmpRoomName[tmpRoomName.length() - 1];
if (lastChar >= '0' && lastChar <= '9')
{
ChatServer::destroyRoom(tmpRoomName);
return;
}
}
}
}
const ChatServerRoomOwner *owner = instance().chatInterface->getRoomOwner(roomName);
if (!instance().ownerSystem)
{
DEBUG_WARNING(true, ("Chat ownerSystem is NULL"));
return;
}
if (owner)
{
RoomOwnerSequencePair *pair = new RoomOwnerSequencePair(0, owner);
static Unicode::String wideAddr = Unicode::narrowToWide(std::string("SWG") + "+" + ConfigChatServer::getClusterName());
static ChatUnicodeString chatAddr(wideAddr.data(), wideAddr.size());
instance().chatInterface->RequestDestroyRoom(instance().ownerSystem, owner->getAddress(), (void *)pair);
}
}
//-----------------------------------------------------------------------
void ChatServer::disconnectAvatar(const ChatAvatar & avatar)
{
ChatServer::fileLog(false, "ChatServer", "disconnectAvatar() avatar(%s)", ChatServer::getFullChatAvatarName(&avatar).c_str());
if (&avatar == instance().ownerSystem)
{
instance().ownerSystem = NULL;
}
ChatAvatarList::iterator i;
for(i = instance().chatAvatars.begin(); i != instance().chatAvatars.end(); ++i)
{
if((*i).second.chatAvatar.getAvatarID() == avatar.getAvatarID())
{
disconnectPlayer((*i).first);
break;
}
}
}
//-----------------------------------------------------------------------
void ChatServer::disconnectPlayer(const NetworkId & id)
{
ChatServer::fileLog(false, "ChatServer", "disconnectPlayer() id(%s)", id.getValueString().c_str());
ChatAvatarList::iterator f = instance().chatAvatars.find(id);
if(f != instance().chatAvatars.end())
{
ChatServerAvatarOwner *owner = instance().chatInterface->getAvatarOwner(&((*f).second.chatAvatar));
ChatAvatarId avatarId;
makeAvatarId((*f).second.chatAvatar, avatarId);
instance().chatInterface->disconnectPlayer(avatarId);
instance().chatInterface->RequestLogoutAvatar(&((*f).second.chatAvatar), (void *)owner);
instance().chatAvatars.erase(f);
}
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::iterator cf = instance().clientMap.find(id);
if(cf != instance().clientMap.end())
{
instance().clientMap.erase(cf);
}
s_chatServerMetricsData->setClientCount(instance().clientMap.size());
VoiceChatAvatarList::iterator voiceMapItr = instance().m_voiceChatIdMap.find(id);
if(voiceMapItr != instance().m_voiceChatIdMap.end())
{
std::map<std::string,NetworkId>::iterator nameMapItr = instance().m_voiceChatNameToIdMap.find(toLower(voiceMapItr->second.playerName));
if(nameMapItr != instance().m_voiceChatNameToIdMap.end())
{
instance().m_voiceChatNameToIdMap.erase(nameMapItr);
}
nameMapItr = instance().m_voiceLoginNameToIdMap.find(toLower(voiceMapItr->second.loginName));
if(nameMapItr != instance().m_voiceLoginNameToIdMap.end())
{
instance().m_voiceLoginNameToIdMap.erase(nameMapItr);
}
instance().m_voiceChatIdMap.erase(voiceMapItr);
}
s_godClients.erase(id);
s_notSubscribedClients.erase(id);
}
//-----------------------------------------------------------------------
void ChatServer::enterRoom(const NetworkId & id, const unsigned int sequence, const unsigned int roomId)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "enterRoom() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId);
//REPORT_LOG(true, ("EnterRoom(%s, %u)\n", id.getValueString().c_str(), roomId));
const ChatAvatar * avatar = getAvatarByNetworkId(id);
const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomId);
if(avatar && room)
{
unsigned track = instance().chatInterface->RequestEnterRoom(avatar, room->getAddress(), (void *)sequence);
instance().pendingRequests[track] = id;
}
else
{
s_pendingEntersById.insert(std::make_pair(id, std::make_pair(sequence, roomId)));
}
}
//-----------------------------------------------------------------------
void ChatServer::enterRoom(const ChatAvatarId & id, const std::string & roomName, bool forceCreate, bool createPrivate)
{
canonicalizeAvatarId(id);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "enterRoom() id(%s) roomName(%s)", id.getFullName().c_str(), roomName.c_str());
const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomName);
const ChatAvatar *avatar = getAvatarByNetworkId(getNetworkIdByAvatarId(id));
if (room && avatar)
{
instance().chatInterface->RequestEnterRoom(avatar, room->getAddress(), NULL);
}
else
{
if(! room)
{
if(forceCreate)
{
// create a room for the avatar and wait for the OnCreateRoom to return
createRoom(NetworkId::cms_invalid, 0, roomName, false, !createPrivate, "");
s_pendingEntersByName.insert(std::make_pair(toLower(roomName), id)); // for game server generated requests
}
}
//REPORT_LOG(!room, ("room is not found\n"));
//REPORT_LOG(!avatar, ("avatar is not found\n"));
}
}
//-----------------------------------------------------------------------
void ChatServer::putSystemAvatarInRoom(const std::string & roomName)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "putSystemAvatarInRoom() roomName(%s)", roomName.c_str());
const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomName);
if (room && instance().ownerSystem)
{
instance().chatInterface->RequestEnterRoom(instance().ownerSystem, room->getAddress(), NULL);
}
}
//-----------------------------------------------------------------------
void ChatServer::enterRoom(const NetworkId & id, const unsigned int sequence, const std::string & roomName)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "enterRoom() id(%s) sequence(%u) roomName(%s)", id.getValueString().c_str(), sequence, roomName.c_str());
//REPORT_LOG(true, ("enterRoom3(%s, %s)\n", id.getValueString().c_str(), roomName.c_str()));
const ChatAvatar * avatar = getAvatarByNetworkId(id);
if(avatar)
{
unsigned errorCode = CHATRESULT_SUCCESS;
unsigned roomId = 0;
const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
// We can now get a room ID
roomId = roomOwner->getRoomData().id;
// prevent players from requesting to enter/leave system rooms
if((roomName.rfind(".") != std::string::npos))
{
std::string leaf = roomName.substr(0, roomName.rfind("."));
std::string lowerLeaf = toLower(leaf);
if(lowerLeaf != toLower(ChatRoomTypes::ROOM_SYSTEM))
{
const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomName);
if (room)
{
unsigned track = instance().chatInterface->RequestEnterRoom(avatar, room->getAddress(), (void *)sequence);
instance().pendingRequests[track] = id;
return;
}
}
}
errorCode = CHATRESULT_ROOM_UNKNOWNFAILURE;
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId avatarId;
makeAvatarId(*avatar, avatarId);
ChatOnEnteredRoom fail(sequence, errorCode, roomId, avatarId); //lint !e641 enum to int
sendToClient(id, fail);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::unbanFromRoom(const unsigned sequence, const NetworkId &banner, const ChatAvatarId &bannee, const std::string &roomName)
{
canonicalizeAvatarId(bannee);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "unbanFromRoom() sequence(%u) banner(%s) bannee(%s) roomName(%s)", sequence, banner.getValueString().c_str(), bannee.getFullName().c_str(), roomName.c_str());
const ChatAvatar *bannerAvatar = getAvatarByNetworkId(banner);
if (bannerAvatar)
{
unsigned errorCode = CHATRESULT_SUCCESS;
const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
Unicode::String banName;
Unicode::String banAddress;
splitChatAvatarId(bannee, banName, banAddress);
AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequence, bannee);
unsigned track = instance().chatInterface->RequestRemoveBan(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = banner;
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId bannerAvatarId;
makeAvatarId(*bannerAvatar, bannerAvatarId);
ChatOnUnbanAvatarFromRoom msg(sequence, errorCode, roomName, bannerAvatarId, bannee);
instance().chatInterface->sendMessageToAvatar(bannerAvatarId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::banFromRoom(const unsigned sequence, const NetworkId &banner, const ChatAvatarId &bannee, const std::string &roomName)
{
canonicalizeAvatarId(bannee);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "banFromRoom() sequence(%u) banner(%s) bannee(%s) roomName(%s)", sequence, banner.getValueString().c_str(), bannee.getFullName().c_str(), roomName.c_str());
// can't ban god accounts
NetworkId networkId = getNetworkIdByAvatarId(bannee);
if(isGod(networkId))
{
return;
}
const ChatAvatar *bannerAvatar = getAvatarByNetworkId(banner);
if (bannerAvatar)
{
unsigned errorCode = CHATRESULT_SUCCESS;
const ChatServerRoomOwner *roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
Unicode::String banName;
Unicode::String banAddress;
splitChatAvatarId(bannee, banName, banAddress);
// Remove the bannee from the invited list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, bannee);
instance().chatInterface->RequestRemoveInvite(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair);
}
// Remove the bannee from the moderator list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, bannee);
instance().chatInterface->RequestRemoveModerator(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair);
}
// Ban the avatar
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(sequence, bannee);
unsigned track = instance().chatInterface->RequestAddBan(bannerAvatar, banName, banAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = banner;
}
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId bannerAvatarId;
makeAvatarId(*bannerAvatar, bannerAvatarId);
ChatOnBanAvatarFromRoom msg(sequence, errorCode, roomName, bannerAvatarId, bannee);
instance().chatInterface->sendMessageToAvatar(bannerAvatarId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::invite(const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName)
{
canonicalizeAvatarId(avatarId);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "invite() id(%s) avatar(%s) roomName(%s)", id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str());
// Try to get an invitor
ChatAvatar const * invitor = NULL;
if (id != NetworkId::cms_invalid)
{
invitor = getAvatarByNetworkId(id);
}
else
{
invitor = instance().ownerSystem;
}
if (invitor)
{
unsigned errorCode = CHATRESULT_SUCCESS;
ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
Unicode::String inviteName;
Unicode::String inviteAddress;
splitChatAvatarId(avatarId, inviteName, inviteAddress);
// Remove the avatar from the banned list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId);
instance().chatInterface->RequestRemoveBan(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair);
}
// Invite the avatar
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId);
unsigned track = instance().chatInterface->RequestAddInvite(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = id;
}
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId invitorId;
makeAvatarId(*invitor, invitorId);
ChatOnInviteToRoom msg(errorCode, roomName, invitorId, avatarId);
instance().chatInterface->sendMessageToAvatar(invitorId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::inviteGroupMembers(const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName, const stdvector<NetworkId>::fwd & members)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "inviteGroupMembers() id(%s) avatarId(%s) roomName(%s) number of members (%u)", id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str(), members.size());
// Try to get an invitor
ChatAvatar const * const invitor = getAvatarByNetworkId(id);
if (invitor)
{
unsigned errorCode = CHATRESULT_SUCCESS;
ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
// Invite each member
for (unsigned i = 0; i < members.size(); ++i)
{
NetworkId const & memberNetworkId = members[i];
ChatAvatar const * const memberAvatar = getAvatarByNetworkId(memberNetworkId);
if (memberAvatar)
{
ChatAvatarId memberId;
makeAvatarId(*memberAvatar, memberId);
// Break up the member name
Unicode::String inviteName;
Unicode::String inviteAddress;
splitChatAvatarId(memberId, inviteName, inviteAddress);
// Remove the avatar from the banned list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, memberId);
instance().chatInterface->RequestRemoveBan(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair);
}
// Invite the avatar
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, memberId);
unsigned track = instance().chatInterface->RequestAddInvite(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = id;
}
}
}
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId invitorId;
makeAvatarId(*invitor, invitorId);
ChatOnInviteGroupToRoom msg(errorCode, roomName, invitorId, avatarId);
instance().chatInterface->sendMessageToAvatar(invitorId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::removeSystemAvatarFromRoom(const ChatRoom *room)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeSystemAvatarFromRoom() room(%s)", (room != NULL) ? toNarrowString(room->getRoomName()).c_str() : "NULL");
if (!room || !instance().ownerSystem)
{
return;
}
AvatarIterator i = room->getFirstAvatar();
if (!i.outOfBounds())
{
if ((*i) != instance().ownerSystem)
{
return;
}
}
instance().chatInterface->RequestLeaveRoom(instance().ownerSystem, room->getAddress(), NULL);
}
//-----------------------------------------------------------------------
void ChatServer::leaveRoom(const NetworkId & id, const unsigned int sequence, const unsigned int roomId)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "leaveRoom() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId);
const ChatAvatar * avatar = getAvatarByNetworkId(id);
if (avatar)
{
unsigned errorCode = CHATRESULT_SUCCESS;
// Try to get the room
ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomId);
if (roomOwner)
{
unsigned track = instance().chatInterface->RequestLeaveRoom(avatar, roomOwner->getAddress(), (void *)sequence);
instance().pendingRequests[track] = id;
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId avatarId;
makeAvatarId(*avatar, avatarId);
ChatOnLeaveRoom msg(sequence, errorCode, roomId, avatarId);
instance().chatInterface->sendMessageToAvatar(avatarId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::removeAvatarFromRoom(const NetworkId & id, const ChatAvatarId & avatarName, const std::string & roomName)
{
canonicalizeAvatarId(avatarName);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeAvatarFromRoom() id(%s) avatarName(%s) roomName(%s)", id.getValueString().c_str(), avatarName.getFullName().c_str(), roomName.c_str());
const ChatAvatar * avatar = getAvatarByNetworkId(id);
if (avatar != nullptr) {
ChatAvatarId removerId;
makeAvatarId(*avatar, removerId);
size_t pos = roomName.rfind(".");
std::string leaf;
if (pos != std::string::npos)
{
leaf = toLower(roomName.substr(pos));
}
//REPORT_LOG(true, ("removeAvatarFromRoom()\n"));
if (avatar)
{
bool removeAvatar = false;
if (avatarName == removerId)
{
// avatar is attempting to remove self from the room
if (leaf != ".system")
removeAvatar = true;
}
else if (isGod(id))
{
removeAvatar = true;
}
else
{
const ChatServerRoomOwner * r = instance().chatInterface->getRoomByName(roomName);
if (r)
{
// if the avatar is the room owner, remove the target
if (r->getRoomData().owner == removerId)
{
removeAvatar = true;
}
// if the avatar is the room creator, remove the target
else if (r->getRoomData().creator == removerId)
{
removeAvatar = true;
}
// if the avatar is a moderator, remove the target
else
{
/*MLSTODO if(r->getRoom())
{
AvatarIterator i = r->getRoom()->getFirstModerator();
for(; !i.outOfBounds(); ++i)
{
ChatAvatarId tmpAvatarId;
makeAvatarId(*(*i), tmpAvatarId);
if(tmpAvatarId == removerId)
{
removeAvatar = true;
break;
}
}
}
*/
}
}
}
if (removeAvatar)
{
const ChatServerRoomOwner * r = instance().chatInterface->getRoomByName(roomName);
const NetworkId &id = getNetworkIdByAvatarId(avatarName);
if (r)
{
leaveRoom(id, 0, r->getRoomData().id);
}
}
}
}
}
//-----------------------------------------------------------------------
void ChatServer::removeAvatarFromRoom(const ChatAvatarId & avatarName, const std::string & roomName)
{
canonicalizeAvatarId(avatarName);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "removeAvatarFromRoom() avatarName(%s) roomName(%s)", avatarName.getFullName().c_str(), roomName.c_str());
const ChatServerRoomOwner * r = instance().chatInterface->getRoomByName(roomName);
const NetworkId &id = getNetworkIdByAvatarId(avatarName);
if (r)
{
leaveRoom(id, 0, r->getRoomData().id);
}
}
//-----------------------------------------------------------------------
void ChatServer::kickAvatarFromRoom(const NetworkId & id, const ChatAvatarId & avatarId, const std::string & roomName)
{
canonicalizeAvatarId(avatarId);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "kickAvatarFromRoom() moderator(%s) avatarName(%s) roomName(%s)", id.getValueString().c_str(), avatarId.getFullName().c_str(), roomName.c_str());
unsigned errorCode = CHATRESULT_SUCCESS;
ChatAvatar const * const moderatorChatAvatar = getAvatarByNetworkId(id);
if (moderatorChatAvatar)
{
ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomByName(roomName);
if (roomOwner)
{
Unicode::String kickName;
Unicode::String kickAddress;
splitChatAvatarId(avatarId, kickName, kickAddress);
// Remove the avatar from the invited list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId);
instance().chatInterface->RequestRemoveInvite(moderatorChatAvatar, kickName, kickAddress, roomOwner->getAddress(), (void *)pair);
}
// Remove the avatar from the moderator list
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId);
instance().chatInterface->RequestRemoveModerator(moderatorChatAvatar, kickName, kickAddress, roomOwner->getAddress(), (void *)pair);
}
// Kick the avatar from the room
{
AvatarIdSequencePair *pair = new AvatarIdSequencePair(0, avatarId);
unsigned track = instance().chatInterface->RequestKickAvatar(moderatorChatAvatar, kickName, kickAddress, roomOwner->getAddress(), (void*)pair);
instance().pendingRequests[track] = id;
}
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId moderatorAvatarId;
makeAvatarId(*moderatorChatAvatar, moderatorAvatarId);
ChatOnKickAvatarFromRoom msg(errorCode, moderatorAvatarId, avatarId, roomName);
instance().chatInterface->sendMessageToAvatar(moderatorAvatarId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::queryRoom(const NetworkId & id, ConnectionServerConnection * connection, const unsigned int sequence, const std::string & roomName)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "queryRoom() id(%s) roomName(%s)", id.getValueString().c_str(), roomName.c_str());
instance().chatInterface->queryRoom(id, connection, sequence, roomName);
}
//-----------------------------------------------------------------------
void ChatServer::requestPersistentMessage(const NetworkId &id, const unsigned int sequence, const unsigned int messageId)
{
ChatServer::fileLog(false, "ChatServer", "requestPersistentMessage() id(%s) sequence(%u) messageId(%u)", id.getValueString().c_str(), sequence, messageId);
const ChatAvatar * avatar = getAvatarByNetworkId(id);
if (avatar)
{
IGNORE_RETURN(instance().chatInterface->RequestGetPersistentMessage(avatar, messageId, (void *)sequence));
}
else
{
LOG("ChatServer", ("requestPersistentMessage() id(%s) Unable to resolve network id to ChatAvatar, request failed", id.getValueString().c_str()));
}
}
//-----------------------------------------------------------------------
void ChatServer::requestRoomList(const NetworkId & id, ConnectionServerConnection * connection)
{
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "requestRoomList() id(%s) connection(%s)", id.getValueString().c_str(), getConnectionAddress(connection).c_str());
instance().chatInterface->requestRoomList(id, connection);
}
//-----------------------------------------------------------------------
//This is for system messages only
void ChatServer::sendInstantMessage(const ChatAvatarId & from, const ChatAvatarId & to, const Unicode::String & message, const Unicode::String & outOfBand)
{
canonicalizeAvatarId(from);
canonicalizeAvatarId(to);
ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() from(%s) to(%s)", from.getFullName().c_str(), to.getFullName().c_str());
const NetworkId &toNetworkId = getNetworkIdByAvatarId(to);
const ChatAvatar * toAvatar = getAvatarByNetworkId(toNetworkId);
if (toAvatar != NULL)
{
ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() resolved tell locally");
ChatAvatarId toId;
makeAvatarId(*toAvatar, toId);
ChatSystemMessage chat(ChatSystemMessage::PERSONAL, message, outOfBand); //lint !e641 enum to int
instance().chatInterface->sendMessageToAvatar(toId, chat);
}
else
{
ChatSystemMessage chat(ChatSystemMessage::PERSONAL, message, outOfBand); //lint !e641 enum to int
bool success = instance().chatInterface->sendMessageToPendingAvatar(to, chat);
if (!success)
{
//I don't know who this is, send it to the chat api
const NetworkId &fromNetworkId = getNetworkIdByAvatarId(from);
const ChatAvatar * fromAvatar = getAvatarByNetworkId(fromNetworkId);
if (fromAvatar)
{
ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() sending tell through chat API");
Unicode::String friendName;
Unicode::String friendAddress;
splitChatAvatarId(to, friendName, friendAddress);
IGNORE_RETURN(instance().chatInterface->RequestSendInstantMessage(fromAvatar,
ChatUnicodeString(friendName.data(), friendName.size()),
ChatUnicodeString(friendAddress.data(), friendAddress.size()),
ChatUnicodeString(message.data(), message.size()), ChatUnicodeString(outOfBand.data(), outOfBand.size()), NULL));
}
}
}
Unicode::String const wideTo(Unicode::narrowToWide(to.getFullName()));
Unicode::String const wideFrom(Unicode::narrowToWide(from.getFullName()));
if(from != getSystemAvatarId())
{
ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, message, s_channelTell);
ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, message, s_channelTell);
}
}
//-----------------------------------------------------------------------
void ChatServer::sendInstantMessage(const NetworkId & fromId, const unsigned int sequence, const ChatAvatarId & n, const Unicode::String & message, const Unicode::String & oob)
{
canonicalizeAvatarId(n);
ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() fromId(%s) sequence(%u) toName(%s)", fromId.getValueString().c_str(), sequence, n.getFullName().c_str());
ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(fromId);
if (aed)
{
// see if player is squelched
if (aed->unsquelchTime != 0)
{
if (aed->unsquelchTime < 0) // squelched indefinitely
{
return;
}
else if (::time(NULL) < aed->unsquelchTime) // still in squelch period
{
return;
}
else // squelch has expired
{
aed->unsquelchTime = 0;
}
}
unsigned int const maxTellLength = 512;
if(message.length() < maxTellLength)
{
const ChatAvatar * from = &(aed->chatAvatar);
const NetworkId &toNetworkId = getNetworkIdByAvatarId(n);
const ChatAvatar * toAvatar = getAvatarByNetworkId(toNetworkId);
ChatAvatarId fromAvatarId;
Unicode::String wideFrom;
Unicode::String wideTo;
if (from != NULL)
{
makeAvatarId(*from, fromAvatarId);
wideFrom = (Unicode::narrowToWide(fromAvatarId.getFullName()));
}
ChatAvatarId toAvatarId;
if (toAvatar != NULL)
{
ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() resolved tell locally");
makeAvatarId(*toAvatar, toAvatarId);
wideTo = Unicode::narrowToWide(toAvatarId.getFullName());
if (from)
{
ChatInstantMessageToClient chat(fromAvatarId, message, oob);
instance().chatInterface->sendMessageToAvatar(toAvatarId, chat);
ChatOnSendInstantMessage chat2(sequence, 0);
IGNORE_RETURN(instance().chatInterface->sendMessageToAvatar(fromAvatarId, chat2));
}
if(fromAvatarId != getSystemAvatarId())
{
ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, message, s_channelTell);
}
}
else
{
ChatServer::fileLog(false, "ChatServer", "sendInstantMessage() sending tell through chat API");
wideTo = Unicode::narrowToWide(n.getFullName());
Unicode::String friendName;
Unicode::String friendAddress;
splitChatAvatarId(n, friendName, friendAddress);
unsigned track = instance().chatInterface->RequestSendInstantMessage(from,
ChatUnicodeString(friendName.data(), friendName.size()),
ChatUnicodeString(friendAddress.data(), friendAddress.size()),
ChatUnicodeString(message.data(), message.size()), ChatUnicodeString(oob.data(), oob.size()), (void *)sequence);
instance().pendingRequests[track] = fromId;
}
if(fromAvatarId != getSystemAvatarId())
{
ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, message, s_channelTell);
}
}
else
{
ChatServer::fileLog(true, "ChatServer", "sendInstantMessage() ERROR: Unable to send tell longer than %u", maxTellLength);
//ChatOnSendInstantMessage chat(sequence, CHAT_RESULT_FAIL_INSUFFICIENT_PRIVILEGES); //lint !e641 enum to int
//sendToClient(fromId, chat);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::sendPersistentMessage(const ChatAvatarId & from, const ChatAvatarId & to, const Unicode::String & subject, const Unicode::String & message, const Unicode::String & oob)
{
canonicalizeAvatarId(from);
canonicalizeAvatarId(to);
ChatServer::fileLog(false, "ChatServer", "sendPersistentMessage() from(%s) to(%s) subject(%s)", from.getFullName().c_str(), to.getFullName().c_str(), Unicode::wideToNarrow(subject).c_str());
Unicode::String wideFromName(Unicode::narrowToWide(from.name));
Unicode::String friendName;
Unicode::String friendAddress;
splitChatAvatarId(to, friendName, friendAddress);
instance().chatInterface->RequestSendPersistentMessage(
ChatUnicodeString(wideFromName.data(), wideFromName.size()),
ChatUnicodeString(friendName.data(), friendName.size()),
ChatUnicodeString(friendAddress.data(), friendAddress.size()),
ChatUnicodeString(subject.data(), subject.size()),
ChatUnicodeString(message.data(), message.size()),
ChatUnicodeString(oob.data(), oob.size()),
NULL
);
Unicode::String log;
log.append(Unicode::narrowToWide("[subject] "));
log.append(subject);
log.append(Unicode::narrowToWide(" "));
log.append(Unicode::narrowToWide("[message] "));
log.append(message);
Unicode::String const wideTo(Unicode::narrowToWide(to.getFullName()));
Unicode::String const wideFrom(Unicode::narrowToWide(from.getFullName()));
ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, log, ChatServer::getChannelEmail());
ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, log, ChatServer::getChannelEmail());
}
//-----------------------------------------------------------------------
void ChatServer::sendPersistentMessage(const NetworkId & fromId, const unsigned int sequenceId, const ChatAvatarId & to, const Unicode::String & subject, const Unicode::String & message, const Unicode::String & oob)
{
canonicalizeAvatarId(to);
ChatServer::fileLog(false, "ChatServer", "sendPersistentMessage() fromId(%s) sequence(%u) to(%s) subject(%s)", fromId.getValueString().c_str(), sequenceId, to.getFullName().c_str(), Unicode::wideToNarrow(subject).c_str());
// printf("Sending a message to %s.%s.%s\n", to.gameCode.c_str(),
// to.cluster.c_str(), to.name.c_str());
UNREF(sequenceId);
ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(fromId);
const ChatAvatar * from = (aed ? &(aed->chatAvatar) : NULL);
if(from)
{
// see if player is squelched
if (aed->unsquelchTime != 0)
{
if (aed->unsquelchTime < 0) // squelched indefinitely
{
return;
}
else if (::time(NULL) < aed->unsquelchTime) // still in squelch period
{
return;
}
else // squelch has expired
{
aed->unsquelchTime = 0;
}
}
Unicode::String friendName;
Unicode::String friendAddress;
splitChatAvatarId(to, friendName, friendAddress);
unsigned track = instance().chatInterface->RequestSendPersistentMessage(
from,
ChatUnicodeString(friendName.data(), friendName.size()),
ChatUnicodeString(friendAddress.data(), friendAddress.size()),
ChatUnicodeString(subject.data(), subject.size()),
ChatUnicodeString(message.data(), message.size()),
ChatUnicodeString(oob.data(), oob.size()),
(void *)sequenceId
);
instance().pendingRequests[track] = fromId;
}
ChatAvatarId fromAvatarId;
if (from != NULL)
{
makeAvatarId(*from, fromAvatarId);
}
Unicode::String log;
log.append(Unicode::narrowToWide("[subject] "));
log.append(subject);
log.append(Unicode::narrowToWide(" "));
log.append(Unicode::narrowToWide("[message] "));
log.append(message);
Unicode::String const wideTo(Unicode::narrowToWide(to.getFullName()));
Unicode::String const wideFrom(Unicode::narrowToWide(fromAvatarId.getFullName()));
ChatServer::instance().logChatMessage(wideTo, wideFrom, wideTo, log, ChatServer::getChannelEmail());
ChatServer::instance().logChatMessage(wideFrom, wideFrom, wideTo, log, ChatServer::getChannelEmail());
}
//-----------------------------------------------------------------------
//for system avatars
void ChatServer::sendRoomMessage(const ChatAvatarId &id, const std::string & roomName, const Unicode::String & msg, const Unicode::String & oob)
{
if(! msg.empty() || !oob.empty())
{
UNREF(id);
ChatServer::fileLog(false, "ChatServer", "sendRoomMessage() id(%s) roomName(%s)", id.getFullName().c_str(), roomName.c_str());
if (!instance().ownerSystem)
{
DEBUG_WARNING(true, ("Chat ownerSystem is NULL"));
return;
}
// get room id
std::string lowerName = toLower(roomName);
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator f = instance().chatInterface->getRoomList().find(lowerName);
if(f != instance().chatInterface->getRoomList().end())
{
const ChatAvatar *sender = instance().ownerSystem;
IGNORE_RETURN(instance().chatInterface->RequestSendRoomMessage(sender, (*f).second.getAddress(), ChatUnicodeString(msg.data(), msg.size()), ChatUnicodeString(oob.data(), oob.size()), NULL));
}
}
}
//-----------------------------------------------------------------------
void ChatServer::sendRoomMessage(const NetworkId & id, const unsigned int sequence, const unsigned int roomId, const Unicode::String &msg, const Unicode::String & oob)
{
if(!msg.empty() || !oob.empty())
{
ChatServer::fileLog(false, "ChatServer", "sendRoomMessage() id(%s) sequence(%u) roomId(%u)", id.getValueString().c_str(), sequence, roomId);
UNREF(sequence);
ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(id);
const ChatAvatar * sender = (aed ? &(aed->chatAvatar) : NULL);
const ChatServerRoomOwner *room = instance().chatInterface->getRoomOwner(roomId);
if(sender && room)
{
if(msg.length() < 512)
{
// track amount of room chat for the character, except for group chat
time_t timeNow = 0;
bool allowToSpeak = true;
bool squelched = false;
if (!room->isGroupChatRoom())
{
// update chat character count
aed->nonSpatialCharCount += msg.size();
// sync chat character count with game server
timeNow = ::time(NULL);
if ((timeNow > aed->chatSpamNextTimeToSyncWithGameServer) || (timeNow > aed->chatSpamTimeEndInterval))
{
GenericValueTypeMessage<std::pair<std::pair<NetworkId, int>, std::pair<int, int> > > chatStatistics("ChatStatisticsCS", std::make_pair(std::make_pair(id, static_cast<int>(aed->chatSpamTimeEndInterval)), std::make_pair(aed->spatialCharCount, aed->nonSpatialCharCount)));
sendToClient(id, chatStatistics);
aed->chatSpamNextTimeToSyncWithGameServer = timeNow + ConfigChatServer::getChatStatisticsReportIntervalSeconds();
}
// see if player has exceeded chat limit
if (ConfigChatServer::getChatSpamLimiterEnabledForFreeTrial() &&
!aed->isSubscribed &&
(aed->chatSpamTimeEndInterval > timeNow) &&
((aed->spatialCharCount + aed->nonSpatialCharCount) > ConfigChatServer::getChatSpamLimiterNumCharacters()))
{
allowToSpeak = false;
}
}
// see if player is squelched
if (allowToSpeak && (aed->unsquelchTime != 0))
{
if (aed->unsquelchTime < 0) // squelched indefinitely
{
allowToSpeak = false;
squelched = true;
}
else if (::time(NULL) < aed->unsquelchTime) // still in squelch period
{
allowToSpeak = false;
squelched = true;
}
else // squelch has expired
{
aed->unsquelchTime = 0;
}
}
if (allowToSpeak)
{
// character allowed to talk
unsigned track = instance().chatInterface->RequestSendRoomMessage(sender, room->getAddress(), ChatUnicodeString(msg.data(), msg.size()), ChatUnicodeString(oob.data(), oob.size()), (void *)sequence);
instance().pendingRequests[track] = id;
}
else if (!squelched && (ConfigChatServer::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds() > 0) && (timeNow >= aed->chatSpamNextTimeToNotifyPlayerWhenLimited))
{
// send message telling character he can no longer talk
GenericValueTypeMessage<int> csl("ChatSpamLimited", static_cast<int>(aed->chatSpamTimeEndInterval - timeNow));
sendToClient(id, csl);
aed->chatSpamNextTimeToNotifyPlayerWhenLimited = timeNow + ConfigChatServer::getChatSpamNotifyPlayerWhenLimitedIntervalSeconds();
}
}
else
{
//ChatOnSendRoomMessage chat(sequence, CHAT_RESULT_FAIL_INSUFFICIENT_PRIVILEGES); //lint !e641 enum to int
//sendToClient(id, chat);
}
}
}
}
//-----------------------------------------------------------------------
void ChatServer::sendStandardRoomMessage(const ChatAvatarId &senderId, const std::string & roomName, const Unicode::String & msg, const Unicode::String & oob)
{
if(!msg.empty() || !oob.empty())
{
canonicalizeAvatarId(senderId);
ChatServer::fileLog(false, "ChatServer", "sendStandardRoomMessage() senderId(%s) roomName(%s)", senderId.getFullName().c_str(), roomName.c_str());
std::string systemRoom = toLower(std::string("SWG.") + ConfigChatServer::getClusterName() + std::string(".system"));
// get room id
std::string lowerName = toLower(roomName);
if (lowerName == systemRoom)
{
ChatSystemMessage chat(ChatSystemMessage::BROADCAST, msg,
oob); //lint !e641 enum to int
instance().chatInterface->sendMessageToAllAvatars(chat);
return;
}
std::unordered_map<std::string, ChatServerRoomOwner>::const_iterator f = instance().chatInterface->getRoomList().find(lowerName);
if(f != instance().chatInterface->getRoomList().end())
{
const ChatAvatar *sender;
if (senderId.name == "SYSTEM" || senderId.name == "system")
{
sender = instance().ownerSystem;
}
else
{
sender = getAvatarByNetworkId(getNetworkIdByAvatarId(senderId));
}
if (sender)
{
IGNORE_RETURN(instance().chatInterface->RequestSendRoomMessage(sender, (*f).second.getAddress(), ChatUnicodeString(msg.data(), msg.size()), ChatUnicodeString(oob.data(), oob.size()), NULL));
}
}
}
}
//-----------------------------------------------------------------------
void ChatServer::uninvite(const NetworkId &id , const unsigned int sequence, const ChatAvatarId &avatarId , const std::string &roomName )
{
canonicalizeAvatarId(avatarId);
ChatServer::fileLog(s_enableChatRoomLogs, "ChatServer", "uninvite() id(%s) sequence(%u) avatarId(%s) roomName(%s)", id.getValueString().c_str(), sequence, avatarId.getFullName().c_str(), roomName.c_str());
// Try to get the invitor
ChatAvatar const * invitor = getAvatarByNetworkId(id);
if (invitor)
{
unsigned errorCode = CHATRESULT_SUCCESS;
// Try to get the room
ChatServerRoomOwner const * const roomOwner = instance().chatInterface->getRoomOwner(roomName);
if (roomOwner)
{
Unicode::String inviteName;
Unicode::String inviteAddress;
splitChatAvatarId(avatarId, inviteName, inviteAddress);
AvatarIdSequencePair * pair = new AvatarIdSequencePair(sequence, avatarId);
unsigned track = instance().chatInterface->RequestRemoveInvite(invitor, inviteName, inviteAddress, roomOwner->getAddress(), (void *)pair);
instance().pendingRequests[track] = id;
}
else
{
errorCode = CHATRESULT_ADDRESSNOTROOM;
}
if (errorCode != CHATRESULT_SUCCESS)
{
ChatAvatarId invitorId;
makeAvatarId(*invitor, invitorId);
ChatOnUninviteFromRoom msg(sequence, errorCode, roomName, invitorId, avatarId);
instance().chatInterface->sendMessageToAvatar(invitorId, msg);
}
}
}
//-----------------------------------------------------------------------
void ChatServer::removeConnectionServerConnection(ConnectionServerConnection * target)
{
ChatServer::fileLog(false, "ChatServer", "removeConnectionServerConnection() target(%s)", getConnectionAddress(target).c_str());
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash> tmpList = instance().clientMap;
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::const_iterator i;
for(i = tmpList.begin(); i != tmpList.end(); ++i)
{
if((*i).second == target)
disconnectPlayer((*i).first);
std::unordered_map<NetworkId, ConnectionServerConnection *, NetworkId::Hash>::iterator f = instance().clientMap.find((*i).first);
if (f != instance().clientMap.end())
{
instance().clientMap.erase(f);
}
}
std::set<ConnectionServerConnection *>::iterator ci = instance().connectionServerConnections.find(target);
if (ci != instance().connectionServerConnections.end())
{
instance().connectionServerConnections.erase(ci);
}
s_chatServerMetricsData->setConnectionServerConnectionCount(instance().connectionServerConnections.size());
}
//-----------------------------------------------------------------------
void ChatServer::sendToAllConnectionServers(const GameNetworkMessage &message)
{
ChatServer::fileLog(false, "ChatServer", "sendToAllConnectionServers() message(%s)", message.getCmdName().c_str());
std::set<ConnectionServerConnection *>::const_iterator i;
for(i = instance().connectionServerConnections.begin(); i != instance().connectionServerConnections.end(); ++i)
{
ConnectionServerConnection * c = (*i);
c->sendToClient(NetworkId::cms_invalid, message);
}
}
// ----------------------------------------------------------------------
void ChatServer::broadcastToGameServers(const GameNetworkMessage &message)
{
ChatServer::fileLog(false, "ChatServer", "broadcastToGameServers() message(%s)", message.getCmdName().c_str());
if (instance().gameService)
{
static Archive::ByteStream bs;
bs.clear();
message.pack(bs);
instance().gameService->broadcast(bs, true);
}
}
// ----------------------------------------------------------------------
std::string ChatServer::getFullChatAvatarName(ChatAvatar const *chatAvatar)
{
std::string result;
if (chatAvatar != NULL)
{
result += toNarrowString(chatAvatar->getName());
result += '.';
result += toNarrowString(chatAvatar->getAddress());
}
else
{
result = "NULL";
}
return result;
}
// ----------------------------------------------------------------------
std::string ChatServer::toNarrowString(ChatUnicodeString const &chatUnicodeString)
{
std::string result;
for (unsigned int index = 0; index < chatUnicodeString.string_length; ++index)
{
result += static_cast<char>(chatUnicodeString.string_data[index]);
}
return result;
}
// ----------------------------------------------------------------------
std::string ChatServer::getConnectionAddress(Connection const *connection)
{
std::string result;
if (connection != NULL)
{
char text[256];
snprintf(text, sizeof(text), "%s:%d", connection->getRemoteAddress().c_str(), connection->getRemotePort());
result = text;
}
else
{
result = "NULL";
}
return result;
}
// ----------------------------------------------------------------------
std::string ChatServer::getChatRoomNameNarrow(ChatRoom const *chatRoom)
{
return Unicode::wideToNarrow(getChatRoomName(chatRoom));
}
// ----------------------------------------------------------------------
Unicode::String ChatServer::getChatRoomName(ChatRoom const *chatRoom)
{
Unicode::String result;
if (chatRoom != NULL)
{
result = toUnicodeString(chatRoom->getRoomName());
}
else
{
result = Unicode::narrowToWide("NULL");
}
return result;
}
// ----------------------------------------------------------------------
void ChatServer::clearCustomerServiceServerConnection()
{
if (instance().customerServiceServerConnection != NULL)
{
instance().customerServiceServerConnection->disconnect();
}
instance().customerServiceServerConnection = NULL;
}
// ----------------------------------------------------------------------
void ChatServer::connectToCustomerServiceServer(const std::string &address, const unsigned short port)
{
//DEBUG_REPORT_LOG(true, ("***ChatServer::connectToCustomerServiceServer() address(%s) port(%d)\n", address.c_str(), port));
if (instance().customerServiceServerConnection != NULL)
{
instance().customerServiceServerConnection->disconnect();
}
instance().customerServiceServerConnection = new CustomerServiceServerConnection(address, port);
}
// ----------------------------------------------------------------------
bool ChatServer::isValidChatAvatarName(Unicode::String const &chatAvatarName)
{
// This function is retarded. We need to get an API call to determine if a chat avatar name is valid
std::string lowerNarrowName(Unicode::toLower(Unicode::wideToNarrow(chatAvatarName)));
//DEBUG_REPORT_LOG(true, ("ChatServer::isValidChatAvatarName() chatAvatarName(%s)\n", lowerNarrowName.c_str()));
bool result = false;
ChatAvatarList::const_iterator iterChatAvatars = instance().chatAvatars.begin();
for (; iterChatAvatars != instance().chatAvatars.end(); ++iterChatAvatars)
{
ChatAvatar const *chatAvatar = &(iterChatAvatars->second.chatAvatar);
if (toNarrowString(chatAvatar->getName()) == lowerNarrowName)
{
result = true;
break;
}
}
if (result == false)
{
// How many dots are in this name
int dotCount = 0;
for (unsigned int i = 0; i < lowerNarrowName.length(); ++i)
{
if (lowerNarrowName[i] == '.')
{
++dotCount;
}
}
// Tack on extra code info for the name match
Unicode::String const wideDot(Unicode::narrowToWide("."));
Unicode::String searchAvatarName;
if (dotCount == 0)
{
searchAvatarName = Unicode::narrowToWide(instance().systemAvatarId.gameCode) + wideDot + Unicode::narrowToWide(instance().systemAvatarId.cluster) + wideDot + chatAvatarName;
}
else if (dotCount == 1)
{
searchAvatarName = Unicode::narrowToWide(instance().systemAvatarId.gameCode) + wideDot + chatAvatarName;
}
else
{
searchAvatarName = chatAvatarName;
}
result = ChatLogManager::isPlayerInLogs(searchAvatarName);
}
return result;
}
// ----------------------------------------------------------------------
void ChatServer::logChatMessage(Unicode::String const &logPlayer, Unicode::String const &fromPlayer, Unicode::String const &toPlayer, Unicode::String const &text, Unicode::String const &channel)
{
DEBUG_WARNING(toPlayer.empty(), ("toPlayer is NULL"));
Unicode::String lowerLogPlayer(Unicode::toLower(logPlayer));
Unicode::String lowerFromPlayer(Unicode::toLower(fromPlayer));
Unicode::String lowerToPlayer(Unicode::toLower(toPlayer));
ChatServer::fileLog(false, "ChatServer", "logChatMessage() logPlayer(%s) fromPlayer(%s) toPlayer(%s) channel(%s) text(%s)", Unicode::wideToNarrow(lowerLogPlayer).c_str(), Unicode::wideToNarrow(lowerFromPlayer).c_str(), Unicode::wideToNarrow(lowerToPlayer).c_str(), Unicode::wideToNarrow(channel).c_str(), Unicode::wideToNarrow(text).c_str());
int const messageIndex = ChatLogManager::getNextMessageIndex();
time_t const time = Os::getRealSystemTime();
ChatLogManager::logChat(lowerFromPlayer, lowerToPlayer, text, channel, messageIndex, time);
PlayerMessageList::iterator iterPlayerMessageList = s_playerMessageList.find(lowerLogPlayer);
if (iterPlayerMessageList != s_playerMessageList.end())
{
// The player already has some messages logged, append the message
iterPlayerMessageList->second.push_back(std::make_pair(messageIndex, time));
ChatServer::fileLog(false, "ChatServer", "logChatMessage() player(%s) messageIndex(%d) time(%u) messageCount(%u)", Unicode::wideToNarrow(lowerLogPlayer).c_str(), messageIndex, time, iterPlayerMessageList->second.size());
}
else
{
// The player does not have any message logged, add the first one
MessageList messageList;
messageList.push_back(std::make_pair(messageIndex, time));
s_playerMessageList.insert(std::make_pair(lowerLogPlayer, messageList));
ChatServer::fileLog(false, "ChatServer", "logChatMessage() player(%s) messageIndex(%d) time(%u) first message entered", Unicode::wideToNarrow(lowerLogPlayer).c_str(), messageIndex, time);
}
}
// ----------------------------------------------------------------------
Unicode::String ChatServer::toUnicodeString(ChatUnicodeString const &chatUnicodeString)
{
return Unicode::String(chatUnicodeString.string_data, chatUnicodeString.string_length);
}
// ----------------------------------------------------------------------
Unicode::String const &ChatServer::getChannelTell()
{
return s_channelTell;
}
// ----------------------------------------------------------------------
Unicode::String const &ChatServer::getChannelEmail()
{
return s_channelEmail;
}
// ----------------------------------------------------------------------
void ChatServer::fileLog(bool const forceLog, char const * const label, char const * const format, ...)
{
if ( forceLog
|| s_loggingEnabled)
{
char text[8192];
va_list va;
va_start(va, format);
_vsnprintf(text, sizeof(text), format, va);
text[sizeof(text) - 1] = '\0';
va_end(va);
LOG(label, (text));
}
}
// ----------------------------------------------------------------------
void ChatServer::requestTransferAvatar(const TransferCharacterData & request)
{
if(instance().chatInterface)
{
ChatAvatarId sourceAvatar("SWG", request.getSourceGalaxy(), request.getSourceCharacterName());
std::string destination = request.getDestinationGalaxy();
if(destination.empty())
destination = request.getSourceGalaxy();
ChatAvatarId destinationAvatar("SWG", destination, request.getDestinationCharacterName());
instance().chatInterface->RequestTransferAvatar(request.getSourceStationId(), makeChatUnicodeString(sourceAvatar.getName()), makeChatUnicodeString(sourceAvatar.getAPIAddress()), request.getDestinationStationId(), makeChatUnicodeString(destinationAvatar.getName()), makeChatUnicodeString(destinationAvatar.getAPIAddress()), true, NULL);
}
}
// ----------------------------------------------------------------------
void ChatServer::onCreateRoomSuccess(const std::string & lowerName, const unsigned int roomId)
{
std::set<std::pair<std::string, ChatAvatarId> >::iterator nameIter;
for(nameIter = s_pendingEntersByName.begin(); nameIter != s_pendingEntersByName.end();)
{
if(nameIter->first == lowerName)
{
enterRoom(nameIter->second, nameIter->first, false, false);
s_pendingEntersByName.erase(nameIter++);
}
else
{
++nameIter;
}
}
std::set<std::pair<NetworkId, std::pair<unsigned int, unsigned int> > >::iterator idIter;
for(idIter = s_pendingEntersById.begin(); idIter != s_pendingEntersById.end();)
{
if(idIter->second.second == roomId)
{
enterRoom(idIter->first, idIter->second.first, idIter->second.second);
s_pendingEntersById.erase(idIter++);
}
else
{
++idIter;
}
}
}
// ----------------------------------------------------------------------
bool ChatServer::isGod(const NetworkId & networkId)
{
bool result = false;
if(s_godClients.find(networkId) != s_godClients.end())
{
result = true;
}
return result;
}
// ----------------------------------------------------------------------
void ChatServer::setUnsquelchTime(NetworkId const & character, time_t unsquelchTime)
{
ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(character);
if (aed)
{
aed->unsquelchTime = unsquelchTime;
}
}
// ----------------------------------------------------------------------
void ChatServer::handleChatStatisticsFromGameServer(NetworkId const & character, time_t unsquelchTime, time_t chatSpamTimeEndInterval, int spatialNumCharacters, int nonSpatialNumCharacters)
{
// update character chat data with chat data from game server
ChatServer::AvatarExtendedData * aed = getAvatarExtendedDataByNetworkId(character);
if (aed)
{
// squelch state is tracked by the game server
aed->unsquelchTime = unsquelchTime;
// spatial chat is tracked by the game server
aed->spatialCharCount = spatialNumCharacters;
// we are out of sync with the game server, so use
// all information passed from game server
if (aed->chatSpamTimeEndInterval != chatSpamTimeEndInterval)
{
aed->nonSpatialCharCount = nonSpatialNumCharacters;
aed->chatSpamTimeEndInterval = chatSpamTimeEndInterval;
}
// we are in sync with the game server, and we have additional
// non-spatial chat to report to the game server
else if (aed->nonSpatialCharCount != nonSpatialNumCharacters)
{
time_t const timeNow = ::time(NULL);
if (timeNow > aed->chatSpamNextTimeToSyncWithGameServer)
{
GenericValueTypeMessage<std::pair<std::pair<NetworkId, int>, std::pair<int, int> > > chatStatistics("ChatStatisticsCS", std::make_pair(std::make_pair(character, static_cast<int>(aed->chatSpamTimeEndInterval)), std::make_pair(aed->spatialCharCount, aed->nonSpatialCharCount)));
sendToClient(character, chatStatistics);
aed->chatSpamNextTimeToSyncWithGameServer = timeNow + ConfigChatServer::getChatStatisticsReportIntervalSeconds();
}
}
}
}
// ======================================================================
VChatInterface* ChatServer::getVChatInterface()
{
return instance().voiceChatInterface;
}
// ----------------------------------------------------------------------
unsigned ChatServer::registerGameServerConnection(GameServerConnection *connection)
{
static unsigned nextId = 0;
++nextId;
m_gameServerConnectionRegistry.insert(std::make_pair(nextId, connection));
return nextId;
}
//-----------------------------------------------------------------------
void ChatServer::unregisterGameServerConnection(unsigned const connectionId)
{
GameServerMap::iterator i = m_gameServerConnectionRegistry.find(connectionId);
if(i != m_gameServerConnectionRegistry.end())
{
m_gameServerConnectionRegistry.erase(i);
}
}
// ----------------------------------------------------------------------
void ChatServer::sendToGameServerById(unsigned const connectionId, GameNetworkMessage const & message)
{
GameServerConnection* connection = getGameServerConnectionFromId(connectionId);
if(connection)
{
connection->send(message, true);
}
else
{
DEBUG_WARNING(true, ("VoiceChatServer::sendToGameServer could not find connection"));
}
}
//-----------------------------------------------------------------------
GameServerConnection *ChatServer::getGameServerConnectionFromId(unsigned int sequence)
{
GameServerConnection * result = NULL;
std::unordered_map<unsigned int, GameServerConnection *>::iterator f = m_gameServerConnectionRegistry.find(sequence);
if(f != m_gameServerConnectionRegistry.end())
{
result = (*f).second;
}
return result;
}
//-----------------------------------------------------------------------
void ChatServer::sendResponse(ReturnAddress const & requester, const GameNetworkMessage & response)
{
fileLog(false, "ChatServer", "sendResponse() target(%s) responseType(%s)", requester.debugString().c_str(), response.getCmdName().c_str());
switch(requester.type)
{
case ReturnAddress::RAT_invalid: break;
case ReturnAddress::RAT_client:
{
sendToClient(requester.clientId, response);
}
break;
case ReturnAddress::RAT_gameserver:
{
sendToGameServerById(requester.gameServerId, response);
}
break;
default:
DEBUG_WARNING(true, ("ChatServer: Trying to send a response to a return address of unknown type."));
}
}
//-----------------------------------------------------------------------
//voice chat actions
//TODO: remove these and integrate their functionality where it should rightly go
void ChatServer::requestGetChannel(ReturnAddress const & requester, std::string const &roomName, bool isPublic, bool isPersistant, uint32 limit, std::list<std::string> const & moderators)
{
fileLog(false, "ChatServer", "request to create room from(%s) name(%s)", requester.debugString().c_str(), roomName.c_str());
//TODO: real passwords and descriptions?
const std::string description = "";
const std::string password = "";
getVChatInterface()->requestGetChannel(roomName, description, password, limit, isPublic, isPersistant, moderators, requester);
}
void ChatServer::requestChannelInfo(ReturnAddress const & requester, std::string const &roomName)
{
fileLog(false, "ChatServer", "request for channel info from (%s) channel (%s)", requester.debugString().c_str(), roomName.c_str());
getVChatInterface()->requestChannelInfo(roomName, requester);
}
//-----------------------------------------------------------------------
void ChatServer::requestDeleteChannel(ReturnAddress const & requester, std::string const & roomName)
{
getVChatInterface()->requestDeleteChannel(roomName, requester);
}
//-----------------------------------------------------------------------
void ChatServer::requestAddClientToChannel(const NetworkId & id, std::string const & playerName, std::string const &roomName, bool forceShortlist)
{
fileLog(false, "ChatServer", "requestAddClientToChannel id(%s) name(%s) roomName(%s) forceShortlist(%i)", id.getValueString().c_str(), playerName.c_str(), roomName.c_str(), forceShortlist ? 1 : 0);
getVChatInterface()->addClientToChannel(roomName, id, playerName, forceShortlist);
}
//-----------------------------------------------------------------------
void ChatServer::requestRemoveClientFromChannel(const NetworkId & id, std::string const & playerName, std::string const &roomName)
{
fileLog(false, "ChatServer", "requestRemoveClientFromChannel id(%s) name(%s) roomName(%s)", id.getValueString().c_str(), playerName.c_str(), roomName.c_str());
getVChatInterface()->removeClientFromChannel(roomName, id, playerName);
}
//-----------------------------------------------------------------------
void ChatServer::requestChannelCommand(ReturnAddress const & requester,
const std::string &srcUserName, const std::string &destUserName, const std::string &destChannelAddress,
unsigned command,unsigned banTimeout)
{
getVChatInterface()->requestChannelCommand(requester, srcUserName, destUserName, destChannelAddress, command, banTimeout);
}
//-----------------------------------------------------------------------
void ChatServer::requestBroadcastChannelMessage(std::string const & channelName, std::string const & textMessage, bool isRemove)
{
LOG("CustomerService", ("BroadcastVoiceChannel: ChatServer::requestBroadcastGlobalChannel chan(%s) text(%s)", channelName.c_str(), textMessage.c_str()));
getVChatInterface()->broadcastGlobalChannelMessage(channelName, textMessage, isRemove);
}
//-----------------------------------------------------------------------
bool ChatServer::getVoiceChatLoginInfoFromId(NetworkId const & id, std::string & userName, std::string & playerName)
{
if(id.getValue() != 0)
{
VoiceChatAvatarList::const_iterator i = instance().m_voiceChatIdMap.find(id);
if(i != instance().m_voiceChatIdMap.end())
{
userName = i->second.loginName;
playerName = i->second.playerName;
return true;
}
}
return false;
}
//-----------------------------------------------------------------------
bool ChatServer::getVoiceChatLoginInfoFromName(std::string const & playerName, NetworkId & id)
{
std::map<std::string,NetworkId>::const_iterator i = instance().m_voiceChatNameToIdMap.find(toLower(playerName));
if(i != instance().m_voiceChatNameToIdMap.end())
{
id = i->second;
return true;
}
return false;
}
//-----------------------------------------------------------------------
bool ChatServer::getVoiceChatLoginInfoFromLoginName(std::string const & loginName, NetworkId & id)
{
std::map<std::string,NetworkId>::const_iterator i = instance().m_voiceLoginNameToIdMap.find(toLower(loginName));
if(i != instance().m_voiceLoginNameToIdMap.end())
{
id = i->second;
return true;
}
return false;
}
//-----------------------------------------------------------------------
void ChatServer::voiceChatGotLoginInfo(NetworkId const & id, std::string const & userName, std::string const & playerName)
{
if(id.getValue() != 0)
{
VoiceChatAvatarData data;
data.loginName = userName;
data.playerName = playerName;
instance().m_voiceChatIdMap.insert(std::make_pair(id, data));
instance().m_voiceChatNameToIdMap.insert(std::make_pair(toLower(playerName), id));
instance().m_voiceLoginNameToIdMap.insert(std::make_pair(toLower(userName), id));
}
}
//-----------------------------------------------------------------------
void ChatServer::requestInvitePlayerToChannel(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName)
{
if(channelName == getVChatInterface()->buildPersonalChannelName(sourceId))
{
getVChatInterface()->requestInvite(sourceId, targetId, channelName);
}
}
void ChatServer::requestKickPlayerFromChannel(NetworkId const & sourceId, NetworkId const & targetId, std::string const & channelName)
{
if(channelName == getVChatInterface()->buildPersonalChannelName(sourceId))
{
getVChatInterface()->requestKick(sourceId, targetId, channelName);
}
}