Changeset View
Changeset View
Standalone View
Standalone View
source/lobby/XmppClient.cpp
Show All 19 Lines | |||||
#include "XmppClient.h" | #include "XmppClient.h" | ||||
#include "StanzaExtensions.h" | #include "StanzaExtensions.h" | ||||
#ifdef WIN32 | #ifdef WIN32 | ||||
# include <winsock2.h> | # include <winsock2.h> | ||||
#endif | #endif | ||||
#include "i18n/L10n.h" | #include "i18n/L10n.h" | ||||
#include "lobby/scripting/GlooxScriptConversions.cpp" | |||||
#include "lib/external_libraries/enet.h" | #include "lib/external_libraries/enet.h" | ||||
#include "lib/utf8.h" | #include "lib/utf8.h" | ||||
#include "network/NetServer.h" | #include "network/NetServer.h" | ||||
#include "network/StunClient.h" | #include "network/StunClient.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/ConfigDB.h" | #include "ps/ConfigDB.h" | ||||
#include "ps/Pyrogenesis.h" | #include "ps/Pyrogenesis.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include <gloox/gloox.h> | #include <gloox/gloox.h> | ||||
//debug | //debug | ||||
#if 1 | #if 0 | ||||
Stan: Intended ? | |||||
Done Inline ActionsYes, because I uploaded it as a backup and because the DbgXMPP calls must be tested as they are changed too. elexis: Yes, because I uploaded it as a backup and because the DbgXMPP calls must be tested as they are… | |||||
#define DbgXMPP(x) | #define DbgXMPP(x) | ||||
#else | #else | ||||
#define DbgXMPP(x) std::cout << x << std::endl; | #define DbgXMPP(x) std::cout << x << std::endl; | ||||
static std::string tag_xml(const glooxwrapper::IQ& iq) | static std::string tag_xml(const glooxwrapper::IQ& iq) | ||||
{ | { | ||||
std::string ret; | std::string ret; | ||||
glooxwrapper::Tag* tag = iq.tag(); | glooxwrapper::Tag* tag = iq.tag(); | ||||
▲ Show 20 Lines • Show All 213 Lines • ▼ Show 20 Lines | void XmppClient::onDisconnect(gloox::ConnectionError error) | ||||
m_BoardList.clear(); | m_BoardList.clear(); | ||||
m_GameList.clear(); | m_GameList.clear(); | ||||
m_PlayerMap.clear(); | m_PlayerMap.clear(); | ||||
m_Profile.clear(); | m_Profile.clear(); | ||||
m_HistoricGuiMessages.clear(); | m_HistoricGuiMessages.clear(); | ||||
m_isConnected = false; | m_isConnected = false; | ||||
CreateGUIMessage("system", "disconnected", std::time(nullptr), "reason", ConnectionErrorToString(error)); | CreateGUIMessage("system", "disconnected", std::time(nullptr), "reason", error, "cert_status", m_certStatus); | ||||
} | } | ||||
/** | /** | ||||
* Handle TLS connection. | * Handle TLS connection. | ||||
*/ | */ | ||||
bool XmppClient::onTLSConnect(const glooxwrapper::CertInfo& info) | bool XmppClient::onTLSConnect(const glooxwrapper::CertInfo& info) | ||||
{ | { | ||||
DbgXMPP("onTLSConnect"); | DbgXMPP("onTLSConnect"); | ||||
Show All 15 Lines | bool XmppClient::onTLSConnect(const glooxwrapper::CertInfo& info) | ||||
return info.status == gloox::CertOk || !verify_certificate; | return info.status == gloox::CertOk || !verify_certificate; | ||||
} | } | ||||
/** | /** | ||||
* Handle MUC room errors | * Handle MUC room errors | ||||
*/ | */ | ||||
void XmppClient::handleMUCError(glooxwrapper::MUCRoom*, gloox::StanzaError err) | void XmppClient::handleMUCError(glooxwrapper::MUCRoom*, gloox::StanzaError err) | ||||
{ | { | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", StanzaErrorToString(err)); | CreateGUIMessage("system", "error", std::time(nullptr), "text", err); | ||||
} | } | ||||
/***************************************************** | /***************************************************** | ||||
* Requests to server * | * Requests to server * | ||||
*****************************************************/ | *****************************************************/ | ||||
/** | /** | ||||
* Request the leaderboard data from the server. | * Request the leaderboard data from the server. | ||||
▲ Show 20 Lines • Show All 170 Lines • ▼ Show 20 Lines | void XmppClient::handleRegistrationFields(const glooxwrapper::JID&, int fields, glooxwrapper::string) | ||||
m_registration->createAccount(fields, vals); | m_registration->createAccount(fields, vals); | ||||
} | } | ||||
void XmppClient::handleRegistrationResult(const glooxwrapper::JID&, gloox::RegistrationResult result) | void XmppClient::handleRegistrationResult(const glooxwrapper::JID&, gloox::RegistrationResult result) | ||||
{ | { | ||||
if (result == gloox::RegistrationSuccess) | if (result == gloox::RegistrationSuccess) | ||||
CreateGUIMessage("system", "registered", std::time(nullptr)); | CreateGUIMessage("system", "registered", std::time(nullptr)); | ||||
else | else | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", RegistrationResultToString(result)); | CreateGUIMessage("system", "error", std::time(nullptr), "text", result); | ||||
disconnect(); | disconnect(); | ||||
} | } | ||||
void XmppClient::handleAlreadyRegistered(const glooxwrapper::JID&) | void XmppClient::handleAlreadyRegistered(const glooxwrapper::JID&) | ||||
{ | { | ||||
DbgXMPP("the account already exists"); | DbgXMPP("the account already exists"); | ||||
} | } | ||||
Show All 17 Lines | |||||
* | * | ||||
* @return A JS array containing all known players and their presences | * @return A JS array containing all known players and their presences | ||||
*/ | */ | ||||
void XmppClient::GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | void XmppClient::GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | ||||
{ | { | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
scriptInterface.CreateArray(ret); | ScriptInterface::CreateArray(cx, ret); | ||||
int j = 0; | int j = 0; | ||||
for (const std::pair<std::string, std::vector<std::string> >& p : m_PlayerMap) | for (const std::pair<glooxwrapper::string, SPlayer>& p : m_PlayerMap) | ||||
{ | { | ||||
JS::RootedValue player(cx); | JS::RootedValue player(cx); | ||||
scriptInterface.CreateObject( | ScriptInterface::CreateObject( | ||||
cx, | |||||
&player, | &player, | ||||
"name", wstring_from_utf8(p.first), | "name", p.first, | ||||
"presence", wstring_from_utf8(p.second[0]), | "presence", p.second.m_Presence, | ||||
"rating", wstring_from_utf8(p.second[1]), | "rating", p.second.m_Rating, | ||||
"role", wstring_from_utf8(p.second[2])); | "role", p.second.m_Role); | ||||
scriptInterface.SetPropertyInt(ret, j++, player); | scriptInterface.SetPropertyInt(ret, j++, player); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Handle requests from the GUI for the list of all active games. | * Handle requests from the GUI for the list of all active games. | ||||
* | * | ||||
* @return A JS array containing all known games | * @return A JS array containing all known games | ||||
*/ | */ | ||||
void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | ||||
{ | { | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
scriptInterface.CreateArray(ret); | ScriptInterface::CreateArray(cx, ret); | ||||
int j = 0; | int j = 0; | ||||
const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state", | const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state", | ||||
"nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", | "nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", | ||||
"victoryCondition", "startTime", "mods" }; | "victoryCondition", "startTime", "mods" }; | ||||
for(const glooxwrapper::Tag* const& t : m_GameList) | for(const glooxwrapper::Tag* const& t : m_GameList) | ||||
{ | { | ||||
JS::RootedValue game(cx); | JS::RootedValue game(cx); | ||||
scriptInterface.CreateObject(&game); | ScriptInterface::CreateObject(cx, &game); | ||||
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | ||||
scriptInterface.SetProperty(game, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string())); | scriptInterface.SetProperty(game, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string())); | ||||
scriptInterface.SetPropertyInt(ret, j++, game); | scriptInterface.SetPropertyInt(ret, j++, game); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Handle requests from the GUI for leaderboard data. | * Handle requests from the GUI for leaderboard data. | ||||
* | * | ||||
* @return A JS array containing all known leaderboard data | * @return A JS array containing all known leaderboard data | ||||
*/ | */ | ||||
void XmppClient::GUIGetBoardList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | void XmppClient::GUIGetBoardList(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | ||||
{ | { | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
scriptInterface.CreateArray(ret); | ScriptInterface::CreateArray(cx, ret); | ||||
int j = 0; | int j = 0; | ||||
const char* attributes[] = { "name", "rank", "rating" }; | const char* attributes[] = { "name", "rank", "rating" }; | ||||
for(const glooxwrapper::Tag* const& t : m_BoardList) | for(const glooxwrapper::Tag* const& t : m_BoardList) | ||||
{ | { | ||||
JS::RootedValue board(cx); | JS::RootedValue board(cx); | ||||
scriptInterface.CreateObject(&board); | ScriptInterface::CreateObject(cx, &board); | ||||
for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i) | for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i) | ||||
scriptInterface.SetProperty(board, attributes[i], wstring_from_utf8(t->findAttribute(attributes[i]).to_string())); | scriptInterface.SetProperty(board, attributes[i], wstring_from_utf8(t->findAttribute(attributes[i]).to_string())); | ||||
scriptInterface.SetPropertyInt(ret, j++, board); | scriptInterface.SetPropertyInt(ret, j++, board); | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Handle requests from the GUI for profile data. | * Handle requests from the GUI for profile data. | ||||
* | * | ||||
* @return A JS array containing the specific user's profile data | * @return A JS array containing the specific user's profile data | ||||
*/ | */ | ||||
void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::MutableHandleValue ret) | ||||
{ | { | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
scriptInterface.CreateArray(ret); | ScriptInterface::CreateArray(cx, ret); | ||||
int j = 0; | int j = 0; | ||||
const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" }; | const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" }; | ||||
for (const glooxwrapper::Tag* const& t : m_Profile) | for (const glooxwrapper::Tag* const& t : m_Profile) | ||||
{ | { | ||||
JS::RootedValue profile(cx); | JS::RootedValue profile(cx); | ||||
scriptInterface.CreateObject(&profile); | ScriptInterface::CreateObject(cx, &profile); | ||||
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) | ||||
scriptInterface.SetProperty(profile, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string())); | scriptInterface.SetProperty(profile, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string())); | ||||
scriptInterface.SetPropertyInt(ret, j++, profile); | scriptInterface.SetPropertyInt(ret, j++, profile); | ||||
} | } | ||||
} | } | ||||
Show All 22 Lines | void XmppClient::CreateGUIMessage( | ||||
const std::time_t time, | const std::time_t time, | ||||
Args const&... args) | Args const&... args) | ||||
{ | { | ||||
if (!m_ScriptInterface) | if (!m_ScriptInterface) | ||||
return; | return; | ||||
JSContext* cx = m_ScriptInterface->GetContext(); | JSContext* cx = m_ScriptInterface->GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue message(cx); | JS::RootedValue message(cx); | ||||
m_ScriptInterface->CreateObject(&message, "type", type, "level", level, "time", static_cast<double>(time)); | ScriptInterface::CreateObject(cx, &message, "type", type, "level", level, "time", static_cast<double>(time)); | ||||
JS::RootedObject messageObj(cx, message.toObjectOrNull()); | JS::RootedObject messageObj(cx, message.toObjectOrNull()); | ||||
SetGUIMessageProperty(cx, messageObj, args...); | SetGUIMessageProperty(cx, messageObj, args...); | ||||
m_ScriptInterface->FreezeObject(message, true); | m_ScriptInterface->FreezeObject(message, true); | ||||
m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message)); | m_GuiMessageQueue.push_back(JS::Heap<JS::Value>(message)); | ||||
} | } | ||||
bool XmppClient::GuiPollPresenceStatusUpdate() | bool XmppClient::GuiPollPresenceStatusUpdate() | ||||
{ | { | ||||
Show All 26 Lines | |||||
} | } | ||||
JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface) | JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInterface) | ||||
{ | { | ||||
JSContext* cx = scriptInterface.GetContext(); | JSContext* cx = scriptInterface.GetContext(); | ||||
JSAutoRequest rq(cx); | JSAutoRequest rq(cx); | ||||
JS::RootedValue ret(cx); | JS::RootedValue ret(cx); | ||||
scriptInterface.CreateArray(&ret); | ScriptInterface::CreateArray(cx, &ret); | ||||
int j = 0; | int j = 0; | ||||
for (const JS::Heap<JS::Value>& message : m_HistoricGuiMessages) | for (const JS::Heap<JS::Value>& message : m_HistoricGuiMessages) | ||||
scriptInterface.SetPropertyInt(ret, j++, message); | scriptInterface.SetPropertyInt(ret, j++, message); | ||||
return ret; | return ret; | ||||
} | } | ||||
Show All 11 Lines | |||||
void XmppClient::handleMUCMessage(glooxwrapper::MUCRoom*, const glooxwrapper::Message& msg, bool priv) | void XmppClient::handleMUCMessage(glooxwrapper::MUCRoom*, const glooxwrapper::Message& msg, bool priv) | ||||
{ | { | ||||
DbgXMPP(msg.from().resource() << " said " << msg.body()); | DbgXMPP(msg.from().resource() << " said " << msg.body()); | ||||
CreateGUIMessage( | CreateGUIMessage( | ||||
"chat", | "chat", | ||||
priv ? "private-message" : "room-message", | priv ? "private-message" : "room-message", | ||||
ComputeTimestamp(msg), | ComputeTimestamp(msg), | ||||
"from", msg.from().resource().to_string(), | "from", msg.from().resource(), | ||||
"text", msg.body().to_string()); | "text", msg.body()); | ||||
} | } | ||||
/** | /** | ||||
* Handle a private message. | * Handle a private message. | ||||
*/ | */ | ||||
void XmppClient::handleMessage(const glooxwrapper::Message& msg, glooxwrapper::MessageSession*) | void XmppClient::handleMessage(const glooxwrapper::Message& msg, glooxwrapper::MessageSession*) | ||||
{ | { | ||||
DbgXMPP("type " << msg.subtype() << ", subject " << msg.subject() | DbgXMPP("type " << msg.subtype() << ", subject " << msg.subject() | ||||
<< ", message " << msg.body() << ", thread id " << msg.thread()); | << ", message " << msg.body() << ", thread id " << msg.thread()); | ||||
CreateGUIMessage( | CreateGUIMessage( | ||||
"chat", | "chat", | ||||
"private-message", | "private-message", | ||||
ComputeTimestamp(msg), | ComputeTimestamp(msg), | ||||
"from", msg.from().resource().to_string(), | "from", msg.from().resource(), | ||||
"text", msg.body().to_string()); | "text", msg.body()); | ||||
} | } | ||||
/** | /** | ||||
* Handle portions of messages containing custom stanza extensions. | * Handle portions of messages containing custom stanza extensions. | ||||
*/ | */ | ||||
bool XmppClient::handleIq(const glooxwrapper::IQ& iq) | bool XmppClient::handleIq(const glooxwrapper::IQ& iq) | ||||
{ | { | ||||
DbgXMPP("handleIq [" << tag_xml(iq) << "]"); | DbgXMPP("handleIq [" << tag_xml(iq) << "]"); | ||||
Show All 26 Lines | if (bq) | ||||
m_BoardList.emplace_back(t->clone()); | m_BoardList.emplace_back(t->clone()); | ||||
CreateGUIMessage("game", "leaderboard", std::time(nullptr)); | CreateGUIMessage("game", "leaderboard", std::time(nullptr)); | ||||
} | } | ||||
else if (bq->m_Command == "ratinglist") | else if (bq->m_Command == "ratinglist") | ||||
{ | { | ||||
for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) | for (const glooxwrapper::Tag* const& t : bq->m_StanzaBoardList) | ||||
{ | { | ||||
std::string name = t->findAttribute("name").to_string(); | glooxwrapper::string name = t->findAttribute("name"); | ||||
if (m_PlayerMap.find(name) != m_PlayerMap.end()) | if (m_PlayerMap.find(name) != m_PlayerMap.end()) | ||||
m_PlayerMap[name][1] = t->findAttribute("rating").to_string(); | m_PlayerMap.at(name).m_Rating = t->findAttribute("rating"); | ||||
} | } | ||||
CreateGUIMessage("game", "ratinglist", std::time(nullptr)); | CreateGUIMessage("game", "ratinglist", std::time(nullptr)); | ||||
} | } | ||||
} | } | ||||
if (pq) | if (pq) | ||||
{ | { | ||||
for (const glooxwrapper::Tag* const& t : m_Profile) | for (const glooxwrapper::Tag* const& t : m_Profile) | ||||
Show All 18 Lines | if (lobbyAuth) | ||||
if (g_NetServer) | if (g_NetServer) | ||||
g_NetServer->OnLobbyAuth(iq.from().username(), lobbyAuth->m_Token.to_string()); | g_NetServer->OnLobbyAuth(iq.from().username(), lobbyAuth->m_Token.to_string()); | ||||
else | else | ||||
LOGERROR("Received lobby authentication request, but not hosting currently!"); | LOGERROR("Received lobby authentication request, but not hosting currently!"); | ||||
} | } | ||||
} | } | ||||
else if (iq.subtype() == gloox::IQ::Error) | else if (iq.subtype() == gloox::IQ::Error) | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", StanzaErrorToString(iq.error_error())); | CreateGUIMessage("system", "error", std::time(nullptr), "text", iq.error_error()); | ||||
else | else | ||||
{ | { | ||||
CreateGUIMessage("system", "error", std::time(nullptr), "text", g_L10n.Translate("unknown subtype (see logs)")); | CreateGUIMessage("system", "error", std::time(nullptr), "text", wstring_from_utf8(g_L10n.Translate("unknown subtype (see logs)"))); | ||||
LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); | LOGMESSAGE("unknown subtype '%s'", tag_name(iq).c_str()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* Update local data when a user changes presence. | * Update local data when a user changes presence. | ||||
*/ | */ | ||||
void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const glooxwrapper::MUCRoomParticipant participant, const glooxwrapper::Presence& presence) | void XmppClient::handleMUCParticipantPresence(glooxwrapper::MUCRoom*, const glooxwrapper::MUCRoomParticipant participant, const glooxwrapper::Presence& presence) | ||||
{ | { | ||||
std::string nick = participant.nick->resource().to_string(); | const glooxwrapper::string& nick = participant.nick->resource(); | ||||
gloox::Presence::PresenceType presenceType = presence.presence(); | |||||
std::string presenceString, roleString; | |||||
GetPresenceString(presenceType, presenceString); | |||||
GetRoleString(participant.role, roleString); | |||||
if (presenceType == gloox::Presence::Unavailable) | if (presence.presence() == gloox::Presence::Unavailable) | ||||
{ | { | ||||
if (!participant.newNick.empty() && (participant.flags & (gloox::UserNickChanged | gloox::UserSelf))) | if (!participant.newNick.empty() && (participant.flags & (gloox::UserNickChanged | gloox::UserSelf))) | ||||
{ | { | ||||
// we have a nick change | // we have a nick change | ||||
std::string newNick = participant.newNick.to_string(); | m_PlayerMap[nick].m_Presence = presence.presence(); | ||||
m_PlayerMap[newNick].resize(3); | m_PlayerMap[nick].m_Role = participant.role; | ||||
Done Inline Actions
elexis: 1. s/nick/newNick
2. Piecewise construct in place and post a LOGERROR if the item already… | |||||
m_PlayerMap[newNick][0] = presenceString; | |||||
m_PlayerMap[newNick][2] = roleString; | |||||
DbgXMPP(nick << " is now known as " << participant.newNick.to_string()); | DbgXMPP(nick << " is now known as " << participant.newNick); | ||||
CreateGUIMessage("chat", "nick", std::time(nullptr), "oldnick", nick, "newnick", participant.newNick.to_string()); | CreateGUIMessage( | ||||
"chat", | |||||
"nick", | |||||
std::time(nullptr), | |||||
"oldnick", nick, | |||||
"newnick", participant.newNick); | |||||
} | } | ||||
else if (participant.flags & gloox::UserKicked) | else if (participant.flags & gloox::UserKicked) | ||||
{ | { | ||||
DbgXMPP(nick << " was kicked. Reason: " << participant.reason.to_string()); | DbgXMPP(nick << " was kicked. Reason: " << participant.reason); | ||||
CreateGUIMessage("chat", "kicked", std::time(nullptr), "nick", nick, "reason", participant.reason.to_string()); | CreateGUIMessage( | ||||
"chat", | |||||
"kicked", | |||||
std::time(nullptr), | |||||
"nick", nick, | |||||
"reason", participant.reason); | |||||
} | } | ||||
else if (participant.flags & gloox::UserBanned) | else if (participant.flags & gloox::UserBanned) | ||||
{ | { | ||||
DbgXMPP(nick << " was banned. Reason: " << participant.reason.to_string()); | DbgXMPP(nick << " was banned. Reason: " << participant.reason); | ||||
CreateGUIMessage("chat", "banned", std::time(nullptr), "nick", nick, "reason", participant.reason.to_string()); | CreateGUIMessage( | ||||
"chat", | |||||
"banned", | |||||
std::time(nullptr), | |||||
"nick", nick, | |||||
"reason", participant.reason); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
DbgXMPP(nick << " left the room (flags " << participant.flags << ")"); | DbgXMPP(nick << " left the room (flags " << participant.flags << ")"); | ||||
CreateGUIMessage("chat", "leave", std::time(nullptr), "nick", nick); | CreateGUIMessage( | ||||
"chat", | |||||
"leave", | |||||
std::time(nullptr), | |||||
"nick", nick); | |||||
} | } | ||||
m_PlayerMap.erase(nick); | m_PlayerMap.erase(nick); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
/* During the initialization process, we receive join messages for everyone | /* During the initialization process, we receive join messages for everyone | ||||
* currently in the room. We don't want to display these, so we filter them | * currently in the room. We don't want to display these, so we filter them | ||||
* out. We will always be the last to join during initialization. | * out. We will always be the last to join during initialization. | ||||
*/ | */ | ||||
if (!m_initialLoadComplete) | if (!m_initialLoadComplete) | ||||
{ | { | ||||
if (m_mucRoom->nick().to_string() == nick) | if (m_mucRoom->nick() == nick) | ||||
m_initialLoadComplete = true; | m_initialLoadComplete = true; | ||||
} | } | ||||
else if (m_PlayerMap.find(nick) == m_PlayerMap.end()) | else if (m_PlayerMap.count(nick) == 0) | ||||
CreateGUIMessage("chat", "join", std::time(nullptr), "nick", nick); | { | ||||
else if (m_PlayerMap[nick][2] != roleString) | CreateGUIMessage( | ||||
CreateGUIMessage("chat", "role", std::time(nullptr), "nick", nick, "oldrole", m_PlayerMap[nick][2], "newrole", roleString); | "chat", | ||||
"join", | |||||
std::time(nullptr), | |||||
"nick", nick); | |||||
} | |||||
else if (m_PlayerMap.at(nick).m_Role != participant.role) | |||||
{ | |||||
CreateGUIMessage( | |||||
"chat", | |||||
"role", | |||||
std::time(nullptr), | |||||
"nick", nick, | |||||
"oldrole", m_PlayerMap.at(nick).m_Role, | |||||
"newrole", participant.role); | |||||
} | |||||
else | else | ||||
// Don't create a GUI message for regular presence changes, because | // Don't create a GUI message for regular presence changes, because | ||||
// several hundreds of them accumulate during a match, impacting performance terribly and | // several hundreds of them accumulate during a match, impacting performance terribly and | ||||
// the only way they are used is to determine whether to update the playerlist. | // the only way they are used is to determine whether to update the playerlist. | ||||
m_PresenceUpdate = true; | m_PresenceUpdate = true; | ||||
DbgXMPP(nick << " is in the room, presence : " << (int)presenceType); | DbgXMPP(nick << " is in the room, presence : " << static_cast<int>(presence.presence())); | ||||
m_PlayerMap[nick].resize(3); | m_PlayerMap[nick].m_Presence = presence.presence(); | ||||
m_PlayerMap[nick][0] = presenceString; | m_PlayerMap[nick].m_Role = participant.role; | ||||
Done Inline ActionsCan avoid the second [] operator which compares each key of the map until it found the correct one by saving a reference after the first [] operator call! (Also the debug string is to be improved) elexis: Can avoid the second `[]` operator which compares each key of the map until it found the… | |||||
m_PlayerMap[nick][2] = roleString; | |||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Update local cache when subject changes. | * Update local cache when subject changes. | ||||
*/ | */ | ||||
void XmppClient::handleMUCSubject(glooxwrapper::MUCRoom*, const glooxwrapper::string& nick, const glooxwrapper::string& subject) | void XmppClient::handleMUCSubject(glooxwrapper::MUCRoom*, const glooxwrapper::string& nick, const glooxwrapper::string& subject) | ||||
{ | { | ||||
m_Subject = subject.c_str(); | m_Subject = subject.to_string(); | ||||
CreateGUIMessage("chat", "subject", std::time(nullptr), "nick", nick.c_str(), "subject", m_Subject); | |||||
CreateGUIMessage( | |||||
"chat", | |||||
"subject", | |||||
std::time(nullptr), | |||||
"nick", nick, | |||||
"subject", subject); | |||||
} | } | ||||
/** | /** | ||||
* Get current subject. | * Get current subject. | ||||
* | * | ||||
* @param topic Variable to store subject in. | * @param topic Variable to store subject in. | ||||
*/ | */ | ||||
void XmppClient::GetSubject(std::string& subject) | void XmppClient::GetSubject(std::string& subject) | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
* Get the current xmpp presence of the given nick. | * Get the current xmpp presence of the given nick. | ||||
* | * | ||||
* @param nick Nickname to look up presence for | * @param nick Nickname to look up presence for | ||||
* @param presence Variable to store the presence in | * @param presence Variable to store the presence in | ||||
*/ | */ | ||||
void XmppClient::GetPresence(const std::string& nick, std::string& presence) | void XmppClient::GetPresence(const std::string& nick, std::string& presence) | ||||
{ | { | ||||
if (m_PlayerMap.find(nick) != m_PlayerMap.end()) | if (m_PlayerMap.find(nick) != m_PlayerMap.end()) | ||||
presence = m_PlayerMap[nick][0]; | GetPresenceString(m_PlayerMap.at(nick).m_Presence, presence); | ||||
else | else | ||||
presence = "offline"; | presence = "offline"; | ||||
} | } | ||||
/** | /** | ||||
* Get the current xmpp role of the given nick. | * Get the current xmpp role of the given nick. | ||||
* | * | ||||
* @param nick Nickname to look up presence for | * @param nick Nickname to look up presence for | ||||
* @param role Variable to store the role in | * @param role Variable to store the role in | ||||
Done Inline Actionscomments outdated. elexis: comments outdated. | |||||
*/ | */ | ||||
void XmppClient::GetRole(const std::string& nick, std::string& role) | void XmppClient::GetRole(const std::string& nick, std::string& role) | ||||
{ | { | ||||
if (m_PlayerMap.find(nick) != m_PlayerMap.end()) | if (m_PlayerMap.find(nick) != m_PlayerMap.end()) | ||||
role = m_PlayerMap[nick][2]; | GetRoleString(m_PlayerMap.at(nick).m_Role, role); | ||||
Done Inline ActionsHere it finds the same item in the map twice, it could just store the result of the first iterator. elexis: Here it finds the same item in the map twice, it could just store the result of the first… | |||||
else | else | ||||
role = ""; | role = ""; | ||||
} | } | ||||
/***************************************************** | /***************************************************** | ||||
* Utilities * | * Utilities * | ||||
*****************************************************/ | *****************************************************/ | ||||
/** | /** | ||||
* Parse and return the timestamp of a historic chat message and return the current time for new chat messages. | * Parse and return the timestamp of a historic chat message and return the current time for new chat messages. | ||||
* Historic chat messages are implement as DelayedDelivers as specified in XEP-0203. | * Historic chat messages are implement as DelayedDelivers as specified in XEP-0203. | ||||
* Hence, their timestamp MUST be in UTC and conform to the DateTime format XEP-0082. | * Hence, their timestamp MUST be in UTC and conform to the DateTime format XEP-0082. | ||||
* | * | ||||
* @returns Seconds since the epoch. | * @returns Seconds since the epoch. | ||||
*/ | */ | ||||
std::time_t XmppClient::ComputeTimestamp(const glooxwrapper::Message& msg) const | std::time_t XmppClient::ComputeTimestamp(const glooxwrapper::Message& msg) | ||||
{ | { | ||||
// Only historic messages contain a timestamp! | // Only historic messages contain a timestamp! | ||||
if (!msg.when()) | if (!msg.when()) | ||||
return std::time(nullptr); | return std::time(nullptr); | ||||
// The locale is irrelevant, because the XMPP date format doesn't contain written month names | // The locale is irrelevant, because the XMPP date format doesn't contain written month names | ||||
for (const std::string& format : std::vector<std::string>{ "Y-M-d'T'H:m:sZ", "Y-M-d'T'H:m:s.SZ" }) | for (const std::string& format : std::vector<std::string>{ "Y-M-d'T'H:m:sZ", "Y-M-d'T'H:m:s.SZ" }) | ||||
{ | { | ||||
UDate dateTime = g_L10n.ParseDateTime(msg.when()->stamp().to_string(), format, icu::Locale::getUS()); | UDate dateTime = g_L10n.ParseDateTime(msg.when()->stamp().to_string(), format, icu::Locale::getUS()); | ||||
if (dateTime) | if (dateTime) | ||||
return dateTime / 1000.0; | return dateTime / 1000.0; | ||||
} | } | ||||
return std::time(nullptr); | return std::time(nullptr); | ||||
} | } | ||||
/** | /** | ||||
* Convert a gloox presence type to string. | * Convert a gloox presence type to string. | ||||
* | * | ||||
* @param p Presence to be converted | * @param p Presence to be converted | ||||
* @param presence Variable to store the converted presence string in | * @param presence Variable to store the converted presence string in | ||||
*/ | */ | ||||
void XmppClient::GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const | void XmppClient::GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) | ||||
{ | { | ||||
switch(p) | switch(p) | ||||
{ | { | ||||
#define CASE(x,y) case gloox::Presence::x: presence = y; break | #define CASE(x,y) case gloox::Presence::x: presence = y; break | ||||
CASE(Available, "available"); | CASE(Available, "available"); | ||||
CASE(Chat, "chat"); | CASE(Chat, "chat"); | ||||
CASE(Away, "away"); | CASE(Away, "away"); | ||||
CASE(DND, "playing"); | CASE(DND, "playing"); | ||||
Show All 10 Lines | |||||
} | } | ||||
/** | /** | ||||
* Convert a gloox role type to string. | * Convert a gloox role type to string. | ||||
* | * | ||||
* @param p Role to be converted | * @param p Role to be converted | ||||
* @param presence Variable to store the converted role string in | * @param presence Variable to store the converted role string in | ||||
*/ | */ | ||||
void XmppClient::GetRoleString(const gloox::MUCRoomRole r, std::string& role) const | void XmppClient::GetRoleString(const gloox::MUCRoomRole r, std::string& role) | ||||
{ | { | ||||
switch(r) | switch(r) | ||||
{ | { | ||||
#define CASE(X, Y) case gloox::X: role = Y; break | #define CASE(X, Y) case gloox::X: role = Y; break | ||||
CASE(RoleNone, "none"); | CASE(RoleNone, "none"); | ||||
CASE(RoleVisitor, "visitor"); | CASE(RoleVisitor, "visitor"); | ||||
CASE(RoleParticipant, "participant"); | CASE(RoleParticipant, "participant"); | ||||
CASE(RoleModerator, "moderator"); | CASE(RoleModerator, "moderator"); | ||||
CASE(RoleInvalid, "invalid"); | CASE(RoleInvalid, "invalid"); | ||||
default: | default: | ||||
LOGERROR("Unknown role type '%d'", (int)r); | LOGERROR("Unknown role type '%d'", (int)r); | ||||
break; | break; | ||||
#undef CASE | #undef CASE | ||||
} | } | ||||
} | } | ||||
/** | /** | ||||
* Translates a gloox certificate error codes, i.e. gloox certificate statuses except CertOk. | * Translates a gloox certificate error codes, i.e. gloox certificate statuses except CertOk. | ||||
* Keep in sync with specifications. | * Keep in sync with specifications. | ||||
*/ | */ | ||||
std::string XmppClient::TLSErrorToString(gloox::CertStatus status) const | std::string XmppClient::CertStatusToString(gloox::CertStatus status) | ||||
{ | { | ||||
// TODO: Use translation | |||||
std::map<gloox::CertStatus, std::string> certificateErrorStrings = { | std::map<gloox::CertStatus, std::string> certificateErrorStrings = { | ||||
{ gloox::CertInvalid, ("The certificate is not trusted.") }, | { gloox::CertInvalid, g_L10n.Translate("The certificate is not trusted.") }, | ||||
{ gloox::CertSignerUnknown, ("The certificate hasn't got a known issuer.") }, | { gloox::CertSignerUnknown, g_L10n.Translate("The certificate hasn't got a known issuer.") }, | ||||
{ gloox::CertRevoked, ("The certificate has been revoked.") }, | { gloox::CertRevoked, g_L10n.Translate("The certificate has been revoked.") }, | ||||
{ gloox::CertExpired, ("The certificate has expired.") }, | { gloox::CertExpired, g_L10n.Translate("The certificate has expired.") }, | ||||
{ gloox::CertNotActive, ("The certifiacte is not yet active.") }, | { gloox::CertNotActive, g_L10n.Translate("The certifiacte is not yet active.") }, | ||||
{ gloox::CertWrongPeer, ("The certificate has not been issued for the peer we're connected to.") }, | { gloox::CertWrongPeer, g_L10n.Translate("The certificate has not been issued for the peer we're connected to.") }, | ||||
{ gloox::CertSignerNotCa, ("The signer is not a CA.") } | { gloox::CertSignerNotCa, g_L10n.Translate("The signer is not a CA.") } | ||||
}; | }; | ||||
std::string result = ""; | std::string result = ""; | ||||
for (std::map<gloox::CertStatus, std::string>::iterator it = certificateErrorStrings.begin(); it != certificateErrorStrings.end(); ++it) | for (std::map<gloox::CertStatus, std::string>::iterator it = certificateErrorStrings.begin(); it != certificateErrorStrings.end(); ++it) | ||||
if (status & it->first) | if (status & it->first) | ||||
result += "\n" + it->second; | result += "\n" + it->second; | ||||
return result; | return result; | ||||
} | } | ||||
/** | /** | ||||
* Convert a gloox stanza error type to string. | * Convert a gloox stanza error type to string. | ||||
* Keep in sync with Gloox documentation | * Keep in sync with Gloox documentation | ||||
* | * | ||||
* @param err Error to be converted | * @param err Error to be converted | ||||
* @return Converted error string | * @return Converted error string | ||||
*/ | */ | ||||
std::string XmppClient::StanzaErrorToString(gloox::StanzaError err) const | std::string XmppClient::StanzaErrorToString(gloox::StanzaError err) | ||||
{ | { | ||||
#define CASE(X, Y) case gloox::X: return Y | #define CASE(X, Y) case gloox::X: return Y | ||||
#define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" | #define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" | ||||
switch (err) | switch (err) | ||||
{ | { | ||||
CASE(StanzaErrorUndefined, g_L10n.Translate("No error")); | CASE(StanzaErrorUndefined, g_L10n.Translate("No error")); | ||||
DEBUG_CASE(StanzaErrorBadRequest, "Server received malformed XML"); | DEBUG_CASE(StanzaErrorBadRequest, "Server received malformed XML"); | ||||
CASE(StanzaErrorConflict, g_L10n.Translate("Player already logged in")); | CASE(StanzaErrorConflict, g_L10n.Translate("Player already logged in")); | ||||
Show All 27 Lines | |||||
/** | /** | ||||
* Convert a gloox connection error enum to string | * Convert a gloox connection error enum to string | ||||
* Keep in sync with Gloox documentation | * Keep in sync with Gloox documentation | ||||
* | * | ||||
* @param err Error to be converted | * @param err Error to be converted | ||||
* @return Converted error string | * @return Converted error string | ||||
*/ | */ | ||||
std::string XmppClient::ConnectionErrorToString(gloox::ConnectionError err) const | std::string XmppClient::ConnectionErrorToString(gloox::ConnectionError err) | ||||
{ | { | ||||
#define CASE(X, Y) case gloox::X: return Y | #define CASE(X, Y) case gloox::X: return Y | ||||
#define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" | #define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" | ||||
switch (err) | switch (err) | ||||
{ | { | ||||
CASE(ConnNoError, g_L10n.Translate("No error")); | CASE(ConnNoError, g_L10n.Translate("No error")); | ||||
CASE(ConnStreamError, g_L10n.Translate("Stream error")); | CASE(ConnStreamError, g_L10n.Translate("Stream error")); | ||||
CASE(ConnStreamVersionError, g_L10n.Translate("The incoming stream version is unsupported")); | CASE(ConnStreamVersionError, g_L10n.Translate("The incoming stream version is unsupported")); | ||||
CASE(ConnStreamClosed, g_L10n.Translate("The stream has been closed by the server")); | CASE(ConnStreamClosed, g_L10n.Translate("The stream has been closed by the server")); | ||||
DEBUG_CASE(ConnProxyAuthRequired, "The HTTP/SOCKS5 proxy requires authentication"); | DEBUG_CASE(ConnProxyAuthRequired, "The HTTP/SOCKS5 proxy requires authentication"); | ||||
DEBUG_CASE(ConnProxyAuthFailed, "HTTP/SOCKS5 proxy authentication failed"); | DEBUG_CASE(ConnProxyAuthFailed, "HTTP/SOCKS5 proxy authentication failed"); | ||||
DEBUG_CASE(ConnProxyNoSupportedAuth, "The HTTP/SOCKS5 proxy requires an unsupported authentication mechanism"); | DEBUG_CASE(ConnProxyNoSupportedAuth, "The HTTP/SOCKS5 proxy requires an unsupported authentication mechanism"); | ||||
CASE(ConnIoError, g_L10n.Translate("An I/O error occurred")); | CASE(ConnIoError, g_L10n.Translate("An I/O error occurred")); | ||||
DEBUG_CASE(ConnParseError, "An XML parse error occurred"); | DEBUG_CASE(ConnParseError, "An XML parse error occurred"); | ||||
CASE(ConnConnectionRefused, g_L10n.Translate("The connection was refused by the server")); | CASE(ConnConnectionRefused, g_L10n.Translate("The connection was refused by the server")); | ||||
CASE(ConnDnsError, g_L10n.Translate("Resolving the server's hostname failed")); | CASE(ConnDnsError, g_L10n.Translate("Resolving the server's hostname failed")); | ||||
CASE(ConnOutOfMemory, g_L10n.Translate("This system is out of memory")); | CASE(ConnOutOfMemory, g_L10n.Translate("This system is out of memory")); | ||||
DEBUG_CASE(ConnNoSupportedAuth, "The authentication mechanisms the server offered are not supported or no authentication mechanisms were available"); | DEBUG_CASE(ConnNoSupportedAuth, "The authentication mechanisms the server offered are not supported or no authentication mechanisms were available"); | ||||
CASE(ConnTlsFailed, g_L10n.Translate("The server's certificate could not be verified or the TLS handshake did not complete successfully") + TLSErrorToString(m_certStatus)); | CASE(ConnTlsFailed, g_L10n.Translate("The server's certificate could not be verified or the TLS handshake did not complete successfully")); | ||||
CASE(ConnTlsNotAvailable, g_L10n.Translate("The server did not offer required TLS encryption")); | CASE(ConnTlsNotAvailable, g_L10n.Translate("The server did not offer required TLS encryption")); | ||||
DEBUG_CASE(ConnCompressionFailed, "Negotiation/initializing compression failed"); | DEBUG_CASE(ConnCompressionFailed, "Negotiation/initializing compression failed"); | ||||
CASE(ConnAuthenticationFailed, g_L10n.Translate("Authentication failed. Incorrect password or account does not exist")); | CASE(ConnAuthenticationFailed, g_L10n.Translate("Authentication failed. Incorrect password or account does not exist")); | ||||
CASE(ConnUserDisconnected, g_L10n.Translate("The user or system requested a disconnect")); | CASE(ConnUserDisconnected, g_L10n.Translate("The user or system requested a disconnect")); | ||||
CASE(ConnNotConnected, g_L10n.Translate("There is no active connection")); | CASE(ConnNotConnected, g_L10n.Translate("There is no active connection")); | ||||
default: | default: | ||||
return g_L10n.Translate("Unknown error"); | return g_L10n.Translate("Unknown error"); | ||||
} | } | ||||
#undef DEBUG_CASE | #undef DEBUG_CASE | ||||
#undef CASE | #undef CASE | ||||
} | } | ||||
/** | /** | ||||
* Convert a gloox registration result enum to string | * Convert a gloox registration result enum to string | ||||
* Keep in sync with Gloox documentation | * Keep in sync with Gloox documentation | ||||
* | * | ||||
* @param err Enum to be converted | * @param err Enum to be converted | ||||
* @return Converted string | * @return Converted string | ||||
*/ | */ | ||||
std::string XmppClient::RegistrationResultToString(gloox::RegistrationResult res) const | std::string XmppClient::RegistrationResultToString(gloox::RegistrationResult res) | ||||
{ | { | ||||
#define CASE(X, Y) case gloox::X: return Y | #define CASE(X, Y) case gloox::X: return Y | ||||
#define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" | #define DEBUG_CASE(X, Y) case gloox::X: return g_L10n.Translate("Error") + " (" + Y + ")" | ||||
switch (res) | switch (res) | ||||
{ | { | ||||
CASE(RegistrationSuccess, g_L10n.Translate("Your account has been successfully registered")); | CASE(RegistrationSuccess, g_L10n.Translate("Your account has been successfully registered")); | ||||
CASE(RegistrationNotAcceptable, g_L10n.Translate("Not all necessary information provided")); | CASE(RegistrationNotAcceptable, g_L10n.Translate("Not all necessary information provided")); | ||||
CASE(RegistrationConflict, g_L10n.Translate("Username already exists")); | CASE(RegistrationConflict, g_L10n.Translate("Username already exists")); | ||||
▲ Show 20 Lines • Show All 49 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
Intended ?