diff --git a/build/premake/premake4.lua b/build/premake/premake4.lua
index a9f55de440..da7bd929c7 100644
--- a/build/premake/premake4.lua
+++ b/build/premake/premake4.lua
@@ -18,6 +18,9 @@ newoption { trigger = "sysroot", description = "Set compiler system root path, u
newoption { trigger = "macosx-version-min", description = "Set minimum required version of the OS X API, the build will possibly fail if an older SDK is used, while newer API functions will be weakly linked (i.e. resolved at runtime)" }
newoption { trigger = "macosx-bundle", description = "Enable OSX bundle, the argument is the bundle identifier string (e.g. com.wildfiregames.0ad)" }
+newoption { trigger = "build-shared-glooxwrapper", description = "Rebuild glooxwrapper DLL for Windows. Requires the same compiler version that gloox was built with" }
+newoption { trigger = "use-shared-glooxwrapper", description = "Use prebuilt glooxwrapper DLL for Windows" }
+
newoption { trigger = "bindir", description = "Directory for executables (typically '/usr/games'); default is to be relocatable" }
newoption { trigger = "datadir", description = "Directory for data files (typically '/usr/share/games/0ad'); default is ../data/ relative to executable" }
newoption { trigger = "libdir", description = "Directory for libraries (typically '/usr/lib/games/0ad'); default is ./ relative to executable" }
@@ -523,6 +526,24 @@ function setup_static_lib_project (project_name, rel_source_dirs, extern_libs, e
end
end
+function setup_shared_lib_project (project_name, rel_source_dirs, extern_libs, extra_params)
+
+ local target_type = "SharedLib"
+ project_create(project_name, target_type)
+ project_add_contents(source_root, rel_source_dirs, {}, extra_params)
+ project_add_extern_libs(extern_libs, target_type)
+ project_add_x11_dirs()
+
+ if not extra_params["no_default_link"] then
+ table.insert(static_lib_names, project_name)
+ end
+
+ if os.is("windows") then
+ flags { "NoRTTI" }
+ links { "delayimp" }
+ end
+end
+
-- this is where the source tree is chopped up into static libs.
-- can be changed very easily; just copy+paste a new setup_static_lib_project,
@@ -546,6 +567,23 @@ function setup_all_libs ()
}
setup_static_lib_project("network", source_dirs, extern_libs, {})
+ if _OPTIONS["use-shared-glooxwrapper"] and not _OPTIONS["build-shared-glooxwrapper"] then
+ table.insert(static_lib_names_debug, "glooxwrapper_dbg")
+ table.insert(static_lib_names_release, "glooxwrapper")
+ else
+ source_dirs = {
+ "lobby/glooxwrapper",
+ }
+ extern_libs = {
+ "boost",
+ "gloox",
+ }
+ if _OPTIONS["build-shared-glooxwrapper"] then
+ setup_shared_lib_project("glooxwrapper", source_dirs, extern_libs, {})
+ else
+ setup_static_lib_project("glooxwrapper", source_dirs, extern_libs, {})
+ end
+ end
source_dirs = {
"simulation2",
@@ -1240,6 +1278,12 @@ function setup_tests()
configure_cxxtestgen()
links { static_lib_names }
+ configuration "Debug"
+ links { static_lib_names_debug }
+ configuration "Release"
+ links { static_lib_names_release }
+ configuration { }
+
links { "mocks_test" }
if _OPTIONS["atlas"] then
links { "AtlasObject" }
@@ -1320,6 +1364,11 @@ setup_all_libs()
-- work when changing the static lib breakdown.
project("pyrogenesis") -- Set the main project active
links { static_lib_names }
+ configuration "Debug"
+ links { static_lib_names_debug }
+ configuration "Release"
+ links { static_lib_names_release }
+ configuration { }
if _OPTIONS["atlas"] then
setup_atlas_projects()
diff --git a/build/workspaces/update-workspaces.bat b/build/workspaces/update-workspaces.bat
index 9b7fe290ab..c74722b4c6 100644
--- a/build/workspaces/update-workspaces.bat
+++ b/build/workspaces/update-workspaces.bat
@@ -2,7 +2,7 @@
rem ** Create Visual Studio Workspaces on Windows **
cd ..\premake
-if not exist ..\workspaces\vc2008\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2008" --collada %* vs2008
-if not exist ..\workspaces\vc2010\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2010" --collada %* vs2010
-if not exist ..\workspaces\vc2012\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2012" --collada %* vs2012
+if not exist ..\workspaces\vc2008\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2008" --collada --use-shared-glooxwrapper %* vs2008
+if not exist ..\workspaces\vc2010\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2010" --collada --use-shared-glooxwrapper %* vs2010
+if not exist ..\workspaces\vc2012\SKIP_PREMAKE_HERE premake4\bin\release\premake4 --outpath="../workspaces/vc2012" --collada --use-shared-glooxwrapper %* vs2012
cd ..\workspaces
diff --git a/source/lobby/glooxwrapper/glooxwrapper.cpp b/source/lobby/glooxwrapper/glooxwrapper.cpp
new file mode 100644
index 0000000000..e95f01c8a3
--- /dev/null
+++ b/source/lobby/glooxwrapper/glooxwrapper.cpp
@@ -0,0 +1,718 @@
+/* Copyright (C) 2013 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. 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 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
+
+#include "glooxwrapper.h"
+
+#include
+#include
+#include
+#include
+
+#if OS_WIN
+const std::string gloox::EmptyString = "";
+#endif
+
+void* glooxwrapper::glooxwrapper_alloc(size_t size)
+{
+ void* p = malloc(size);
+ if (p == NULL)
+ throw std::bad_alloc();
+ return p;
+}
+
+void glooxwrapper::glooxwrapper_free(void* p)
+{
+ free(p);
+}
+
+
+namespace glooxwrapper
+{
+
+class ConnectionListenerWrapper : public gloox::ConnectionListener
+{
+ glooxwrapper::ConnectionListener* m_Wrapped;
+public:
+ ConnectionListenerWrapper(glooxwrapper::ConnectionListener* wrapped) : m_Wrapped(wrapped) {}
+
+ virtual void onConnect()
+ {
+ m_Wrapped->onConnect();
+ }
+
+ virtual void onDisconnect(gloox::ConnectionError e)
+ {
+ m_Wrapped->onDisconnect(e);
+ }
+
+ virtual bool onTLSConnect(const gloox::CertInfo& info)
+ {
+ glooxwrapper::CertInfo infoWrapped;
+#define COPY(n) infoWrapped.n = info.n
+ COPY(status);
+ COPY(chain);
+ COPY(issuer);
+ COPY(server);
+ COPY(date_from);
+ COPY(date_to);
+ COPY(protocol);
+ COPY(cipher);
+ COPY(mac);
+ COPY(compression);
+#undef COPY
+ return m_Wrapped->onTLSConnect(infoWrapped);
+ }
+};
+
+class IqHandlerWrapper : public gloox::IqHandler
+{
+ glooxwrapper::IqHandler* m_Wrapped;
+public:
+ IqHandlerWrapper(glooxwrapper::IqHandler* wrapped) : m_Wrapped(wrapped) {}
+
+ virtual bool handleIq(const gloox::IQ& iq)
+ {
+ return m_Wrapped->handleIq(glooxwrapper::IQ(iq));
+ }
+
+ virtual void handleIqID(const gloox::IQ& iq, int context)
+ {
+ m_Wrapped->handleIqID(glooxwrapper::IQ(iq), context);
+ }
+};
+
+class MessageHandlerWrapper : public gloox::MessageHandler
+{
+ glooxwrapper::MessageHandler* m_Wrapped;
+public:
+ MessageHandlerWrapper(glooxwrapper::MessageHandler* wrapped) : m_Wrapped(wrapped) {}
+
+ virtual void handleMessage(const gloox::Message& msg, gloox::MessageSession* UNUSED(session))
+ {
+ /* MessageSession not supported */
+ glooxwrapper::Message msgWrapper(const_cast(&msg), false);
+ m_Wrapped->handleMessage(msgWrapper, NULL);
+ }
+};
+
+class MUCRoomHandlerWrapper : public gloox::MUCRoomHandler
+{
+ glooxwrapper::MUCRoomHandler* m_Wrapped;
+public:
+ MUCRoomHandlerWrapper(glooxwrapper::MUCRoomHandler* wrapped) : m_Wrapped(wrapped) {}
+
+ virtual ~MUCRoomHandlerWrapper() {}
+
+ virtual void handleMUCParticipantPresence(gloox::MUCRoom* UNUSED(room), const gloox::MUCRoomParticipant participant, const gloox::Presence& presence)
+ {
+ glooxwrapper::MUCRoomParticipant part;
+ glooxwrapper::JID nick(*participant.nick);
+ glooxwrapper::JID jid(*participant.jid);
+ glooxwrapper::JID actor(*participant.actor);
+ glooxwrapper::JID alternate(*participant.alternate);
+ part.nick = participant.nick ? &nick : NULL;
+ part.affiliation = participant.affiliation;
+ part.role = participant.role;
+ part.jid = participant.jid ? &jid : NULL;
+ part.flags = participant.flags;
+ part.reason = participant.reason;
+ part.actor = participant.actor ? &actor : NULL;
+ part.newNick = participant.newNick;
+ part.status = participant.status;
+ part.alternate = participant.alternate ? &alternate : NULL;
+
+ /* MUCRoom not supported */
+ m_Wrapped->handleMUCParticipantPresence(NULL, part, glooxwrapper::Presence(presence.presence()));
+
+ /* gloox 1.0 leaks some JIDs (fixed in 1.0.1), so clean them up */
+#if GLOOXVERSION == 0x10000
+ delete participant.jid;
+ delete participant.actor;
+ delete participant.alternate;
+#endif
+ }
+
+ virtual void handleMUCMessage(gloox::MUCRoom* UNUSED(room), const gloox::Message& msg, bool priv)
+ {
+ glooxwrapper::Message msgWrapper(const_cast(&msg), false);
+
+ /* MUCRoom not supported */
+ m_Wrapped->handleMUCMessage(NULL, msgWrapper, priv);
+ }
+
+ virtual bool handleMUCRoomCreation(gloox::MUCRoom* UNUSED(room))
+ {
+ /* Not supported */
+ return false;
+ }
+
+ virtual void handleMUCSubject(gloox::MUCRoom* UNUSED(room), const std::string& UNUSED(nick), const std::string& UNUSED(subject))
+ {
+ /* Not supported */
+ }
+
+ virtual void handleMUCInviteDecline(gloox::MUCRoom* UNUSED(room), const gloox::JID& UNUSED(invitee), const std::string& UNUSED(reason))
+ {
+ /* Not supported */
+ }
+
+ virtual void handleMUCError(gloox::MUCRoom* UNUSED(room), gloox::StanzaError error)
+ {
+ /* MUCRoom not supported */
+ m_Wrapped->handleMUCError(NULL, error);
+ }
+
+ virtual void handleMUCInfo(gloox::MUCRoom* UNUSED(room), int UNUSED(features), const std::string& UNUSED(name), const gloox::DataForm* UNUSED(infoForm))
+ {
+ /* Not supported */
+ }
+
+ virtual void handleMUCItems(gloox::MUCRoom* UNUSED(room), const gloox::Disco::ItemList& UNUSED(items))
+ {
+ /* Not supported */
+ }
+};
+
+class RegistrationHandlerWrapper : public gloox::RegistrationHandler
+{
+ glooxwrapper::RegistrationHandler* m_Wrapped;
+public:
+ RegistrationHandlerWrapper(glooxwrapper::RegistrationHandler* wrapped) : m_Wrapped(wrapped) {}
+
+ virtual void handleRegistrationFields(const gloox::JID& from, int fields, std::string instructions)
+ {
+ glooxwrapper::JID fromWrapped(from);
+ m_Wrapped->handleRegistrationFields(fromWrapped, fields, instructions);
+ }
+
+ virtual void handleAlreadyRegistered(const gloox::JID& from)
+ {
+ glooxwrapper::JID fromWrapped(from);
+ m_Wrapped->handleAlreadyRegistered(fromWrapped);
+ }
+
+ virtual void handleRegistrationResult(const gloox::JID& from, gloox::RegistrationResult regResult)
+ {
+ glooxwrapper::JID fromWrapped(from);
+ m_Wrapped->handleRegistrationResult(fromWrapped, regResult);
+ }
+
+ virtual void handleDataForm(const gloox::JID& from, const gloox::DataForm& UNUSED(form))
+ {
+ glooxwrapper::JID fromWrapped(from);
+ /* DataForm not supported */
+ m_Wrapped->handleDataForm(fromWrapped, *(glooxwrapper::DataForm*)NULL);
+ }
+
+ virtual void handleOOB(const gloox::JID& from, const gloox::OOB& UNUSED(oob))
+ {
+ glooxwrapper::JID fromWrapped(from);
+ /* OOB not supported */
+ m_Wrapped->handleOOB(fromWrapped, *(glooxwrapper::OOB*)NULL);
+ }
+};
+
+class StanzaExtensionWrapper : public gloox::StanzaExtension
+{
+public:
+ const glooxwrapper::StanzaExtension* m_Wrapped;
+ bool m_Owned;
+ std::string m_FilterString;
+
+ StanzaExtensionWrapper(const glooxwrapper::StanzaExtension* wrapped, bool owned) :
+ gloox::StanzaExtension(wrapped->extensionType()), m_Wrapped(wrapped), m_Owned(owned)
+ {
+ m_FilterString = m_Wrapped->filterString().to_string();
+ }
+
+ ~StanzaExtensionWrapper()
+ {
+ if (m_Owned)
+ delete m_Wrapped;
+ }
+
+ virtual const std::string& filterString() const
+ {
+ return m_FilterString;
+ }
+
+ virtual gloox::StanzaExtension* newInstance(const gloox::Tag* tag) const
+ {
+ glooxwrapper::Tag* tagWrapper = glooxwrapper::Tag::allocate(const_cast(tag), false);
+ gloox::StanzaExtension* ret = new StanzaExtensionWrapper(m_Wrapped->newInstance(tagWrapper), true);
+ glooxwrapper::Tag::free(tagWrapper);
+ return ret;
+ }
+
+ virtual gloox::Tag* tag() const
+ {
+ glooxwrapper::Tag* wrapper = m_Wrapped->tag();
+ gloox::Tag* ret = wrapper->stealWrapped();
+ glooxwrapper::Tag::free(wrapper);
+ return ret;
+ }
+
+ virtual gloox::StanzaExtension* clone() const
+ {
+ return new StanzaExtensionWrapper(m_Wrapped->clone(), true);
+ }
+};
+
+class ClientImpl
+{
+public:
+ // List of registered callback wrappers, to get deleted when Client is deleted
+ std::list > m_ConnectionListeners;
+ std::list > m_MessageHandlers;
+ std::list > m_IqHandlers;
+};
+
+} // namespace glooxwrapper
+
+
+glooxwrapper::Client::Client(const string& server)
+{
+ m_Wrapped = new gloox::Client(server.to_string());
+ m_DiscoWrapper = new glooxwrapper::Disco(m_Wrapped->disco());
+ m_Impl = new ClientImpl;
+}
+
+glooxwrapper::Client::Client(const JID& jid, const string& password, int port)
+{
+ m_Wrapped = new gloox::Client(jid.getWrapped(), password.to_string(), port);
+ m_DiscoWrapper = new glooxwrapper::Disco(m_Wrapped->disco());
+ m_Impl = new ClientImpl;
+}
+
+glooxwrapper::Client::~Client()
+{
+ delete m_Wrapped;
+ delete m_DiscoWrapper;
+ delete m_Impl;
+}
+
+bool glooxwrapper::Client::connect(bool block)
+{
+ return m_Wrapped->connect(block);
+}
+
+gloox::ConnectionError glooxwrapper::Client::recv(int timeout)
+{
+ return m_Wrapped->recv(timeout);
+}
+
+void glooxwrapper::Client::send(const IQ& iq)
+{
+ m_Wrapped->send(iq.getWrapped());
+}
+
+void glooxwrapper::Client::setTls(gloox::TLSPolicy tls)
+{
+ m_Wrapped->setTls(tls);
+}
+
+void glooxwrapper::Client::setCompression(bool compression)
+{
+ m_Wrapped->setCompression(compression);
+}
+
+void glooxwrapper::Client::setSASLMechanisms(int mechanisms)
+{
+ m_Wrapped->setSASLMechanisms(mechanisms);
+}
+
+void glooxwrapper::Client::disconnect()
+{
+ m_Wrapped->disconnect();
+}
+
+void glooxwrapper::Client::registerStanzaExtension(glooxwrapper::StanzaExtension* ext)
+{
+ gloox::StanzaExtension* stanza = new StanzaExtensionWrapper(ext, true);
+ m_Wrapped->registerStanzaExtension(stanza);
+}
+
+void glooxwrapper::Client::registerConnectionListener(glooxwrapper::ConnectionListener* hnd)
+{
+ gloox::ConnectionListener* listener = new ConnectionListenerWrapper(hnd);
+ m_Wrapped->registerConnectionListener(listener);
+ m_Impl->m_ConnectionListeners.push_back(boost::shared_ptr(listener));
+}
+
+void glooxwrapper::Client::registerMessageHandler(glooxwrapper::MessageHandler* hnd)
+{
+ gloox::MessageHandler* handler = new MessageHandlerWrapper(hnd);
+ m_Wrapped->registerMessageHandler(handler);
+ m_Impl->m_MessageHandlers.push_back(boost::shared_ptr(handler));
+}
+
+void glooxwrapper::Client::registerIqHandler(glooxwrapper::IqHandler* ih, int exttype)
+{
+ gloox::IqHandler* handler = new IqHandlerWrapper(ih);
+ m_Wrapped->registerIqHandler(handler, exttype);
+ m_Impl->m_IqHandlers.push_back(boost::shared_ptr(handler));
+}
+
+bool glooxwrapper::Client::removePresenceExtension(int type)
+{
+ return m_Wrapped->removePresenceExtension(type);
+}
+
+void glooxwrapper::Client::setPresence(gloox::Presence::PresenceType pres, int priority, const string& status)
+{
+ m_Wrapped->setPresence(pres, priority, status.to_string());
+}
+
+
+glooxwrapper::Disco::Disco(gloox::Disco* wrapped)
+{
+ m_Wrapped = wrapped;
+}
+
+void glooxwrapper::Disco::setVersion(const string& name, const string& version, const string& os)
+{
+ m_Wrapped->setVersion(name.to_string(), version.to_string(), os.to_string());
+}
+
+void glooxwrapper::Disco::setIdentity(const string& category, const string& type, const string& name)
+{
+ m_Wrapped->setIdentity(category.to_string(), type.to_string(), name.to_string());
+}
+
+
+glooxwrapper::IQ::IQ(gloox::IQ::IqType type, const JID& to, const string& id)
+{
+ m_Wrapped = new gloox::IQ(type, to.getWrapped(), id.to_string());
+ m_Owned = true;
+}
+
+glooxwrapper::IQ::~IQ()
+{
+ if (m_Owned)
+ delete m_Wrapped;
+}
+
+void glooxwrapper::IQ::addExtension(const glooxwrapper::StanzaExtension* se)
+{
+ m_Wrapped->addExtension(new StanzaExtensionWrapper(se, true));
+}
+
+const glooxwrapper::StanzaExtension* glooxwrapper::IQ::findExtension(int type) const
+{
+ const gloox::StanzaExtension* ext = m_Wrapped->findExtension(type);
+ if (!ext)
+ return NULL;
+ return static_cast(ext)->m_Wrapped;
+}
+
+gloox::StanzaError glooxwrapper::IQ::error_error() const
+{
+ return m_Wrapped->error()->error();
+}
+
+glooxwrapper::Tag* glooxwrapper::IQ::tag() const
+{
+ return Tag::allocate(m_Wrapped->tag(), true);
+}
+
+gloox::IQ::IqType glooxwrapper::IQ::subtype() const
+{
+ return m_Wrapped->subtype();
+}
+
+
+glooxwrapper::JID::JID()
+{
+ m_Wrapped = new gloox::JID();
+ m_Owned = true;
+}
+
+glooxwrapper::JID::JID(const glooxwrapper::string& jid)
+{
+ m_Wrapped = new gloox::JID(jid.to_string());
+ m_Owned = true;
+}
+
+void glooxwrapper::JID::init(const char* data, size_t len)
+{
+ m_Wrapped = new gloox::JID(std::string(data, data+len));
+ m_Owned = true;
+}
+
+glooxwrapper::JID::~JID()
+{
+ if (m_Owned)
+ delete m_Wrapped;
+}
+
+glooxwrapper::string glooxwrapper::JID::username() const
+{
+ return m_Wrapped->username();
+}
+
+glooxwrapper::string glooxwrapper::JID::resource() const
+{
+ return m_Wrapped->resource();
+};
+
+
+glooxwrapper::Message::Message(gloox::Message* wrapped, bool owned)
+ : m_Wrapped(wrapped), m_Owned(owned)
+{
+ m_From = new glooxwrapper::JID(m_Wrapped->from());
+}
+
+glooxwrapper::Message::~Message()
+{
+ if (m_Owned)
+ delete m_Wrapped;
+ delete m_From;
+}
+
+gloox::Message::MessageType glooxwrapper::Message::subtype() const
+{
+ return m_Wrapped->subtype();
+}
+
+const glooxwrapper::JID& glooxwrapper::Message::from() const
+{
+ return *m_From;
+}
+
+glooxwrapper::string glooxwrapper::Message::body() const
+{
+ return m_Wrapped->body();
+}
+
+glooxwrapper::string glooxwrapper::Message::subject(const string& lang) const
+{
+ return m_Wrapped->subject(lang.to_string());
+}
+
+glooxwrapper::string glooxwrapper::Message::thread() const
+{
+ return m_Wrapped->thread();
+}
+
+
+glooxwrapper::MUCRoom::MUCRoom(Client* parent, const JID& nick, MUCRoomHandler* mrh, MUCRoomConfigHandler* UNUSED(mrch))
+{
+ m_HandlerWrapper = new MUCRoomHandlerWrapper(mrh);
+ m_Wrapped = new gloox::MUCRoom(parent ? parent->getWrapped() : NULL, nick.getWrapped(), m_HandlerWrapper);
+}
+
+glooxwrapper::MUCRoom::~MUCRoom()
+{
+ delete m_Wrapped;
+ delete m_HandlerWrapper;
+}
+
+const glooxwrapper::string glooxwrapper::MUCRoom::nick() const
+{
+ return m_Wrapped->nick();
+}
+
+void glooxwrapper::MUCRoom::join(gloox::Presence::PresenceType type, const string& status, int priority)
+{
+ m_Wrapped->join(type, status.to_string(), priority);
+}
+
+void glooxwrapper::MUCRoom::leave(const string& msg)
+{
+ m_Wrapped->leave(msg.to_string());
+}
+
+void glooxwrapper::MUCRoom::send(const string& message)
+{
+ m_Wrapped->send(message.to_string());
+}
+
+void glooxwrapper::MUCRoom::setNick(const string& nick)
+{
+ m_Wrapped->setNick(nick.to_string());
+}
+
+void glooxwrapper::MUCRoom::setPresence(gloox::Presence::PresenceType presence, const string& msg)
+{
+ m_Wrapped->setPresence(presence, msg.to_string());
+}
+
+void glooxwrapper::MUCRoom::setRequestHistory(int value, gloox::MUCRoom::HistoryRequestType type)
+{
+ m_Wrapped->setRequestHistory(value, type);
+}
+
+void glooxwrapper::MUCRoom::kick(const string& nick, const string& reason)
+{
+ m_Wrapped->kick(nick.to_string(), reason.to_string());
+}
+
+void glooxwrapper::MUCRoom::ban(const string& nick, const string& reason)
+{
+ m_Wrapped->ban(nick.to_string(), reason.to_string());
+}
+
+
+glooxwrapper::Registration::Registration(Client* parent)
+{
+ m_Wrapped = new gloox::Registration(parent->getWrapped());
+}
+
+glooxwrapper::Registration::~Registration()
+{
+ delete m_Wrapped;
+}
+
+void glooxwrapper::Registration::fetchRegistrationFields()
+{
+ m_Wrapped->fetchRegistrationFields();
+}
+
+bool glooxwrapper::Registration::createAccount(int fields, const glooxwrapper::RegistrationFields& values)
+{
+ gloox::RegistrationFields valuesUnwrapped;
+#define COPY(n) valuesUnwrapped.n = values.n.to_string()
+ COPY(username);
+ COPY(nick);
+ COPY(password);
+ COPY(name);
+ COPY(first);
+ COPY(last);
+ COPY(email);
+ COPY(address);
+ COPY(city);
+ COPY(state);
+ COPY(zip);
+ COPY(phone);
+ COPY(url);
+ COPY(date);
+ COPY(misc);
+ COPY(text);
+#undef COPY
+ return m_Wrapped->createAccount(fields, valuesUnwrapped);
+}
+
+void glooxwrapper::Registration::registerRegistrationHandler(RegistrationHandler* rh)
+{
+ gloox::RegistrationHandler* handler = new RegistrationHandlerWrapper(rh);
+ m_Wrapped->registerRegistrationHandler(handler);
+ m_RegistrationHandlers.push_back(boost::shared_ptr(handler));
+}
+
+
+glooxwrapper::Tag::Tag(const string& name)
+{
+ m_Wrapped = new gloox::Tag(name.to_string());
+ m_Owned = true;
+}
+
+glooxwrapper::Tag::Tag(const string& name, const string& cdata)
+{
+ m_Wrapped = new gloox::Tag(name.to_string(), cdata.to_string());
+ m_Owned = true;
+}
+
+glooxwrapper::Tag::~Tag()
+{
+ if (m_Owned)
+ delete m_Wrapped;
+}
+
+glooxwrapper::Tag* glooxwrapper::Tag::allocate(const string& name)
+{
+ return new glooxwrapper::Tag(name);
+}
+
+glooxwrapper::Tag* glooxwrapper::Tag::allocate(const string& name, const string& cdata)
+{
+ return new glooxwrapper::Tag(name, cdata);
+}
+
+glooxwrapper::Tag* glooxwrapper::Tag::allocate(gloox::Tag* wrapped, bool owned)
+{
+ return new glooxwrapper::Tag(wrapped, owned);
+}
+
+void glooxwrapper::Tag::free(const glooxwrapper::Tag* tag)
+{
+ delete tag;
+}
+
+bool glooxwrapper::Tag::addAttribute(const string& name, const string& value)
+{
+ return m_Wrapped->addAttribute(name.to_string(), value.to_string());
+}
+
+glooxwrapper::string glooxwrapper::Tag::findAttribute(const string& name) const
+{
+ return m_Wrapped->findAttribute(name.to_string());
+}
+
+glooxwrapper::Tag* glooxwrapper::Tag::clone() const
+{
+ return new glooxwrapper::Tag(m_Wrapped->clone(), true);
+}
+
+glooxwrapper::string glooxwrapper::Tag::xmlns() const
+{
+ return m_Wrapped->xmlns();
+}
+
+bool glooxwrapper::Tag::setXmlns(const string& xmlns)
+{
+ return m_Wrapped->setXmlns(xmlns.to_string());
+}
+
+glooxwrapper::string glooxwrapper::Tag::xml() const
+{
+ return m_Wrapped->xml();
+}
+
+void glooxwrapper::Tag::addChild(Tag* child)
+{
+ m_Wrapped->addChild(child->stealWrapped());
+ Tag::free(child);
+}
+
+glooxwrapper::string glooxwrapper::Tag::name() const
+{
+ return m_Wrapped->name();
+}
+
+glooxwrapper::string glooxwrapper::Tag::cdata() const
+{
+ return m_Wrapped->cdata();
+}
+
+const glooxwrapper::Tag* glooxwrapper::Tag::findTag_clone(const string& expression) const
+{
+ const gloox::Tag* tag = m_Wrapped->findTag(expression.to_string());
+ if (!tag)
+ return NULL;
+ return new glooxwrapper::Tag(const_cast(tag), false);
+}
+
+glooxwrapper::ConstTagList glooxwrapper::Tag::findTagList_clone(const string& expression) const
+{
+ gloox::ConstTagList tagList = m_Wrapped->findTagList(expression.to_string());
+ glooxwrapper::ConstTagList tagListWrapper;
+ for (gloox::ConstTagList::iterator it = tagList.begin(); it != tagList.end(); ++it)
+ tagListWrapper.push_back(new glooxwrapper::Tag(const_cast(*it), false));
+ return tagListWrapper;
+}
diff --git a/source/lobby/glooxwrapper/glooxwrapper.h b/source/lobby/glooxwrapper/glooxwrapper.h
new file mode 100644
index 0000000000..9e110ca6ec
--- /dev/null
+++ b/source/lobby/glooxwrapper/glooxwrapper.h
@@ -0,0 +1,563 @@
+/* Copyright (C) 2013 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. 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 0 A.D. If not, see .
+ */
+
+#ifndef INCLUDED_GLOOXWRAPPER_H
+#define INCLUDED_GLOOXWRAPPER_H
+
+/*
+
+The gloox API uses various STL types (std::string, std::list, etc), and
+it has functions that acquire/release ownership of objects and expect the
+library's user's 'new'/'delete' functions to be compatible with the library's.
+
+These assumptions are invalid when the game and library are built with
+different compiler versions (or the same version with different build flags):
+the STL types have different layouts, and new/delete can use different heaps.
+
+We want to let people build the game on Windows with any compiler version
+(VC2008, 2010, 2012, 2013, and debug vs release), without requiring them to
+rebuild the gloox library themselves. And we don't want to provide ~8 different
+prebuilt versions of the library.
+
+glooxwrapper replaces the gloox API with a version that is safe to use across
+compiler versions. glooxwrapper and gloox must be compiled together with the
+same version, but the resulting library can be used with any other compiler.
+
+This is the small subset of the API that the game currently uses, with no
+attempt to be comprehensive.
+
+General design and rules:
+
+ * There is a strict boundary between gloox+glooxwrapper.cpp, and the game
+ code that includes glooxwrapper.h.
+ Objects allocated with new/delete on one side of the boundary must be
+ freed/allocated on the same side.
+ Objects allocated with glooxwrapper_alloc()/glooxwrapper_delete() can be
+ freely shared across the boundary.
+
+ * glooxwrapper.h and users of glooxwrapper must not use any types from
+ the gloox namespace, except for enums.
+
+ * std::string is replaced with glooxwrapper::string,
+ std::list with glooxwrapper::list
+
+ * Most glooxwrapper classes are simple wrappers around gloox classes.
+ Some always take ownership of their wrapped gloox object (i.e. their
+ destructor will delete the wrapped object too); some never do; and some
+ can be used either way (indicated by an m_Owned field).
+
+*/
+
+#if OS_WIN
+# include "lib/sysdep/os/win/win.h"
+// Prevent gloox pulling in windows.h
+# define _WINDOWS_
+#endif
+
+#include
+#include
+#include
+#include
+
+#include
+
+#if OS_WIN
+#define GLOOXWRAPPER_API __declspec(dllexport)
+#else
+#define GLOOXWRAPPER_API
+#endif
+
+namespace glooxwrapper
+{
+ class Client;
+ class DataForm;
+ class Disco;
+ class IQ;
+ class JID;
+ class MUCRoom;
+ class MUCRoomConfigHandler;
+ class Message;
+ class MessageSession;
+ class OOB;
+ class Presence;
+ class StanzaError;
+ class StanzaExtension;
+ class Tag;
+
+ class ClientImpl;
+ class MUCRoomHandlerWrapper;
+
+ GLOOXWRAPPER_API void* glooxwrapper_alloc(size_t size);
+ GLOOXWRAPPER_API void glooxwrapper_free(void* p);
+
+ class string
+ {
+ private:
+ size_t m_Size;
+ char* m_Data;
+ public:
+ string()
+ {
+ m_Size = 0;
+ m_Data = (char*)glooxwrapper_alloc(1);
+ m_Data[0] = '\0';
+ }
+
+ string(const string& str)
+ {
+ m_Size = str.m_Size;
+ m_Data = (char*)glooxwrapper_alloc(m_Size + 1);
+ memcpy(m_Data, str.m_Data, m_Size + 1);
+ }
+
+ string(const std::string& str) : m_Data(NULL)
+ {
+ m_Size = str.size();
+ m_Data = (char*)glooxwrapper_alloc(m_Size + 1);
+ memcpy(m_Data, str.c_str(), m_Size + 1);
+ }
+
+ string(const char* str)
+ {
+ m_Size = strlen(str);
+ m_Data = (char*)glooxwrapper_alloc(m_Size + 1);
+ memcpy(m_Data, str, m_Size + 1);
+ }
+
+ string& operator=(const string& str)
+ {
+ if (this != &str)
+ {
+ glooxwrapper_free(m_Data);
+ m_Size = str.m_Size;
+ m_Data = (char*)glooxwrapper_alloc(m_Size + 1);
+ memcpy(m_Data, str.m_Data, m_Size + 1);
+ }
+ return *this;
+ }
+
+ ~string()
+ {
+ glooxwrapper_free(m_Data);
+ }
+
+ std::string to_string() const
+ {
+ return std::string(m_Data, m_Size);
+ }
+
+ const char* c_str() const
+ {
+ return m_Data;
+ }
+
+ bool empty() const
+ {
+ return m_Size == 0;
+ }
+
+ bool operator==(const char* str) const
+ {
+ return strcmp(m_Data, str) == 0;
+ }
+
+ bool operator!=(const char* str) const
+ {
+ return strcmp(m_Data, str) != 0;
+ }
+ };
+
+ static inline std::ostream& operator<<(std::ostream& stream, const string& string)
+ {
+ return stream << string.c_str();
+ }
+
+ template
+ class list
+ {
+ private:
+ struct node
+ {
+ node(const T& item) : m_Item(item), m_Next(NULL) {}
+ T m_Item;
+ node* m_Next;
+ };
+ node* m_Head;
+ node* m_Tail;
+
+ public:
+ struct const_iterator
+ {
+ const node* m_Node;
+ const_iterator(const node* n) : m_Node(n) {}
+ bool operator!=(const const_iterator& it) { return m_Node != it.m_Node; }
+ const_iterator& operator++() { m_Node = m_Node->m_Next; return *this; }
+ const T& operator*() { return m_Node->m_Item; }
+ };
+ const_iterator begin() const { return const_iterator(m_Head); }
+ const_iterator end() const { return const_iterator(NULL); }
+
+ list() : m_Head(NULL), m_Tail(NULL) {}
+
+ list(const list& src) : m_Head(NULL), m_Tail(NULL)
+ {
+ *this = src;
+ }
+
+ list& operator=(const list& src)
+ {
+ if (this != &src)
+ {
+ clear();
+ for (node* n = src.m_Head; n; n = n->m_Next)
+ push_back(n->m_Item);
+ }
+ return *this;
+ }
+
+ ~list()
+ {
+ clear();
+ }
+
+ void push_back(const T& item)
+ {
+ node* n = new (glooxwrapper_alloc(sizeof(node))) node(item);
+ if (m_Tail)
+ m_Tail->m_Next = n;
+ m_Tail = n;
+ if (!m_Head)
+ m_Head = n;
+ }
+
+ void clear()
+ {
+ node* n = m_Head;
+ while (n)
+ {
+ node* next = n->m_Next;
+ glooxwrapper_free(n);
+ n = next;
+ }
+ m_Head = m_Tail = NULL;
+ }
+ };
+
+ typedef glooxwrapper::list TagList;
+ typedef glooxwrapper::list ConstTagList;
+
+ struct CertInfo
+ {
+ int status;
+ bool chain;
+ string issuer;
+ string server;
+ int date_from;
+ int date_to;
+ string protocol;
+ string cipher;
+ string mac;
+ string compression;
+ };
+
+ struct RegistrationFields
+ {
+ string username;
+ string nick;
+ string password;
+ string name;
+ string first;
+ string last;
+ string email;
+ string address;
+ string city;
+ string state;
+ string zip;
+ string phone;
+ string url;
+ string date;
+ string misc;
+ string text;
+ };
+
+ struct MUCRoomParticipant
+ {
+ JID* nick;
+ gloox::MUCRoomAffiliation affiliation;
+ gloox::MUCRoomRole role;
+ JID* jid;
+ int flags;
+ string reason;
+ JID* actor;
+ string newNick;
+ string status;
+ JID* alternate;
+ };
+
+
+ class GLOOXWRAPPER_API ConnectionListener
+ {
+ public:
+ virtual ~ConnectionListener() {}
+ virtual void onConnect() = 0;
+ virtual void onDisconnect(gloox::ConnectionError e) = 0;
+ virtual bool onTLSConnect(const CertInfo& info) = 0;
+ };
+
+ class GLOOXWRAPPER_API IqHandler
+ {
+ public:
+ virtual ~IqHandler() {}
+ virtual bool handleIq(const IQ& iq) = 0;
+ virtual void handleIqID(const IQ& iq, int context) = 0;
+ };
+
+ class GLOOXWRAPPER_API MessageHandler
+ {
+ public:
+ virtual ~MessageHandler() {}
+ virtual void handleMessage(const Message& msg, MessageSession* session = 0) = 0; // MessageSession not supported
+ };
+
+ class GLOOXWRAPPER_API MUCRoomHandler
+ {
+ public:
+ virtual ~MUCRoomHandler() {}
+ virtual void handleMUCParticipantPresence(MUCRoom* room, const MUCRoomParticipant participant, const Presence& presence) = 0; // MUCRoom not supported
+ virtual void handleMUCMessage(MUCRoom* room, const Message& msg, bool priv) = 0; // MUCRoom not supported
+ virtual void handleMUCError(MUCRoom* room, gloox::StanzaError error) = 0; // MUCRoom not supported
+ };
+
+ class GLOOXWRAPPER_API RegistrationHandler
+ {
+ public:
+ virtual ~RegistrationHandler() {}
+ virtual void handleRegistrationFields(const JID& from, int fields, string instructions) = 0;
+ virtual void handleAlreadyRegistered(const JID& from) = 0;
+ virtual void handleRegistrationResult(const JID& from, gloox::RegistrationResult regResult) = 0;
+ virtual void handleDataForm(const JID& from, const DataForm& form) = 0; // DataForm not supported
+ virtual void handleOOB(const JID& from, const OOB& oob) = 0; // OOB not supported
+ };
+
+ class GLOOXWRAPPER_API StanzaExtension
+ {
+ public:
+ StanzaExtension(int type) : m_extensionType(type) {}
+ virtual ~StanzaExtension() {}
+ virtual const string& filterString() const = 0;
+ virtual StanzaExtension* newInstance(const Tag* tag) const = 0;
+ virtual glooxwrapper::Tag* tag() const = 0;
+ virtual StanzaExtension* clone() const = 0;
+
+ int extensionType() const { return m_extensionType; }
+ private:
+ int m_extensionType;
+ };
+
+
+ class GLOOXWRAPPER_API Client
+ {
+ NONCOPYABLE(Client);
+ private:
+ gloox::Client* m_Wrapped;
+ ClientImpl* m_Impl;
+ Disco* m_DiscoWrapper;
+
+ public:
+ gloox::Client* getWrapped() { return m_Wrapped; }
+
+ bool connect(bool block = true);
+ gloox::ConnectionError recv(int timeout = -1);
+ void send(const IQ& iq);
+
+ void setTls(gloox::TLSPolicy tls);
+ void setCompression(bool compression);
+
+ void setSASLMechanisms(int mechanisms);
+ void registerStanzaExtension(StanzaExtension* ext);
+ void registerConnectionListener(ConnectionListener* cl);
+ void registerIqHandler(IqHandler* ih, int exttype);
+ void registerMessageHandler(MessageHandler* mh);
+
+ bool removePresenceExtension(int type);
+
+ Disco* disco() const { return m_DiscoWrapper; }
+
+ Client(const string& server);
+ Client(const JID& jid, const string& password, int port = -1);
+ ~Client();
+
+ void setPresence(gloox::Presence::PresenceType pres, int priority, const string& status = "");
+ void disconnect();
+ };
+
+ class GLOOXWRAPPER_API Disco
+ {
+ NONCOPYABLE(Disco);
+ private:
+ gloox::Disco* m_Wrapped;
+ public:
+ Disco(gloox::Disco* wrapped);
+ void setVersion(const string& name, const string& version, const string& os = "");
+ void setIdentity(const string& category, const string& type, const string& name = "");
+ };
+
+ class GLOOXWRAPPER_API IQ
+ {
+ NONCOPYABLE(IQ);
+ private:
+ gloox::IQ* m_Wrapped;
+ bool m_Owned;
+ public:
+ const gloox::IQ& getWrapped() const { return *m_Wrapped; }
+ IQ(const gloox::IQ& iq) : m_Wrapped(const_cast(&iq)), m_Owned(false) { }
+
+ IQ(gloox::IQ::IqType type, const JID& to, const string& id = "");
+ ~IQ();
+
+ void addExtension(const StanzaExtension* se);
+ const StanzaExtension* findExtension(int type) const;
+
+ template
+ inline const T* findExtension(int type) const
+ {
+ return static_cast(findExtension(type));
+ }
+
+ gloox::IQ::IqType subtype() const;
+
+ gloox::StanzaError error_error() const; // wrapper for ->error()->error()
+ Tag* tag() const;
+ };
+
+ class GLOOXWRAPPER_API JID
+ {
+ NONCOPYABLE(JID);
+ private:
+ gloox::JID* m_Wrapped;
+ bool m_Owned;
+ void init(const char* data, size_t len);
+ public:
+ const gloox::JID& getWrapped() const { return *m_Wrapped; }
+ JID(const gloox::JID& jid) : m_Wrapped(const_cast(&jid)), m_Owned(false) { }
+
+ JID();
+ JID(const string& jid);
+ JID(const std::string& jid) { init(jid.c_str(), jid.size()); }
+ ~JID();
+
+ string username() const;
+ string resource() const;
+ };
+
+ class GLOOXWRAPPER_API Message
+ {
+ NONCOPYABLE(Message);
+ private:
+ gloox::Message* m_Wrapped;
+ bool m_Owned;
+ glooxwrapper::JID* m_From;
+ public:
+ Message(gloox::Message* wrapped, bool owned);
+ ~Message();
+ gloox::Message::MessageType subtype() const;
+ const JID& from() const;
+ string body() const;
+ string subject(const string& lang = "default") const;
+ string thread() const;
+ };
+
+ class GLOOXWRAPPER_API MUCRoom
+ {
+ NONCOPYABLE(MUCRoom);
+ private:
+ gloox::MUCRoom* m_Wrapped;
+ MUCRoomHandlerWrapper* m_HandlerWrapper;
+ public:
+ MUCRoom(Client* parent, const JID& nick, MUCRoomHandler* mrh, MUCRoomConfigHandler* mrch = 0);
+ ~MUCRoom();
+ const string nick() const;
+ void join(gloox::Presence::PresenceType type = gloox::Presence::Available, const string& status = "", int priority = 0);
+ void leave(const string& msg = "");
+ void send(const string& message);
+ void setNick(const string& nick);
+ void setPresence(gloox::Presence::PresenceType presence, const string& msg = "");
+ void setRequestHistory(int value, gloox::MUCRoom::HistoryRequestType type);
+ void kick(const string& nick, const string& reason);
+ void ban(const string& nick, const string& reason);
+ };
+
+ class GLOOXWRAPPER_API Presence
+ {
+ gloox::Presence::PresenceType m_Presence;
+ public:
+ Presence(gloox::Presence::PresenceType presence) : m_Presence(presence) {}
+ gloox::Presence::PresenceType presence() const { return m_Presence; }
+ };
+
+ class GLOOXWRAPPER_API Registration
+ {
+ NONCOPYABLE(Registration);
+ private:
+ gloox::Registration* m_Wrapped;
+ std::list > m_RegistrationHandlers;
+ public:
+ Registration(Client* parent);
+ ~Registration();
+ void fetchRegistrationFields();
+ bool createAccount(int fields, const RegistrationFields& values);
+ void registerRegistrationHandler(RegistrationHandler* rh);
+ };
+
+ class GLOOXWRAPPER_API Tag
+ {
+ NONCOPYABLE(Tag);
+ private:
+ gloox::Tag* m_Wrapped;
+ bool m_Owned;
+
+ Tag(const string& name);
+ Tag(const string& name, const string& cdata);
+ Tag(gloox::Tag* wrapped, bool owned) : m_Wrapped(wrapped), m_Owned(owned) {}
+ ~Tag();
+
+ public:
+ // Internal use:
+ gloox::Tag* getWrapped() { return m_Wrapped; }
+ gloox::Tag* stealWrapped() { m_Owned = false; return m_Wrapped; }
+ static Tag* allocate(gloox::Tag* wrapped, bool owned);
+
+ // Instead of using new/delete, Tags must be allocated/freed with these functions
+ static Tag* allocate(const string& name);
+ static Tag* allocate(const string& name, const string& cdata);
+ static void free(const Tag* tag);
+
+ bool addAttribute(const string& name, const string& value);
+ string findAttribute(const string& name) const;
+ Tag* clone() const;
+ string xmlns() const;
+ bool setXmlns(const string& xmlns);
+ string xml() const;
+ void addChild(Tag* child);
+ string name() const;
+ string cdata() const;
+ const Tag* findTag_clone(const string& expression) const; // like findTag but must be Tag::free()d
+ ConstTagList findTagList_clone(const string& expression) const; // like findTagList but each tag must be Tag::free()d
+ };
+}
+
+#endif // INCLUDED_GLOOXWRAPPER_H
diff --git a/source/pch/glooxwrapper/precompiled.cpp b/source/pch/glooxwrapper/precompiled.cpp
new file mode 100644
index 0000000000..82eb54bbb0
--- /dev/null
+++ b/source/pch/glooxwrapper/precompiled.cpp
@@ -0,0 +1,18 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. 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 0 A.D. If not, see .
+ */
+
+#include "precompiled.h"
diff --git a/source/pch/glooxwrapper/precompiled.h b/source/pch/glooxwrapper/precompiled.h
new file mode 100644
index 0000000000..8d3653b99f
--- /dev/null
+++ b/source/pch/glooxwrapper/precompiled.h
@@ -0,0 +1,18 @@
+/* Copyright (C) 2009 Wildfire Games.
+ * This file is part of 0 A.D.
+ *
+ * 0 A.D. 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 0 A.D. 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 0 A.D. If not, see .
+ */
+
+#include "lib/precompiled.h" // common precompiled header