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