123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- /*
- EQ2Emulator: Everquest II Server Emulator
- Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
- This file is part of EQ2Emulator.
- EQ2Emulator is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- EQ2Emulator is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
- */
- #include <assert.h>
- #ifdef _WIN32
- #include <WinSock2.h>
- #include <windows.h>
- #include <process.h>
- #else
- #include <pthread.h>
- #include <errno.h>
- #include "../../common/unix.h"
- #endif
- #include "IRCReplyCodes.h"
- #include "IRC.h"
- #include "../Chat/Chat.h"
- #include "../../common/Log.h"
- #include "../Rules/Rules.h"
- extern Chat chat;
- extern RuleManager rule_manager;
- IRC::IRC() {
- running = false;
- m_globalServer = 0;
- m_servers.SetName("IRC::servers");
- }
- IRC::~IRC() {
- map<int32, IRCServer *>::iterator itr;
- m_servers.writelock(__FUNCTION__, __LINE__);
- for (itr = servers.begin(); itr != servers.end(); itr++)
- safe_delete(itr->second);
- m_servers.releasewritelock(__FUNCTION__, __LINE__);
- safe_delete(m_globalServer);
- }
- ThreadReturnType ServerLoop(void *arg);
- void IRC::Start() {
- if (running)
- return;
- running = true;
- #ifdef _WIN32
- _beginthread(ServerLoop, 0, this);
- #else
- pthread_t thread;
- pthread_create(&thread, NULL, ServerLoop, this);
- pthread_detach(thread);
- #endif
- }
- int32 IRC::GetNumServers() {
- int32 count;
- m_servers.readlock(__FUNCTION__, __LINE__);
- count = servers.size();
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- return count;
- }
- const char * IRC::GetSafeChannelName(const char *channel_name) {
- char *safe_channel_name;
- size_t len;
- assert(channel_name != NULL);
- len = strlen(channel_name) + 2;
- safe_channel_name = new char[len];
- if (channel_name[0] != '#')
- snprintf(safe_channel_name, len, "#%s", channel_name);
- else
- strncpy(safe_channel_name, channel_name, len);
- return safe_channel_name;
- }
- void IRC::ConnectToServer(Client *client, const char *host, short port, const char *nick) {
- int32 character_id;
- IRCServer *server;
- int ret;
- assert(client != NULL);
- assert(host != NULL);
- character_id = client->GetCharacterID();
- m_servers.writelock(__FUNCTION__, __LINE__);
- if (servers.count(character_id) > 0)
- client->Message(CHANNEL_COLOR_YELLOW, "You are already connected to IRC server %s.", servers[character_id]->GetHost());
- else {
- client->Message(CHANNEL_COLOR_YELLOW, "Connecting to IRC server %s:%i.", host, port);
- server = new IRCServer(character_id, host, port, nick == NULL || strlen(nick) == 0 ? client->GetPlayer()->GetName() : nick);
- ret = server->Connect();
- switch (ret) {
- case IRC_CONNECT_SUCCESS:
- servers[character_id] = server;
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Successfully connected to IRC server!");
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can now join channels on this server using /irc join <channel name>.");
- break;
- case IRC_CONNECT_ALREADY_CONNECTED:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already connected to this IRC server!");
- break;
- case IRC_CONNECT_NO_NICK:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. A nick was never given.");
- break;
- case IRC_CONNECT_WINSOCK_INIT:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Failed to initailize Winsock.");
- break;
- case IRC_CONNECT_WINSOCK_VERSION:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Winsock version 2.2 was not found. Contact your EQ2Emu server administrator.");
- break;
- case IRC_CONNECT_SOCKET:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Failed to create a socket.");
- break;
- case IRC_CONNECT_NO_HOST:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. That host does not exist.");
- break;
- case IRC_CONNECT_FAIL:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Failed to connect.");
- break;
- case IRC_CONNECT_SOCKET_OPT:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Could not set socket options.");
- break;
- default:
- client->Message(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Unknown error (%i).", ret);
- break;
- }
- }
- m_servers.releasewritelock(__FUNCTION__, __LINE__);
- }
- void IRC::ConnectToGlobalServer(const char *host, short port, const char *nick) {
- IRCServer* server = 0;
- ChatChannel* channel = 0;
- const char* channel_name = 0;
- int ret;
- assert(host != NULL);
- assert(nick != NULL);
- if (m_globalServer)
- LogWrite(CHAT__ERROR, 0, "IRC", "You are already connected to the global IRC server %s.", m_globalServer->GetHost());
- else {
- LogWrite(CHAT__DEBUG, 0, "IRC", "Connecting to IRC server %s:%i.", host, port);
- server = new IRCServer(host, port, nick);
- ret = server->Connect();
- switch (ret) {
- case IRC_CONNECT_SUCCESS:
- m_globalServer = server;
- LogWrite(CHAT__DEBUG, 0, "IRC", "Successfully connected to the global IRC server!");
- // Get the global irc channel
- channel_name = rule_manager.GetGlobalRule(R_World, IRCChan)->GetString();
- // Join the channel
- m_globalServer->JoinChannel(channel_name);
- // Remove the leading # if there was one
- if (channel_name[0] == '#')
- channel_name++;
- // Check to see if a EQ2 chat channel exists, if not create it
- if (!chat.ChannelExists(channel_name)) {
- //chat.CreateChannel(channel_name);
- ChatChannel* new_channel = new ChatChannel();
- new_channel->SetName(channel_name);
-
- new_channel->SetLevelRestriction(0);
- new_channel->SetClassesAllowed(0);
- new_channel->SetRacesAllowed(0);
- new_channel->SetType(CHAT_CHANNEL_TYPE_WORLD);
- chat.AddChannel(new_channel);
- }
- // Get the EQ2 Channel
- channel = chat.GetChannel(channel_name);
- // Make sure we got the channel
- if (channel) {
- // Set the channel as the global IRC channel
- channel->SetGlobalIRCChannel(true);
- }
- else {
- // "Should" never end up here as we make sure the channel exists before we get it, send an error if we do end up in here some how
- LogWrite(CHAT__ERROR, 0, "IRC", "Unable to set the global IRC channel");
- }
- break;
- case IRC_CONNECT_ALREADY_CONNECTED:
- LogWrite(CHAT__ERROR, 0, "IRC", "You are already connected to the global IRC server!");
- safe_delete(server);
- break;
- case IRC_CONNECT_NO_NICK:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. A nick was never given.");
- safe_delete(server);
- break;
- case IRC_CONNECT_WINSOCK_INIT:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Failed to initailize Winsock.");
- safe_delete(server);
- break;
- case IRC_CONNECT_WINSOCK_VERSION:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Winsock version 2.2 was not found. Contact your EQ2Emu server administrator.");
- safe_delete(server);
- break;
- case IRC_CONNECT_SOCKET:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Failed to create a socket.");
- safe_delete(server);
- break;
- case IRC_CONNECT_NO_HOST:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. That host does not exist.");
- safe_delete(server);
- break;
- case IRC_CONNECT_FAIL:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Failed to connect.");
- safe_delete(server);
- break;
- case IRC_CONNECT_SOCKET_OPT:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Could not set socket options.");
- safe_delete(server);
- break;
- default:
- LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Unknown error (%i).", ret);
- safe_delete(server);
- break;
- }
- }
- }
- void IRC::DisconnectFromServer(Client *client) {
- IRCServer *server;
- int32 character_id;
- assert(client != NULL);
- character_id = client->GetCharacterID();
- m_servers.writelock(__FUNCTION__, __LINE__);
- if (servers.count(character_id) == 0)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
- else {
- server = servers[character_id];
- client->Message(CHANNEL_COLOR_YELLOW, "You have been disconnected from IRC server %s.", server->GetHost());
- server->Disconnect();
- safe_delete(server);
- servers.erase(character_id);
- }
- m_servers.releasewritelock(__FUNCTION__, __LINE__);
- }
- void IRC::DisconnectFromGlobalServer() {
- if (!m_globalServer)
- LogWrite(CHAT__ERROR, 0, "IRC", "You are not connected to a global IRC server!");
- else {
- LogWrite(CHAT__DEBUG, 0, "IRC", "You have been disconnected from the global IRC server (%s).", m_globalServer->GetHost());
- m_globalServer->Disconnect();
- safe_delete(m_globalServer);
- }
- }
- void IRC::JoinChannel(Client *client, const char *channel_name) {
- const char *safe_channel_name;
- int32 character_id;
- int ret;
- assert(client != NULL);
- assert(channel_name != NULL);
- character_id = client->GetCharacterID();
- //if the user didn't include a hash in the channel name, add it
- safe_channel_name = GetSafeChannelName(channel_name);
- m_servers.readlock(__FUNCTION__, __LINE__);
- if (servers.count(character_id) == 0)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
- else {
- ret = servers[character_id]->JoinChannel(safe_channel_name);
- switch (ret) {
- case IRC_JOIN_CHANNEL_SUCCESS:
- client->Message(CHANNEL_COLOR_YELLOW, "Joining IRC channel %s.", safe_channel_name);
- if (channel_name[0] == '#')
- channel_name++;
- if (!chat.ChannelExists(channel_name))
- chat.CreateChannel(channel_name);
- if (!chat.IsInChannel(client, channel_name))
- chat.JoinChannel(client, channel_name);
- break;
- case IRC_JOIN_CHANNEL_ALREADY_IN:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already in that IRC channel!");
- break;
- default:
- client->Message(CHANNEL_COLOR_YELLOW, "Error joining channel. Unknown error (%i).", ret);
- break;
- }
- }
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- safe_delete_array(safe_channel_name);
- }
- void IRC::LeaveChannel(Client *client, const char *channel_name) {
- const char *safe_channel_name;
- int32 character_id;
- int ret;
- assert(client != NULL);
- assert(channel_name != NULL);
- character_id = client->GetCharacterID();
- //if the user didn't include a hash in the channel name, add it
- safe_channel_name = GetSafeChannelName(channel_name);
- m_servers.readlock(__FUNCTION__, __LINE__);
- if (servers.count(character_id) == 0)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
- else {
- ret = servers[character_id]->LeaveChannel(safe_channel_name);
- switch (ret) {
- case IRC_LEAVE_CHANNEL_SUCCESS:
- client->Message(CHANNEL_COLOR_YELLOW, "You have left IRC channel %s.", safe_channel_name);
- break;
- case IRC_LEAVE_CHANNEL_NOT_IN:
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not in that IRC channel.");
- break;
- default:
- client->Message(CHANNEL_COLOR_YELLOW, "Error leaving channel. Unknown error (%i).", ret);
- break;
- }
- }
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- safe_delete_array(safe_channel_name);
- }
- void IRC::ListChannels(Client *client) {
- vector<IRCChannel *> *channels;
- vector<IRCChannel *>::iterator itr;
- IRCServer *server;
- int32 character_id, i;
- assert(client != NULL);
- character_id = client->GetCharacterID();
- m_servers.readlock(__FUNCTION__, __LINE__);
- if (servers.count(character_id) == 0)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
- else {
- server = servers[character_id];
- channels = server->GetChannels();
- client->Message(CHANNEL_COLOR_YELLOW, "IRC Channels you are logged into on %s:", server->GetHost());
- if (channels->size() == 0)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, " None");
- else {
- i = 1;
- for (itr = channels->begin(); itr != channels->end(); itr++)
- client->Message(CHANNEL_COLOR_YELLOW, " %i) %s", i++, ((*itr)->GetName()));
- }
- }
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- }
- void IRC::Say(Client *client, const char *channel_name, const char *message) {
- const char *safe_channel_name;
- int32 character_id;
- int ret;
- IRCServer* server = 0;
- assert(channel_name != NULL);
- assert(message != NULL);
- if (client)
- character_id = client->GetCharacterID();
- //if the user didn't include a hash in the channel name, add it
- safe_channel_name = GetSafeChannelName(channel_name);
- m_servers.readlock(__FUNCTION__, __LINE__);
- if (!m_globalServer && servers.count(character_id) == 0) {
- if (client)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
- else
- LogWrite(CHAT__DEBUG, 0, "IRC", "Not connected to a global IRC server");
- }
- else {
- if (client)
- server = servers[character_id];
- else
- server = m_globalServer;
- ret = server->Say(safe_channel_name, message);
- switch (ret) {
- case IRC_SAY_SUCCESS:
- //client->Message(CHANNEL_COLOR_YELLOW, "You say to %s, \"%s\"", safe_channel_name, message);
- break;
- case IRC_SAY_NOT_IN:
- if (client)
- client->Message(CHANNEL_COLOR_YELLOW, "You are not in channel %s. Use /irc list to see what channels you are in.", safe_channel_name);
- else
- LogWrite(CHAT__DEBUG, 0, "IRC", "Global IRC does not contain the channel %s.", safe_channel_name);
- break;
- default:
- if (client)
- client->Message(CHANNEL_COLOR_YELLOW, "Error sending message to %s. Unknown error (%i).", safe_channel_name, ret);
- else
- LogWrite(CHAT__DEBUG, 0, "IRC", "Error sending message to %s. Unknown error (%i).", safe_channel_name, ret);
- break;
- }
- }
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- safe_delete_array(safe_channel_name);
- }
- void IRC::Say(Client *client, int32 channel_index, const char *message) {
- IRCChannel *channel;
- int32 character_id;
- int ret;
- assert(client != NULL);
- assert(message != NULL);
- character_id = client->GetCharacterID();
- m_servers.readlock(__FUNCTION__, __LINE__);
- if (servers.count(character_id) == 0)
- client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
- else {
- ret = servers[character_id]->Say(channel_index, message);
- channel = servers[character_id]->GetChannel(channel_index);
- switch (ret) {
- case IRC_SAY_SUCCESS:
- client->Message(CHANNEL_COLOR_YELLOW, "You say to %s, \"%s\"", channel->GetName(), message);
- break;
- case IRC_SAY_NOT_IN:
- client->Message(CHANNEL_COLOR_YELLOW, "You are not in a channel at index %u. Use /irc list to see what channels you are in.", channel_index);
- break;
- default:
- client->Message(CHANNEL_COLOR_YELLOW, "Error sending message to channel at index %i. Unknown error (%i).", channel_index, ret);
- break;
- }
- }
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- }
- void IRC::Process() {
- map<int32, IRCServer *>::iterator itr;
- vector<int32> removes;
- vector<int32>::iterator itr_removes;
- int32 character_id;
- IRCServer *server;
- m_servers.readlock(__FUNCTION__, __LINE__);
- for (itr = servers.begin(); itr != servers.end(); itr++) {
- server = itr->second;
- if (server->IsConnected()) {
- //if this connection fails to process, disconnect it
- if (!server->Process())
- removes.push_back(itr->first);
- }
- }
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- // Process the global irc server if there is one
- if (m_globalServer && m_globalServer->IsConnected())
- m_globalServer->Process();
- //process any bad connections
- if (removes.size() > 0) {
- m_servers.writelock(__FUNCTION__, __LINE__);
- for (itr_removes = removes.begin(); itr_removes != removes.end(); itr_removes++) {
- character_id = *itr_removes;
- if (servers.count(character_id) > 0) {
- safe_delete(servers[character_id]);
- servers.erase(character_id);
- }
- }
- m_servers.releasewritelock(__FUNCTION__, __LINE__);
- }
- }
- ThreadReturnType ServerLoop(void *arg) {
- IRC *irc = (IRC *)arg;
- while (irc->IsRunning()) {
- irc->Process();
-
- if (irc->GetNumServers() == 0)
- Sleep(1000);
- else
- Sleep(100);
- }
- THREAD_RETURN(NULL);
- }
- IRCServer* IRC::GetServer(Client* client) {
- IRCServer* ret = 0;
- m_servers.readlock(__FUNCTION__, __LINE__);
- if (servers.count(client->GetCharacterID()) != 0)
- ret = servers[client->GetCharacterID()];
- m_servers.releasereadlock(__FUNCTION__, __LINE__);
- return ret;
- }
|