1 /*
2 * network_metaserver.cpp - Metaserver client
3
4 Copyright (C) 2004 and beyond by Woody Zenfell, III
5 and the "Aleph One" developers.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 This license is contained in the file "COPYING",
18 which is included with this source code; it is available online at
19 http://www.gnu.org/licenses/gpl.html
20
21 April 15, 2004 (Woody Zenfell):
22 Created.
23 */
24
25 #if !defined(DISABLE_NETWORKING)
26
27 #include "cseries.h"
28
29 #include "network_metaserver.h"
30
31 #include "metaserver_messages.h"
32
33 #include "Message.h"
34 #include "MessageHandler.h"
35 #include "MessageDispatcher.h"
36 #include "MessageInflater.h"
37 #include "CommunicationsChannel.h"
38 #include "preferences.h"
39 #include "alephversion.h"
40 #include "HTTP.h"
41
42 #include <string>
43 #include <iostream>
44 #include <iterator> // ostream_iterator
45 #include <algorithm>
46 #include "Logging.h"
47
48 #include <boost/algorithm/string/predicate.hpp>
49
50
51 using namespace std;
52
53
54 set<MetaserverClient*> MetaserverClient::s_instances;
55 set<string> MetaserverClient::s_ignoreNames;
56
57
58 static const int kKeyLength = 16;
59
60 static std::string remove_formatting(const std::string &s);
61
62 void
handleUnexpectedMessage(Message * inMessage,CommunicationsChannel * inChannel)63 MetaserverClient::handleUnexpectedMessage(Message* inMessage, CommunicationsChannel* inChannel)
64 {
65 logAnomaly("Metaserver received message ID %i", inMessage->type());
66 if(inMessage->type() == UninflatedMessage::kTypeID)
67 {
68 UninflatedMessage* theMessage = dynamic_cast<UninflatedMessage*>(inMessage);
69 if(theMessage != NULL)
70 logAnomaly("-- internal ID %i, length %i", theMessage->inflatedType(), theMessage->length());
71 }
72 }
73
74
75 void
handleBroadcastMessage(BroadcastMessage * inMessage,CommunicationsChannel * inChannel)76 MetaserverClient::handleBroadcastMessage(BroadcastMessage* inMessage, CommunicationsChannel* inChannel)
77 {
78 if(m_notificationAdapter)
79 m_notificationAdapter->receivedBroadcastMessage(inMessage->message());
80 }
81
82
83 void
handleChatMessage(ChatMessage * message,CommunicationsChannel * inChannel)84 MetaserverClient::handleChatMessage(ChatMessage* message, CommunicationsChannel* inChannel)
85 {
86 if(message->internalType() == 0 && m_notificationAdapter)
87 {
88 std::string realSenderName = remove_formatting(message->senderName());
89 if (realSenderName[0] == '\260') realSenderName.erase(realSenderName.begin());
90 if (network_preferences->mute_metaserver_guests && boost::algorithm::starts_with(realSenderName, "Guest "))
91 return;
92 if (s_ignoreNames.find(realSenderName) != s_ignoreNames.end())
93 return;
94
95 if (message->directed())
96 m_notificationAdapter->receivedPrivateMessage(message->senderName(), message->senderID(), message->message());
97 else
98 m_notificationAdapter->receivedChatMessage(message->senderName(), message->senderID(), message->message());
99 }
100 }
101
handlePrivateMessage(PrivateMessage * message,CommunicationsChannel * inChannel)102 void MetaserverClient::handlePrivateMessage(PrivateMessage* message, CommunicationsChannel* inChannel)
103 {
104 if (message->internalType() == 0 && m_notificationAdapter)
105 {
106 std::string realSenderName = remove_formatting(message->senderName());
107 if (realSenderName[0] == '\260') realSenderName.erase(realSenderName.begin());
108 if (network_preferences->mute_metaserver_guests && boost::algorithm::starts_with(realSenderName, "Guest "))
109 return;
110
111 if (s_ignoreNames.find(realSenderName) != s_ignoreNames.end())
112 return;
113
114 if (message->directed())
115 m_notificationAdapter->receivedPrivateMessage(message->senderName(), message->senderID(), message->message());
116 else
117 m_notificationAdapter->receivedChatMessage(message->senderName(), message->senderID(), message->message());
118 }
119 }
120
121
122 void
handleKeepAliveMessage(Message * inMessage,CommunicationsChannel * inChannel)123 MetaserverClient::handleKeepAliveMessage(Message* inMessage, CommunicationsChannel* inChannel)
124 {
125 inChannel->enqueueOutgoingMessage(KeepAliveMessage());
126 }
127
128
129 void
handlePlayerListMessage(PlayerListMessage * inMessage,CommunicationsChannel * inChannel)130 MetaserverClient::handlePlayerListMessage(PlayerListMessage* inMessage, CommunicationsChannel* inChannel)
131 {
132 std::vector<MetaserverPlayerInfo> players = inMessage->players();
133 if (m_notificationAdapter)
134 {
135 // metaserver says invisible people leave twice
136 std::vector<MetaserverPlayerInfo>::iterator it = players.begin();
137 while (it != players.end())
138 {
139 if (it->verb() == PlayersInRoom::kDelete && !find_player(it->playerID()))
140 {
141 it = players.erase(it);
142 }
143 else
144 {
145 ++it;
146 }
147 }
148 }
149
150 m_playersInRoom.processUpdates(inMessage->players());
151
152 if(m_notificationAdapter) {
153 m_notificationAdapter->playersInRoomChanged(players);
154 }
155 }
156
157
158 void
handleRoomListMessage(RoomListMessage * inMessage,CommunicationsChannel * inChannel)159 MetaserverClient::handleRoomListMessage(RoomListMessage* inMessage, CommunicationsChannel* inChannel)
160 {
161 m_rooms = inMessage->rooms();
162 }
163
164 void
handleGameListMessage(GameListMessage * inMessage,CommunicationsChannel * inChannel)165 MetaserverClient::handleGameListMessage(GameListMessage* inMessage, CommunicationsChannel* inChannel)
166 {
167 vector<GameListMessage::GameListEntry> entries = inMessage->entries();
168 for (vector<GameListMessage::GameListEntry>::iterator it = entries.begin(); it != entries.end(); ++it)
169 {
170 const MetaserverPlayerInfo *player = m_playersInRoom.find(it->m_hostPlayerID);
171 if (player)
172 {
173 it->m_hostPlayerName = player->name();
174 }
175 }
176
177 m_gamesInRoom.processUpdates(entries);
178
179 if(m_notificationAdapter) {
180 m_notificationAdapter->gamesInRoomChanged(inMessage->entries());
181 }
182 }
183
184
MetaserverClient()185 MetaserverClient::MetaserverClient()
186 : m_channel(new CommunicationsChannel())
187 , m_inflater(new MessageInflater())
188 , m_dispatcher(new MessageDispatcher())
189 , m_loginDispatcher(new MessageDispatcher())
190 , m_notificationAdapter(NULL)
191 , m_notifiedOfDisconnected(false)
192 , m_gameAnnounced(false)
193 {
194 m_unexpectedMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleUnexpectedMessage));
195 m_broadcastMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleBroadcastMessage));
196 m_chatMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleChatMessage));
197 m_privateMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handlePrivateMessage));
198 m_keepAliveMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleKeepAliveMessage));
199 m_playerListMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handlePlayerListMessage));
200 m_roomListMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleRoomListMessage));
201 m_gameListMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleGameListMessage));
202 m_setPlayerDataMessageHandler.reset(newMessageHandlerMethod(this, &MetaserverClient::handleSetPlayerDataMessage));
203
204 m_inflater->learnPrototype(SaltMessage());
205 m_inflater->learnPrototype(AcceptMessage());
206 m_inflater->learnPrototype(RoomListMessage());
207 m_inflater->learnPrototype(IDAndLimitMessage());
208 m_inflater->learnPrototype(DenialMessage());
209 m_inflater->learnPrototype(BroadcastMessage());
210 m_inflater->learnPrototype(ChatMessage());
211 m_inflater->learnPrototype(PrivateMessage());
212 m_inflater->learnPrototype(KeepAliveMessage());
213 m_inflater->learnPrototype(PlayerListMessage());
214 m_inflater->learnPrototype(LoginSuccessfulMessage());
215 m_inflater->learnPrototype(SetPlayerDataMessage());
216 m_inflater->learnPrototype(GameListMessage());
217
218 m_channel->setMessageInflater(m_inflater.get());
219
220 m_dispatcher->setDefaultHandler(m_unexpectedMessageHandler.get());
221 m_dispatcher->setHandlerForType(m_broadcastMessageHandler.get(), BroadcastMessage::kType);
222 m_dispatcher->setHandlerForType(m_chatMessageHandler.get(), ChatMessage::kType);
223 m_dispatcher->setHandlerForType(m_privateMessageHandler.get(), PrivateMessage::kType);
224 m_dispatcher->setHandlerForType(m_keepAliveMessageHandler.get(), KeepAliveMessage::kType);
225 m_dispatcher->setHandlerForType(m_playerListMessageHandler.get(), PlayerListMessage::kType);
226 m_dispatcher->setHandlerForType(m_roomListMessageHandler.get(), RoomListMessage::kType);
227 m_dispatcher->setHandlerForType(m_gameListMessageHandler.get(), GameListMessage::kType);
228 m_dispatcher->setHandlerForType(m_setPlayerDataMessageHandler.get(), SetPlayerDataMessage::kType);
229
230 m_loginDispatcher->setDefaultHandler(m_unexpectedMessageHandler.get());
231 m_loginDispatcher->setHandlerForType(m_setPlayerDataMessageHandler.get(), SetPlayerDataMessage::kType);
232
233 s_instances.insert(this);
234 s_ignoreNames.insert("Bacon");
235
236 }
237
238 void
connect(const std::string & serverName,uint16 port,const std::string & userName,const std::string & userPassword)239 MetaserverClient::connect(const std::string& serverName, uint16 port, const std::string& userName, const std::string& userPassword)
240 {
241 try
242 {
243 m_channel->setMessageHandler(m_loginDispatcher.get());
244
245 if (m_channel->isConnected()) m_channel->disconnect();
246
247 m_playersInRoom.clear();
248 m_gamesInRoom.clear();
249
250 m_channel->connect(serverName.c_str(), port);
251
252 LoginAndPlayerInfoMessage theLoginMessage(userName, m_playerName, m_teamName);
253 m_channel->enqueueOutgoingMessage(theLoginMessage);
254
255 std::unique_ptr<Message> theSaltOrAcceptMessage(m_channel->receiveMessage());
256 if (theSaltOrAcceptMessage.get() == 0)
257 throw ServerConnectException("Server Disconnected");
258
259 if (dynamic_cast<SaltMessage*>(theSaltOrAcceptMessage.get()) != 0)
260 {
261 SaltMessage* theSaltMessage = dynamic_cast<SaltMessage*>(theSaltOrAcceptMessage.get());
262
263 char theKey[kKeyLength];
264 char thePasswordCopy[kKeyLength];
265 memset(thePasswordCopy, 0x23, sizeof(thePasswordCopy));
266 strncpy(reinterpret_cast<char*>(thePasswordCopy), userPassword.c_str(), kKeyLength);
267
268 if (theSaltMessage->encryptionType() == SaltMessage::kPlaintextEncryption)
269 {
270 strncpy(theKey, thePasswordCopy, kKeyLength);
271 }
272 else if (theSaltMessage->encryptionType() == SaltMessage::kBraindeadSimpleEncryption)
273 {
274 for(size_t i = 0; i < sizeof(theKey); i++)
275 {
276 theKey[i] = thePasswordCopy[i] ^ (theSaltMessage->salt()[i]);
277 }
278
279 for(size_t i = 1; i < sizeof(theKey); i++)
280 {
281 theKey[i] = theKey[i]^theKey[i - 1];
282 }
283
284 for(size_t i = 1; i < sizeof(theKey); i++) {
285 short value;
286
287 value = ~( theKey[i]*theKey[i-1]);
288 theKey[i] = (unsigned char) value;
289 }
290 }
291 else if (theSaltMessage->encryptionType() == SaltMessage::kHTTPSEncryption)
292 {
293 HTTPClient conn;
294 HTTPClient::parameter_map params;
295 params["username"] = userName;
296 params["password"] = userPassword;
297 params["salt"] = std::string(reinterpret_cast<const char *>(theSaltMessage->salt()));
298
299 if (conn.Post(A1_METASERVER_LOGIN_URL, params))
300 {
301 strncpy(theKey, conn.Response().c_str(), sizeof(theKey));
302 }
303 else
304 {
305 throw ServerConnectException("HTTPS Connection Failed");
306 }
307 }
308 else
309 {
310 throw ServerConnectException("Unsupported Encryption");
311 }
312
313 BigChunkOfDataMessage theKeyMessage(kCLIENT_KEY, (uint8 *) theKey, sizeof(theKey));
314 m_channel->enqueueOutgoingMessage(theKeyMessage);
315
316 std::unique_ptr<Message> theResponseMessage(m_channel->receiveMessage());
317 if (!theResponseMessage.get())
318 {
319 throw ServerConnectException("Server Disconnected");
320 }
321 else if (dynamic_cast<DenialMessage*>(theResponseMessage.get()))
322 {
323 DenialMessage *dm = dynamic_cast<DenialMessage*>(theResponseMessage.get());
324 throw LoginDeniedException(dm->code(), dm->message());
325 }
326 else if (!dynamic_cast<AcceptMessage*>(theResponseMessage.get()))
327 {
328 throw CommunicationsChannel::FailedToReceiveSpecificMessageException();
329 }
330 }
331 else if (dynamic_cast<AcceptMessage*>(theSaltOrAcceptMessage.get()) == 0)
332 {
333 if (dynamic_cast<DenialMessage*>(theSaltOrAcceptMessage.get()))
334 {
335 DenialMessage *dm = dynamic_cast<DenialMessage*>(theSaltOrAcceptMessage.get());
336 throw LoginDeniedException(dm->code(), dm->message());
337 }
338 else
339 {
340 throw CommunicationsChannel::FailedToReceiveSpecificMessageException();
341 }
342 }
343
344 m_channel->enqueueOutgoingMessage(LocalizationMessage());
345
346 std::unique_ptr<LoginSuccessfulMessage> theLoginSuccessfulMessage(m_channel->receiveSpecificMessageOrThrow<LoginSuccessfulMessage>());
347
348 // std::unique_ptr<SetPlayerDataMessage> theSetPlayerDataMessage(m_channel->receiveSpecificMessageOrThrow<SetPlayerDataMessage>());
349
350 std::unique_ptr<RoomListMessage> theRoomListMessage(m_channel->receiveSpecificMessageOrThrow<RoomListMessage>());
351 m_dispatcher.get()->handle(theRoomListMessage.get(), m_channel.get());
352
353 m_channel->disconnect();
354
355 ///// ROOM CONNECTION
356
357 if (!m_rooms.size())
358 {
359 throw ServerConnectException("No Rooms Available");
360 }
361
362 IPaddress roomServerAddress = m_rooms[0].roomServerAddress();
363
364 for (int i = 0; i < m_rooms.size(); i++)
365 {
366 if (m_rooms[i].roomName() == "Arrival")
367 {
368 roomServerAddress = m_rooms[i].roomServerAddress();
369 break;
370 }
371 }
372
373 // roomServerAddress.host = 0xC0A80108;
374 // roomServerAddress.host = 0x0801A8C0;
375
376 m_channel->connect(roomServerAddress);
377
378 m_channel->enqueueOutgoingMessage(RoomLoginMessage(userName, theLoginSuccessfulMessage->token()));
379
380 m_channel->enqueueOutgoingMessage(NameAndTeamMessage(m_playerName, m_teamName));
381
382 std::unique_ptr<IDAndLimitMessage> theIDAndLimitMessage(m_channel->receiveSpecificMessageOrThrow<IDAndLimitMessage>());
383 m_playerID = theIDAndLimitMessage->playerID();
384
385 std::unique_ptr<DenialMessage> theRoomAcceptMessage(m_channel->receiveSpecificMessageOrThrow<DenialMessage>());
386
387 m_channel->setMessageHandler(m_dispatcher.get());
388 }
389 catch (const CommunicationsChannel::FailedToReceiveSpecificMessageException&)
390 {
391 // translate for caller
392 throw ServerConnectException("Unexpected Response");
393 }
394 }
395
396
397
398 bool
isConnected() const399 MetaserverClient::isConnected() const
400 {
401 return m_channel->isConnected();
402 }
403
404
405
406 void
disconnect()407 MetaserverClient::disconnect()
408 {
409 // don't throw, we're called in ~MetaserverClient
410 try {
411 m_channel->enqueueOutgoingMessage(LogoutMessage());
412 m_channel->pump();
413 }
414 catch(...) { }
415 m_channel->disconnect();
416 }
417
418
419
420 void
pump()421 MetaserverClient::pump()
422 {
423 m_channel->pump();
424 m_channel->dispatchIncomingMessages();
425 if (!m_channel->isConnected() && !m_notifiedOfDisconnected && m_notificationAdapter)
426 {
427 m_notifiedOfDisconnected = true;
428 m_notificationAdapter->roomDisconnected();
429 }
430 }
431
432
433
434
435 void
pumpAll()436 MetaserverClient::pumpAll()
437 {
438 for_each(s_instances.begin(), s_instances.end(), mem_fun(&MetaserverClient::pump));
439 }
440
441
442
443
444 void
sendChatMessage(const std::string & message)445 MetaserverClient::sendChatMessage(const std::string& message)
446 {
447 if (message == ".available" || message == ".avail") {
448 if(m_notificationAdapter) {
449 string players = "Available Players: ";
450 bool found_players = false;
451 for (size_t i = 0; i < playersInRoom().size(); i++) {
452 if (!playersInRoom()[i].away()) {
453 if (found_players)
454 players += ", ";
455 found_players = true;
456 players += "\"" + playersInRoom()[i].name() + "\"";
457 }
458 }
459 if (!found_players)
460 players += "none";
461 m_notificationAdapter->receivedLocalMessage(players);
462 }
463 } else if (message == ".who") {
464 if(m_notificationAdapter) {
465 string players = "Players: ";
466 if (playersInRoom().size()) {
467 players += "\"" + playersInRoom()[0].name() + "\"";
468 for (size_t i = 1; i < playersInRoom().size(); i++) {
469 players += ", \"" + playersInRoom()[i].name() + "\"";
470 }
471 } else {
472 players += "none";
473 }
474 m_notificationAdapter->receivedLocalMessage(players);
475 }
476 } else if (message.compare(0, strlen(".pork"), ".pork") == 0) {
477 if (m_notificationAdapter) {
478 m_notificationAdapter->receivedLocalMessage("NO BACON FOR YOU");
479 }
480 } else if (message == ".ignore") {
481 if (m_notificationAdapter) {
482 // list the players on the ignore list
483 string players = "Ignoring: ";
484 for (set<string>::iterator it = s_ignoreNames.begin(); it != s_ignoreNames.end(); it++)
485 {
486 if (it == s_ignoreNames.begin())
487 {
488 players += "\"" + *it + "\"";
489 }
490 else
491 {
492 players += ", \"" + *it +"\"";
493 }
494 }
495
496 m_notificationAdapter->receivedLocalMessage(players);
497 }
498 } else if (message.compare(0, strlen(".ignore "), ".ignore ") == 0) {
499 // everything after the space is the name to ignore
500 string name = message.substr(strlen(".ignore "));
501 ignore(name);
502 } else if (message == ".games") {
503 if (m_notificationAdapter) {
504 m_notificationAdapter->receivedLocalMessage("Games:");
505 vector<GameListMessage::GameListEntry> games = gamesInRoom();
506 vector<MetaserverPlayerInfo> players = playersInRoom();
507 for (vector<GameListMessage::GameListEntry>::iterator it = games.begin(); it != games.end(); ++it)
508 {
509 // look up the player name
510 string player_name;
511 for (vector<MetaserverPlayerInfo>::iterator player_it = players.begin(); player_it != players.end(); ++player_it)
512 {
513 if (player_it->id() == it->m_hostPlayerID)
514 {
515 player_name = player_it->name();
516 break;
517 }
518 }
519
520 if (player_name.size() > 0) {
521 m_notificationAdapter->receivedLocalMessage(it->format_for_chat(player_name));
522 }
523 }
524 }
525 } else {
526 m_channel->enqueueOutgoingMessage(ChatMessage(m_playerID, m_playerName, message));
527 }
528 }
529
530 void
sendPrivateMessage(MetaserverPlayerInfo::IDType id,const std::string & message)531 MetaserverClient::sendPrivateMessage(MetaserverPlayerInfo::IDType id, const std::string& message)
532 {
533 m_channel->enqueueOutgoingMessage(PrivateMessage(m_playerID, m_playerName, id, message));
534 }
535
536 void
announceGame(uint16 gamePort,const GameDescription & description)537 MetaserverClient::announceGame(uint16 gamePort, const GameDescription& description)
538 {
539 m_channel->enqueueOutgoingMessage(CreateGameMessage(gamePort, description));
540 m_gameDescription = description;
541 m_gamePort = gamePort;
542 m_gameAnnounced = true;
543 }
544
545 void
announcePlayersInGame(uint8 players)546 MetaserverClient::announcePlayersInGame(uint8 players)
547 {
548 m_gameDescription.m_numPlayers = players;
549 m_channel->enqueueOutgoingMessage(CreateGameMessage(m_gamePort, m_gameDescription));
550 }
551
552 void
announceGameStarted(int32 gameTimeInSeconds)553 MetaserverClient::announceGameStarted(int32 gameTimeInSeconds)
554 {
555 m_gameDescription.m_closed = true;
556 m_gameDescription.m_running = true;
557 m_channel->enqueueOutgoingMessage(CreateGameMessage(m_gamePort, m_gameDescription));
558 m_channel->enqueueOutgoingMessage(StartGameMessage(gameTimeInSeconds == INT32_MAX ? INT32_MIN : gameTimeInSeconds));
559 }
560
561
562
563 void
announceGameReset()564 MetaserverClient::announceGameReset()
565 {
566 m_channel->enqueueOutgoingMessage(ResetGameMessage());
567 }
568
569
570
571 void
announceGameDeleted()572 MetaserverClient::announceGameDeleted()
573 {
574 if (m_gameAnnounced)
575 {
576 m_channel->enqueueOutgoingMessage(RemoveGameMessage());
577 m_gameAnnounced = false;
578 }
579 }
580
style_code(char c)581 static inline bool style_code(char c)
582 {
583 switch(tolower(c)) {
584 case 'p':
585 case 'b':
586 case 'i':
587 case 'l':
588 case 'r':
589 case 'c':
590 case 's':
591 return true;
592 default:
593 return false;
594 }
595 }
596
remove_formatting(const std::string & s)597 static std::string remove_formatting(const std::string &s)
598 {
599 string temp;
600 int i = 0;
601 while (i < s.size()) {
602 if (s[i] == '|' && style_code(s[i + 1]))
603 i += 2;
604 else
605 temp += s[i++];
606 }
607
608 return temp;
609 }
610
ignore(const std::string & name)611 void MetaserverClient::ignore(const std::string& name)
612 {
613 std::string cleaned_name = remove_formatting(name);
614 if (s_ignoreNames.find(cleaned_name) != s_ignoreNames.end())
615 {
616 s_ignoreNames.erase(cleaned_name);
617 if (m_notificationAdapter) {
618 m_notificationAdapter->receivedLocalMessage("Removing \"" + cleaned_name + "\" from the ignore list");
619 }
620 } else {
621 s_ignoreNames.insert(cleaned_name);
622 if (m_notificationAdapter) {
623 m_notificationAdapter->receivedLocalMessage("Adding \"" + cleaned_name + "\" to the ignore list");
624 }
625 }
626 }
627
ignore(MetaserverPlayerInfo::IDType id)628 void MetaserverClient::ignore(MetaserverPlayerInfo::IDType id)
629 {
630 // find the guy's name, remove the \266 if it's there
631 const MetaserverPlayerInfo *player = m_playersInRoom.find(id);
632 if (player)
633 {
634 std::string name = player->name();
635 if (name[0] == '\260') name.erase(name.begin());
636
637 ignore(name);
638 }
639 }
640
is_ignored(MetaserverPlayerInfo::IDType id)641 bool MetaserverClient::is_ignored(MetaserverPlayerInfo::IDType id)
642 {
643 std::string name;
644 const MetaserverPlayerInfo *player = m_playersInRoom.find(id);
645 if (player)
646 {
647 std::string name = player->name();
648 if (name[0] == '\260') name.erase(name.begin());
649
650 return (s_ignoreNames.find(remove_formatting(name)) != s_ignoreNames.end());
651 }
652 else
653 {
654 // uh, what do we do?
655 return false;
656 }
657 }
658
659
660 void
syncGames()661 MetaserverClient::syncGames()
662 {
663 m_channel->enqueueOutgoingMessage(SyncGamesMessage());
664 }
665
666
setAway(bool away,const std::string & away_message)667 void MetaserverClient::setAway(bool away, const std::string& away_message)
668 {
669 m_channel->enqueueOutgoingMessage(NameAndTeamMessage(m_playerName, m_teamName, away, away_message));
670 }
671
setMode(uint16 mode,const std::string & session_id)672 void MetaserverClient::setMode(uint16 mode, const std::string& session_id)
673 {
674 m_channel->enqueueOutgoingMessage(SetPlayerModeMessage(mode, session_id));
675 }
676
677 void
setPlayerName(const std::string & name)678 MetaserverClient::setPlayerName(const std::string& name)
679 {
680 m_playerName = name;
681 }
682
683
684
685 void
setPlayerTeamName(const std::string & name)686 MetaserverClient::setPlayerTeamName(const std::string& name)
687 {
688 m_teamName = name;
689 }
690
691
692
~MetaserverClient()693 MetaserverClient::~MetaserverClient()
694 {
695 disconnect();
696 s_instances.erase(this);
697 }
698
699 #endif // !defined(DISABLE_NETWORKING)
700