IRC.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539
  1. /*
  2. EQ2Emulator: Everquest II Server Emulator
  3. Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
  4. This file is part of EQ2Emulator.
  5. EQ2Emulator is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. EQ2Emulator is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <assert.h>
  17. #ifdef _WIN32
  18. #include <WinSock2.h>
  19. #include <windows.h>
  20. #include <process.h>
  21. #else
  22. #include <pthread.h>
  23. #include <errno.h>
  24. #include "../../common/unix.h"
  25. #endif
  26. #include "IRCReplyCodes.h"
  27. #include "IRC.h"
  28. #include "../Chat/Chat.h"
  29. #include "../../common/Log.h"
  30. #include "../Rules/Rules.h"
  31. extern Chat chat;
  32. extern RuleManager rule_manager;
  33. IRC::IRC() {
  34. running = false;
  35. m_globalServer = 0;
  36. m_servers.SetName("IRC::servers");
  37. }
  38. IRC::~IRC() {
  39. map<int32, IRCServer *>::iterator itr;
  40. m_servers.writelock(__FUNCTION__, __LINE__);
  41. for (itr = servers.begin(); itr != servers.end(); itr++)
  42. safe_delete(itr->second);
  43. m_servers.releasewritelock(__FUNCTION__, __LINE__);
  44. safe_delete(m_globalServer);
  45. }
  46. ThreadReturnType ServerLoop(void *arg);
  47. void IRC::Start() {
  48. if (running)
  49. return;
  50. running = true;
  51. #ifdef _WIN32
  52. _beginthread(ServerLoop, 0, this);
  53. #else
  54. pthread_t thread;
  55. pthread_create(&thread, NULL, ServerLoop, this);
  56. pthread_detach(thread);
  57. #endif
  58. }
  59. int32 IRC::GetNumServers() {
  60. int32 count;
  61. m_servers.readlock(__FUNCTION__, __LINE__);
  62. count = servers.size();
  63. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  64. return count;
  65. }
  66. const char * IRC::GetSafeChannelName(const char *channel_name) {
  67. char *safe_channel_name;
  68. size_t len;
  69. assert(channel_name != NULL);
  70. len = strlen(channel_name) + 2;
  71. safe_channel_name = new char[len];
  72. if (channel_name[0] != '#')
  73. snprintf(safe_channel_name, len, "#%s", channel_name);
  74. else
  75. strncpy(safe_channel_name, channel_name, len);
  76. return safe_channel_name;
  77. }
  78. void IRC::ConnectToServer(Client *client, const char *host, short port, const char *nick) {
  79. int32 character_id;
  80. IRCServer *server;
  81. int ret;
  82. assert(client != NULL);
  83. assert(host != NULL);
  84. character_id = client->GetCharacterID();
  85. m_servers.writelock(__FUNCTION__, __LINE__);
  86. if (servers.count(character_id) > 0)
  87. client->Message(CHANNEL_COLOR_YELLOW, "You are already connected to IRC server %s.", servers[character_id]->GetHost());
  88. else {
  89. client->Message(CHANNEL_COLOR_YELLOW, "Connecting to IRC server %s:%i.", host, port);
  90. server = new IRCServer(character_id, host, port, nick == NULL || strlen(nick) == 0 ? client->GetPlayer()->GetName() : nick);
  91. ret = server->Connect();
  92. switch (ret) {
  93. case IRC_CONNECT_SUCCESS:
  94. servers[character_id] = server;
  95. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Successfully connected to IRC server!");
  96. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You can now join channels on this server using /irc join <channel name>.");
  97. break;
  98. case IRC_CONNECT_ALREADY_CONNECTED:
  99. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already connected to this IRC server!");
  100. break;
  101. case IRC_CONNECT_NO_NICK:
  102. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. A nick was never given.");
  103. break;
  104. case IRC_CONNECT_WINSOCK_INIT:
  105. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Failed to initailize Winsock.");
  106. break;
  107. case IRC_CONNECT_WINSOCK_VERSION:
  108. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Winsock version 2.2 was not found. Contact your EQ2Emu server administrator.");
  109. break;
  110. case IRC_CONNECT_SOCKET:
  111. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Failed to create a socket.");
  112. break;
  113. case IRC_CONNECT_NO_HOST:
  114. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. That host does not exist.");
  115. break;
  116. case IRC_CONNECT_FAIL:
  117. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Failed to connect.");
  118. break;
  119. case IRC_CONNECT_SOCKET_OPT:
  120. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Could not set socket options.");
  121. break;
  122. default:
  123. client->Message(CHANNEL_COLOR_YELLOW, "Could not connect to IRC server. Unknown error (%i).", ret);
  124. break;
  125. }
  126. }
  127. m_servers.releasewritelock(__FUNCTION__, __LINE__);
  128. }
  129. void IRC::ConnectToGlobalServer(const char *host, short port, const char *nick) {
  130. IRCServer* server = 0;
  131. ChatChannel* channel = 0;
  132. const char* channel_name = 0;
  133. int ret;
  134. assert(host != NULL);
  135. assert(nick != NULL);
  136. if (m_globalServer)
  137. LogWrite(CHAT__ERROR, 0, "IRC", "You are already connected to the global IRC server %s.", m_globalServer->GetHost());
  138. else {
  139. LogWrite(CHAT__DEBUG, 0, "IRC", "Connecting to IRC server %s:%i.", host, port);
  140. server = new IRCServer(host, port, nick);
  141. ret = server->Connect();
  142. switch (ret) {
  143. case IRC_CONNECT_SUCCESS:
  144. m_globalServer = server;
  145. LogWrite(CHAT__DEBUG, 0, "IRC", "Successfully connected to the global IRC server!");
  146. // Get the global irc channel
  147. channel_name = rule_manager.GetGlobalRule(R_World, IRCChan)->GetString();
  148. // Join the channel
  149. m_globalServer->JoinChannel(channel_name);
  150. // Remove the leading # if there was one
  151. if (channel_name[0] == '#')
  152. channel_name++;
  153. // Check to see if a EQ2 chat channel exists, if not create it
  154. if (!chat.ChannelExists(channel_name)) {
  155. //chat.CreateChannel(channel_name);
  156. ChatChannel* new_channel = new ChatChannel();
  157. new_channel->SetName(channel_name);
  158. new_channel->SetLevelRestriction(0);
  159. new_channel->SetClassesAllowed(0);
  160. new_channel->SetRacesAllowed(0);
  161. new_channel->SetType(CHAT_CHANNEL_TYPE_WORLD);
  162. chat.AddChannel(new_channel);
  163. }
  164. // Get the EQ2 Channel
  165. channel = chat.GetChannel(channel_name);
  166. // Make sure we got the channel
  167. if (channel) {
  168. // Set the channel as the global IRC channel
  169. channel->SetGlobalIRCChannel(true);
  170. }
  171. else {
  172. // "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
  173. LogWrite(CHAT__ERROR, 0, "IRC", "Unable to set the global IRC channel");
  174. }
  175. break;
  176. case IRC_CONNECT_ALREADY_CONNECTED:
  177. LogWrite(CHAT__ERROR, 0, "IRC", "You are already connected to the global IRC server!");
  178. safe_delete(server);
  179. break;
  180. case IRC_CONNECT_NO_NICK:
  181. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. A nick was never given.");
  182. safe_delete(server);
  183. break;
  184. case IRC_CONNECT_WINSOCK_INIT:
  185. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Failed to initailize Winsock.");
  186. safe_delete(server);
  187. break;
  188. case IRC_CONNECT_WINSOCK_VERSION:
  189. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Winsock version 2.2 was not found. Contact your EQ2Emu server administrator.");
  190. safe_delete(server);
  191. break;
  192. case IRC_CONNECT_SOCKET:
  193. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Failed to create a socket.");
  194. safe_delete(server);
  195. break;
  196. case IRC_CONNECT_NO_HOST:
  197. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. That host does not exist.");
  198. safe_delete(server);
  199. break;
  200. case IRC_CONNECT_FAIL:
  201. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Failed to connect.");
  202. safe_delete(server);
  203. break;
  204. case IRC_CONNECT_SOCKET_OPT:
  205. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Could not set socket options.");
  206. safe_delete(server);
  207. break;
  208. default:
  209. LogWrite(CHAT__ERROR, 0, "IRC", "Could not connect to global IRC server. Unknown error (%i).", ret);
  210. safe_delete(server);
  211. break;
  212. }
  213. }
  214. }
  215. void IRC::DisconnectFromServer(Client *client) {
  216. IRCServer *server;
  217. int32 character_id;
  218. assert(client != NULL);
  219. character_id = client->GetCharacterID();
  220. m_servers.writelock(__FUNCTION__, __LINE__);
  221. if (servers.count(character_id) == 0)
  222. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
  223. else {
  224. server = servers[character_id];
  225. client->Message(CHANNEL_COLOR_YELLOW, "You have been disconnected from IRC server %s.", server->GetHost());
  226. server->Disconnect();
  227. safe_delete(server);
  228. servers.erase(character_id);
  229. }
  230. m_servers.releasewritelock(__FUNCTION__, __LINE__);
  231. }
  232. void IRC::DisconnectFromGlobalServer() {
  233. if (!m_globalServer)
  234. LogWrite(CHAT__ERROR, 0, "IRC", "You are not connected to a global IRC server!");
  235. else {
  236. LogWrite(CHAT__DEBUG, 0, "IRC", "You have been disconnected from the global IRC server (%s).", m_globalServer->GetHost());
  237. m_globalServer->Disconnect();
  238. safe_delete(m_globalServer);
  239. }
  240. }
  241. void IRC::JoinChannel(Client *client, const char *channel_name) {
  242. const char *safe_channel_name;
  243. int32 character_id;
  244. int ret;
  245. assert(client != NULL);
  246. assert(channel_name != NULL);
  247. character_id = client->GetCharacterID();
  248. //if the user didn't include a hash in the channel name, add it
  249. safe_channel_name = GetSafeChannelName(channel_name);
  250. m_servers.readlock(__FUNCTION__, __LINE__);
  251. if (servers.count(character_id) == 0)
  252. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
  253. else {
  254. ret = servers[character_id]->JoinChannel(safe_channel_name);
  255. switch (ret) {
  256. case IRC_JOIN_CHANNEL_SUCCESS:
  257. client->Message(CHANNEL_COLOR_YELLOW, "Joining IRC channel %s.", safe_channel_name);
  258. if (channel_name[0] == '#')
  259. channel_name++;
  260. if (!chat.ChannelExists(channel_name))
  261. chat.CreateChannel(channel_name);
  262. if (!chat.IsInChannel(client, channel_name))
  263. chat.JoinChannel(client, channel_name);
  264. break;
  265. case IRC_JOIN_CHANNEL_ALREADY_IN:
  266. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are already in that IRC channel!");
  267. break;
  268. default:
  269. client->Message(CHANNEL_COLOR_YELLOW, "Error joining channel. Unknown error (%i).", ret);
  270. break;
  271. }
  272. }
  273. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  274. safe_delete_array(safe_channel_name);
  275. }
  276. void IRC::LeaveChannel(Client *client, const char *channel_name) {
  277. const char *safe_channel_name;
  278. int32 character_id;
  279. int ret;
  280. assert(client != NULL);
  281. assert(channel_name != NULL);
  282. character_id = client->GetCharacterID();
  283. //if the user didn't include a hash in the channel name, add it
  284. safe_channel_name = GetSafeChannelName(channel_name);
  285. m_servers.readlock(__FUNCTION__, __LINE__);
  286. if (servers.count(character_id) == 0)
  287. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
  288. else {
  289. ret = servers[character_id]->LeaveChannel(safe_channel_name);
  290. switch (ret) {
  291. case IRC_LEAVE_CHANNEL_SUCCESS:
  292. client->Message(CHANNEL_COLOR_YELLOW, "You have left IRC channel %s.", safe_channel_name);
  293. break;
  294. case IRC_LEAVE_CHANNEL_NOT_IN:
  295. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not in that IRC channel.");
  296. break;
  297. default:
  298. client->Message(CHANNEL_COLOR_YELLOW, "Error leaving channel. Unknown error (%i).", ret);
  299. break;
  300. }
  301. }
  302. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  303. safe_delete_array(safe_channel_name);
  304. }
  305. void IRC::ListChannels(Client *client) {
  306. vector<IRCChannel *> *channels;
  307. vector<IRCChannel *>::iterator itr;
  308. IRCServer *server;
  309. int32 character_id, i;
  310. assert(client != NULL);
  311. character_id = client->GetCharacterID();
  312. m_servers.readlock(__FUNCTION__, __LINE__);
  313. if (servers.count(character_id) == 0)
  314. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
  315. else {
  316. server = servers[character_id];
  317. channels = server->GetChannels();
  318. client->Message(CHANNEL_COLOR_YELLOW, "IRC Channels you are logged into on %s:", server->GetHost());
  319. if (channels->size() == 0)
  320. client->SimpleMessage(CHANNEL_COLOR_YELLOW, " None");
  321. else {
  322. i = 1;
  323. for (itr = channels->begin(); itr != channels->end(); itr++)
  324. client->Message(CHANNEL_COLOR_YELLOW, " %i) %s", i++, ((*itr)->GetName()));
  325. }
  326. }
  327. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  328. }
  329. void IRC::Say(Client *client, const char *channel_name, const char *message) {
  330. const char *safe_channel_name;
  331. int32 character_id;
  332. int ret;
  333. IRCServer* server = 0;
  334. assert(channel_name != NULL);
  335. assert(message != NULL);
  336. if (client)
  337. character_id = client->GetCharacterID();
  338. //if the user didn't include a hash in the channel name, add it
  339. safe_channel_name = GetSafeChannelName(channel_name);
  340. m_servers.readlock(__FUNCTION__, __LINE__);
  341. if (!m_globalServer && servers.count(character_id) == 0) {
  342. if (client)
  343. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
  344. else
  345. LogWrite(CHAT__DEBUG, 0, "IRC", "Not connected to a global IRC server");
  346. }
  347. else {
  348. if (client)
  349. server = servers[character_id];
  350. else
  351. server = m_globalServer;
  352. ret = server->Say(safe_channel_name, message);
  353. switch (ret) {
  354. case IRC_SAY_SUCCESS:
  355. //client->Message(CHANNEL_COLOR_YELLOW, "You say to %s, \"%s\"", safe_channel_name, message);
  356. break;
  357. case IRC_SAY_NOT_IN:
  358. if (client)
  359. client->Message(CHANNEL_COLOR_YELLOW, "You are not in channel %s. Use /irc list to see what channels you are in.", safe_channel_name);
  360. else
  361. LogWrite(CHAT__DEBUG, 0, "IRC", "Global IRC does not contain the channel %s.", safe_channel_name);
  362. break;
  363. default:
  364. if (client)
  365. client->Message(CHANNEL_COLOR_YELLOW, "Error sending message to %s. Unknown error (%i).", safe_channel_name, ret);
  366. else
  367. LogWrite(CHAT__DEBUG, 0, "IRC", "Error sending message to %s. Unknown error (%i).", safe_channel_name, ret);
  368. break;
  369. }
  370. }
  371. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  372. safe_delete_array(safe_channel_name);
  373. }
  374. void IRC::Say(Client *client, int32 channel_index, const char *message) {
  375. IRCChannel *channel;
  376. int32 character_id;
  377. int ret;
  378. assert(client != NULL);
  379. assert(message != NULL);
  380. character_id = client->GetCharacterID();
  381. m_servers.readlock(__FUNCTION__, __LINE__);
  382. if (servers.count(character_id) == 0)
  383. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not connected to an IRC server!");
  384. else {
  385. ret = servers[character_id]->Say(channel_index, message);
  386. channel = servers[character_id]->GetChannel(channel_index);
  387. switch (ret) {
  388. case IRC_SAY_SUCCESS:
  389. client->Message(CHANNEL_COLOR_YELLOW, "You say to %s, \"%s\"", channel->GetName(), message);
  390. break;
  391. case IRC_SAY_NOT_IN:
  392. 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);
  393. break;
  394. default:
  395. client->Message(CHANNEL_COLOR_YELLOW, "Error sending message to channel at index %i. Unknown error (%i).", channel_index, ret);
  396. break;
  397. }
  398. }
  399. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  400. }
  401. void IRC::Process() {
  402. map<int32, IRCServer *>::iterator itr;
  403. vector<int32> removes;
  404. vector<int32>::iterator itr_removes;
  405. int32 character_id;
  406. IRCServer *server;
  407. m_servers.readlock(__FUNCTION__, __LINE__);
  408. for (itr = servers.begin(); itr != servers.end(); itr++) {
  409. server = itr->second;
  410. if (server->IsConnected()) {
  411. //if this connection fails to process, disconnect it
  412. if (!server->Process())
  413. removes.push_back(itr->first);
  414. }
  415. }
  416. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  417. // Process the global irc server if there is one
  418. if (m_globalServer && m_globalServer->IsConnected())
  419. m_globalServer->Process();
  420. //process any bad connections
  421. if (removes.size() > 0) {
  422. m_servers.writelock(__FUNCTION__, __LINE__);
  423. for (itr_removes = removes.begin(); itr_removes != removes.end(); itr_removes++) {
  424. character_id = *itr_removes;
  425. if (servers.count(character_id) > 0) {
  426. safe_delete(servers[character_id]);
  427. servers.erase(character_id);
  428. }
  429. }
  430. m_servers.releasewritelock(__FUNCTION__, __LINE__);
  431. }
  432. }
  433. ThreadReturnType ServerLoop(void *arg) {
  434. IRC *irc = (IRC *)arg;
  435. while (irc->IsRunning()) {
  436. irc->Process();
  437. if (irc->GetNumServers() == 0)
  438. Sleep(1000);
  439. else
  440. Sleep(100);
  441. }
  442. THREAD_RETURN(NULL);
  443. }
  444. IRCServer* IRC::GetServer(Client* client) {
  445. IRCServer* ret = 0;
  446. m_servers.readlock(__FUNCTION__, __LINE__);
  447. if (servers.count(client->GetCharacterID()) != 0)
  448. ret = servers[client->GetCharacterID()];
  449. m_servers.releasereadlock(__FUNCTION__, __LINE__);
  450. return ret;
  451. }