From f035510e47989e2a2ba3beb8bd8be069dbc6394f Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 8 Dec 2011 17:55:23 +0100 Subject: [PATCH 01/74] Fixed PresenceOracle --- .../CombinedOutgoingFileTransferManager.cpp | 3 +- .../CombinedOutgoingFileTransferManager.h | 6 +- include/transport/presenceoracle.h | 57 ++++++++ include/transport/transport.h | 6 +- include/transport/user.h | 4 +- src/presenceoracle.cpp | 134 ++++++++++++++++++ src/transport.cpp | 4 +- src/user.cpp | 1 + 8 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 include/transport/presenceoracle.h create mode 100644 src/presenceoracle.cpp diff --git a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp index 710b8f83..ac06ab75 100644 --- a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp +++ b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.cpp @@ -18,13 +18,12 @@ #include #include #include -#include #include namespace Swift { -CombinedOutgoingFileTransferManager::CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, PresenceOracle *presOracle, SOCKS5BytestreamServer *bytestreamServer) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), presenceOracle(presOracle), bytestreamServer(bytestreamServer) { +CombinedOutgoingFileTransferManager::CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle *presOracle, SOCKS5BytestreamServer *bytestreamServer) : jsManager(jingleSessionManager), iqRouter(router), capsProvider(capsProvider), remoteFactory(remoteFactory), localFactory(localFactory), bytestreamRegistry(bytestreamRegistry), bytestreamProxy(bytestreamProxy), presenceOracle(presOracle), bytestreamServer(bytestreamServer) { idGenerator = new IDGenerator(); } diff --git a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h index 765e6ba2..17e7fc58 100644 --- a/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h +++ b/include/Swiften/FileTransfer/CombinedOutgoingFileTransferManager.h @@ -11,6 +11,8 @@ #include +#include "transport/presenceoracle.h" + namespace Swift { class JingleSessionManager; @@ -30,7 +32,7 @@ class PresenceOracle; class CombinedOutgoingFileTransferManager { public: - CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, PresenceOracle* presOracle, SOCKS5BytestreamServer *server); + CombinedOutgoingFileTransferManager(JingleSessionManager* jingleSessionManager, IQRouter* router, EntityCapsProvider* capsProvider, RemoteJingleTransportCandidateSelectorFactory* remoteFactory, LocalJingleTransportCandidateGeneratorFactory* localFactory, SOCKS5BytestreamRegistry* bytestreamRegistry, SOCKS5BytestreamProxy* bytestreamProxy, Transport::PresenceOracle* presOracle, SOCKS5BytestreamServer *server); ~CombinedOutgoingFileTransferManager(); boost::shared_ptr createOutgoingFileTransfer(const JID& from, const JID& to, boost::shared_ptr, const StreamInitiationFileInfo&); @@ -46,7 +48,7 @@ private: IDGenerator *idGenerator; SOCKS5BytestreamRegistry* bytestreamRegistry; SOCKS5BytestreamProxy* bytestreamProxy; - PresenceOracle* presenceOracle; + Transport::PresenceOracle* presenceOracle; SOCKS5BytestreamServer *bytestreamServer; }; diff --git a/include/transport/presenceoracle.h b/include/transport/presenceoracle.h new file mode 100644 index 00000000..763cf83d --- /dev/null +++ b/include/transport/presenceoracle.h @@ -0,0 +1,57 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once + +#include + +#include +#include +#include + +#include + +namespace Transport { + +class PresenceOracle { + public: + PresenceOracle(Swift::StanzaChannel* stanzaChannel); + ~PresenceOracle(); + + Swift::Presence::ref getLastPresence(const Swift::JID&) const; + Swift::Presence::ref getHighestPriorityPresence(const Swift::JID& bareJID) const; + std::vector getAllPresence(const Swift::JID& bareJID) const; + + public: + boost::signal onPresenceChange; + + private: + void handleIncomingPresence(Swift::Presence::ref presence); + void handleStanzaChannelAvailableChanged(bool); + + private: + typedef std::map PresenceMap; + typedef std::map PresencesMap; + PresencesMap entries_; + Swift::StanzaChannel* stanzaChannel_; +}; + +} + diff --git a/include/transport/transport.h b/include/transport/transport.h index 40442dcc..4a875754 100644 --- a/include/transport/transport.h +++ b/include/transport/transport.h @@ -27,7 +27,6 @@ #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Disco/CapsManager.h" #include "Swiften/Disco/CapsMemoryStorage.h" -#include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Network/BoostTimerFactory.h" #include "Swiften/Network/BoostIOServiceThread.h" #include "Swiften/Server/UserRegistry.h" @@ -37,6 +36,7 @@ #include #include "transport/config.h" #include "transport/factory.h" +#include "transport/presenceoracle.h" namespace Transport { // typedef enum { CLIENT_FEATURE_ROSTERX = 2, @@ -92,7 +92,7 @@ namespace Transport { /// You can use it to check current resource connected for particular user. /// \return Swift::PresenceOracle associated with this Transport::Component. - Swift::PresenceOracle *getPresenceOracle(); + PresenceOracle *getPresenceOracle(); /// Returns True if the component is in server mode. @@ -179,7 +179,7 @@ namespace Transport { Swift::EntityCapsManager *m_entityCapsManager; Swift::CapsManager *m_capsManager; Swift::CapsMemoryStorage *m_capsMemoryStorage; - Swift::PresenceOracle *m_presenceOracle; + PresenceOracle *m_presenceOracle; Swift::StanzaChannel *m_stanzaChannel; Swift::IQRouter *m_iqRouter; diff --git a/include/transport/user.h b/include/transport/user.h index de134634..4e98c4a8 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -22,7 +22,6 @@ #include #include "Swiften/Swiften.h" -#include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Disco/EntityCapsProvider.h" #include "storagebackend.h" @@ -35,6 +34,7 @@ class Component; class RosterManager; class ConversationManager; class UserManager; +class PresenceOracle; struct UserInfo; /// Represents online XMPP user. @@ -125,7 +125,7 @@ class User : public Swift::EntityCapsProvider { UserManager *m_userManager; ConversationManager *m_conversationManager; Swift::EntityCapsManager *m_entityCapsManager; - Swift::PresenceOracle *m_presenceOracle; + PresenceOracle *m_presenceOracle; UserInfo m_userInfo; void *m_data; bool m_connected; diff --git a/src/presenceoracle.cpp b/src/presenceoracle.cpp new file mode 100644 index 00000000..c6717f3b --- /dev/null +++ b/src/presenceoracle.cpp @@ -0,0 +1,134 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/presenceoracle.h" + +#include + +using namespace Swift; + +namespace Transport { + +PresenceOracle::PresenceOracle(StanzaChannel* stanzaChannel) { + stanzaChannel_ = stanzaChannel; + stanzaChannel_->onPresenceReceived.connect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); + stanzaChannel_->onAvailableChanged.connect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); +} + +PresenceOracle::~PresenceOracle() { + stanzaChannel_->onPresenceReceived.disconnect(boost::bind(&PresenceOracle::handleIncomingPresence, this, _1)); + stanzaChannel_->onAvailableChanged.disconnect(boost::bind(&PresenceOracle::handleStanzaChannelAvailableChanged, this, _1)); +} + +void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) { + if (available) { + entries_.clear(); + } +} + + +void PresenceOracle::handleIncomingPresence(Presence::ref presence) { + // ignore presences for some contact, we're checking only presences for the transport itself here. + if (!presence->getTo().getNode().empty()) { + return; + } + + JID bareJID(presence->getFrom().toBare()); + if (presence->getType() == Presence::Subscribe) { + } + else { + Presence::ref passedPresence = presence; + if (presence->getType() == Presence::Unsubscribe) { + /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ + passedPresence = Presence::ref(new Presence()); + passedPresence->setType(Presence::Unavailable); + passedPresence->setFrom(bareJID); + passedPresence->setStatus(presence->getStatus()); + } + std::map > jidMap = entries_[bareJID]; + if (passedPresence->getFrom().isBare() && presence->getType() == Presence::Unavailable) { + /* Have a bare-JID only presence of offline */ + jidMap.clear(); + } else if (passedPresence->getType() == Presence::Available) { + /* Don't have a bare-JID only offline presence once there are available presences */ + jidMap.erase(bareJID); + } + if (passedPresence->getType() == Presence::Unavailable && jidMap.size() > 1) { + jidMap.erase(passedPresence->getFrom()); + } else { + jidMap[passedPresence->getFrom()] = passedPresence; + } + entries_[bareJID] = jidMap; + onPresenceChange(passedPresence); + } +} + +Presence::ref PresenceOracle::getLastPresence(const JID& jid) const { + PresencesMap::const_iterator i = entries_.find(jid.toBare()); + if (i == entries_.end()) { + return Presence::ref(); + } + PresenceMap presenceMap = i->second; + PresenceMap::const_iterator j = presenceMap.find(jid); + if (j != presenceMap.end()) { + return j->second; + } + else { + return Presence::ref(); + } +} + +std::vector PresenceOracle::getAllPresence(const JID& bareJID) const { + std::vector results; + PresencesMap::const_iterator i = entries_.find(bareJID); + if (i == entries_.end()) { + return results; + } + PresenceMap presenceMap = i->second; + PresenceMap::const_iterator j = presenceMap.begin(); + for (; j != presenceMap.end(); ++j) { + Presence::ref current = j->second; + results.push_back(current); + } + return results; +} + +Presence::ref PresenceOracle::getHighestPriorityPresence(const JID& bareJID) const { + PresencesMap::const_iterator i = entries_.find(bareJID); + if (i == entries_.end()) { + return Presence::ref(); + } + PresenceMap presenceMap = i->second; + PresenceMap::const_iterator j = presenceMap.begin(); + Presence::ref highest; + for (; j != presenceMap.end(); ++j) { + Presence::ref current = j->second; + if (!highest + || current->getPriority() > highest->getPriority() + || (current->getPriority() == highest->getPriority() + && StatusShow::typeToAvailabilityOrdering(current->getShow()) > StatusShow::typeToAvailabilityOrdering(highest->getShow()))) { + highest = current; + } + + } + return highest; +} + +} diff --git a/src/transport.cpp b/src/transport.cpp index ddcda381..f7e862d8 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -137,7 +137,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_entityCapsManager = new EntityCapsManager(m_capsManager, m_stanzaChannel); m_entityCapsManager->onCapsChanged.connect(boost::bind(&Component::handleCapsChanged, this, _1)); - m_presenceOracle = new PresenceOracle(m_stanzaChannel); + m_presenceOracle = new Transport::PresenceOracle(m_stanzaChannel); m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1)); m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter, m_config); @@ -170,7 +170,7 @@ Swift::StanzaChannel *Component::getStanzaChannel() { return m_stanzaChannel; } -Swift::PresenceOracle *Component::getPresenceOracle() { +Transport::PresenceOracle *Component::getPresenceOracle() { return m_presenceOracle; } diff --git a/src/user.cpp b/src/user.cpp index 61740525..0467ee86 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -24,6 +24,7 @@ #include "transport/rostermanager.h" #include "transport/usermanager.h" #include "transport/conversationmanager.h" +#include "transport/presenceoracle.h" #include "Swiften/Swiften.h" #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Elements/StreamError.h" From 23f8b4ef14f14c9aec6c067285ab02abfb664338 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 8 Dec 2011 23:19:09 +0100 Subject: [PATCH 02/74] Fixed registration from Pidgin --- src/userregistration.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 646722ed..9160465f 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -286,6 +286,10 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID else if (textSingle->getName() == "encoding") { encoding = textSingle->getValue(); } + // Pidgin sends it as textSingle, not sure why... + else if (textSingle->getName() == "password") { + payload->setPassword(textSingle->getValue()); + } continue; } From 1dafed2e6b187e6f95d6d2b0863a83bfbb90fbb1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 9 Dec 2011 12:12:16 +0100 Subject: [PATCH 03/74] Changelog update --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3372f46a..36a65268 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Version 2.0.0-beta (X-X-X): + General: + * Fixed registration from Pidgin. + * Unsubscribe presence sent to some buddy doesn't disconnect the account. + * Remote Roster requests are not sent to resources, but to bare JID. + * Added automatic reconnection in case of non-fatal error. + * Added more error messages. + version 2.0.0 alpha (2011-12-06): General: * First Spectrum 2.0.0 alpha release, check more on From 4c334e9f1c0ba952c32a1b52eadd232c58f363ca Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 9 Dec 2011 13:51:50 +0100 Subject: [PATCH 04/74] Move random port generating to util.cpp --- include/transport/util.h | 2 ++ spectrum/src/sample2.cfg | 4 +++- spectrum_manager/src/CMakeLists.txt | 2 +- src/config.cpp | 18 ++++-------------- src/presenceoracle.cpp | 6 ++++-- src/transport.cpp | 1 + src/util.cpp | 9 +++++++++ 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/include/transport/util.h b/include/transport/util.h index fe171115..d79a555f 100644 --- a/include/transport/util.h +++ b/include/transport/util.h @@ -40,6 +40,8 @@ std::string serializeGroups(const std::vector &groups); std::vector deserializeGroups(std::string &groups); +int getRandomPort(const std::string &s); + } } diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index ae1f0d73..91ab58fc 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -24,7 +24,9 @@ port = 5222 backend_host = localhost # Port on which Spectrum listens for backends. -backend_port=10001 +# By default Spectrum chooses random backend port and there's +# no need to change it normally +#backend_port=10001 # Full path to PKCS#12 cetficiate used for TLS in server mode. #cert= diff --git a/spectrum_manager/src/CMakeLists.txt b/spectrum_manager/src/CMakeLists.txt index 5024e70c..5f93dd9c 100644 --- a/spectrum_manager/src/CMakeLists.txt +++ b/spectrum_manager/src/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp) -ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp) +ADD_EXECUTABLE(spectrum2_manager ${SRC} ../../src/config.cpp ../../src/util.cpp) target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY}) diff --git a/src/config.cpp b/src/config.cpp index b72caa86..c5ca48b5 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -19,6 +19,7 @@ */ #include "transport/config.h" +#include "transport/util.h" #include #ifdef _MSC_VER #include @@ -120,13 +121,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description else if (opt.string_key == "service.backend_port") { found_backend_port = true; if (opt.value[0] == "0") { - unsigned long r = 0; - BOOST_FOREACH(char c, _jid) { - r += (int) c; - } - srand(time(NULL) + r); - int randomPort = 30000 + rand() % 10000; - opt.value[0] = boost::lexical_cast(randomPort); + opt.value[0] = boost::lexical_cast(Util::getRandomPort(_jid.empty() ? jid : _jid)); } } else if (opt.string_key == "service.working_dir") { @@ -148,14 +143,9 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description parsed.options.push_back(boost::program_options::basic_option("service.pidfile", value)); } if (!found_backend_port) { - unsigned long r = 0; - BOOST_FOREACH(char c, _jid) { - r += (int) c; - } - srand(time(NULL) + r); - int randomPort = 30000 + rand() % 10000; std::vector value; - value.push_back(boost::lexical_cast(randomPort)); + std::string p = boost::lexical_cast(Util::getRandomPort(_jid.empty() ? jid : _jid)); + value.push_back(p); parsed.options.push_back(boost::program_options::basic_option("service.backend_port", value)); } diff --git a/src/presenceoracle.cpp b/src/presenceoracle.cpp index c6717f3b..13b3ca5b 100644 --- a/src/presenceoracle.cpp +++ b/src/presenceoracle.cpp @@ -19,6 +19,7 @@ */ #include "transport/presenceoracle.h" +#include "Swiften/Swiften.h" #include @@ -46,9 +47,10 @@ void PresenceOracle::handleStanzaChannelAvailableChanged(bool available) { void PresenceOracle::handleIncomingPresence(Presence::ref presence) { // ignore presences for some contact, we're checking only presences for the transport itself here. - if (!presence->getTo().getNode().empty()) { + bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; + // filter out login/logout presence spam + if (!presence->getTo().getNode().empty() && isMUC == false) return; - } JID bareJID(presence->getFrom().toBare()); if (presence->getType() == Presence::Subscribe) { diff --git a/src/transport.cpp b/src/transport.cpp index f7e862d8..0d1d06ea 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -45,6 +45,7 @@ #include "log4cxx/consoleappender.h" #include "log4cxx/patternlayout.h" #include "log4cxx/propertyconfigurator.h" +#include "Swiften/Swiften.h" using namespace Swift; using namespace boost; diff --git a/src/util.cpp b/src/util.cpp index 7053ea06..315726cb 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -128,6 +128,15 @@ std::vector deserializeGroups(std::string &groups) { return ret; } +int getRandomPort(const std::string &s) { + unsigned long r = 0; + BOOST_FOREACH(char c, s) { + r += (int) c; + } + srand(time(NULL) + r); + return 30000 + rand() % 10000; +} + } } From 25390730f602c53814a2e570661f912a10753469 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 9 Dec 2011 15:03:46 +0100 Subject: [PATCH 05/74] Don't pass subscription in PresenceEracle --- src/presenceoracle.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/presenceoracle.cpp b/src/presenceoracle.cpp index 13b3ca5b..a3245502 100644 --- a/src/presenceoracle.cpp +++ b/src/presenceoracle.cpp @@ -53,11 +53,11 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) { return; JID bareJID(presence->getFrom().toBare()); - if (presence->getType() == Presence::Subscribe) { + if (presence->getType() == Presence::Subscribe || presence->getType() == Presence::Subscribed) { } else { Presence::ref passedPresence = presence; - if (presence->getType() == Presence::Unsubscribe) { + if (presence->getType() == Presence::Unsubscribe || presence->getType() == Presence::Unsubscribed) { /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ passedPresence = Presence::ref(new Presence()); passedPresence->setType(Presence::Unavailable); From 9e84e718548dcdc9de279cdccb0ccd12166cbfe0 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 9 Dec 2011 15:13:58 +0100 Subject: [PATCH 06/74] Handle code 432 on IRC --- backends/libcommuni/session.cpp | 17 +++++++++++++++-- backends/libcommuni/session.h | 1 + 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 088ebd1a..bd78ab61 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -26,6 +26,7 @@ MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std this->np = np; this->user = user; this->suffix = suffix; + m_connected = false; rooms = 0; connect(this, SIGNAL(disconnected()), SLOT(on_disconnected())); connect(this, SIGNAL(connected()), SLOT(on_connected())); @@ -33,6 +34,7 @@ MyIrcSession::MyIrcSession(const std::string &user, NetworkPlugin *np, const std } void MyIrcSession::on_connected() { + m_connected = true; if (suffix.empty()) { np->handleConnected(user); } @@ -51,6 +53,7 @@ void MyIrcSession::on_connected() { void MyIrcSession::on_disconnected() { if (suffix.empty()) np->handleDisconnected(user, 0, ""); + m_connected = false; } bool MyIrcSession::correctNickname(std::string &nickname) { @@ -156,6 +159,9 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) { } void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { + QString channel; + QStringList members; + IrcNumericMessage *m = (IrcNumericMessage *) message; switch (m->code()) { case 332: @@ -165,8 +171,8 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { np->handleSubject(user, m->parameters().value(1).toStdString() + suffix, m_topicData, m->parameters().value(2).toStdString()); break; case 353: - QString channel = m->parameters().value(2); - QStringList members = m->parameters().value(3).split(" "); + channel = m->parameters().value(2); + members = m->parameters().value(3).split(" "); for (int i = 0; i < members.size(); i++) { bool flags = 0; @@ -176,6 +182,13 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE); } break; + case 432: + if (m_connected) { + np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname"); + } + break; + default: + break; } //qDebug() << "numeric message received:" << receiver() << origin << code << params; diff --git a/backends/libcommuni/session.h b/backends/libcommuni/session.h index 3589dcb4..8b31da58 100644 --- a/backends/libcommuni/session.h +++ b/backends/libcommuni/session.h @@ -65,6 +65,7 @@ protected: std::string m_identify; std::list m_autoJoin; std::string m_topicData; + bool m_connected; }; //class MyIrcBuffer : public Irc::Buffer From f46cd8f14c48a1589291d2ce16ffe726e2390700 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 9 Dec 2011 16:31:48 +0100 Subject: [PATCH 07/74] Handle ICQ related requestInput requests --- backends/libcommuni/session.cpp | 1 + backends/libpurple/main.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index bd78ab61..971c2c0c 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -221,5 +221,6 @@ void MyIrcSession::onMessageReceived(IrcMessage *message) { case IrcMessage::Numeric: on_numericMessageReceived(message); break; + default:break; } } diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 2c04df27..58d71daa 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -441,6 +441,16 @@ static void * requestInput(const char *title, const char *primary,const char *se ((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me."); return NULL; } + else if (primaryString == "Authorization Request Message:") { + LOG4CXX_INFO(logger, "Authorization Request Message: calling ok_cb(...)"); + ((PurpleRequestInputCb) ok_cb)(user_data, "Please authorize me."); + return NULL; + } + else if (primaryString == "Authorization Denied Message:") { + LOG4CXX_INFO(logger, "Authorization Deined Message: calling ok_cb(...)"); + ((PurpleRequestInputCb) ok_cb)(user_data, "Authorization denied."); + return NULL; + } else { LOG4CXX_WARN(logger, "Unhandled request input. primary=" << primaryString); } From 742ed6bc69877ff660d4fa780a1be3e837ab4f6d Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 9 Dec 2011 19:00:53 +0100 Subject: [PATCH 08/74] pre-initial support for PostgreSQL --- CMakeLists.txt | 13 ++ cmake_modules/pqxxConfig.cmake | 16 ++ include/transport/pqxxbackend.h | 106 ++++++++++ spectrum/src/main.cpp | 19 +- src/CMakeLists.txt | 4 +- src/pqxxbackend.cpp | 329 ++++++++++++++++++++++++++++++++ 6 files changed, 484 insertions(+), 3 deletions(-) create mode 100644 cmake_modules/pqxxConfig.cmake create mode 100644 include/transport/pqxxbackend.h create mode 100644 src/pqxxbackend.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d7cb5928..3f4802e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -53,6 +53,9 @@ find_package(log4cxx) set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(event) +set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(pqxx) + find_package(Doxygen) INCLUDE(FindQt4) @@ -101,6 +104,16 @@ else (MYSQL_FOUND) message("MySQL : no (install mysql-devel)") endif (MYSQL_FOUND) +if (PQXX_FOUND) + ADD_DEFINITIONS(-DWITH_PQXX) + include_directories(${PQXX_INCLUDE_DIR}) + message("PostgreSQL : yes") +else (PQXX_FOUND) + set(PQXX_LIBRARY "") + set(PQ_LIBRARY "") + message("PostgreSQL : no (install libpqxx-devel)") +endif (PQXX_FOUND) + if (PROTOBUF_FOUND) ADD_DEFINITIONS(-DWITH_PROTOBUF) include_directories(${PROTOBUF_INCLUDE_DIRS}) diff --git a/cmake_modules/pqxxConfig.cmake b/cmake_modules/pqxxConfig.cmake new file mode 100644 index 00000000..9c53550c --- /dev/null +++ b/cmake_modules/pqxxConfig.cmake @@ -0,0 +1,16 @@ +FIND_PATH(PQXX_INCLUDE_DIR pqxx/pqxx PATHS) +MARK_AS_ADVANCED(PQXX_INCLUDE_DIR) + +FIND_LIBRARY(PQXX_LIBRARY pqxx ) +MARK_AS_ADVANCED(PQXX_LIBRARY) + +FIND_LIBRARY(PQ_LIBRARY pq ) +MARK_AS_ADVANCED(PQ_LIBRARY) + +if(PQXX_LIBRARY AND PQ_LIBRARY AND PQXX_INCLUDE_DIR) + set( PQXX_FOUND 1 ) + message( STATUS "Found pqxx: ${PQXX_LIBRARY}, ${PQ_LIBRARY}, ${PQXX_INCLUDE_DIR}") +else() + message(STATUS "Could NOT find pqxx and pq library") +endif() + diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h new file mode 100644 index 00000000..77df7843 --- /dev/null +++ b/include/transport/pqxxbackend.h @@ -0,0 +1,106 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once + +#ifdef WITH_PQXX + +#include +#include +#include "Swiften/Swiften.h" +#include "transport/storagebackend.h" +#include "transport/config.h" +#include "mysql.h" + +namespace Transport { + +/// Used to store transport data into SQLite3 database. +class PQXXBackend : public StorageBackend +{ + public: + /// Creates new PQXXBackend instance. + /// \param config cofiguration, this class uses following Config values: + /// - database.database - path to SQLite3 database file, database file is created automatically + /// - service.prefix - prefix for tables created by createDatabase method + PQXXBackend(Config *config); + + /// Destructor. + ~PQXXBackend(); + + /// Connects to the database and creates it if it's needed. This method call createDatabase() function + /// automatically. + /// \return true if database is opened successfully. + bool connect(); + void disconnect(); + + /// Creates database structure. + /// \see connect() + /// \return true if database structure has been created successfully. Note that it returns True also if database structure + /// already exists. + bool createDatabase(); + + /// Stores user into database. + /// \param user user struct containing all information about user which have to be stored + void setUser(const UserInfo &user); + + /// Gets user data from database and stores them into user reference. + /// \param barejid barejid of user + /// \param user UserInfo object where user data will be stored + /// \return true if user has been found in database + bool getUser(const std::string &barejid, UserInfo &user); + + /// Changes users online state variable in database. + /// \param id id of user - UserInfo.id + /// \param online online state + void setUserOnline(long id, bool online); + + /// Removes user and all connected data from database. + /// \param id id of user - UserInfo.id + /// \return true if user has been found in database and removed + bool removeUser(long id); + + /// Returns JIDs of all buddies in user's roster. + /// \param id id of user - UserInfo.id + /// \param roster string list used to store user's roster + /// \return true if user has been found in database and roster has been fetched + bool getBuddies(long id, std::list &roster); + + bool getOnlineUsers(std::vector &users); + + long addBuddy(long userId, const BuddyInfo &buddyInfo); + + void updateBuddy(long userId, const BuddyInfo &buddyInfo); + void removeBuddy(long id) {} + + void getUserSetting(long userId, const std::string &variable, int &type, std::string &value); + void updateUserSetting(long userId, const std::string &variable, const std::string &value); + + void beginTransaction(); + void commitTransaction(); + + private: + bool exec(const std::string &query); + Config *m_config; + std::string m_prefix; +}; + +} + +#endif diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index c0b8fb9b..ea8f33d6 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -5,6 +5,7 @@ #include "transport/logger.h" #include "transport/sqlite3backend.h" #include "transport/mysqlbackend.h" +#include "transport/pqxxbackend.h" #include "transport/userregistration.h" #include "transport/networkpluginserver.h" #include "transport/admininterface.h" @@ -379,7 +380,23 @@ int main(int argc, char **argv) } #endif - if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3") { +#ifdef WITH_PQXX + if (CONFIG_STRING(&config, "database.type") == "pqxx") { + storageBackend = new PQXXBackend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "pqxx") { + std::cerr << "Spectrum2 is not compiled with pqxx backend.\n"; + return -2; + } +#endif + + if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3" + && CONFIG_STRING(&config, "database.type") != "pqxx") { std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n"; return -2; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7a258e7a..ac077b20 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,9 +35,9 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif() if (WIN32) - TARGET_LINK_LIBRARIES(transport ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) + TARGET_LINK_LIBRARIES(transport ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) else (WIN32) - TARGET_LINK_LIBRARIES(transport ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) + TARGET_LINK_LIBRARIES(transport ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) endif(WIN32) SET_TARGET_PROPERTIES(transport PROPERTIES diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp new file mode 100644 index 00000000..8b326a51 --- /dev/null +++ b/src/pqxxbackend.cpp @@ -0,0 +1,329 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifdef WITH_PQXX + +#include "transport/pqxxbackend.h" +#include "transport/util.h" +#include +#include "log4cxx/logger.h" + +using namespace log4cxx; +using namespace boost; + +namespace Transport { + +static LoggerPtr logger = Logger::getLogger("PQXXBackend"); + +PQXXBackend::PQXXBackend(Config *config) { + m_config = config; + m_prefix = CONFIG_STRING(m_config, "database.prefix"); +} + +PQXXBackend::~PQXXBackend(){ + disconnect(); +} + +void PQXXBackend::disconnect() { + LOG4CXX_INFO(logger, "Disconnecting"); +} + +bool PQXXBackend::connect() { + LOG4CXX_INFO(logger, "Connecting PostgreSQL server " << CONFIG_STRING(m_config, "database.server") << ", user " << + CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") << + ", port " << CONFIG_INT(m_config, "database.port") + ); + + createDatabase(); + + return true; +} + +bool PQXXBackend::createDatabase() { + int not_exist = exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "buddies` (" + "`id` int(10) unsigned NOT NULL auto_increment," + "`user_id` int(10) unsigned NOT NULL," + "`uin` varchar(255) collate utf8_bin NOT NULL," + "`subscription` enum('to','from','both','ask','none') collate utf8_bin NOT NULL," + "`nickname` varchar(255) collate utf8_bin NOT NULL," + "`groups` varchar(255) collate utf8_bin NOT NULL," + "`flags` smallint(4) NOT NULL DEFAULT '0'," + "PRIMARY KEY (`id`)," + "UNIQUE KEY `user_id` (`user_id`,`uin`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + + if (not_exist) { + exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "buddies_settings` (" + "`user_id` int(10) unsigned NOT NULL," + "`buddy_id` int(10) unsigned NOT NULL," + "`var` varchar(50) collate utf8_bin NOT NULL," + "`type` smallint(4) unsigned NOT NULL," + "`value` varchar(255) collate utf8_bin NOT NULL," + "PRIMARY KEY (`buddy_id`,`var`)," + "KEY `user_id` (`user_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + + exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "users` (" + "`id` int(10) unsigned NOT NULL auto_increment," + "`jid` varchar(255) collate utf8_bin NOT NULL," + "`uin` varchar(4095) collate utf8_bin NOT NULL," + "`password` varchar(255) collate utf8_bin NOT NULL," + "`language` varchar(25) collate utf8_bin NOT NULL," + "`encoding` varchar(50) collate utf8_bin NOT NULL default 'utf8'," + "`last_login` datetime," + "`vip` tinyint(1) NOT NULL default '0'," + "`online` tinyint(1) NOT NULL default '0'," + "PRIMARY KEY (`id`)," + "UNIQUE KEY `jid` (`jid`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + + exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "users_settings` (" + "`user_id` int(10) unsigned NOT NULL," + "`var` varchar(50) collate utf8_bin NOT NULL," + "`type` smallint(4) unsigned NOT NULL," + "`value` varchar(255) collate utf8_bin NOT NULL," + "PRIMARY KEY (`user_id`,`var`)," + "KEY `user_id` (`user_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + + exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "db_version` (" + "`ver` int(10) unsigned NOT NULL default '1'," + "UNIQUE KEY `ver` (`ver`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + + exec("INSERT IGNORE INTO db_version (ver) VALUES ('2');"); + } + + return true; +} + +bool PQXXBackend::exec(const std::string &query) { +// if (mysql_query(&m_conn, query.c_str())) { +// LOG4CXX_ERROR(logger, query << " " << mysql_error(&m_conn)); +// return false; +// } + return true; +} + +void PQXXBackend::setUser(const UserInfo &user) { +// std::string encrypted = user.password; +// if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { +// encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); +// } +// *m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted; +// EXEC(m_setUser, setUser(user)); +} + +bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { +// *m_getUser << barejid; +// EXEC(m_getUser, getUser(barejid, user)); +// if (!exec_ok) +// return false; + + int ret = false; +// while (m_getUser->fetch() == 0) { +// ret = true; +// *m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip; + +// if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { +// user.password = Util::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key")); +// } +// } + + return ret; +} + +void PQXXBackend::setUserOnline(long id, bool online) { +// *m_setUserOnline << online << id; +// EXEC(m_setUserOnline, setUserOnline(id, online)); +} + +bool PQXXBackend::getOnlineUsers(std::vector &users) { +// EXEC(m_getOnlineUsers, getOnlineUsers(users)); +// if (!exec_ok) +// return false; + +// std::string jid; +// while (m_getOnlineUsers->fetch() == 0) { +// *m_getOnlineUsers >> jid; +// users.push_back(jid); +// } + + return true; +} + +long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { +// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)" +// std::string groups = Util::serializeGroups(buddyInfo.groups); +// *m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription; +// *m_addBuddy << groups; +// *m_addBuddy << buddyInfo.alias << buddyInfo.flags; + +// EXEC(m_addBuddy, addBuddy(userId, buddyInfo)); + +// long id = (long) mysql_insert_id(&m_conn); + +// INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) +// if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { +// *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; +// EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); +// } + + return 0; +} + +void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { +// "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?" +// std::string groups = Util::serializeGroups(buddyInfo.groups); +// *m_updateBuddy << groups; +// *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; +// *m_updateBuddy << userId << buddyInfo.legacyName; + +// EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo)); +} + +bool PQXXBackend::getBuddies(long id, std::list &roster) { +// SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC +// *m_getBuddies << id; + +// "SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC" +// *m_getBuddiesSettings << id; + +// SettingVariableInfo var; +// long buddy_id = -1; +// std::string key; + +// EXEC(m_getBuddies, getBuddies(id, roster)); +// if (!exec_ok) +// return false; + +// while (m_getBuddies->fetch() == 0) { +// BuddyInfo b; + +// std::string group; +// *m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags; + +// if (!group.empty()) { +// b.groups = Util::deserializeGroups(group); +// } + +// roster.push_back(b); +// } + +// EXEC(m_getBuddiesSettings, getBuddies(id, roster)); +// if (!exec_ok) +// return false; + +// BOOST_FOREACH(BuddyInfo &b, roster) { +// if (buddy_id == b.id) { +//// std::cout << "Adding buddy info setting " << key << "\n"; +// b.settings[key] = var; +// buddy_id = -1; +// } + +// while(buddy_id == -1 && m_getBuddiesSettings->fetch() == 0) { +// std::string val; +// *m_getBuddiesSettings >> buddy_id >> var.type >> key >> val; + +// switch (var.type) { +// case TYPE_BOOLEAN: +// var.b = atoi(val.c_str()); +// break; +// case TYPE_STRING: +// var.s = val; +// break; +// default: +// if (buddy_id == b.id) { +// buddy_id = -1; +// } +// continue; +// break; +// } +// if (buddy_id == b.id) { +//// std::cout << "Adding buddy info setting " << key << "=" << val << "\n"; +// b.settings[key] = var; +// buddy_id = -1; +// } +// } +// } + +// while(m_getBuddiesSettings->fetch() == 0) { +// // TODO: probably remove those settings, because there's no buddy for them. +// // It should not happend, but one never know... +// } + + return true; +} + +bool PQXXBackend::removeUser(long id) { +// *m_removeUser << (int) id; +// EXEC(m_removeUser, removeUser(id)); +// if (!exec_ok) +// return false; + +// *m_removeUserSettings << (int) id; +// EXEC(m_removeUserSettings, removeUser(id)); +// if (!exec_ok) +// return false; + +// *m_removeUserBuddies << (int) id; +// EXEC(m_removeUserBuddies, removeUser(id)); +// if (!exec_ok) +// return false; + +// *m_removeUserBuddiesSettings << (int) id; +// EXEC(m_removeUserBuddiesSettings, removeUser(id)); +// if (!exec_ok) +// return false; + + return true; +} + +void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { +//// "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?" +// *m_getUserSetting << id << variable; +// EXEC(m_getUserSetting, getUserSetting(id, variable, type, value)); +// if (m_getUserSetting->fetch() != 0) { +//// "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)" +// *m_setUserSetting << id << variable << type << value; +// EXEC(m_setUserSetting, getUserSetting(id, variable, type, value)); +// } +// else { +// *m_getUserSetting >> type >> value; +// } +} + +void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { +//// "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?" +// *m_updateUserSetting << value << id << variable; +// EXEC(m_updateUserSetting, updateUserSetting(id, variable, value)); +} + +void PQXXBackend::beginTransaction() { +// exec("START TRANSACTION;"); +} + +void PQXXBackend::commitTransaction() { +// exec("COMMIT;"); +} + +} + +#endif From fe74083e2e3ca3d91c6efab093f16540a2ca86b8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 10 Dec 2011 15:44:43 +0100 Subject: [PATCH 09/74] Do not try to serialize something what is not Storage element --- include/transport/pqxxbackend.h | 4 +++- src/storageresponder.cpp | 18 +++++++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index 77df7843..00581a2c 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -27,7 +27,7 @@ #include "Swiften/Swiften.h" #include "transport/storagebackend.h" #include "transport/config.h" -#include "mysql.h" +#include namespace Transport { @@ -99,6 +99,8 @@ class PQXXBackend : public StorageBackend bool exec(const std::string &query); Config *m_config; std::string m_prefix; + + pqxx::connection *m_conn; }; } diff --git a/src/storageresponder.cpp b/src/storageresponder.cpp index 84423593..b5f4e5aa 100644 --- a/src/storageresponder.cpp +++ b/src/storageresponder.cpp @@ -71,11 +71,19 @@ bool StorageResponder::handleSetRequest(const Swift::JID& from, const Swift::JID return true; } - StorageSerializer serializer; - std::string value = serializer.serializePayload(boost::dynamic_pointer_cast(payload->getPayload())); - m_storageBackend->updateUserSetting(user->getUserInfo().id, "storage", value); - LOG4CXX_INFO(logger, from.toBare().toString() << ": Storing jabber:iq:storage"); - sendResponse(from, id, boost::shared_ptr()); + boost::shared_ptr storage = boost::dynamic_pointer_cast(payload->getPayload()); + + if (storage) { + StorageSerializer serializer; + std::string value = serializer.serializePayload(boost::dynamic_pointer_cast(payload->getPayload())); + m_storageBackend->updateUserSetting(user->getUserInfo().id, "storage", value); + LOG4CXX_INFO(logger, from.toBare().toString() << ": Storing jabber:iq:storage"); + sendResponse(from, id, boost::shared_ptr()); + } + else { + LOG4CXX_INFO(logger, from.toBare().toString() << ": Unknown element. Libtransport does not support serialization of this."); + sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Cancel); + } return true; } From 2568753cca4b6dde6591e68f6b6a352daa088b5b Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 12 Dec 2011 14:32:51 +0100 Subject: [PATCH 10/74] create postgresql db --- src/pqxxbackend.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 8b326a51..4a7d2e94 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -43,6 +43,8 @@ PQXXBackend::~PQXXBackend(){ void PQXXBackend::disconnect() { LOG4CXX_INFO(logger, "Disconnecting"); + + delete m_conn; } bool PQXXBackend::connect() { @@ -50,6 +52,12 @@ bool PQXXBackend::connect() { CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") << ", port " << CONFIG_INT(m_config, "database.port") ); + + std::string str = "dbname="; + str += CONFIG_STRING(m_config, "database.database") + " "; + + str += "user=" + CONFIG_STRING(m_config, "database.user") + " "; + m_conn = new pqxx::connection(str); createDatabase(); @@ -115,10 +123,9 @@ bool PQXXBackend::createDatabase() { } bool PQXXBackend::exec(const std::string &query) { -// if (mysql_query(&m_conn, query.c_str())) { -// LOG4CXX_ERROR(logger, query << " " << mysql_error(&m_conn)); -// return false; -// } + pqxx::work txn(*m_conn); + txn.exec(query); + txn.commit(); return true; } From 3fd77c64ac1933cf67e2fa88869078b02fa5b180 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 13 Dec 2011 11:29:08 +0100 Subject: [PATCH 11/74] Create pgsql database --- include/transport/pqxxbackend.h | 2 +- src/pqxxbackend.cpp | 109 +++++++++++++++++--------------- 2 files changed, 60 insertions(+), 51 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index 00581a2c..21d54339 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -96,7 +96,7 @@ class PQXXBackend : public StorageBackend void commitTransaction(); private: - bool exec(const std::string &query); + bool exec(const std::string &query, bool show_error = true); Config *m_config; std::string m_prefix; diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 4a7d2e94..426b8eb9 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -65,67 +65,76 @@ bool PQXXBackend::connect() { } bool PQXXBackend::createDatabase() { - int not_exist = exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "buddies` (" - "`id` int(10) unsigned NOT NULL auto_increment," - "`user_id` int(10) unsigned NOT NULL," - "`uin` varchar(255) collate utf8_bin NOT NULL," - "`subscription` enum('to','from','both','ask','none') collate utf8_bin NOT NULL," - "`nickname` varchar(255) collate utf8_bin NOT NULL," - "`groups` varchar(255) collate utf8_bin NOT NULL," - "`flags` smallint(4) NOT NULL DEFAULT '0'," - "PRIMARY KEY (`id`)," - "UNIQUE KEY `user_id` (`user_id`,`uin`)" - ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + + int exist = exec("SELECT * FROM " + m_prefix + "buddies_settings LIMIT 1;", false); - if (not_exist) { - exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "buddies_settings` (" - "`user_id` int(10) unsigned NOT NULL," - "`buddy_id` int(10) unsigned NOT NULL," - "`var` varchar(50) collate utf8_bin NOT NULL," - "`type` smallint(4) unsigned NOT NULL," - "`value` varchar(255) collate utf8_bin NOT NULL," - "PRIMARY KEY (`buddy_id`,`var`)," - "KEY `user_id` (`user_id`)" - ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + if (!exist) { + exec("CREATE TABLE " + m_prefix + "buddies_settings (" + "user_id integer NOT NULL," + "buddy_id integer NOT NULL," + "var varchar(50) NOT NULL," + "type smallint NOT NULL," + "value varchar(255) NOT NULL," + "PRIMARY KEY (buddy_id,var)" + ");"); + + exec("CREATE TYPE Subscription AS ENUM ('to','from','both','ask','none');"); + exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "buddies (" + "id SERIAL," + "user_id integer NOT NULL," + "uin varchar(255) NOT NULL," + "subscription Subscription NOT NULL," + "nickname varchar(255) NOT NULL," + "groups varchar(255) NOT NULL," + "flags smallint NOT NULL DEFAULT '0'," + "PRIMARY KEY (id)," + "UNIQUE (user_id,uin)" + ");"); - exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "users` (" - "`id` int(10) unsigned NOT NULL auto_increment," - "`jid` varchar(255) collate utf8_bin NOT NULL," - "`uin` varchar(4095) collate utf8_bin NOT NULL," - "`password` varchar(255) collate utf8_bin NOT NULL," - "`language` varchar(25) collate utf8_bin NOT NULL," - "`encoding` varchar(50) collate utf8_bin NOT NULL default 'utf8'," - "`last_login` datetime," - "`vip` tinyint(1) NOT NULL default '0'," - "`online` tinyint(1) NOT NULL default '0'," - "PRIMARY KEY (`id`)," - "UNIQUE KEY `jid` (`jid`)" - ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "users (" + "id SERIAL," + "jid varchar(255) NOT NULL," + "uin varchar(4095) NOT NULL," + "password varchar(255) NOT NULL," + "language varchar(25) NOT NULL," + "encoding varchar(50) NOT NULL default 'utf8'," + "last_login timestamp," + "vip boolean NOT NULL default '0'," + "online boolean NOT NULL default '0'," + "PRIMARY KEY (id)," + "UNIQUE (jid)" + ");"); - exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "users_settings` (" - "`user_id` int(10) unsigned NOT NULL," - "`var` varchar(50) collate utf8_bin NOT NULL," - "`type` smallint(4) unsigned NOT NULL," - "`value` varchar(255) collate utf8_bin NOT NULL," - "PRIMARY KEY (`user_id`,`var`)," - "KEY `user_id` (`user_id`)" - ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "users_settings (" + "user_id integer NOT NULL," + "var varchar(50) NOT NULL," + "type smallint NOT NULL," + "value varchar(255) NOT NULL," + "PRIMARY KEY (user_id,var)" + ");"); - exec("CREATE TABLE IF NOT EXISTS `" + m_prefix + "db_version` (" - "`ver` int(10) unsigned NOT NULL default '1'," - "UNIQUE KEY `ver` (`ver`)" - ") ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;"); + exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "db_version (" + "ver integer NOT NULL default '1'," + "UNIQUE (ver)" + ");"); - exec("INSERT IGNORE INTO db_version (ver) VALUES ('2');"); +// exec("INSERT INTO db_version (ver) VALUES ('2');"); } return true; } -bool PQXXBackend::exec(const std::string &query) { +bool PQXXBackend::exec(const std::string &query, bool show_error) { pqxx::work txn(*m_conn); - txn.exec(query); - txn.commit(); + try { + txn.exec(query); + txn.commit(); + } + catch (std::exception& e) { + if (show_error) + LOG4CXX_ERROR(logger, e.what()); + return false; + } return true; } From 77c68bb770747930c810c7a9061c9a5e0d41d13e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 21 Dec 2011 10:39:28 +0100 Subject: [PATCH 12/74] Support 'none' storage backend --- spectrum/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index ea8f33d6..c57573ea 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -396,7 +396,7 @@ int main(int argc, char **argv) #endif if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3" - && CONFIG_STRING(&config, "database.type") != "pqxx") { + && CONFIG_STRING(&config, "database.type") != "pqxx" && CONFIG_STRING(&config, "database.type") != "none") { std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n"; return -2; } From 630bee4b67f6c6a417137ed300b8c1f1a28b0acf Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 22 Dec 2011 16:28:45 +0100 Subject: [PATCH 13/74] Removed IF NOT EXISTS clausule --- src/pqxxbackend.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 426b8eb9..bc28772b 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -79,7 +79,7 @@ bool PQXXBackend::createDatabase() { ");"); exec("CREATE TYPE Subscription AS ENUM ('to','from','both','ask','none');"); - exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "buddies (" + exec("CREATE TABLE " + m_prefix + "buddies (" "id SERIAL," "user_id integer NOT NULL," "uin varchar(255) NOT NULL," @@ -91,7 +91,7 @@ bool PQXXBackend::createDatabase() { "UNIQUE (user_id,uin)" ");"); - exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "users (" + exec("CREATE TABLE " + m_prefix + "users (" "id SERIAL," "jid varchar(255) NOT NULL," "uin varchar(4095) NOT NULL," @@ -105,7 +105,7 @@ bool PQXXBackend::createDatabase() { "UNIQUE (jid)" ");"); - exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "users_settings (" + exec("CREATE TABLE " + m_prefix + "users_settings (" "user_id integer NOT NULL," "var varchar(50) NOT NULL," "type smallint NOT NULL," @@ -113,7 +113,7 @@ bool PQXXBackend::createDatabase() { "PRIMARY KEY (user_id,var)" ");"); - exec("CREATE TABLE IF NOT EXISTS " + m_prefix + "db_version (" + exec("CREATE TABLE " + m_prefix + "db_version (" "ver integer NOT NULL default '1'," "UNIQUE (ver)" ");"); From 12d117f54ffe3a9fa4da2b15651266a2764bd1a8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 22 Dec 2011 20:47:36 +0100 Subject: [PATCH 14/74] Working setUser for postgres --- include/transport/pqxxbackend.h | 1 + src/pqxxbackend.cpp | 24 ++++++++++++++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index 21d54339..e13c6b03 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -97,6 +97,7 @@ class PQXXBackend : public StorageBackend private: bool exec(const std::string &query, bool show_error = true); + bool exec(pqxx::work &txn, const std::string &query, bool show_error = true); Config *m_config; std::string m_prefix; diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index bc28772b..05ba1a5c 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -126,6 +126,10 @@ bool PQXXBackend::createDatabase() { bool PQXXBackend::exec(const std::string &query, bool show_error) { pqxx::work txn(*m_conn); + return exec(txn, query, show_error); +} + +bool PQXXBackend::exec(pqxx::work &txn, const std::string &query, bool show_error) { try { txn.exec(query); txn.commit(); @@ -139,12 +143,20 @@ bool PQXXBackend::exec(const std::string &query, bool show_error) { } void PQXXBackend::setUser(const UserInfo &user) { -// std::string encrypted = user.password; -// if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { -// encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); -// } -// *m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted; -// EXEC(m_setUser, setUser(user)); + std::string encrypted = user.password; + if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { + encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); + } + pqxx::work txn(*m_conn); + exec(txn, "UPDATE " + m_prefix + "users SET uin=" + txn.quote(user.uin) + ", password=" + txn.quote(encrypted) + ";" + "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + "(" + txn.quote(user.jid) + "," + + txn.quote(user.uin) + "," + + txn.quote(encrypted) + "," + + txn.quote(user.language) + "," + + txn.quote(user.encoding) + "," + + "NOW()," + + txn.quote(user.vip) +")"); } bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { From 5efb6707da4f947ce207f689681dfdbcc86e5aac Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 22 Dec 2011 21:47:47 +0100 Subject: [PATCH 15/74] setUser --- src/pqxxbackend.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 05ba1a5c..b4b54f2f 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -160,22 +160,30 @@ void PQXXBackend::setUser(const UserInfo &user) { } bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { -// *m_getUser << barejid; -// EXEC(m_getUser, getUser(barejid, user)); -// if (!exec_ok) -// return false; + try { + pqxx::work txn(*m_conn); - int ret = false; -// while (m_getUser->fetch() == 0) { -// ret = true; -// *m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip; + pqxx::result r = txn.exec("SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=" + + txn.quote(barejid)); -// if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { -// user.password = Util::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key")); -// } -// } + if (r.size() == 0) { + return false; + } - return ret; + user.id = r[0][0].as(); + user.jid = r[0][1].as(); + user.uin = r[0][2].as(); + user.password = r[0][3].as(); + user.encoding = r[0][4].as(); + user.language = r[0][5].as(); + // user.vip = r[0][6].as(); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + return false; + } + + return true; } void PQXXBackend::setUserOnline(long id, bool online) { From 9bc058ae376fdb13c840d7be1c7ef3740c474680 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 23 Dec 2011 13:37:17 +0100 Subject: [PATCH 16/74] setUserONline, getOnlineUsers --- src/pqxxbackend.cpp | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index b4b54f2f..af0efd36 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -176,7 +176,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { user.password = r[0][3].as(); user.encoding = r[0][4].as(); user.language = r[0][5].as(); - // user.vip = r[0][6].as(); + user.vip = r[0][6].as(); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -187,20 +187,28 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { } void PQXXBackend::setUserOnline(long id, bool online) { -// *m_setUserOnline << online << id; -// EXEC(m_setUserOnline, setUserOnline(id, online)); + try { + pqxx::work txn(*m_conn); + exec(txn, "UPDATE " + m_prefix + "users SET online=" + txn.quote(online) + ", last_login=NOW() WHERE id=" + txn.quote(id)); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } bool PQXXBackend::getOnlineUsers(std::vector &users) { -// EXEC(m_getOnlineUsers, getOnlineUsers(users)); -// if (!exec_ok) -// return false; + try { + pqxx::work txn(*m_conn); + pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online=1"); -// std::string jid; -// while (m_getOnlineUsers->fetch() == 0) { -// *m_getOnlineUsers >> jid; -// users.push_back(jid); -// } + for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { + users.push_back((*it)[0].as()); + } + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + return false; + } return true; } From 3118610c0aa5b8cd36225f3bc254250242a3cd9e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 25 Dec 2011 13:14:33 +0100 Subject: [PATCH 17/74] More debug --- backends/libpurple/main.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 58d71daa..86a6f201 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -614,11 +614,13 @@ class SpectrumNetworkPlugin : public NetworkPlugin { return; } - LOG4CXX_INFO(logger, "Creating account with name '" << name.c_str() << "' and protocol '" << protocol << "'"); - if (purple_accounts_find(name.c_str(), protocol.c_str()) != NULL){ + + if (purple_accounts_find(name.c_str(), protocol.c_str()) != NULL) { + LOG4CXX_INFO(logger, "Using previously created account with name '" << name.c_str() << "' and protocol '" << protocol << "'"); account = purple_accounts_find(name.c_str(), protocol.c_str()); } else { + LOG4CXX_INFO(logger, "Creating account with name '" << name.c_str() << "' and protocol '" << protocol << "'"); account = purple_account_new(name.c_str(), protocol.c_str()); purple_accounts_add(account); } @@ -1088,6 +1090,8 @@ static void buddyListNewNode(PurpleBlistNode *node) { PurpleBuddy *buddy = (PurpleBuddy *) node; PurpleAccount *account = purple_buddy_get_account(buddy); + LOG4CXX_INFO(logger, "Buddy updated " << np->m_accounts[account] << " " << purple_buddy_get_name(buddy) << " " << getAlias(buddy)); + // Status pbnetwork::StatusType status = pbnetwork::STATUS_NONE; std::string message; From a94eb22e7620fbcc6665b8f55a7fd4e278e34376 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 17 Jan 2012 17:46:03 +0100 Subject: [PATCH 18/74] Handle properly --- include/Swiften/Server/ServerStanzaChannel.cpp | 11 +++++++++++ include/Swiften/Server/ServerStanzaChannel.h | 1 + 2 files changed, 12 insertions(+) diff --git a/include/Swiften/Server/ServerStanzaChannel.cpp b/include/Swiften/Server/ServerStanzaChannel.cpp index bb3fbf6e..9597cc1c 100644 --- a/include/Swiften/Server/ServerStanzaChannel.cpp +++ b/include/Swiften/Server/ServerStanzaChannel.cpp @@ -32,11 +32,13 @@ void ServerStanzaChannel::addSession(boost::shared_ptr sessions[session->getRemoteJID().toBare().toString()].push_back(session); session->onSessionFinished.connect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); session->onElementReceived.connect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); + session->onDataRead.connect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session)); } void ServerStanzaChannel::removeSession(boost::shared_ptr session) { session->onSessionFinished.disconnect(boost::bind(&ServerStanzaChannel::handleSessionFinished, this, _1, session)); session->onElementReceived.disconnect(boost::bind(&ServerStanzaChannel::handleElement, this, _1, session)); + session->onDataRead.disconnect(boost::bind(&ServerStanzaChannel::handleDataRead, this, _1, session)); std::list > &lst = sessions[session->getRemoteJID().toBare().toString()]; lst.erase(std::remove(lst.begin(), lst.end(), session), lst.end()); } @@ -53,6 +55,15 @@ void ServerStanzaChannel::sendPresence(boost::shared_ptr presence) { send(presence); } +void ServerStanzaChannel::handleDataRead(const SafeByteArray &data, const boost::shared_ptr &session) { + if (safeByteArrayToString(data).find("") != std::string::npos) { + Swift::Presence::ref presence = Swift::Presence::create(); + presence->setFrom(session->getRemoteJID()); + presence->setType(Swift::Presence::Unavailable); + onPresenceReceived(presence); + } +} + void ServerStanzaChannel::finishSession(const JID& to, boost::shared_ptr element, bool last) { std::vector > candidateSessions; for (std::list >::const_iterator i = sessions[to.toBare().toString()].begin(); i != sessions[to.toBare().toString()].end(); ++i) { diff --git a/include/Swiften/Server/ServerStanzaChannel.h b/include/Swiften/Server/ServerStanzaChannel.h index 69158eea..99c857be 100644 --- a/include/Swiften/Server/ServerStanzaChannel.h +++ b/include/Swiften/Server/ServerStanzaChannel.h @@ -41,6 +41,7 @@ namespace Swift { void send(boost::shared_ptr stanza); void handleSessionFinished(const boost::optional&, const boost::shared_ptr &session); void handleElement(boost::shared_ptr element, const boost::shared_ptr &session); + void handleDataRead(const SafeByteArray &data, const boost::shared_ptr &session); void handleSessionInitialized(); private: From c643e5b81d603fb070223c8ddc07ca180a797260 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 18 Jan 2012 09:39:32 +0100 Subject: [PATCH 19/74] Skype backend --- backends/CMakeLists.txt | 1 + backends/skype/CMakeLists.txt | 13 + backends/skype/geventloop.cpp | 248 +++++++++ backends/skype/geventloop.h | 33 ++ backends/skype/main.cpp | 791 +++++++++++++++++++++++++++ backends/skype/spectrumeventloop.cpp | 90 +++ backends/skype/spectrumeventloop.h | 49 ++ spectrum/src/sample2.cfg | 2 + 8 files changed, 1227 insertions(+) create mode 100644 backends/skype/CMakeLists.txt create mode 100644 backends/skype/geventloop.cpp create mode 100644 backends/skype/geventloop.h create mode 100644 backends/skype/main.cpp create mode 100644 backends/skype/spectrumeventloop.cpp create mode 100644 backends/skype/spectrumeventloop.h diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 9ecb3b5c..1c056d11 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -9,6 +9,7 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) + ADD_SUBDIRECTORY(skype) endif() endif() diff --git a/backends/skype/CMakeLists.txt b/backends/skype/CMakeLists.txt new file mode 100644 index 00000000..fa6e9266 --- /dev/null +++ b/backends/skype/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) +FILE(GLOB SRC *.cpp) + +include_directories(/usr/include/dbus-1.0/) +include_directories(/usr/lib/dbus-1.0/include/) +include_directories(/usr/lib64/dbus-1.0/include/) + +ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) + +target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread dbus-glib-1 dbus-1 gobject-2.0 transport-plugin) + +INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) + diff --git a/backends/skype/geventloop.cpp b/backends/skype/geventloop.cpp new file mode 100644 index 00000000..d00d7a56 --- /dev/null +++ b/backends/skype/geventloop.cpp @@ -0,0 +1,248 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "geventloop.h" +#ifdef _WIN32 +#include "win32/win32dep.h" +#endif +#ifdef WITH_LIBEVENT +#include "event.h" +#endif + +typedef struct _PurpleIOClosure { + PurpleInputFunction function; + guint result; + gpointer data; +#ifdef WITH_LIBEVENT + GSourceFunc function2; + struct timeval timeout; + struct event evfifo; +#endif +} PurpleIOClosure; + +static gboolean io_invoke(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + PurpleIOClosure *closure = (PurpleIOClosure* )data; + PurpleInputCondition purple_cond = (PurpleInputCondition)0; + + int tmp = 0; + if (condition & READ_COND) + { + tmp |= PURPLE_INPUT_READ; + purple_cond = (PurpleInputCondition)tmp; + } + if (condition & WRITE_COND) + { + tmp |= PURPLE_INPUT_WRITE; + purple_cond = (PurpleInputCondition)tmp; + } + + closure->function(closure->data, g_io_channel_unix_get_fd(source), purple_cond); + + return TRUE; +} + +static void io_destroy(gpointer data) +{ + g_free(data); +} + +static guint input_add(gint fd, + PurpleInputCondition condition, + PurpleInputFunction function, + gpointer data) +{ + PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = (GIOCondition)0; + closure->function = function; + closure->data = data; + + int tmp = 0; + if (condition & PURPLE_INPUT_READ) + { + tmp |= READ_COND; + cond = (GIOCondition)tmp; + } + if (condition & PURPLE_INPUT_WRITE) + { + tmp |= WRITE_COND; + cond = (GIOCondition)tmp; + } + +#ifdef WIN32 + channel = wpurple_g_io_channel_win32_new_socket(fd); +#else + channel = g_io_channel_unix_new(fd); +#endif + closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, + io_invoke, closure, io_destroy); + + g_io_channel_unref(channel); + return closure->result; +} + +static PurpleEventLoopUiOps eventLoopOps = +{ + g_timeout_add, + g_source_remove, + input_add, + g_source_remove, + NULL, +#if GLIB_CHECK_VERSION(2,14,0) + g_timeout_add_seconds, +#else + NULL, +#endif + + NULL, + NULL, + NULL +}; + +#ifdef WITH_LIBEVENT + +static GHashTable *events = NULL; +static unsigned long id = 0; + +static void event_io_destroy(gpointer data) +{ + PurpleIOClosure *closure = (PurpleIOClosure* )data; + event_del(&closure->evfifo); + g_free(data); +} + +static void event_io_invoke(int fd, short event, void *data) +{ + PurpleIOClosure *closure = (PurpleIOClosure* )data; + PurpleInputCondition purple_cond = (PurpleInputCondition)0; + int tmp = 0; + if (event & EV_READ) + { + tmp |= PURPLE_INPUT_READ; + purple_cond = (PurpleInputCondition)tmp; + } + if (event & EV_WRITE) + { + tmp |= PURPLE_INPUT_WRITE; + purple_cond = (PurpleInputCondition)tmp; + } + if (event & EV_TIMEOUT) + { +// tmp |= PURPLE_INPUT_WRITE; +// purple_cond = (PurpleInputCondition)tmp; + if (closure->function2(closure->data)) + evtimer_add(&closure->evfifo, &closure->timeout); +// else +// event_io_destroy(data); + return; + } + + closure->function(closure->data, fd, purple_cond); +} + +static gboolean event_input_remove(guint handle) +{ + PurpleIOClosure *closure = (PurpleIOClosure *) g_hash_table_lookup(events, &handle); + if (closure) + event_io_destroy(closure); + return TRUE; +} + +static guint event_input_add(gint fd, + PurpleInputCondition condition, + PurpleInputFunction function, + gpointer data) +{ + PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); + GIOChannel *channel; + GIOCondition cond = (GIOCondition)0; + closure->function = function; + closure->data = data; + + int tmp = EV_PERSIST; + if (condition & PURPLE_INPUT_READ) + { + tmp |= EV_READ; + } + if (condition & PURPLE_INPUT_WRITE) + { + tmp |= EV_WRITE; + } + + event_set(&closure->evfifo, fd, tmp, event_io_invoke, closure); + event_add(&closure->evfifo, NULL); + + int *f = (int *) g_malloc(sizeof(int)); + *f = id; + id++; + g_hash_table_replace(events, f, closure); + + return *f; +} + +static guint event_timeout_add (guint interval, GSourceFunc function, gpointer data) { + struct timeval timeout; + PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); + closure->function2 = function; + closure->data = data; + + timeout.tv_sec = interval/1000; + timeout.tv_usec = (interval%1000)*1000; + evtimer_set(&closure->evfifo, event_io_invoke, closure); + evtimer_add(&closure->evfifo, &timeout); + closure->timeout = timeout; + + guint *f = (guint *) g_malloc(sizeof(guint)); + *f = id; + id++; + g_hash_table_replace(events, f, closure); + return *f; +} + +static PurpleEventLoopUiOps libEventLoopOps = +{ + event_timeout_add, + event_input_remove, + event_input_add, + event_input_remove, + NULL, +// #if GLIB_CHECK_VERSION(2,14,0) +// g_timeout_add_seconds, +// #else + NULL, +// #endif + + NULL, + NULL, + NULL +}; + +#endif /* WITH_LIBEVENT*/ + +PurpleEventLoopUiOps * getEventLoopUiOps(void){ + return &eventLoopOps; +#ifdef WITH_LIBEVENT + events = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); + return &libEventLoopOps; +#endif +} diff --git a/backends/skype/geventloop.h b/backends/skype/geventloop.h new file mode 100644 index 00000000..3febd65e --- /dev/null +++ b/backends/skype/geventloop.h @@ -0,0 +1,33 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef _HI_EVENTLOOP_H +#define _HI_EVENTLOOP_H + +#include +#include "purple.h" +#include "eventloop.h" + +#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) +#define WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) + +PurpleEventLoopUiOps * getEventLoopUiOps(void); + +#endif diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp new file mode 100644 index 00000000..5a135410 --- /dev/null +++ b/backends/skype/main.cpp @@ -0,0 +1,791 @@ +#include "glib.h" +#include + +#include "transport/config.h" +#include "transport/transport.h" +#include "transport/usermanager.h" +#include "transport/logger.h" +#include "transport/sqlite3backend.h" +#include "transport/userregistration.h" +#include "transport/user.h" +#include "transport/storagebackend.h" +#include "transport/rostermanager.h" +#include "transport/conversation.h" +#include "transport/networkplugin.h" +#include "spectrumeventloop.h" +#include +#include "geventloop.h" +#include "log4cxx/logger.h" +#include "log4cxx/consoleappender.h" +#include "log4cxx/patternlayout.h" +#include "log4cxx/propertyconfigurator.h" +#include "log4cxx/helpers/properties.h" +#include "log4cxx/helpers/fileinputstream.h" +#include "sys/wait.h" +#include "sys/signal.h" +// #include "valgrind/memcheck.h" +#include "malloc.h" +#include + + +using namespace log4cxx; + +static LoggerPtr logger = Logger::getLogger("backend"); + +using namespace Transport; + +class SpectrumNetworkPlugin; + + +SpectrumNetworkPlugin *np; + +static gboolean nodaemon = FALSE; +static gchar *logfile = NULL; +static gchar *lock_file = NULL; +static gchar *host = NULL; +static int port = 10000; +static gboolean ver = FALSE; +static gboolean list_purple_settings = FALSE; + +int m_sock; +static int writeInput; + +static GOptionEntry options_entries[] = { + { "nodaemon", 'n', 0, G_OPTION_ARG_NONE, &nodaemon, "Disable background daemon mode", NULL }, + { "logfile", 'l', 0, G_OPTION_ARG_STRING, &logfile, "Set file to log", NULL }, + { "pidfile", 'p', 0, G_OPTION_ARG_STRING, &lock_file, "File where to write transport PID", NULL }, + { "version", 'v', 0, G_OPTION_ARG_NONE, &ver, "Shows Spectrum version", NULL }, + { "list-purple-settings", 's', 0, G_OPTION_ARG_NONE, &list_purple_settings, "Lists purple settings which can be used in config file", NULL }, + { "host", 'h', 0, G_OPTION_ARG_STRING, &host, "Host to connect to", NULL }, + { "port", 'p', 0, G_OPTION_ARG_INT, &port, "Port to connect to", NULL }, + { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL } +}; + +DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data); + +static pbnetwork::StatusType getStatus(const std::string &st) { + pbnetwork::StatusType status = pbnetwork::STATUS_ONLINE; + if (st == "SKYPEOUT" || st == "OFFLINE") { + status = pbnetwork::STATUS_NONE; + } + else if (st == "DND") { + status = pbnetwork::STATUS_DND; + } + else if (st == "NA") { + status = pbnetwork::STATUS_XA; + } + else if (st == "AWAY") { + status = pbnetwork::STATUS_AWAY; + } + return status; +} + +class Skype { + public: + Skype(const std::string &user, const std::string &username, const std::string &password); + ~Skype() { logout(); } + void login(); + void logout(); + std::string send_command(const std::string &message); + + const std::string &getUser() { + return m_user; + } + + const std::string &getUsername() { + return m_username; + } + + private: + std::string m_username; + std::string m_password; + GPid m_pid; + DBusGConnection *m_connection; + DBusGProxy *m_proxy; + std::string m_user; +}; + +class SpectrumNetworkPlugin : public NetworkPlugin { + public: + SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + } + + ~SpectrumNetworkPlugin() { + for (std::map::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) { + delete (*it).first; + } + } + + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + std::string name = legacyName; + name = name.substr(name.find(".") + 1); + LOG4CXX_INFO(logger, "Creating account with name '" << name); + + Skype *skype = new Skype(user, name, password); + m_sessions[user] = skype; + m_accounts[skype] = user; + + skype->login(); + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + Skype *skype = m_sessions[user]; + if (skype) { + skype->logout(); + exit(1); + } + } + + void handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage) { + Skype *skype = m_sessions[user]; + if (!skype) + return; + + std::string st; + switch(status) { + case Swift::StatusShow::Away: { + st = "AWAY"; + break; + } + case Swift::StatusShow::DND: { + st = "DND"; + break; + } + case Swift::StatusShow::XA: { + st = "NA"; + break; + } + case Swift::StatusShow::None: { + break; + } + case pbnetwork::STATUS_INVISIBLE: + st = "INVISIBLE"; + break; + default: + st = "ONLINE"; + break; + } + skype->send_command("SET USERSTATUS " + st); + + if (!statusMessage.empty()) { + skype->send_command("SET PROFILE MOOD_TEXT " + statusMessage); + } + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml) { + Skype *skype = m_sessions[user]; + if (skype) { + skype->send_command("MESSAGE " + legacyName + " " + message); + } + + } + + void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) { + Skype *skype = m_sessions[user]; + if (skype) { + std::string name = legacyName; + if (name.find("skype.") == 0) { + name = name.substr(6); + } + std::string photo; + gchar *filename = NULL; + gchar *new_filename = NULL; + gchar *image_data = NULL; + gsize image_data_len = 0; + gchar *ret; + int fh; + GError *error; + const gchar *userfiles[] = {"user256", "user1024", "user4096", "user16384", "user32768", "user65536", + "profile256", "profile1024", "profile4096", "profile16384", "profile32768", + NULL}; + char *username = g_strdup_printf("\x03\x10%s", name.c_str()); + for (fh = 0; userfiles[fh]; fh++) { + filename = g_strconcat("/tmp/skype/", skype->getUsername().c_str(), "/", skype->getUsername().c_str(), "/", userfiles[fh], ".dbb", NULL); + std::cout << "getting filename:" << filename << "\n"; + if (g_file_get_contents(filename, &image_data, &image_data_len, NULL)) + { + std::cout << "got\n"; + char *start = (char *)memmem(image_data, image_data_len, username, strlen(username)+1); + if (start != NULL) + { + char *next = image_data; + char *last = next; + //find last index of l33l + while ((next = (char *)memmem(next+4, start-next-4, "l33l", 4))) + { + last = next; + } + start = last; + if (start != NULL) + { + char *img_start; + //find end of l33l block + char *end = (char *)memmem(start+4, image_data+image_data_len-start-4, "l33l", 4); + if (!end) end = image_data+image_data_len; + + //look for start of JPEG block + img_start = (char *)memmem(start, end-start, "\xFF\xD8", 2); + if (img_start) + { + //look for end of JPEG block + char *img_end = (char *)memmem(img_start, end-img_start, "\xFF\xD9", 2); + if (img_end) + { + image_data_len = img_end - img_start + 2; + photo = std::string(img_start, image_data_len); + } + } + } + } + g_free(image_data); + } + g_free(filename); + } + g_free(username); + + std::string alias = ""; + std::cout << skype->getUsername() << " " << name << "\n"; + if (skype->getUsername() == name) { + alias = skype->send_command("GET PROFILE FULLNAME"); + alias = alias.substr(17); + } + handleVCard(user, id, legacyName, "", alias, photo); + } + } + + void sendData(const std::string &string) { + write(m_sock, string.c_str(), string.size()); +// if (writeInput == 0) +// writeInput = purple_input_add(m_sock, PURPLE_INPUT_WRITE, &transportDataReceived, NULL); + } + + void handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname) { + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + } + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + + } + + void handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) { + + } + + void handleTypingRequest(const std::string &user, const std::string &buddyName) { + + } + + void handleTypedRequest(const std::string &user, const std::string &buddyName) { + + } + + void handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) { + + } + + void handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) { + + } + + std::map m_sessions; + std::map m_accounts; + std::map m_vcards; + Config *config; + +}; + + Skype::Skype(const std::string &user, const std::string &username, const std::string &password) { + m_username = username; + m_user = user; + m_password = password; + m_pid = 0; + m_connection = 0; + m_proxy = 0; + } + + void Skype::login() { + boost::filesystem::path path(std::string("/tmp/skype/") + m_username); + if (!boost::filesystem::exists(path)) { + boost::filesystem::create_directories(path); + boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username ); + boost::filesystem::create_directories(path2); + } + + std::string shared_xml = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "2\n" + "en\n" + "\n" + "\n"; + g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL); + + std::string config_xml = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "\n" + "30000000\n" + "300000000\n" + "" + boost::lexical_cast(time(NULL)) + "\n" + "\n" + "\n" + "\n" + "\n" + "Spectrum\n" + "\n" + "\n" + "\n" + "\n"; + g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL); + std::string db_path = std::string("/tmp/skype/") + m_username; + char *db = (char *) malloc(db_path.size() + 1); + strcpy(db, db_path.c_str()); + LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db); + gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0}; + + int fd; + int fd_output; + g_spawn_async_with_pipes(NULL, + argv, + NULL /*envp*/, + G_SPAWN_SEARCH_PATH, + NULL /*child_setup*/, + NULL /*user_data*/, + &m_pid /*child_pid*/, + &fd, + NULL, + &fd_output, + NULL /*error*/); + std::string login_data = std::string(m_username + " " + m_password + "\n"); + LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data); + write(fd, login_data.c_str(), login_data.size()); + close(fd); + + fcntl (fd_output, F_SETFL, O_NONBLOCK); + + free(db); + + sleep(2); + + GError *error = NULL; + DBusObjectPathVTable vtable; + + //Initialise threading + dbus_threads_init_default(); + + if (m_connection == NULL) + { + m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (m_connection == NULL && error != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + g_error_free(error); + return; + } + } + + if (m_proxy == NULL) + { + m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, + "com.Skype.API", + "/com/Skype", + "com.Skype.API", + &error); + if (m_proxy == NULL && error != NULL) + { + LOG4CXX_INFO(logger, m_username << ":" << error->message); + g_error_free(error); + } + + vtable.message_function = &skype_notify_handler; + dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this); + } + + int counter = 0; + std::string re = "CONNSTATUS OFFLINE"; + while (re == "CONNSTATUS OFFLINE" || re.empty()) { + sleep(1); + gchar buffer[1024]; + int bytes_read; + bytes_read = read (fd_output, buffer, 1023); + if (bytes_read > 0) { + buffer[bytes_read] = 0; + np->handleDisconnected(m_user, 0, buffer); + close(fd_output); + logout(); + return; + } + re = send_command("NAME Spectrum"); + if (counter++ > 15) + break; + } + + close(fd_output); + + if (send_command("PROTOCOL 7") != "PROTOCOL 7") { + np->handleDisconnected(m_user, 0, "Skype is not ready"); + logout(); + return; + } + + np->handleConnected(m_user); + + std::map group_map; + std::string groups = send_command("SEARCH GROUPS CUSTOM"); + groups = groups.substr(groups.find(' ') + 1); + std::vector grps; + boost::split(grps, groups, boost::is_any_of(",")); + BOOST_FOREACH(std::string grp, grps) { + std::vector data; + std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME"); + boost::split(data, name, boost::is_any_of(" ")); + name = name.substr(name.find("DISPLAYNAME") + 12); + + std::string users = send_command("GET GROUP " + data[1] + " USERS"); + users = name.substr(name.find("USERS") + 6); + boost::split(data, users, boost::is_any_of(",")); + BOOST_FOREACH(std::string u, data) { + group_map[u] = grp; + } + } + + std::string friends = send_command("GET AUTH_CONTACTS_PROFILES"); + + char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0); + if (full_friends_list && full_friends_list[0]) + { + //in the format of: username;full name;phone;office phone;mobile phone; + // online status;friendly name;voicemail;mood + // (comma-seperated lines, usernames can have comma's) + + for (int i=0; full_friends_list[i] && *full_friends_list[i] != '\0'; i+=8) + { + std::string buddy = full_friends_list[i]; + + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + std::cout << "BUDDY '" << buddy << "'\n"; + std::string st = full_friends_list[i + 5]; + + pbnetwork::StatusType status = getStatus(st); + + std::string alias = full_friends_list[i + 6]; + + std::string mood_text = ""; + if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { + mood_text = full_friends_list[i + 8]; + i++; + } + + std::vector groups; + groups.push_back(group_map[buddy]); + np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); + } + } + g_strfreev(full_friends_list); + + send_command("SET AUTOAWAY OFF"); + } + + void Skype::logout() { + if (m_pid != 0) { + send_command("SET USERSTATUS INVISIBLE"); + send_command("SET USERSTATUS OFFLINE"); + sleep(2); + g_object_unref(m_proxy); + LOG4CXX_INFO(logger, m_username << ": Killing Skype instance"); + kill((int) m_pid, SIGTERM); + m_pid = 0; + } + } + + std::string Skype::send_command(const std::string &message) { + GError *error = NULL; + gchar *str = NULL; +// int message_num; +// gchar error_return[30]; + + if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID, + G_TYPE_STRING, &str, G_TYPE_INVALID)) + { + if (error && error->message) + { + LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + g_error_free(error); + } else { + LOG4CXX_INFO(logger, m_username << ": DBUS no response"); + } + + } + if (str != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS:" << str); + } + return str ? std::string(str) : std::string(); + } + +static void handle_skype_message(std::string &message, Skype *sk) { + std::vector cmd; + boost::split(cmd, message, boost::is_any_of(" ")); + + if (cmd[0] == "USER") { + if (cmd[1] == sk->getUsername()) { + return; + } + + if (cmd[2] == "ONLINESTATUS") { + if (cmd[3] == "SKYPEOUT" || cmd[3] == "UNKNOWN") { + return; + } + else { + pbnetwork::StatusType status = getStatus(cmd[3]); + std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT"); + mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10); + + std::string alias = sk->send_command("GET USER " + cmd[1] + " FULLNAME"); + alias = alias.substr(alias.find("FULLNAME") + 9); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); + } + } + else if (cmd[2] == "MOOD_TEXT") { + std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS"); + st = st.substr(st.find("ONLINESTATUS") + 13); + pbnetwork::StatusType status = getStatus(st); + + std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); + } + else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") { + std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS"); + st = st.substr(st.find("ONLINESTATUS") + 13); + pbnetwork::StatusType status = getStatus(st); + + std::string mood_text = message.substr(message.find("MOOD_TEXT") + 10); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); + } + } + else if (cmd[0] == "CHATMESSAGE") { + if (cmd[3] == "RECEIVED") { + std::string body = sk->send_command("GET CHATMESSAGE " + cmd[1] + " BODY"); + body = body.substr(body.find("BODY") + 5); + + std::string chatname = sk->send_command("GET CHATMESSAGE " + cmd[1] + " CHATNAME"); + size_t start = chatname.find("$") + 1; + size_t len = chatname.find(";") - start; + std::string from = chatname.substr(start, len); + + std::string from_handle = sk->send_command("GET CHATMESSAGE " + cmd[1] + " FROM_HANDLE"); + from_handle = from_handle.substr(from_handle.find("FROM_HANDLE") + 12); + +// if (from_handle != sk->getUsername()) { + from = from_handle; +// } + if (from_handle == sk->getUsername()) + return; + + np->handleMessage(sk->getUser(), from, body); + } + } +} + +DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer user_data) { + DBusMessageIter iterator; + gchar *message_temp; + DBusMessage *temp_message; + + temp_message = dbus_message_ref(message); + dbus_message_iter_init(temp_message, &iterator); + if (dbus_message_iter_get_arg_type(&iterator) != DBUS_TYPE_STRING) + { + dbus_message_unref(message); + return (DBusHandlerResult) FALSE; + } + + do { + dbus_message_iter_get_basic(&iterator, &message_temp); + std::string m(message_temp); + LOG4CXX_INFO(logger,"DBUS message: " << m); + handle_skype_message(m, (Skype *) user_data); + } while(dbus_message_iter_has_next(&iterator) && dbus_message_iter_next(&iterator)); + + dbus_message_unref(message); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static void spectrum_sigchld_handler(int sig) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} + +static int create_socket(char *host, int portno) { + struct sockaddr_in serv_addr; + + int m_sock = socket(AF_INET, SOCK_STREAM, 0); + memset((char *) &serv_addr, 0, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(portno); + + hostent *hos; // Resolve name + if ((hos = gethostbyname(host)) == NULL) { + // strerror() will not work for gethostbyname() and hstrerror() + // is supposedly obsolete + exit(1); + } + serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]); + + if (connect(m_sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { + close(m_sock); + m_sock = 0; + } + + int flags = fcntl(m_sock, F_GETFL); + flags |= O_NONBLOCK; + fcntl(m_sock, F_SETFL, flags); + return m_sock; +} + + +static gboolean transportDataReceived(GIOChannel *source, GIOCondition condition, gpointer data) { + char buffer[65535]; + char *ptr = buffer; + ssize_t n = read(m_sock, ptr, sizeof(buffer)); + if (n <= 0) { + LOG4CXX_INFO(logger, "Diconnecting from spectrum2 server"); + exit(errno); + } + std::string d = std::string(buffer, n); + np->handleDataRead(d); + return TRUE; +} + +static void io_destroy(gpointer data) { + exit(1); +} + +int main(int argc, char **argv) { + GError *error = NULL; + GOptionContext *context; + context = g_option_context_new("config_file_name or profile name"); + g_option_context_add_main_entries(context, options_entries, ""); + if (!g_option_context_parse (context, &argc, &argv, &error)) { + std::cout << "option parsing failed: " << error->message << "\n"; + return -1; + } + + if (ver) { +// std::cout << VERSION << "\n"; + std::cout << "verze\n"; + g_option_context_free(context); + return 0; + } + + if (argc != 2) { +#ifdef WIN32 + std::cout << "Usage: spectrum.exe \n"; +#else + +#if GLIB_CHECK_VERSION(2,14,0) + std::cout << g_option_context_get_help(context, FALSE, NULL); +#else + std::cout << "Usage: spectrum \n"; + std::cout << "See \"man spectrum\" for more info.\n"; +#endif + +#endif + } + else { +#ifndef WIN32 + signal(SIGPIPE, SIG_IGN); + + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + g_option_context_free(context); + return -1; + } +// +// if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) { +// std::cout << "SIGINT handler can't be set\n"; +// g_option_context_free(context); +// return -1; +// } +// +// if (signal(SIGTERM, spectrum_sigterm_handler) == SIG_ERR) { +// std::cout << "SIGTERM handler can't be set\n"; +// g_option_context_free(context); +// return -1; +// } +// +// struct sigaction sa; +// memset(&sa, 0, sizeof(sa)); +// sa.sa_handler = spectrum_sighup_handler; +// if (sigaction(SIGHUP, &sa, NULL)) { +// std::cout << "SIGHUP handler can't be set\n"; +// g_option_context_free(context); +// return -1; +// } +#endif + Config config; + if (!config.load(argv[1])) { + std::cout << "Can't open " << argv[1] << " configuration file.\n"; + return 1; + } + + if (CONFIG_STRING(&config, "logging.backend_config").empty()) { + LoggerPtr root = log4cxx::Logger::getRootLogger(); + root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n"))); + } + else { + log4cxx::helpers::Properties p; + log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config")); + + p.load(istream); + p.setProperty("pid", boost::lexical_cast(getpid())); + log4cxx::PropertyConfigurator::configure(p); + } + +// initPurple(config); + + g_type_init(); + + m_sock = create_socket(host, port); + + + GIOChannel *channel; + GIOCondition cond = (GIOCondition) READ_COND; + channel = g_io_channel_unix_new(m_sock); + g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy); + + np = new SpectrumNetworkPlugin(&config, host, port); + + GMainLoop *m_loop; + m_loop = g_main_loop_new(NULL, FALSE); + + if (m_loop) { + g_main_loop_run(m_loop); + } + } + + g_option_context_free(context); +} diff --git a/backends/skype/spectrumeventloop.cpp b/backends/skype/spectrumeventloop.cpp new file mode 100644 index 00000000..20286e58 --- /dev/null +++ b/backends/skype/spectrumeventloop.cpp @@ -0,0 +1,90 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "spectrumeventloop.h" +#include "glib.h" + +#include + +#ifdef WITH_LIBEVENT +#include +#endif + + +using namespace Swift; + +// Fires the event's callback and frees the event +static gboolean processEvent(void *data) { + Event *ev = (Event *) data; + ev->callback(); + delete ev; + return FALSE; +} + +SpectrumEventLoop::SpectrumEventLoop() : m_isRunning(false) { + m_loop = NULL; + if (true) { + m_loop = g_main_loop_new(NULL, FALSE); + } +#ifdef WITH_LIBEVENT + else { + /*struct event_base *base = (struct event_base *)*/ + event_init(); + } +#endif +} + +SpectrumEventLoop::~SpectrumEventLoop() { + stop(); +} + +void SpectrumEventLoop::run() { + m_isRunning = true; + if (m_loop) { + g_main_loop_run(m_loop); + } +#ifdef WITH_LIBEVENT + else { + event_loop(0); + } +#endif +} + +void SpectrumEventLoop::stop() { + std::cout << "stopped loop\n"; + if (!m_isRunning) + return; + if (m_loop) { + g_main_loop_quit(m_loop); + g_main_loop_unref(m_loop); + m_loop = NULL; + } +#ifdef WITH_LIBEVENT + else { + event_loopexit(NULL); + } +#endif +} + +void SpectrumEventLoop::post(const Event& event) { + // pass copy of event to main thread + Event *ev = new Event(event.owner, event.callback); + g_timeout_add(0, processEvent, ev); +} diff --git a/backends/skype/spectrumeventloop.h b/backends/skype/spectrumeventloop.h new file mode 100644 index 00000000..7e811c89 --- /dev/null +++ b/backends/skype/spectrumeventloop.h @@ -0,0 +1,49 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#ifndef SPECTRUM_EVENT_LOOP_H +#define SPECTRUM_EVENT_LOOP_H + +#include +#include "Swiften/EventLoop/EventLoop.h" +#include "glib.h" + +// Event loop implementation for Spectrum +class SpectrumEventLoop : public Swift::EventLoop { + public: + // Creates event loop according to CONFIG().eventloop settings. + SpectrumEventLoop(); + ~SpectrumEventLoop(); + + // Executes the eventloop. + void run(); + + // Stops tht eventloop. + void stop(); + + // Posts new Swift::Event to main thread. + virtual void post(const Swift::Event& event); + + private: + bool m_isRunning; + GMainLoop *m_loop; +}; + +#endif diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 91ab58fc..d2de8992 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -40,6 +40,8 @@ users_per_backend=10 # Full path to backend binary. backend=/usr/bin/spectrum2_libpurple_backend #backend=/usr/bin/spectrum2_libircclient-qt_backend +# For skype: +#backend=/usr/bin/setsid /usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend # Libpurple protocol-id for spectrum_libpurple_backend protocol=prpl-jabber From f95fa32c2b41c84ea6520f3001c874ef73cd17d8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 24 Jan 2012 16:39:51 +0100 Subject: [PATCH 20/74] Disable skype building temporarily --- backends/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 1c056d11..b8278015 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -9,7 +9,7 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) - ADD_SUBDIRECTORY(skype) +# ADD_SUBDIRECTORY(skype) endif() endif() From 20ba88890d2a10e9c912e3a88d4db805a275e08b Mon Sep 17 00:00:00 2001 From: Dominik Date: Fri, 27 Jan 2012 15:11:24 +0100 Subject: [PATCH 21/74] - registration with local user accounts stub --- src/config.cpp | 2 ++ src/userregistration.cpp | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/config.cpp b/src/config.cpp index c5ca48b5..d456024f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -87,6 +87,8 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.username_label", value()->default_value("Legacy network username:"), "Label for username field") ("registration.username_mask", value()->default_value(""), "Username mask") ("registration.encoding", value()->default_value("utf8"), "Default encoding in registration form") + ("registration.require_local_account", value()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.") + ("registration.local_username_label", value()->default_value("Local username:"), "Label for local usernme field") ("database.type", value()->default_value("none"), "Database type.") ("database.database", value()->default_value(""), "Database used to store data") ("database.server", value()->default_value("localhost"), "Database server.") diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 9160465f..6d3e9fd5 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -241,6 +241,20 @@ bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID boolean->setLabel((("Remove your registration"))); boolean->setValue(0); form->addField(boolean); + } else { + if (CONFIG_BOOL(m_config,"registration.require_local_account")) { + std::string localUsernameField = CONFIG_STRING(m_config, "registration.local_username_label"); + TextSingleFormField::ref local_username = TextSingleFormField::create(); + local_username->setName("local_username"); + local_username->setLabel((localUsernameField)); + local_username->setRequired(true); + form->addField(local_username); + TextPrivateFormField::ref local_password = TextPrivateFormField::create(); + local_password->setName("local_password"); + local_password->setLabel((("Local Password"))); + local_password->setRequired(true); + form->addField(local_password); + } } reg->setForm(form); @@ -273,6 +287,8 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID std::string encoding; std::string language; + std::string local_username(""); + std::string local_password(""); Form::ref form = payload->getForm(); if (form) { @@ -290,6 +306,13 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID else if (textSingle->getName() == "password") { payload->setPassword(textSingle->getValue()); } + else if (textSingle->getName() == "local_username") { + local_username = textSingle->getValue(); + } + // Pidgin sends it as textSingle, not sure why... + else if (textSingle->getName() == "local_password") { + local_password = textSingle->getValue(); + } continue; } @@ -298,6 +321,9 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID if (textPrivate->getName() == "password") { payload->setPassword(textPrivate->getValue()); } + else if (textPrivate->getName() == "local_password") { + local_password = textPrivate->getValue(); + } continue; } @@ -327,6 +353,22 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID return true; } + if (CONFIG_BOOL(m_config,"registration.require_local_account")) { + /* if (!local_username || !local_password) { + sendResponse(from, id, InBandRegistrationPayload::ref()); + return true + } else */ if (local_username == "" || local_password == "") { + sendResponse(from, id, InBandRegistrationPayload::ref()); + return true; + } else if (local_username != "heinz" || local_password != "heinz") { + // TODO: Check local password and username + sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Modify); + return true; + } + } + + printf("here\n"); + if (!payload->getUsername() || !payload->getPassword()) { sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify); return true; From 7619b9e2b2cbd4c6416fcf75f8fed575bb0dc444 Mon Sep 17 00:00:00 2001 From: Dominik Date: Fri, 27 Jan 2012 18:33:18 +0100 Subject: [PATCH 22/74] - check local_username against configured server - TODO: improve really crappy and hacky Swiften password check solution --- spectrum/src/sample2.cfg | 17 +++++++++++++++++ src/config.cpp | 2 ++ src/userregistration.cpp | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index d2de8992..508395e9 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -95,3 +95,20 @@ type = none # Prefix used for tables #prefix = jabber_ + +[registration] +# Enable public registrations +enable_public_registration=1 + +# Text to display upon user registration form +username_label=Jabber JID (e.g. user@server.tld): +instructions=Enter your remote jabber JID and password as well as your local username and password + +# If True a local jabber account on is needed +# for transport registration, the idea is to enable public registration +# from other servers, but only for users, who have already local accounts +require_local_account=1 +local_username_label=Local username (without @server.tld): +local_account_server=localhost +local_account_server_timeout=10000 + diff --git a/src/config.cpp b/src/config.cpp index d456024f..91e5ed67 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -89,6 +89,8 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.encoding", value()->default_value("utf8"), "Default encoding in registration form") ("registration.require_local_account", value()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.") ("registration.local_username_label", value()->default_value("Local username:"), "Label for local usernme field") + ("registration.local_account_server", value()->default_value("localhost"), "The server on which the local accounts will be checked for validity") + ("registration.local_account_server_timeout", value()->default_value(10000), "Timeout when checking local user on local_account_server (msecs)") ("database.type", value()->default_value("none"), "Database type.") ("database.database", value()->default_value(""), "Database used to store data") ("database.server", value()->default_value("localhost"), "Database server.") diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 6d3e9fd5..d5d7d611 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -26,6 +26,8 @@ #include "transport/user.h" #include "Swiften/Elements/ErrorPayload.h" #include +#include +#include #include "log4cxx/logger.h" using namespace Swift; @@ -360,8 +362,36 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID } else */ if (local_username == "" || local_password == "") { sendResponse(from, id, InBandRegistrationPayload::ref()); return true; - } else if (local_username != "heinz" || local_password != "heinz") { - // TODO: Check local password and username + } + Swift::logging = true; + bool validLocal = false; + std::string localLookupServer = CONFIG_STRING(m_config, "registration.local_account_server"); + std::string localLookupJID = local_username + std::string("@") + localLookupServer; + SimpleEventLoop localLookupEventLoop; + BoostNetworkFactories localLookupNetworkFactories(&localLookupEventLoop); + Client localLookupClient(localLookupJID, local_password, &localLookupNetworkFactories); + + // TODO: this is neccessary on my server ... but should maybe omitted + localLookupClient.setAlwaysTrustCertificates(); + localLookupClient.connect(); + + class SimpleLoopRunner { + public: + SimpleLoopRunner() {}; + + static void run(SimpleEventLoop * loop) { + loop->run(); + }; + }; + + // TODO: Really ugly and hacky solution, any other ideas more than welcome! + boost::thread thread(boost::bind(&(SimpleLoopRunner::run), &localLookupEventLoop)); + thread.timed_join(boost::posix_time::millisec(CONFIG_INT(m_config, "registration.local_account_server_timeout"))); + localLookupEventLoop.stop(); + thread.join(); + validLocal = localLookupClient.isAvailable(); + localLookupClient.disconnect(); + if (!validLocal) { sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Modify); return true; } From daf9143bf26005fe951de79a989d865a564da151 Mon Sep 17 00:00:00 2001 From: Dominik Date: Fri, 27 Jan 2012 18:41:47 +0100 Subject: [PATCH 23/74] - forgot to disable logging --- src/userregistration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/userregistration.cpp b/src/userregistration.cpp index d5d7d611..f7de616e 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -363,7 +363,7 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID sendResponse(from, id, InBandRegistrationPayload::ref()); return true; } - Swift::logging = true; +// Swift::logging = true; bool validLocal = false; std::string localLookupServer = CONFIG_STRING(m_config, "registration.local_account_server"); std::string localLookupJID = local_username + std::string("@") + localLookupServer; From 099857ad59ce9a2579b716a3fc73095f6fe396bc Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 14 Feb 2012 21:48:07 +0100 Subject: [PATCH 24/74] smstools3 backend - not working so far --- backends/CMakeLists.txt | 2 + backends/smstools3/CMakeLists.txt | 10 ++ backends/smstools3/main.cpp | 246 ++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 backends/smstools3/CMakeLists.txt create mode 100644 backends/smstools3/main.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index b8278015..c0e3d527 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -7,6 +7,8 @@ if (PROTOBUF_FOUND) ADD_SUBDIRECTORY(libcommuni) endif() +#ADD_SUBDIRECTORY(smstools3) + if (NOT WIN32) ADD_SUBDIRECTORY(frotz) # ADD_SUBDIRECTORY(skype) diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt new file mode 100644 index 00000000..c410cee6 --- /dev/null +++ b/backends/smstools3/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.c *.cpp) + +ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC}) + +target_link_libraries(spectrum2_smstools3_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) + +INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin) + diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp new file mode 100644 index 00000000..60d1e1e3 --- /dev/null +++ b/backends/smstools3/main.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com + * + * This example is free, and not covered by LGPL license. There is no + * restriction applied to their modification, redistribution, using and so on. + * You can study them, modify them, use them in your own program - either + * completely or partially. By using it you may give me some credits in your + * program, but you don't have to. + */ + +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "Swiften/Swiften.h" +#include +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" +#include +#include + +Swift::SimpleEventLoop *loop_; + +#include "log4cxx/logger.h" +#include "log4cxx/consoleappender.h" +#include "log4cxx/patternlayout.h" +#include "log4cxx/propertyconfigurator.h" +#include "log4cxx/helpers/properties.h" +#include "log4cxx/helpers/fileinputstream.h" +#include "log4cxx/helpers/transcoder.h" +#include +#include + +using namespace boost::filesystem; + +using namespace boost::program_options; +using namespace Transport; + +using namespace log4cxx; + +class SMSNetworkPlugin; +SMSNetworkPlugin * np = NULL; + +class SMSNetworkPlugin : public NetworkPlugin { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; + Swift::Timer::ref m_timer; + + SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&SMSNetworkPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); +// m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1)); +// m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this)); + + m_timer = m_factories->getTimerFactory()->createTimer(5000); + m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); + m_timer->start(); + } + + + void handleSMS(const std::string &sms) { + std::ifstream t(sms.c_str()); + std::string str; + + t.seekg(0, std::ios::end); + str.reserve(t.tellg()); + t.seekg(0, std::ios::beg); + + str.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + + std::string to = ""; + std::string msg = ""; + while(str.find("\n") != std::string::npos) { + std::string line = str.substr(0, str.find("\n")); + if (line.find("To: ") == 0) { + to = line.substr(strlen("To: ")); + } + else if (line.empty()) { + msg = str; + break; + } + str = str.substr(str.find("\n") + 1); + } + + } + + void handleSMSDir() { + path p(config->getUnregistered().find("backend.incoming_dir")->second); + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + + try { + if (is_regular(itr->path())) { + handleSMS(itr->path().string()); + remove(itr->path()); + } + } + catch (const filesystem_error& ex) { + + } + } + m_timer->start(); + } + + void sendData(const std::string &string) { + m_conn->write(Swift::createSafeByteArray(string)); + } + + void _handleDataRead(boost::shared_ptr data) { + std::string d(data->begin(), data->end()); + handleDataRead(d); + } + + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + np->handleConnected(user); +// std::vector groups; +// groups.push_back("ZCode"); +// np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE); + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + + } + + void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { + } + + void handleLeaveRoomRequest(const std::string &user, const std::string &room) { + } + + + private: + + Config *config; +}; + +static void spectrum_sigchld_handler(int sig) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} + + +int main (int argc, char* argv[]) { + std::string host; + int port; + + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } + + boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + desc.add_options() + ("host,h", value(&host), "host") + ("port,p", value(&port), "port") + ; + try + { + boost::program_options::variables_map vm; + boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::notify(vm); + } + catch (std::runtime_error& e) + { + std::cout << desc << "\n"; + exit(1); + } + catch (...) + { + std::cout << desc << "\n"; + exit(1); + } + + + if (argc < 5) { + return 1; + } + +// QStringList channels; +// for (int i = 3; i < argc; ++i) +// { +// channels.append(argv[i]); +// } +// +// MyIrcSession session; +// session.setNick(argv[2]); +// session.setAutoJoinChannels(channels); +// session.connectToServer(argv[1], 6667); + + Config config; + if (!config.load(argv[5])) { + std::cerr << "Can't open " << argv[1] << " configuration file.\n"; + return 1; + } + + if (CONFIG_STRING(&config, "logging.backend_config").empty()) { + LoggerPtr root = log4cxx::Logger::getRootLogger(); +#ifndef _MSC_VER + root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n"))); +#else + root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n"))); +#endif + } + else { + log4cxx::helpers::Properties p; + log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config")); + p.load(istream); + LogString pid, jid; + log4cxx::helpers::Transcoder::decode(boost::lexical_cast(getpid()), pid); + log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid); +#ifdef _MSC_VER + p.setProperty(L"pid", pid); + p.setProperty(L"jid", jid); +#else + p.setProperty("pid", pid); + p.setProperty("jid", jid); +#endif + log4cxx::PropertyConfigurator::configure(p); + } + + Swift::SimpleEventLoop eventLoop; + loop_ = &eventLoop; + np = new SMSNetworkPlugin(&config, &eventLoop, host, port); + loop_->run(); + + return 0; +} From db6f7e6c8f8692d8ef69a032c95dc07fcff91aac Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 15 Feb 2012 20:48:51 +0100 Subject: [PATCH 25/74] sending sms works --- backends/CMakeLists.txt | 2 +- backends/smstools3/main.cpp | 22 ++++++++++++++++++++-- spectrum/src/sample.cfg | 4 +++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index c0e3d527..be7163c5 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -7,7 +7,7 @@ if (PROTOBUF_FOUND) ADD_SUBDIRECTORY(libcommuni) endif() -#ADD_SUBDIRECTORY(smstools3) + ADD_SUBDIRECTORY(smstools3) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 60d1e1e3..bc02c24a 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -87,6 +87,8 @@ class SMSNetworkPlugin : public NetworkPlugin { str = str.substr(str.find("\n") + 1); } + std::cout << "INCOMING SMS '" << to << "' '" << msg << "'\n"; + } void handleSMSDir() { @@ -97,7 +99,7 @@ class SMSNetworkPlugin : public NetworkPlugin { try { if (is_regular(itr->path())) { handleSMS(itr->path().string()); - remove(itr->path()); +// remove(itr->path()); } } catch (const filesystem_error& ex) { @@ -107,6 +109,22 @@ class SMSNetworkPlugin : public NetworkPlugin { m_timer->start(); } + void sendSMS(const std::string &to, const std::string &msg) { + std::string data = "To: " + to + "\n"; + data += "\n"; + data += msg; + + std::string bucket = "abcdefghijklmnopqrstuvwxyz"; + std::string uuid; + for (int i = 0; i < 10; i++) { + uuid += bucket[rand() % bucket.size()]; + } + std::ofstream myfile; + myfile.open (std::string("/var/spool/sms/outgoing/spectrum." + uuid).c_str()); + myfile << data; + myfile.close(); + } + void sendData(const std::string &string) { m_conn->write(Swift::createSafeByteArray(string)); } @@ -127,7 +145,7 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { - + sendSMS(legacyName, message); } void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index fcb060d3..10850f05 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,7 +13,8 @@ admin_password=test #cert=server.pfx #patch to PKCS#12 certificate #cert_password=test #password to that certificate if any users_per_backend=10 -backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend +#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend +backend=/home/hanzz/code/libtransport/backends/smstools3/spectrum2_smstools3_backend #backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe #backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend #backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend @@ -25,6 +26,7 @@ irc_server=irc.freenode.org [backend] #default_avatar=catmelonhead.jpg #no_vcard_fetch=true +incoming_dir=/var/spool/sms/incoming [logging] #config=logging.cfg # log4cxx/log4j logging configuration file From d8e60cea9507daf5485ee1627446497c7c1169f8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 15 Feb 2012 21:13:14 +0100 Subject: [PATCH 26/74] Join the database from sms backend --- backends/smstools3/main.cpp | 76 +++++++++++++++++++++++++++++++++++++ spectrum/src/sample.cfg | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index bc02c24a..919480ec 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -10,6 +10,10 @@ #include "transport/config.h" #include "transport/networkplugin.h" +#include "transport/sqlite3backend.h" +#include "transport/mysqlbackend.h" +#include "transport/pqxxbackend.h" +#include "transport/storagebackend.h" #include "Swiften/Swiften.h" #include #include "unistd.h" @@ -40,6 +44,7 @@ using namespace log4cxx; class SMSNetworkPlugin; SMSNetworkPlugin * np = NULL; +StorageBackend *storageBackend; class SMSNetworkPlugin : public NetworkPlugin { public: @@ -135,6 +140,18 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + UserInfo info; + if (!storageBackend->getUser(user, info)) { + handleDisconnected(user, 0, "Not registered user."); + return; + } + std::list roster; + storageBackend->getBuddies(info.id, roster); + + BOOST_FOREACH(BuddyInfo &b, roster) { + handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE); + } + np->handleConnected(user); // std::vector groups; // groups.push_back("ZCode"); @@ -154,6 +171,14 @@ class SMSNetworkPlugin : public NetworkPlugin { void handleLeaveRoomRequest(const std::string &user, const std::string &room) { } + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + + } + private: @@ -255,6 +280,57 @@ int main (int argc, char* argv[]) { log4cxx::PropertyConfigurator::configure(p); } +#ifdef WITH_SQLITE + if (CONFIG_STRING(&config, "database.type") == "sqlite3") { + storageBackend = new SQLite3Backend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "sqlite3") { + std::cerr << "Spectrum2 is not compiled with mysql backend.\n"; + return -2; + } +#endif + +#ifdef WITH_MYSQL + if (CONFIG_STRING(&config, "database.type") == "mysql") { + storageBackend = new MySQLBackend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "mysql") { + std::cerr << "Spectrum2 is not compiled with mysql backend.\n"; + return -2; + } +#endif + +#ifdef WITH_PQXX + if (CONFIG_STRING(&config, "database.type") == "pqxx") { + storageBackend = new PQXXBackend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "pqxx") { + std::cerr << "Spectrum2 is not compiled with pqxx backend.\n"; + return -2; + } +#endif + + if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3" + && CONFIG_STRING(&config, "database.type") != "pqxx" && CONFIG_STRING(&config, "database.type") != "none") { + std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n"; + return -2; + } + Swift::SimpleEventLoop eventLoop; loop_ = &eventLoop; np = new SMSNetworkPlugin(&config, &eventLoop, host, port); diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 10850f05..85f88d37 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -33,6 +33,6 @@ incoming_dir=/var/spool/sms/incoming #backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] -type = none # or "none" without database backend +type = sqlite3 # or "none" without database backend database = test.sql prefix=icq From 57963cf18ec01b4998765f292001cd207e0cc2b1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 15 Feb 2012 22:31:08 +0100 Subject: [PATCH 27/74] working smstools3 with basic pairing --- backends/smstools3/main.cpp | 48 +++++++++++++++++++++++++++++++------ spectrum/src/sample.cfg | 12 +++++++--- src/mysqlbackend.cpp | 10 +++++--- src/sqlite3backend.cpp | 2 ++ 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 919480ec..892a37f9 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -42,6 +42,8 @@ using namespace Transport; using namespace log4cxx; +#define INTERNAL_USER "/sms@backend@internal@user" + class SMSNetworkPlugin; SMSNetworkPlugin * np = NULL; StorageBackend *storageBackend; @@ -52,6 +54,7 @@ class SMSNetworkPlugin : public NetworkPlugin { Swift::BoostIOServiceThread m_boostIOServiceThread; boost::shared_ptr m_conn; Swift::Timer::ref m_timer; + int m_internalUser; SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { this->config = config; @@ -65,6 +68,13 @@ class SMSNetworkPlugin : public NetworkPlugin { m_timer = m_factories->getTimerFactory()->createTimer(5000); m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); m_timer->start(); + + UserInfo info; + info.jid = INTERNAL_USER; + info.password = ""; + storageBackend->setUser(info); + storageBackend->getUser(INTERNAL_USER, info); + m_internalUser = info.id; } @@ -78,21 +88,32 @@ class SMSNetworkPlugin : public NetworkPlugin { str.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - std::string to = ""; + std::string from = ""; std::string msg = ""; while(str.find("\n") != std::string::npos) { std::string line = str.substr(0, str.find("\n")); - if (line.find("To: ") == 0) { - to = line.substr(strlen("To: ")); + if (line.find("From: ") == 0) { + from = line.substr(strlen("From: ")); } else if (line.empty()) { - msg = str; + msg = str.substr(1); break; } str = str.substr(str.find("\n") + 1); } - std::cout << "INCOMING SMS '" << to << "' '" << msg << "'\n"; + std::list roster; + storageBackend->getBuddies(m_internalUser, roster); + + std::string to; + BOOST_FOREACH(BuddyInfo &b, roster) { + if (b.legacyName == from) { + to = b.alias; + } + } + + handleMessage(to, from, msg); + std::cout << "INCOMING SMS '" << from << "' '" << to << "' '" << msg << "'\n"; } @@ -104,7 +125,7 @@ class SMSNetworkPlugin : public NetworkPlugin { try { if (is_regular(itr->path())) { handleSMS(itr->path().string()); -// remove(itr->path()); + remove(itr->path()); } } catch (const filesystem_error& ex) { @@ -162,7 +183,20 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { - sendSMS(legacyName, message); + std::string n = legacyName; + if (n.find("+") == 0) { + n = n.substr(1); + } + + BuddyInfo info; + info.legacyName = n; + info.alias = user; + info.id = -1; + info.subscription = "both"; + info.flags = 0; + storageBackend->addBuddy(m_internalUser, info); + + sendSMS(n, message); } void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 85f88d37..cc57d216 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -33,6 +33,12 @@ incoming_dir=/var/spool/sms/incoming #backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] -type = sqlite3 # or "none" without database backend -database = test.sql -prefix=icq +#type = sqlite3 # or "none" without database backend +#database = test.sql +#prefix=icq +type = mysql # or "none" without database backend....................................................................................................................... +database = test +prefix= +user=root +password=yourrootsqlpassword +#encryption_key=hanzzik diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 4bc2eec4..1af53c3a 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -470,7 +470,7 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { long id = (long) mysql_insert_id(&m_conn); // INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) - if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { + if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end() && !buddyInfo.settings.find("icon_hash")->second.s.empty()) { *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); } @@ -597,6 +597,10 @@ void MySQLBackend::getUserSetting(long id, const std::string &variable, int &typ else { *m_getUserSetting >> type >> value; } + + while (m_getUserSetting->fetch() == 0) { + + } } void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { @@ -606,11 +610,11 @@ void MySQLBackend::updateUserSetting(long id, const std::string &variable, const } void MySQLBackend::beginTransaction() { - exec("START TRANSACTION;"); + //exec("START TRANSACTION;"); } void MySQLBackend::commitTransaction() { - exec("COMMIT;"); + //exec("COMMIT;"); } } diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index ad03bf23..ea869275 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -111,6 +111,8 @@ bool SQLite3Backend::connect() { return false; } + sqlite3_busy_timeout(m_db, 1500); + if (createDatabase() == false) return false; From a67bc0fa96a538343236b538df9ab9c26aab938e Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 08:45:18 +0100 Subject: [PATCH 28/74] SMSTools3 backend logging --- backends/smstools3/main.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 892a37f9..fb5a791b 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -42,6 +42,8 @@ using namespace Transport; using namespace log4cxx; +static LoggerPtr logger = log4cxx::Logger::getLogger("SMSNetworkPlugin"); + #define INTERNAL_USER "/sms@backend@internal@user" class SMSNetworkPlugin; @@ -65,6 +67,8 @@ class SMSNetworkPlugin : public NetworkPlugin { // m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1)); // m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this)); + LOG4CXX_INFO(logger, "Starting the plugin."); + m_timer = m_factories->getTimerFactory()->createTimer(5000); m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); m_timer->start(); @@ -79,6 +83,7 @@ class SMSNetworkPlugin : public NetworkPlugin { void handleSMS(const std::string &sms) { + LOG4CXX_INFO(logger, "Handling SMS " << sms << ".") std::ifstream t(sms.c_str()); std::string str; @@ -112,13 +117,22 @@ class SMSNetworkPlugin : public NetworkPlugin { } } - handleMessage(to, from, msg); - std::cout << "INCOMING SMS '" << from << "' '" << to << "' '" << msg << "'\n"; + if (to.empty()) { + LOG4CXX_WARN(logger, "Received SMS from " << from << ", but this number is not associated with any XMPP user."); + } + LOG4CXX_INFO(logger, "Forwarding SMS from " << from << " to " << to << "."); + handleMessage(to, from, msg); } void handleSMSDir() { - path p(config->getUnregistered().find("backend.incoming_dir")->second); + std::string dir = "/var/spool/sms/incoming/"; + if (config->getUnregistered().find("backend.incoming_dir") != config->getUnregistered().end()) { + dir = config->getUnregistered().find("backend.incoming_dir")->second; + } + LOG4CXX_INFO(logger, "Checking directory " << dir << " for incoming SMS."); + + path p(dir); directory_iterator end_itr; for (directory_iterator itr(p); itr != end_itr; ++itr) { @@ -129,7 +143,7 @@ class SMSNetworkPlugin : public NetworkPlugin { } } catch (const filesystem_error& ex) { - + LOG4CXX_ERROR(logger, "Error when removing the SMS: " << ex.what() << "."); } } m_timer->start(); @@ -196,6 +210,7 @@ class SMSNetworkPlugin : public NetworkPlugin { info.flags = 0; storageBackend->addBuddy(m_internalUser, info); + LOG4CXX_INFO(logger, "Sending SMS from " << user << " to " << n << "."); sendSMS(n, message); } @@ -206,6 +221,7 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << "."); handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); } From 1be2472596ac1ac0f414e3af830112ce992be649 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 09:18:29 +0100 Subject: [PATCH 29/74] more comments --- CMakeLists.txt | 2 +- backends/smstools3/main.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f4802e1..261af42c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) endif() -find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) +find_package(Boost COMPONENTS program_options date_time system filesystem regex signals REQUIRED) message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index fb5a791b..1b0bb044 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -73,6 +73,11 @@ class SMSNetworkPlugin : public NetworkPlugin { m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); m_timer->start(); + // We're reusing our database model here. Buddies of user with JID INTERNAL_USER are there + // to match received GSM messages from number N with the XMPP users who sent message to number N. + // BuddyName = GSM number + // Alias = XMPP user JID to which the messages from this number is sent to. + // TODO: This should be per Modem!!! UserInfo info; info.jid = INTERNAL_USER; info.password = ""; @@ -150,10 +155,12 @@ class SMSNetworkPlugin : public NetworkPlugin { } void sendSMS(const std::string &to, const std::string &msg) { + // TODO: Probably std::string data = "To: " + to + "\n"; data += "\n"; data += msg; + // generate random string here... std::string bucket = "abcdefghijklmnopqrstuvwxyz"; std::string uuid; for (int i = 0; i < 10; i++) { @@ -183,25 +190,25 @@ class SMSNetworkPlugin : public NetworkPlugin { std::list roster; storageBackend->getBuddies(info.id, roster); + // Send available presence to every number in the roster. BOOST_FOREACH(BuddyInfo &b, roster) { handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE); } np->handleConnected(user); -// std::vector groups; -// groups.push_back("ZCode"); -// np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE); } void handleLogoutRequest(const std::string &user, const std::string &legacyName) { } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + // Remove trailing +, because smstools doesn't use it in "From: " field for received messages. std::string n = legacyName; if (n.find("+") == 0) { n = n.substr(1); } + // Create GSM Number - XMPP user pair to match the potential response and send it to the proper JID. BuddyInfo info; info.legacyName = n; info.alias = user; From 2442a31dfd32d9b4fbfe643100aa38fa01624e00 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 10:26:47 +0100 Subject: [PATCH 30/74] Find dbus --- CMakeLists.txt | 12 ++ backends/CMakeLists.txt | 2 +- backends/skype/CMakeLists.txt | 6 +- backends/skype/geventloop.cpp | 248 --------------------------- backends/skype/geventloop.h | 33 ---- backends/skype/main.cpp | 4 +- backends/skype/spectrumeventloop.cpp | 90 ---------- backends/skype/spectrumeventloop.h | 49 ------ cmake_modules/dbusConfig.cmake | 53 ++++++ 9 files changed, 68 insertions(+), 429 deletions(-) delete mode 100644 backends/skype/geventloop.cpp delete mode 100644 backends/skype/geventloop.h delete mode 100644 backends/skype/spectrumeventloop.cpp delete mode 100644 backends/skype/spectrumeventloop.h create mode 100644 cmake_modules/dbusConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 261af42c..e798a842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,9 @@ find_package(event) set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(pqxx) +set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(dbus) + find_package(Doxygen) INCLUDE(FindQt4) @@ -146,12 +149,21 @@ if (PROTOBUF_FOUND) endif() message("Frotz plugin : yes") + message("SMSTools3 plugin : yes") + + if(${LIBDBUSGLIB_FOUND}) + message("Skype plugin : yes") + include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + else() + message("Skype plugin : no (install dbus-glib-devel)") + endif() else() message("Network plugins : no (install libprotobuf-dev)") message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") message("IRC plugin : no (install libircclient-qt and libprotobuf-dev)") message("Frotz plugin : no (install libprotobuf-dev)") + message("SMSTools3 plugin : no (install libprotobuf-dev)") endif() if (LOG4CXX_FOUND) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index be7163c5..2bb2c447 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -11,7 +11,7 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) -# ADD_SUBDIRECTORY(skype) + ADD_SUBDIRECTORY(skype) endif() endif() diff --git a/backends/skype/CMakeLists.txt b/backends/skype/CMakeLists.txt index fa6e9266..4e611208 100644 --- a/backends/skype/CMakeLists.txt +++ b/backends/skype/CMakeLists.txt @@ -1,13 +1,9 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp) - -include_directories(/usr/include/dbus-1.0/) -include_directories(/usr/lib/dbus-1.0/include/) -include_directories(/usr/lib64/dbus-1.0/include/) ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) -target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread dbus-glib-1 dbus-1 gobject-2.0 transport-plugin) +target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES} transport-plugin) INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) diff --git a/backends/skype/geventloop.cpp b/backends/skype/geventloop.cpp deleted file mode 100644 index d00d7a56..00000000 --- a/backends/skype/geventloop.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "geventloop.h" -#ifdef _WIN32 -#include "win32/win32dep.h" -#endif -#ifdef WITH_LIBEVENT -#include "event.h" -#endif - -typedef struct _PurpleIOClosure { - PurpleInputFunction function; - guint result; - gpointer data; -#ifdef WITH_LIBEVENT - GSourceFunc function2; - struct timeval timeout; - struct event evfifo; -#endif -} PurpleIOClosure; - -static gboolean io_invoke(GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - PurpleIOClosure *closure = (PurpleIOClosure* )data; - PurpleInputCondition purple_cond = (PurpleInputCondition)0; - - int tmp = 0; - if (condition & READ_COND) - { - tmp |= PURPLE_INPUT_READ; - purple_cond = (PurpleInputCondition)tmp; - } - if (condition & WRITE_COND) - { - tmp |= PURPLE_INPUT_WRITE; - purple_cond = (PurpleInputCondition)tmp; - } - - closure->function(closure->data, g_io_channel_unix_get_fd(source), purple_cond); - - return TRUE; -} - -static void io_destroy(gpointer data) -{ - g_free(data); -} - -static guint input_add(gint fd, - PurpleInputCondition condition, - PurpleInputFunction function, - gpointer data) -{ - PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = (GIOCondition)0; - closure->function = function; - closure->data = data; - - int tmp = 0; - if (condition & PURPLE_INPUT_READ) - { - tmp |= READ_COND; - cond = (GIOCondition)tmp; - } - if (condition & PURPLE_INPUT_WRITE) - { - tmp |= WRITE_COND; - cond = (GIOCondition)tmp; - } - -#ifdef WIN32 - channel = wpurple_g_io_channel_win32_new_socket(fd); -#else - channel = g_io_channel_unix_new(fd); -#endif - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - io_invoke, closure, io_destroy); - - g_io_channel_unref(channel); - return closure->result; -} - -static PurpleEventLoopUiOps eventLoopOps = -{ - g_timeout_add, - g_source_remove, - input_add, - g_source_remove, - NULL, -#if GLIB_CHECK_VERSION(2,14,0) - g_timeout_add_seconds, -#else - NULL, -#endif - - NULL, - NULL, - NULL -}; - -#ifdef WITH_LIBEVENT - -static GHashTable *events = NULL; -static unsigned long id = 0; - -static void event_io_destroy(gpointer data) -{ - PurpleIOClosure *closure = (PurpleIOClosure* )data; - event_del(&closure->evfifo); - g_free(data); -} - -static void event_io_invoke(int fd, short event, void *data) -{ - PurpleIOClosure *closure = (PurpleIOClosure* )data; - PurpleInputCondition purple_cond = (PurpleInputCondition)0; - int tmp = 0; - if (event & EV_READ) - { - tmp |= PURPLE_INPUT_READ; - purple_cond = (PurpleInputCondition)tmp; - } - if (event & EV_WRITE) - { - tmp |= PURPLE_INPUT_WRITE; - purple_cond = (PurpleInputCondition)tmp; - } - if (event & EV_TIMEOUT) - { -// tmp |= PURPLE_INPUT_WRITE; -// purple_cond = (PurpleInputCondition)tmp; - if (closure->function2(closure->data)) - evtimer_add(&closure->evfifo, &closure->timeout); -// else -// event_io_destroy(data); - return; - } - - closure->function(closure->data, fd, purple_cond); -} - -static gboolean event_input_remove(guint handle) -{ - PurpleIOClosure *closure = (PurpleIOClosure *) g_hash_table_lookup(events, &handle); - if (closure) - event_io_destroy(closure); - return TRUE; -} - -static guint event_input_add(gint fd, - PurpleInputCondition condition, - PurpleInputFunction function, - gpointer data) -{ - PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = (GIOCondition)0; - closure->function = function; - closure->data = data; - - int tmp = EV_PERSIST; - if (condition & PURPLE_INPUT_READ) - { - tmp |= EV_READ; - } - if (condition & PURPLE_INPUT_WRITE) - { - tmp |= EV_WRITE; - } - - event_set(&closure->evfifo, fd, tmp, event_io_invoke, closure); - event_add(&closure->evfifo, NULL); - - int *f = (int *) g_malloc(sizeof(int)); - *f = id; - id++; - g_hash_table_replace(events, f, closure); - - return *f; -} - -static guint event_timeout_add (guint interval, GSourceFunc function, gpointer data) { - struct timeval timeout; - PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); - closure->function2 = function; - closure->data = data; - - timeout.tv_sec = interval/1000; - timeout.tv_usec = (interval%1000)*1000; - evtimer_set(&closure->evfifo, event_io_invoke, closure); - evtimer_add(&closure->evfifo, &timeout); - closure->timeout = timeout; - - guint *f = (guint *) g_malloc(sizeof(guint)); - *f = id; - id++; - g_hash_table_replace(events, f, closure); - return *f; -} - -static PurpleEventLoopUiOps libEventLoopOps = -{ - event_timeout_add, - event_input_remove, - event_input_add, - event_input_remove, - NULL, -// #if GLIB_CHECK_VERSION(2,14,0) -// g_timeout_add_seconds, -// #else - NULL, -// #endif - - NULL, - NULL, - NULL -}; - -#endif /* WITH_LIBEVENT*/ - -PurpleEventLoopUiOps * getEventLoopUiOps(void){ - return &eventLoopOps; -#ifdef WITH_LIBEVENT - events = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); - return &libEventLoopOps; -#endif -} diff --git a/backends/skype/geventloop.h b/backends/skype/geventloop.h deleted file mode 100644 index 3febd65e..00000000 --- a/backends/skype/geventloop.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _HI_EVENTLOOP_H -#define _HI_EVENTLOOP_H - -#include -#include "purple.h" -#include "eventloop.h" - -#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) - -PurpleEventLoopUiOps * getEventLoopUiOps(void); - -#endif diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 5a135410..17f10bd9 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -12,9 +12,7 @@ #include "transport/rostermanager.h" #include "transport/conversation.h" #include "transport/networkplugin.h" -#include "spectrumeventloop.h" #include -#include "geventloop.h" #include "log4cxx/logger.h" #include "log4cxx/consoleappender.h" #include "log4cxx/patternlayout.h" @@ -773,7 +771,7 @@ int main(int argc, char **argv) { GIOChannel *channel; - GIOCondition cond = (GIOCondition) READ_COND; + GIOCondition cond = (GIOCondition) G_IO_IN; channel = g_io_channel_unix_new(m_sock); g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy); diff --git a/backends/skype/spectrumeventloop.cpp b/backends/skype/spectrumeventloop.cpp deleted file mode 100644 index 20286e58..00000000 --- a/backends/skype/spectrumeventloop.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "spectrumeventloop.h" -#include "glib.h" - -#include - -#ifdef WITH_LIBEVENT -#include -#endif - - -using namespace Swift; - -// Fires the event's callback and frees the event -static gboolean processEvent(void *data) { - Event *ev = (Event *) data; - ev->callback(); - delete ev; - return FALSE; -} - -SpectrumEventLoop::SpectrumEventLoop() : m_isRunning(false) { - m_loop = NULL; - if (true) { - m_loop = g_main_loop_new(NULL, FALSE); - } -#ifdef WITH_LIBEVENT - else { - /*struct event_base *base = (struct event_base *)*/ - event_init(); - } -#endif -} - -SpectrumEventLoop::~SpectrumEventLoop() { - stop(); -} - -void SpectrumEventLoop::run() { - m_isRunning = true; - if (m_loop) { - g_main_loop_run(m_loop); - } -#ifdef WITH_LIBEVENT - else { - event_loop(0); - } -#endif -} - -void SpectrumEventLoop::stop() { - std::cout << "stopped loop\n"; - if (!m_isRunning) - return; - if (m_loop) { - g_main_loop_quit(m_loop); - g_main_loop_unref(m_loop); - m_loop = NULL; - } -#ifdef WITH_LIBEVENT - else { - event_loopexit(NULL); - } -#endif -} - -void SpectrumEventLoop::post(const Event& event) { - // pass copy of event to main thread - Event *ev = new Event(event.owner, event.callback); - g_timeout_add(0, processEvent, ev); -} diff --git a/backends/skype/spectrumeventloop.h b/backends/skype/spectrumeventloop.h deleted file mode 100644 index 7e811c89..00000000 --- a/backends/skype/spectrumeventloop.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program 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. - * - * This program 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 this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef SPECTRUM_EVENT_LOOP_H -#define SPECTRUM_EVENT_LOOP_H - -#include -#include "Swiften/EventLoop/EventLoop.h" -#include "glib.h" - -// Event loop implementation for Spectrum -class SpectrumEventLoop : public Swift::EventLoop { - public: - // Creates event loop according to CONFIG().eventloop settings. - SpectrumEventLoop(); - ~SpectrumEventLoop(); - - // Executes the eventloop. - void run(); - - // Stops tht eventloop. - void stop(); - - // Posts new Swift::Event to main thread. - virtual void post(const Swift::Event& event); - - private: - bool m_isRunning; - GMainLoop *m_loop; -}; - -#endif diff --git a/cmake_modules/dbusConfig.cmake b/cmake_modules/dbusConfig.cmake new file mode 100644 index 00000000..532e37da --- /dev/null +++ b/cmake_modules/dbusConfig.cmake @@ -0,0 +1,53 @@ +# - Try to find LIBDBUS GLIB Bindings +# Find LIBDBUSGLIB headers, libraries and the answer to all questions. +# +# LIBDBUSGLIB_FOUND True if libdbus-glib got found +# LIBDBUSGLIB_INCLUDE_DIRS Location of libdbus-glib headers +# LIBDBUSGLIB_LIBRARIES List of libraries to use libdbus-glib +# +# Copyright (c) 2008 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +INCLUDE( FindPkgConfig ) + +IF ( LibDbusGlib_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) +ELSE( LibDbusGlib_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) +ENDIF ( LibDbusGlib_FIND_REQUIRED ) + +IF ( LIBDBUSGLIB_MIN_VERSION ) + PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1>=${LIBDBUSGLIB_MIN_VERSION} ) +ELSE ( LIBDBUSGLIB_MIN_VERSION ) + PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1 ) +ENDIF ( LIBDBUSGLIB_MIN_VERSION ) + + +IF( NOT LIBDBUSGLIB_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( LIBDBUSGLIB_INCLUDE_DIRS dbus/dbus-glib.h PATH_SUFFIXES dbus-1.0 dbus ) + FIND_LIBRARY( LIBDBUSGLIB_LIBRARIES dbus-glib dbus-glib-1) + + # Report results + IF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS ) + SET( LIBDBUSGLIB_FOUND 1 ) + IF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" ) + ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + ELSE ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS ) + IF ( LIBDBUSGLIB_FIND_REQUIRED ) + MESSAGE( SEND_ERROR "Could NOT find libdbus-glib" ) + ELSE ( LIBDBUSGLIB_FIND_REQUIRED ) + IF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + MESSAGE( STATUS "Could NOT find libdbus-glib" ) + ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + ENDIF ( LIBDBUSGLIB_FIND_REQUIRED ) + ENDIF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS ) +else() + MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" ) +ENDIF() + +MARK_AS_ADVANCED( LIBDBUSGLIB_LIBRARIES LIBDBUSGLIB_INCLUDE_DIRS ) \ No newline at end of file From 6dd874964a6100d070a090fc6f8f96c4ef78f0a9 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 11:13:13 +0100 Subject: [PATCH 31/74] Do not build skype if it's not found --- backends/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 2bb2c447..543b60b8 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -11,7 +11,9 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) - ADD_SUBDIRECTORY(skype) + if (${LIBDBUSGLIB_FOUND}) + ADD_SUBDIRECTORY(skype) + endif() endif() endif() From a9341e05497c195e3918200b330c93ce6422407c Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 16 Feb 2012 23:16:13 +0100 Subject: [PATCH 32/74] Log --- src/networkpluginserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index feade943..7a876383 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -257,6 +257,7 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U #endif exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str()); + LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); } NetworkPluginServer::~NetworkPluginServer() { From 5c015b5547db9403cfa4b6174b84d012e6d96466 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 09:43:10 +0100 Subject: [PATCH 33/74] Load SSL related issues --- .../TLS/OpenSSL/OpenSSLServerContext.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp b/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp index ecc60733..ebf798be 100644 --- a/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp +++ b/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp @@ -14,6 +14,13 @@ #include #include +#include "log4cxx/logger.h" +#include "log4cxx/consoleappender.h" +#include "log4cxx/patternlayout.h" +#include "log4cxx/propertyconfigurator.h" +using namespace log4cxx; +static LoggerPtr logger = Logger::getLogger("OpenSSLServerContext"); + #include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h" #include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h" @@ -179,7 +186,7 @@ void OpenSSLServerContext::sendPendingDataToApplication() { bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certificate) { if (certificate.isNull()) { -// std::cout << "error 1\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate can't be loaded."); return false; } @@ -189,7 +196,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi boost::shared_ptr pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free); BIO_free(bio); if (!pkcs12) { -// std::cout << "error 2\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format."); return false; } @@ -199,7 +206,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi STACK_OF(X509)* caCertsPtr = 0; int result = PKCS12_parse(pkcs12.get(), reinterpret_cast(vecptr(certificate.getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr); if (result != 1) { -// std::cout << "error 3\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format."); return false; } boost::shared_ptr cert(certPtr, X509_free); @@ -208,11 +215,11 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi // Use the key & certificates if (SSL_CTX_use_certificate(context_, cert.get()) != 1) { -// std::cout << "error 4\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this certificate"); return false; } if (SSL_CTX_use_PrivateKey(context_, privateKey.get()) != 1) { -// std::cout << "error 5\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this private key"); return false; } return true; From 263f0b11d85144e76975823026443eafe4d9649b Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 09:59:38 +0100 Subject: [PATCH 34/74] Call setsid always when spawning backend --- spectrum/src/sample2.cfg | 2 +- src/networkpluginserver.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 508395e9..981124b9 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -41,7 +41,7 @@ users_per_backend=10 backend=/usr/bin/spectrum2_libpurple_backend #backend=/usr/bin/spectrum2_libircclient-qt_backend # For skype: -#backend=/usr/bin/setsid /usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend +#backend=/usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend # Libpurple protocol-id for spectrum_libpurple_backend protocol=prpl-jabber diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 7a876383..756cff77 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -157,6 +157,7 @@ static unsigned long exec_(std::string path, const char *host, const char *port, // fork and exec pid_t pid = fork(); if ( pid == 0 ) { + setsid(); // child process exit(execv(argv[0], argv)); } else if ( pid < 0 ) { From b6811cfe5a8e96061da43a10a39939d0ba4c2897 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 10:38:44 +0100 Subject: [PATCH 35/74] read all data fetched by sqlite3 --- src/sqlite3backend.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index ea869275..c61ca628 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -236,6 +236,8 @@ bool SQLite3Backend::getUser(const std::string &barejid, UserInfo &user) { user.encoding = (const char *) sqlite3_column_text(m_getUser, 4); user.language = (const char *) sqlite3_column_text(m_getUser, 5); user.vip = sqlite3_column_int(m_getUser, 6) != 0; + while((ret = sqlite3_step(m_getUser)) == SQLITE_ROW) { + } return true; } @@ -390,6 +392,9 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { roster.push_back(b); } + while((ret = sqlite3_step(m_getBuddiesSettings)) == SQLITE_ROW) { + } + if (ret != SQLITE_DONE) { LOG4CXX_ERROR(logger, "getBuddies query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); return false; @@ -446,6 +451,10 @@ void SQLite3Backend::getUserSetting(long id, const std::string &variable, int &t type = GET_INT(m_getUserSetting); value = GET_STR(m_getUserSetting); } + + int ret; + while((ret = sqlite3_step(m_getUserSetting)) == SQLITE_ROW) { + } } void SQLite3Backend::updateUserSetting(long id, const std::string &variable, const std::string &value) { From eb3c5880337ca2576d093f1ee8858cda745dd45a Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 10:47:05 +0100 Subject: [PATCH 36/74] Comment out the registration stuff --- spectrum/src/sample2.cfg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 981124b9..3f755c00 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -101,14 +101,14 @@ type = none enable_public_registration=1 # Text to display upon user registration form -username_label=Jabber JID (e.g. user@server.tld): -instructions=Enter your remote jabber JID and password as well as your local username and password +#username_label=Jabber JID (e.g. user@server.tld): +#instructions=Enter your remote jabber JID and password as well as your local username and password # If True a local jabber account on is needed # for transport registration, the idea is to enable public registration # from other servers, but only for users, who have already local accounts -require_local_account=1 -local_username_label=Local username (without @server.tld): -local_account_server=localhost -local_account_server_timeout=10000 +#require_local_account=1 +#local_username_label=Local username (without @server.tld): +#local_account_server=localhost +#local_account_server_timeout=10000 From 56bb259d89e1e6d4e38ecad72d22c72475a66a93 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 10:57:32 +0100 Subject: [PATCH 37/74] ChangeLog update --- ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 36a65268..ae19ff21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,24 @@ Version 2.0.0-beta (X-X-X): General: + * Fixed potential MySQL/SQLite3 deadlocks. + * Fixed disconnecting in server-mode when client does not send unavailable + presence before disconnection. + * Fixed crash in server-mode when client send its custom jabber:iq:storage + payload. * Fixed registration from Pidgin. * Unsubscribe presence sent to some buddy doesn't disconnect the account. * Remote Roster requests are not sent to resources, but to bare JID. * Added automatic reconnection in case of non-fatal error. * Added more error messages. + Skype: + * Initial support for Skype added, read more on + http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_Skype_backend + + SMSTools3: + * Initial support for SMSTools3, read more on + http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_SMSTools3_backend + version 2.0.0 alpha (2011-12-06): General: * First Spectrum 2.0.0 alpha release, check more on From abf7412731ac5fbfd45a79f12e90ed3c197e5a49 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 11:26:46 +0100 Subject: [PATCH 38/74] Set proper default database --- src/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.cpp b/src/config.cpp index 91e5ed67..18434c24 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -92,7 +92,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.local_account_server", value()->default_value("localhost"), "The server on which the local accounts will be checked for validity") ("registration.local_account_server_timeout", value()->default_value(10000), "Timeout when checking local user on local_account_server (msecs)") ("database.type", value()->default_value("none"), "Database type.") - ("database.database", value()->default_value(""), "Database used to store data") + ("database.database", value()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data") ("database.server", value()->default_value("localhost"), "Database server.") ("database.user", value()->default_value(""), "Database user.") ("database.password", value()->default_value(""), "Database Password.") From 8d97bbe73ec0fd66a118159cbb64633e3f7cd06e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 11:33:00 +0100 Subject: [PATCH 39/74] Respect default value for database.database --- src/config.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/config.cpp b/src/config.cpp index 18434c24..7088889c 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -111,6 +111,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description bool found_working = false; bool found_pidfile = false; bool found_backend_port = false; + bool found_database = false; std::string jid = ""; BOOST_FOREACH(option &opt, parsed.options) { if (opt.string_key == "service.jid") { @@ -134,6 +135,9 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description else if (opt.string_key == "service.pidfile") { found_pidfile = true; } + else if (opt.string_key == "database.database") { + found_database = true; + } } if (!found_working) { @@ -152,6 +156,11 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description value.push_back(p); parsed.options.push_back(boost::program_options::basic_option("service.backend_port", value)); } + if (!found_database) { + std::vector value; + value.push_back("/var/lib/spectrum2/$jid/database.sql"); + parsed.options.push_back(boost::program_options::basic_option("database.database", value)); + } BOOST_FOREACH(option &opt, parsed.options) { if (opt.unregistered) { From f742dae4624834fb6de966e030ffb44569f2c2eb Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 11:50:33 +0100 Subject: [PATCH 40/74] wait 10s --- backends/skype/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 17f10bd9..095c41a9 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -366,7 +366,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { free(db); - sleep(2); + sleep(10); GError *error = NULL; DBusObjectPathVTable vtable; From 31de3415d2828623d695671dab8415665617ee5e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 14:01:01 +0100 Subject: [PATCH 41/74] Removed big sleep from skype --- backends/skype/main.cpp | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 095c41a9..4b21effe 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -107,6 +107,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { public: SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { this->config = config; + LOG4CXX_INFO(logger, "Starting the backend."); } ~SpectrumNetworkPlugin() { @@ -118,7 +119,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { std::string name = legacyName; name = name.substr(name.find(".") + 1); - LOG4CXX_INFO(logger, "Creating account with name '" << name); + LOG4CXX_INFO(logger, "Creating account with name '" << name << "'"); Skype *skype = new Skype(user, name, password); m_sessions[user] = skype; @@ -366,8 +367,6 @@ class SpectrumNetworkPlugin : public NetworkPlugin { free(db); - sleep(10); - GError *error = NULL; DBusObjectPathVTable vtable; @@ -376,6 +375,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (m_connection == NULL) { + LOG4CXX_INFO(logger, "Creating DBus connection."); m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (m_connection == NULL && error != NULL) { @@ -387,15 +387,29 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (m_proxy == NULL) { - m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, - "com.Skype.API", - "/com/Skype", - "com.Skype.API", - &error); - if (m_proxy == NULL && error != NULL) - { - LOG4CXX_INFO(logger, m_username << ":" << error->message); - g_error_free(error); + int counter = 0; + while (m_proxy == NULL) { + counter++; + sleep(1); + LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); + m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, + "com.Skype.API", + "/com/Skype", + "com.Skype.API", + &error); + if (m_proxy == NULL && error != NULL) + { + LOG4CXX_INFO(logger, m_username << ":" << error->message); + + if (counter == 15) { + np->handleDisconnected(m_user, 0, error->message); + close(fd_output); + logout(); + g_error_free(error); + break; + } + g_error_free(error); + } } vtable.message_function = &skype_notify_handler; @@ -466,7 +480,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (buddy[0] == ',') { buddy.erase(buddy.begin()); } - std::cout << "BUDDY '" << buddy << "'\n"; + LOG4CXX_INFO(logger, "Got buddy " << buddy); std::string st = full_friends_list[i + 5]; pbnetwork::StatusType status = getStatus(st); From 1b8fef4d70b58dfc4f0df21b600d77e21dae43f1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:09:35 +0100 Subject: [PATCH 42/74] Skype backend is now non-blocking --- backends/skype/main.cpp | 494 +++++++++++++++++++++------------------- 1 file changed, 266 insertions(+), 228 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 4b21effe..a09b0b80 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -94,6 +94,9 @@ class Skype { return m_username; } + bool createDBusProxy(); + bool loadSkypeBuddies(); + private: std::string m_username; std::string m_password; @@ -101,6 +104,9 @@ class Skype { DBusGConnection *m_connection; DBusGProxy *m_proxy; std::string m_user; + int m_timer; + int m_counter; + int fd_output; }; class SpectrumNetworkPlugin : public NetworkPlugin { @@ -296,250 +302,277 @@ class SpectrumNetworkPlugin : public NetworkPlugin { }; - Skype::Skype(const std::string &user, const std::string &username, const std::string &password) { - m_username = username; - m_user = user; - m_password = password; - m_pid = 0; - m_connection = 0; - m_proxy = 0; - } - void Skype::login() { - boost::filesystem::path path(std::string("/tmp/skype/") + m_username); - if (!boost::filesystem::exists(path)) { - boost::filesystem::create_directories(path); - boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username ); - boost::filesystem::create_directories(path2); - } +Skype::Skype(const std::string &user, const std::string &username, const std::string &password) { + m_username = username; + m_user = user; + m_password = password; + m_pid = 0; + m_connection = 0; + m_proxy = 0; + m_timer = -1; + m_counter = 0; +} - std::string shared_xml = "\n" - "(time(NULL)) + ".0\">\n" - "\n" - "2\n" - "en\n" - "\n" - "\n"; - g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL); - std::string config_xml = "\n" - "(time(NULL)) + ".0\">\n" - "\n" - "\n" - "30000000\n" - "300000000\n" - "" + boost::lexical_cast(time(NULL)) + "\n" - "\n" - "\n" - "\n" - "\n" - "Spectrum\n" - "\n" - "\n" - "\n" - "\n"; - g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL); - std::string db_path = std::string("/tmp/skype/") + m_username; - char *db = (char *) malloc(db_path.size() + 1); - strcpy(db, db_path.c_str()); - LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db); - gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0}; +static gboolean load_skype_buddies(gpointer data) { + Skype *skype = (Skype *) data; + return skype->loadSkypeBuddies(); +} - int fd; - int fd_output; - g_spawn_async_with_pipes(NULL, - argv, - NULL /*envp*/, - G_SPAWN_SEARCH_PATH, - NULL /*child_setup*/, - NULL /*user_data*/, - &m_pid /*child_pid*/, - &fd, - NULL, - &fd_output, - NULL /*error*/); - std::string login_data = std::string(m_username + " " + m_password + "\n"); - LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data); - write(fd, login_data.c_str(), login_data.size()); - close(fd); - - fcntl (fd_output, F_SETFL, O_NONBLOCK); +bool Skype::createDBusProxy() { + if (m_proxy == NULL) { + LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); + m_counter++; - free(db); + GError *error = NULL; + m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, "com.Skype.API", "/com/Skype", "com.Skype.API", &error); + if (m_proxy == NULL && error != NULL) { + LOG4CXX_INFO(logger, m_username << ":" << error->message); - GError *error = NULL; - DBusObjectPathVTable vtable; - - //Initialise threading - dbus_threads_init_default(); - - if (m_connection == NULL) - { - LOG4CXX_INFO(logger, "Creating DBus connection."); - m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (m_connection == NULL && error != NULL) - { - LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); - g_error_free(error); - return; - } - } - - if (m_proxy == NULL) - { - int counter = 0; - while (m_proxy == NULL) { - counter++; - sleep(1); - LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); - m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, - "com.Skype.API", - "/com/Skype", - "com.Skype.API", - &error); - if (m_proxy == NULL && error != NULL) - { - LOG4CXX_INFO(logger, m_username << ":" << error->message); - - if (counter == 15) { - np->handleDisconnected(m_user, 0, error->message); - close(fd_output); - logout(); - g_error_free(error); - break; - } - g_error_free(error); - } - } - - vtable.message_function = &skype_notify_handler; - dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this); - } - - int counter = 0; - std::string re = "CONNSTATUS OFFLINE"; - while (re == "CONNSTATUS OFFLINE" || re.empty()) { - sleep(1); - gchar buffer[1024]; - int bytes_read; - bytes_read = read (fd_output, buffer, 1023); - if (bytes_read > 0) { - buffer[bytes_read] = 0; - np->handleDisconnected(m_user, 0, buffer); - close(fd_output); - logout(); - return; - } - re = send_command("NAME Spectrum"); - if (counter++ > 15) - break; - } - - close(fd_output); - - if (send_command("PROTOCOL 7") != "PROTOCOL 7") { - np->handleDisconnected(m_user, 0, "Skype is not ready"); + if (m_counter == 15) { + np->handleDisconnected(m_user, 0, error->message); logout(); - return; + g_error_free(error); + return FALSE; } - - np->handleConnected(m_user); - - std::map group_map; - std::string groups = send_command("SEARCH GROUPS CUSTOM"); - groups = groups.substr(groups.find(' ') + 1); - std::vector grps; - boost::split(grps, groups, boost::is_any_of(",")); - BOOST_FOREACH(std::string grp, grps) { - std::vector data; - std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME"); - boost::split(data, name, boost::is_any_of(" ")); - name = name.substr(name.find("DISPLAYNAME") + 12); - - std::string users = send_command("GET GROUP " + data[1] + " USERS"); - users = name.substr(name.find("USERS") + 6); - boost::split(data, users, boost::is_any_of(",")); - BOOST_FOREACH(std::string u, data) { - group_map[u] = grp; - } - } - - std::string friends = send_command("GET AUTH_CONTACTS_PROFILES"); - - char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0); - if (full_friends_list && full_friends_list[0]) - { - //in the format of: username;full name;phone;office phone;mobile phone; - // online status;friendly name;voicemail;mood - // (comma-seperated lines, usernames can have comma's) - - for (int i=0; full_friends_list[i] && *full_friends_list[i] != '\0'; i+=8) - { - std::string buddy = full_friends_list[i]; - - if (buddy[0] == ',') { - buddy.erase(buddy.begin()); - } - LOG4CXX_INFO(logger, "Got buddy " << buddy); - std::string st = full_friends_list[i + 5]; - - pbnetwork::StatusType status = getStatus(st); - - std::string alias = full_friends_list[i + 6]; - - std::string mood_text = ""; - if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { - mood_text = full_friends_list[i + 8]; - i++; - } - - std::vector groups; - groups.push_back(group_map[buddy]); - np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); - } - } - g_strfreev(full_friends_list); - - send_command("SET AUTOAWAY OFF"); + g_error_free(error); } - void Skype::logout() { - if (m_pid != 0) { - send_command("SET USERSTATUS INVISIBLE"); - send_command("SET USERSTATUS OFFLINE"); - sleep(2); - g_object_unref(m_proxy); - LOG4CXX_INFO(logger, m_username << ": Killing Skype instance"); - kill((int) m_pid, SIGTERM); - m_pid = 0; - } - } + if (m_proxy) { + LOG4CXX_INFO(logger, "Proxy created."); + DBusObjectPathVTable vtable; + vtable.message_function = &skype_notify_handler; + dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this); - std::string Skype::send_command(const std::string &message) { - GError *error = NULL; - gchar *str = NULL; + m_counter = 0; + m_timer = g_timeout_add_seconds(1, load_skype_buddies, this); + return FALSE; + } + return TRUE; + } + return FALSE; +} + +static gboolean create_dbus_proxy(gpointer data) { + Skype *skype = (Skype *) data; + return skype->createDBusProxy(); +} + +void Skype::login() { + boost::filesystem::path path(std::string("/tmp/skype/") + m_username); + if (!boost::filesystem::exists(path)) { + boost::filesystem::create_directories(path); + boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username ); + boost::filesystem::create_directories(path2); + } + + std::string shared_xml = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "2\n" + "en\n" + "\n" + "\n"; + g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL); + + std::string config_xml = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "\n" + "30000000\n" + "300000000\n" + "" + boost::lexical_cast(time(NULL)) + "\n" + "\n" + "\n" + "\n" + "\n" + "Spectrum\n" + "\n" + "\n" + "\n" + "\n"; + g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL); + + std::string db_path = std::string("/tmp/skype/") + m_username; + char *db = (char *) malloc(db_path.size() + 1); + strcpy(db, db_path.c_str()); + LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db); + gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0}; + + int fd; + g_spawn_async_with_pipes(NULL, + argv, + NULL /*envp*/, + G_SPAWN_SEARCH_PATH, + NULL /*child_setup*/, + NULL /*user_data*/, + &m_pid /*child_pid*/, + &fd, + NULL, + &fd_output, + NULL /*error*/); + std::string login_data = std::string(m_username + " " + m_password + "\n"); + LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data); + write(fd, login_data.c_str(), login_data.size()); + close(fd); + + fcntl (fd_output, F_SETFL, O_NONBLOCK); + + free(db); + + //Initialise threading + dbus_threads_init_default(); + + if (m_connection == NULL) + { + LOG4CXX_INFO(logger, "Creating DBus connection."); + GError *error = NULL; + m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (m_connection == NULL && error != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + g_error_free(error); + return; + } + } + + m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this); +} + +bool Skype::loadSkypeBuddies() { +// std::string re = "CONNSTATUS OFFLINE"; +// while (re == "CONNSTATUS OFFLINE" || re.empty()) { +// sleep(1); + + gchar buffer[1024]; + int bytes_read = read(fd_output, buffer, 1023); + if (bytes_read > 0) { + buffer[bytes_read] = 0; + np->handleDisconnected(m_user, 0, buffer); + close(fd_output); + logout(); + return FALSE; + } + + std::string re = send_command("NAME Spectrum"); + if (m_counter++ > 15) { + np->handleDisconnected(m_user, 0, ""); + close(fd_output); + logout(); + return FALSE; + } + + if (re.empty() || re == "CONNSTATUS OFFLINE") { + return TRUE; + } + + close(fd_output); + + if (send_command("PROTOCOL 7") != "PROTOCOL 7") { + np->handleDisconnected(m_user, 0, "Skype is not ready"); + logout(); + return FALSE; + } + + np->handleConnected(m_user); + + std::map group_map; + std::string groups = send_command("SEARCH GROUPS CUSTOM"); + groups = groups.substr(groups.find(' ') + 1); + std::vector grps; + boost::split(grps, groups, boost::is_any_of(",")); + BOOST_FOREACH(std::string grp, grps) { + std::vector data; + std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME"); + boost::split(data, name, boost::is_any_of(" ")); + name = name.substr(name.find("DISPLAYNAME") + 12); + + std::string users = send_command("GET GROUP " + data[1] + " USERS"); + users = name.substr(name.find("USERS") + 6); + boost::split(data, users, boost::is_any_of(",")); + BOOST_FOREACH(std::string u, data) { + group_map[u] = grp; + } + } + + std::string friends = send_command("GET AUTH_CONTACTS_PROFILES"); + + char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0); + if (full_friends_list && full_friends_list[0]) + { + //in the format of: username;full name;phone;office phone;mobile phone; + // online status;friendly name;voicemail;mood + // (comma-seperated lines, usernames can have comma's) + + for (int i=0; full_friends_list[i] && *full_friends_list[i] != '\0'; i+=8) + { + std::string buddy = full_friends_list[i]; + + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + LOG4CXX_INFO(logger, "Got buddy " << buddy); + std::string st = full_friends_list[i + 5]; + + pbnetwork::StatusType status = getStatus(st); + + std::string alias = full_friends_list[i + 6]; + + std::string mood_text = ""; + if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { + mood_text = full_friends_list[i + 8]; + i++; + } + + std::vector groups; + groups.push_back(group_map[buddy]); + np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); + } + } + g_strfreev(full_friends_list); + + send_command("SET AUTOAWAY OFF"); + return FALSE; +} + +void Skype::logout() { + if (m_pid != 0) { + send_command("SET USERSTATUS INVISIBLE"); + send_command("SET USERSTATUS OFFLINE"); + sleep(2); + g_object_unref(m_proxy); + LOG4CXX_INFO(logger, m_username << ": Killing Skype instance"); + kill((int) m_pid, SIGTERM); + m_pid = 0; + } +} + +std::string Skype::send_command(const std::string &message) { + GError *error = NULL; + gchar *str = NULL; // int message_num; // gchar error_return[30]; - - if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID, - G_TYPE_STRING, &str, G_TYPE_INVALID)) + + if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID, + G_TYPE_STRING, &str, G_TYPE_INVALID)) + { + if (error && error->message) { - if (error && error->message) - { - LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); - g_error_free(error); - } else { - LOG4CXX_INFO(logger, m_username << ": DBUS no response"); - } - - } - if (str != NULL) - { - LOG4CXX_INFO(logger, m_username << ": DBUS:" << str); - } - return str ? std::string(str) : std::string(); + LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + g_error_free(error); + } else { + LOG4CXX_INFO(logger, m_username << ": DBUS no response"); } + } + if (str != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS:" << str); + } + return str ? std::string(str) : std::string(); +} + static void handle_skype_message(std::string &message, Skype *sk) { std::vector cmd; boost::split(cmd, message, boost::is_any_of(" ")); @@ -696,6 +729,10 @@ static void io_destroy(gpointer data) { exit(1); } +static void log_glib_error(const gchar *string) { + LOG4CXX_ERROR(logger, "GLIB ERROR:" << string); +} + int main(int argc, char **argv) { GError *error = NULL; GOptionContext *context; @@ -783,6 +820,7 @@ int main(int argc, char **argv) { m_sock = create_socket(host, port); + g_set_printerr_handler(log_glib_error); GIOChannel *channel; GIOCondition cond = (GIOCondition) G_IO_IN; From f681cbeba6afc79a53be8b2a8671a1b83c454969 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:31:53 +0100 Subject: [PATCH 43/74] Fixed skype buddy list parsing --- backends/skype/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index a09b0b80..c36b46b8 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -522,7 +522,6 @@ bool Skype::loadSkypeBuddies() { std::string mood_text = ""; if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { mood_text = full_friends_list[i + 8]; - i++; } std::vector groups; From fd081a77e7b71b0430f2a0cb7f13ef38d0830b36 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:35:39 +0100 Subject: [PATCH 44/74] Fixed skype buddy list parsing --- backends/skype/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index c36b46b8..699a79d2 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -509,6 +509,7 @@ bool Skype::loadSkypeBuddies() { { std::string buddy = full_friends_list[i]; + buddy = buddy.substr(buddy.rfind(",")); if (buddy[0] == ',') { buddy.erase(buddy.begin()); } From 31a19c5f3fb5a541fdd6b55273e45f821c07c94b Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:38:45 +0100 Subject: [PATCH 45/74] Fixed skype buddy list parsing --- backends/skype/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 699a79d2..42da9f7b 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -509,10 +509,14 @@ bool Skype::loadSkypeBuddies() { { std::string buddy = full_friends_list[i]; - buddy = buddy.substr(buddy.rfind(",")); if (buddy[0] == ',') { buddy.erase(buddy.begin()); } + + if (buddy.rfind(",") != std::string::npos) { + buddy = buddy.substr(buddy.rfind(",")); + } + LOG4CXX_INFO(logger, "Got buddy " << buddy); std::string st = full_friends_list[i + 5]; From d6353232aefdc98f302465d4001f1742e2308043 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:47:42 +0100 Subject: [PATCH 46/74] Fixed skype buddy list parsing --- backends/skype/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 42da9f7b..16614b39 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -517,6 +517,10 @@ bool Skype::loadSkypeBuddies() { buddy = buddy.substr(buddy.rfind(",")); } + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + LOG4CXX_INFO(logger, "Got buddy " << buddy); std::string st = full_friends_list[i + 5]; From cc9d7c7950582b2bf11c4df396bfbf0c97a5463e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:57:40 +0100 Subject: [PATCH 47/74] Forward initial presence to skype --- backends/skype/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 16614b39..d5f6e9d9 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -541,6 +541,7 @@ bool Skype::loadSkypeBuddies() { g_strfreev(full_friends_list); send_command("SET AUTOAWAY OFF"); + send_command("SET USERSTATUS ONLINE"); return FALSE; } From 18ba1b7ac49199ea393f4e8af93d7141ed049e3d Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 16:40:49 +0100 Subject: [PATCH 48/74] Do not send buddies in empty group --- backends/skype/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index d5f6e9d9..c82792ce 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -534,7 +534,9 @@ bool Skype::loadSkypeBuddies() { } std::vector groups; - groups.push_back(group_map[buddy]); + if (group_map.find(buddy) != group_map.end()) { + groups.push_back(group_map[buddy]); + } np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); } } From acd1c0447f771a06c41e7676091890d14aae71d0 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 16:54:40 +0100 Subject: [PATCH 49/74] Send subscribe presences to bare jid --- src/rostermanager.cpp | 6 +++--- src/usermanager.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 23b19a7f..44264588 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -285,8 +285,8 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { // using roster pushes. if (m_component->inServerMode()) { Swift::Presence::ref response = Swift::Presence::create(); - response->setTo(presence->getFrom()); - response->setFrom(presence->getTo()); + response->setTo(presence->getFrom().toBare()); + response->setFrom(presence->getTo().toBare()); Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo())); if (buddy) { LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received and buddy " << Buddy::JIDToLegacyName(presence->getTo()) << " is already there => answering"); @@ -342,7 +342,7 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { Swift::Presence::ref response = Swift::Presence::create(); Swift::Presence::ref currentPresence; response->setTo(presence->getFrom().toBare()); - response->setFrom(presence->getTo().toBare().toString() + "/bot"); + response->setFrom(presence->getTo().toBare()); Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo())); if (buddy) { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index ccb036f4..08823715 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -306,8 +306,8 @@ void UserManager::handleSubscription(Swift::Presence::ref presence) { // answer to subscibe for transport itself if (presence->getType() == Swift::Presence::Subscribe && presence->getTo().getNode().empty()) { Swift::Presence::ref response = Swift::Presence::create(); - response->setFrom(presence->getTo()); - response->setTo(presence->getFrom()); + response->setFrom(presence->getTo().toBare()); + response->setTo(presence->getFrom().toBare()); response->setType(Swift::Presence::Subscribed); m_component->getStanzaChannel()->sendPresence(response); From 04115c5d99f19b4d9ccf9d2e974a61caf30a4ff4 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 17:41:06 +0100 Subject: [PATCH 50/74] changelog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index ae19ff21..942fdfe4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ Version 2.0.0-beta (X-X-X): General: + * Send presences only "from" bare JID (fixed bug with buddies appearing + twice in the roster and potential unregistering issues). * Fixed potential MySQL/SQLite3 deadlocks. * Fixed disconnecting in server-mode when client does not send unavailable presence before disconnection. From 67d6458a411393969bb105ec03d20bb83161aad4 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Thu, 26 Jan 2012 12:36:15 +0800 Subject: [PATCH 51/74] Downgraded PQXX API used due to the 2.6 series on most modern linux distros. Implemented most of the other functions. --- include/transport/pqxxbackend.h | 3 + src/pqxxbackend.cpp | 109 ++++++++++++++++---------------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index e13c6b03..f02d86fc 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -98,6 +98,9 @@ class PQXXBackend : public StorageBackend private: bool exec(const std::string &query, bool show_error = true); bool exec(pqxx::work &txn, const std::string &query, bool show_error = true); + template + std::string quote(pqxx::work &txn, const T &t); + Config *m_config; std::string m_prefix; diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index af0efd36..36953090 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -124,6 +124,11 @@ bool PQXXBackend::createDatabase() { return true; } +template +std::string PQXXBackend::quote(pqxx::work &txn, const T &t) { + return "'" + txn.esc(pqxx::to_string(t)) + "'"; +} + bool PQXXBackend::exec(const std::string &query, bool show_error) { pqxx::work txn(*m_conn); return exec(txn, query, show_error); @@ -148,15 +153,14 @@ void PQXXBackend::setUser(const UserInfo &user) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } pqxx::work txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users SET uin=" + txn.quote(user.uin) + ", password=" + txn.quote(encrypted) + ";" - "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " - "(" + txn.quote(user.jid) + "," - + txn.quote(user.uin) + "," - + txn.quote(encrypted) + "," - + txn.quote(user.language) + "," - + txn.quote(user.encoding) + "," + exec(txn, "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + "(" + quote(txn, user.jid) + "," + + quote(txn, user.uin) + "," + + quote(txn, encrypted) + "," + + quote(txn, user.language) + "," + + quote(txn, user.encoding) + "," + "NOW()," - + txn.quote(user.vip) +")"); + + (user.vip ? "'true'" : "'false'") +")"); } bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { @@ -164,7 +168,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { pqxx::work txn(*m_conn); pqxx::result r = txn.exec("SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=" - + txn.quote(barejid)); + + quote(txn, barejid)); if (r.size() == 0) { return false; @@ -189,7 +193,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { void PQXXBackend::setUserOnline(long id, bool online) { try { pqxx::work txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users SET online=" + txn.quote(online) + ", last_login=NOW() WHERE id=" + txn.quote(id)); + exec(txn, "UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -234,13 +238,13 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { -// "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?" -// std::string groups = Util::serializeGroups(buddyInfo.groups); -// *m_updateBuddy << groups; -// *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; -// *m_updateBuddy << userId << buddyInfo.legacyName; - -// EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo)); + try { + pqxx::work txn(*m_conn); + exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + quote(txn, buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } bool PQXXBackend::getBuddies(long id, std::list &roster) { @@ -317,55 +321,54 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { } bool PQXXBackend::removeUser(long id) { -// *m_removeUser << (int) id; -// EXEC(m_removeUser, removeUser(id)); -// if (!exec_ok) -// return false; + try { + pqxx::work txn(*m_conn); + exec(txn, "DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); + exec(txn, "DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); + exec(txn, "DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); + exec(txn, "DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); -// *m_removeUserSettings << (int) id; -// EXEC(m_removeUserSettings, removeUser(id)); -// if (!exec_ok) -// return false; - -// *m_removeUserBuddies << (int) id; -// EXEC(m_removeUserBuddies, removeUser(id)); -// if (!exec_ok) -// return false; - -// *m_removeUserBuddiesSettings << (int) id; -// EXEC(m_removeUserBuddiesSettings, removeUser(id)); -// if (!exec_ok) -// return false; - - return true; + return true; + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } + return false; } void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { -//// "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?" -// *m_getUserSetting << id << variable; -// EXEC(m_getUserSetting, getUserSetting(id, variable, type, value)); -// if (m_getUserSetting->fetch() != 0) { -//// "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)" -// *m_setUserSetting << id << variable << type << value; -// EXEC(m_setUserSetting, getUserSetting(id, variable, type, value)); -// } -// else { -// *m_getUserSetting >> type >> value; -// } + try { + pqxx::work txn(*m_conn); + + pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); + if (r.size() == 0) { + exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); + } + else { + type = r[0][0].as(); + value = r[0][0].as(); + } + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { -//// "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?" -// *m_updateUserSetting << value << id << variable; -// EXEC(m_updateUserSetting, updateUserSetting(id, variable, value)); + try { + pqxx::work txn(*m_conn); + exec(txn, "UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } void PQXXBackend::beginTransaction() { -// exec("START TRANSACTION;"); + exec("START TRANSACTION;"); } void PQXXBackend::commitTransaction() { -// exec("COMMIT;"); + exec("COMMIT;"); } } From faeb4bd8ef6b293ddaa565165cbfa3a359698432 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Sat, 28 Jan 2012 00:57:13 +0800 Subject: [PATCH 52/74] One more function to go after this. At some future date I'd like to consider if the API provides some better mechanisms, but this'll do for now. --- src/pqxxbackend.cpp | 114 ++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 61 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 36953090..1194b2ef 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -248,76 +248,67 @@ void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { } bool PQXXBackend::getBuddies(long id, std::list &roster) { -// SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC -// *m_getBuddies << id; + try { + pqxx::work txn(*m_conn); -// "SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC" -// *m_getBuddiesSettings << id; + pqxx::result r = txn.exec("SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=" + pqxx::to_string(id) + " ORDER BY id ASC"); + for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { + BuddyInfo b; + std::string group; -// SettingVariableInfo var; -// long buddy_id = -1; -// std::string key; + b.id = r[0][0].as(); + b.legacyName = r[0][1].as(); + b.subscription = r[0][2].as(); + b.alias = r[0][3].as(); + group = r[0][4].as(); + b.flags = r[0][5].as(); -// EXEC(m_getBuddies, getBuddies(id, roster)); -// if (!exec_ok) -// return false; + if (!group.empty()) { + b.groups = Util::deserializeGroups(group); + } -// while (m_getBuddies->fetch() == 0) { -// BuddyInfo b; + roster.push_back(b); + } -// std::string group; -// *m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags; -// if (!group.empty()) { -// b.groups = Util::deserializeGroups(group); -// } + r = txn.exec("SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=" + pqxx::to_string(id) + " ORDER BY buddy_id ASC"); + for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { + SettingVariableInfo var; + long buddy_id = -1; + std::string key; + std::string val; -// roster.push_back(b); -// } + buddy_id = r[0][0].as(); + var.type = r[0][1].as(); + key = r[0][2].as(); + val = r[0][3].as(); + switch (var.type) { + case TYPE_BOOLEAN: + var.b = atoi(val.c_str()); + break; + case TYPE_STRING: + var.s = val; + break; + default: + continue; + break; + } -// EXEC(m_getBuddiesSettings, getBuddies(id, roster)); -// if (!exec_ok) -// return false; + BOOST_FOREACH(BuddyInfo &b, roster) { + if (buddy_id == b.id) { + b.settings[key] = var; + break; + } + } + } -// BOOST_FOREACH(BuddyInfo &b, roster) { -// if (buddy_id == b.id) { -//// std::cout << "Adding buddy info setting " << key << "\n"; -// b.settings[key] = var; -// buddy_id = -1; -// } + return true; + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } -// while(buddy_id == -1 && m_getBuddiesSettings->fetch() == 0) { -// std::string val; -// *m_getBuddiesSettings >> buddy_id >> var.type >> key >> val; - -// switch (var.type) { -// case TYPE_BOOLEAN: -// var.b = atoi(val.c_str()); -// break; -// case TYPE_STRING: -// var.s = val; -// break; -// default: -// if (buddy_id == b.id) { -// buddy_id = -1; -// } -// continue; -// break; -// } -// if (buddy_id == b.id) { -//// std::cout << "Adding buddy info setting " << key << "=" << val << "\n"; -// b.settings[key] = var; -// buddy_id = -1; -// } -// } -// } - -// while(m_getBuddiesSettings->fetch() == 0) { -// // TODO: probably remove those settings, because there's no buddy for them. -// // It should not happend, but one never know... -// } - - return true; + return false; } bool PQXXBackend::removeUser(long id) { @@ -329,6 +320,7 @@ bool PQXXBackend::removeUser(long id) { exec(txn, "DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); return true; + } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); } @@ -345,7 +337,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type } else { type = r[0][0].as(); - value = r[0][0].as(); + value = r[0][1].as(); } } catch (std::exception& e) { From 352a15b226ac1f10258212484fbd5ca6c289e503 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Sat, 28 Jan 2012 05:05:18 +0800 Subject: [PATCH 53/74] Finished last postgres function. --- src/pqxxbackend.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 1194b2ef..ae6ddc9d 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -118,7 +118,7 @@ bool PQXXBackend::createDatabase() { "UNIQUE (ver)" ");"); -// exec("INSERT INTO db_version (ver) VALUES ('2');"); + exec("INSERT INTO db_version (ver) VALUES ('1');"); } return true; @@ -218,29 +218,34 @@ bool PQXXBackend::getOnlineUsers(std::vector &users) { } long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { -// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)" -// std::string groups = Util::serializeGroups(buddyInfo.groups); -// *m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription; -// *m_addBuddy << groups; -// *m_addBuddy << buddyInfo.alias << buddyInfo.flags; + pqxx::work txn(*m_conn); + pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " + + "(" + pqxx::to_string(userId) + "," + + quote(txn, buddyInfo.legacyName) + "," + + quote(txn, buddyInfo.subscription) + "," + + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," + + quote(txn, buddyInfo.alias) + "," + + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); -// EXEC(m_addBuddy, addBuddy(userId, buddyInfo)); + long id = r[0][0].as(); -// long id = (long) mysql_insert_id(&m_conn); + r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string(TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); + if (r.affected_rows() == 0) { + exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + + "(" + pqxx::to_string(userId) + "," + + pqxx::to_string(id) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," + + pqxx::to_string(TYPE_STRING) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); + } -// INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) -// if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { -// *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; -// EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); -// } - - return 0; + return id; } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { pqxx::work txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + quote(txn, buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); From 017935ae158d823aea1dfea713db70820ed67725 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Wed, 15 Feb 2012 23:22:27 +0800 Subject: [PATCH 54/74] Casted TYPE_STRING properly. --- src/pqxxbackend.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index ae6ddc9d..d20bfc95 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -229,13 +229,13 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { long id = r[0][0].as(); - r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string(TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); + r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); if (r.affected_rows() == 0) { exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + "(" + pqxx::to_string(userId) + "," + pqxx::to_string(id) + "," + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," - + pqxx::to_string(TYPE_STRING) + "," + + pqxx::to_string((int)TYPE_STRING) + "," + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); } From 7f13a29090639a9a6d1f2f88924ddf9021b44ed6 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Thu, 16 Feb 2012 01:29:28 +0800 Subject: [PATCH 55/74] Removed auto-transaction postgres handlers in lieu of our own transaction calls. Updated config file to mention postgres. --- include/transport/pqxxbackend.h | 4 ++-- spectrum/src/sample2.cfg | 4 ++-- src/pqxxbackend.cpp | 34 +++++++++++++++++---------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index f02d86fc..f571433b 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -97,9 +97,9 @@ class PQXXBackend : public StorageBackend private: bool exec(const std::string &query, bool show_error = true); - bool exec(pqxx::work &txn, const std::string &query, bool show_error = true); + bool exec(pqxx::nontransaction &txn, const std::string &query, bool show_error = true); template - std::string quote(pqxx::work &txn, const T &t); + std::string quote(pqxx::nontransaction &txn, const T &t); Config *m_config; std::string m_prefix; diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 3f755c00..3181a6a1 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -73,11 +73,11 @@ backend_config = /etc/spectrum2/backend-logging.cfg [database] # Database backend type -# "sqlite3", "mysql" or "none" without database backend +# "sqlite3", "mysql", "pqxx", or "none" without database backend type = none # For SQLite3: Full path to database -# For MySQL: name of database +# For MySQL and PostgreSQL: name of database # default database = /var/lib/spectrum2/$jid/database.sql #database = jabber_transport diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index d20bfc95..c6136bd3 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -125,16 +125,16 @@ bool PQXXBackend::createDatabase() { } template -std::string PQXXBackend::quote(pqxx::work &txn, const T &t) { +std::string PQXXBackend::quote(pqxx::nontransaction &txn, const T &t) { return "'" + txn.esc(pqxx::to_string(t)) + "'"; } bool PQXXBackend::exec(const std::string &query, bool show_error) { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); return exec(txn, query, show_error); } -bool PQXXBackend::exec(pqxx::work &txn, const std::string &query, bool show_error) { +bool PQXXBackend::exec(pqxx::nontransaction &txn, const std::string &query, bool show_error) { try { txn.exec(query); txn.commit(); @@ -152,7 +152,7 @@ void PQXXBackend::setUser(const UserInfo &user) { if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " "(" + quote(txn, user.jid) + "," + quote(txn, user.uin) + "," @@ -165,7 +165,7 @@ void PQXXBackend::setUser(const UserInfo &user) { bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=" + quote(txn, barejid)); @@ -192,7 +192,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { void PQXXBackend::setUserOnline(long id, bool online) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); } catch (std::exception& e) { @@ -202,7 +202,7 @@ void PQXXBackend::setUserOnline(long id, bool online) { bool PQXXBackend::getOnlineUsers(std::vector &users) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online=1"); for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { @@ -218,7 +218,7 @@ bool PQXXBackend::getOnlineUsers(std::vector &users) { } long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " + "(" + pqxx::to_string(userId) + "," + quote(txn, buddyInfo.legacyName) + "," @@ -231,7 +231,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); if (r.affected_rows() == 0) { - exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + "(" + pqxx::to_string(userId) + "," + pqxx::to_string(id) + "," + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," @@ -239,12 +239,14 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); } + txn.commit(); + return id; } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { @@ -254,7 +256,7 @@ void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { bool PQXXBackend::getBuddies(long id, std::list &roster) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=" + pqxx::to_string(id) + " ORDER BY id ASC"); for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { @@ -318,7 +320,7 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { bool PQXXBackend::removeUser(long id) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); exec(txn, "DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); exec(txn, "DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); @@ -334,11 +336,11 @@ bool PQXXBackend::removeUser(long id) { void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); if (r.size() == 0) { - exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); + txn.exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); } else { type = r[0][0].as(); @@ -352,7 +354,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); } catch (std::exception& e) { @@ -361,7 +363,7 @@ void PQXXBackend::updateUserSetting(long id, const std::string &variable, const } void PQXXBackend::beginTransaction() { - exec("START TRANSACTION;"); + exec("BEGIN;"); } void PQXXBackend::commitTransaction() { From 3f2a5840a5eb702a1659c474b5ad432433cc2445 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Thu, 16 Feb 2012 07:12:09 +0800 Subject: [PATCH 56/74] Cleaned up code a bit, more to come. --- src/pqxxbackend.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index c6136bd3..90818d56 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -99,8 +99,8 @@ bool PQXXBackend::createDatabase() { "language varchar(25) NOT NULL," "encoding varchar(50) NOT NULL default 'utf8'," "last_login timestamp," - "vip boolean NOT NULL default '0'," - "online boolean NOT NULL default '0'," + "vip boolean NOT NULL default 'false'," + "online boolean NOT NULL default 'false'," "PRIMARY KEY (id)," "UNIQUE (jid)" ");"); @@ -153,8 +153,8 @@ void PQXXBackend::setUser(const UserInfo &user) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } pqxx::nontransaction txn(*m_conn); - exec(txn, "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " - "(" + quote(txn, user.jid) + "," + txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + + "(" + quote(txn, user.jid) + "," + quote(txn, user.uin) + "," + quote(txn, encrypted) + "," + quote(txn, user.language) + "," @@ -193,7 +193,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { void PQXXBackend::setUserOnline(long id, bool online) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); + txn.exec("UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -203,7 +203,7 @@ void PQXXBackend::setUserOnline(long id, bool online) { bool PQXXBackend::getOnlineUsers(std::vector &users) { try { pqxx::nontransaction txn(*m_conn); - pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online=1"); + pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online='true'"); for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { users.push_back((*it)[0].as()); @@ -247,7 +247,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -321,10 +321,10 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { bool PQXXBackend::removeUser(long id) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); - exec(txn, "DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); - exec(txn, "DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); - exec(txn, "DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); return true; } @@ -340,7 +340,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); if (r.size() == 0) { - txn.exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); + txn.exec("INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string((int)type) + "," + quote(txn, value) + ")"); } else { type = r[0][0].as(); @@ -355,7 +355,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); + txn.exec("UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); From 9cf00ddc59a0d16bb9f00881e56da990fad4d2d7 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Sat, 18 Feb 2012 02:49:57 +0800 Subject: [PATCH 57/74] Cleaned up code a bit, primarily adding more exception catching in proper locations. --- src/pqxxbackend.cpp | 80 +++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 90818d56..c2ae4580 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -57,7 +57,14 @@ bool PQXXBackend::connect() { str += CONFIG_STRING(m_config, "database.database") + " "; str += "user=" + CONFIG_STRING(m_config, "database.user") + " "; - m_conn = new pqxx::connection(str); + + try { + m_conn = new pqxx::connection(str); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + return false; + } createDatabase(); @@ -152,15 +159,20 @@ void PQXXBackend::setUser(const UserInfo &user) { if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } - pqxx::nontransaction txn(*m_conn); - txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " - + "(" + quote(txn, user.jid) + "," - + quote(txn, user.uin) + "," - + quote(txn, encrypted) + "," - + quote(txn, user.language) + "," - + quote(txn, user.encoding) + "," - + "NOW()," - + (user.vip ? "'true'" : "'false'") +")"); + try { + pqxx::nontransaction txn(*m_conn); + txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + + "(" + quote(txn, user.jid) + "," + + quote(txn, user.uin) + "," + + quote(txn, encrypted) + "," + + quote(txn, user.language) + "," + + quote(txn, user.encoding) + "," + + "NOW()," + + (user.vip ? "'true'" : "'false'") +")"); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { @@ -218,30 +230,34 @@ bool PQXXBackend::getOnlineUsers(std::vector &users) { } long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { - pqxx::nontransaction txn(*m_conn); - pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " - + "(" + pqxx::to_string(userId) + "," - + quote(txn, buddyInfo.legacyName) + "," - + quote(txn, buddyInfo.subscription) + "," - + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," - + quote(txn, buddyInfo.alias) + "," - + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); - - long id = r[0][0].as(); - - r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); - if (r.affected_rows() == 0) { - txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + try { + pqxx::nontransaction txn(*m_conn); + pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " + "(" + pqxx::to_string(userId) + "," - + pqxx::to_string(id) + "," - + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," - + pqxx::to_string((int)TYPE_STRING) + "," - + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); + + quote(txn, buddyInfo.legacyName) + "," + + quote(txn, buddyInfo.subscription) + "," + + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," + + quote(txn, buddyInfo.alias) + "," + + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); + + long id = r[0][0].as(); + + r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); + if (r.affected_rows() == 0) { + txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + + "(" + pqxx::to_string(userId) + "," + + pqxx::to_string(id) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," + + pqxx::to_string((int)TYPE_STRING) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); + } + + return id; + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + return -1; } - - txn.commit(); - - return id; } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { From 6e4eb0ed6f15c24188d9dc606e3d5e359d160175 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 19 Feb 2012 10:13:51 +0100 Subject: [PATCH 58/74] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 942fdfe4..97aaa33c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ Version 2.0.0-beta (X-X-X): General: + * Added PostreSQL support (thanks to Jadestorm). * Send presences only "from" bare JID (fixed bug with buddies appearing twice in the roster and potential unregistering issues). * Fixed potential MySQL/SQLite3 deadlocks. From 342df599be765f0b16c8dd98e80e1e338d939dd3 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 19 Feb 2012 15:35:18 +0100 Subject: [PATCH 59/74] link libtransport to libtransport-plugin to allow using these two libraries together --- src/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac077b20..dcb192c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,11 +20,11 @@ endif() if (PROTOBUF_FOUND) if (CMAKE_COMPILER_IS_GNUCXX) - ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc) + ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) else(CMAKE_COMPILER_IS_GNUCXX) - ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc) + ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC}) endif(CMAKE_COMPILER_IS_GNUCXX) - SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) +# SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) ADD_DEPENDENCIES(transport pb) else(PROTOBUF_FOUND) ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) @@ -35,9 +35,9 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif() if (WIN32) - TARGET_LINK_LIBRARIES(transport ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) + TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) else (WIN32) - TARGET_LINK_LIBRARIES(transport ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) + TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) endif(WIN32) SET_TARGET_PROPERTIES(transport PROPERTIES From e53e622e4d4ebc5c34cf2de49616f7f53bd32972 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 20 Feb 2012 10:39:25 +0100 Subject: [PATCH 60/74] Link only against transport --- backends/frotz/CMakeLists.txt | 2 +- backends/libcommuni/CMakeLists.txt | 2 +- backends/skype/CMakeLists.txt | 2 +- backends/smstools3/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/frotz/CMakeLists.txt b/backends/frotz/CMakeLists.txt index 7ce14f86..f9bc283a 100644 --- a/backends/frotz/CMakeLists.txt +++ b/backends/frotz/CMakeLists.txt @@ -6,7 +6,7 @@ FILE(GLOB SRC *.c *.cpp) ADD_EXECUTABLE(spectrum2_frotz_backend ${SRC}) -target_link_libraries(spectrum2_frotz_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) INSTALL(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION bin) diff --git a/backends/libcommuni/CMakeLists.txt b/backends/libcommuni/CMakeLists.txt index a2a14730..38e7507b 100644 --- a/backends/libcommuni/CMakeLists.txt +++ b/backends/libcommuni/CMakeLists.txt @@ -4,7 +4,7 @@ FILE(GLOB HEADERS *.h) QT4_WRAP_CPP(SRC ${HEADERS}) ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC}) -target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport-plugin transport pthread) +target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread) INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin) diff --git a/backends/skype/CMakeLists.txt b/backends/skype/CMakeLists.txt index 4e611208..d27b4296 100644 --- a/backends/skype/CMakeLists.txt +++ b/backends/skype/CMakeLists.txt @@ -3,7 +3,7 @@ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) -target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES} transport-plugin) +target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES}) INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt index c410cee6..a557e243 100644 --- a/backends/smstools3/CMakeLists.txt +++ b/backends/smstools3/CMakeLists.txt @@ -4,7 +4,7 @@ FILE(GLOB SRC *.c *.cpp) ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC}) -target_link_libraries(spectrum2_smstools3_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin) From d0afb12646d78ccf22bd9115112f31bd54392802 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 20 Feb 2012 14:31:23 +0100 Subject: [PATCH 61/74] Fixed zombie process caused by bad waitpid call --- src/networkpluginserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 756cff77..a89117b6 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -175,7 +175,7 @@ static void SigCatcher(int n) { int status; // Read exit code from all children to not have zombies arround // WARNING: Do not put LOG4CXX_ here, because it can lead to deadlock - while ((result = waitpid(0, &status, WNOHANG)) > 0) { + while ((result = waitpid(-1, &status, WNOHANG)) > 0) { if (result != 0) { if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { From 6ca2c3a931e0d4092807eef425fa1264ef8dd7cc Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 22 Feb 2012 08:38:45 +0100 Subject: [PATCH 62/74] pubsub payloads/serializers --- include/Swiften/Elements/PubSubItem.cpp | 14 +++++ include/Swiften/Elements/PubSubItem.h | 35 +++++++++++ include/Swiften/Elements/PubSubPayload.cpp | 14 +++++ include/Swiften/Elements/PubSubPayload.h | 53 ++++++++++++++++ .../Swiften/Elements/PubSubPublishPayload.cpp | 16 +++++ .../Swiften/Elements/PubSubPublishPayload.h | 43 +++++++++++++ .../Elements/PubSubSubscribePayload.cpp | 16 +++++ .../Swiften/Elements/PubSubSubscribePayload.h | 40 +++++++++++++ .../Elements/PubSubSubscriptionPayload.cpp | 16 +++++ .../Elements/PubSubSubscriptionPayload.h | 60 +++++++++++++++++++ .../PubSubItemSerializer.cpp | 31 ++++++++++ .../PayloadSerializers/PubSubItemSerializer.h | 19 ++++++ .../PubSubPayloadSerializer.cpp | 36 +++++++++++ .../PubSubPayloadSerializer.h | 23 +++++++ .../PubSubPublishPayloadSerializer.cpp | 40 +++++++++++++ .../PubSubPublishPayloadSerializer.h | 23 +++++++ .../PubSubSubscribePayloadSerializer.cpp | 34 +++++++++++ .../PubSubSubscribePayloadSerializer.h | 19 ++++++ .../PubSubSubscriptionPayloadSerializer.cpp | 49 +++++++++++++++ .../PubSubSubscriptionPayloadSerializer.h | 19 ++++++ spectrum/src/sample.cfg | 16 ++--- 21 files changed, 608 insertions(+), 8 deletions(-) create mode 100644 include/Swiften/Elements/PubSubItem.cpp create mode 100644 include/Swiften/Elements/PubSubItem.h create mode 100644 include/Swiften/Elements/PubSubPayload.cpp create mode 100644 include/Swiften/Elements/PubSubPayload.h create mode 100644 include/Swiften/Elements/PubSubPublishPayload.cpp create mode 100644 include/Swiften/Elements/PubSubPublishPayload.h create mode 100644 include/Swiften/Elements/PubSubSubscribePayload.cpp create mode 100644 include/Swiften/Elements/PubSubSubscribePayload.h create mode 100644 include/Swiften/Elements/PubSubSubscriptionPayload.cpp create mode 100644 include/Swiften/Elements/PubSubSubscriptionPayload.h create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.cpp create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.cpp create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.cpp create mode 100644 include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h diff --git a/include/Swiften/Elements/PubSubItem.cpp b/include/Swiften/Elements/PubSubItem.cpp new file mode 100644 index 00000000..e146be9d --- /dev/null +++ b/include/Swiften/Elements/PubSubItem.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +namespace Swift { + +PubSubItem::PubSubItem(const std::string &body) : body_(body) { +} + +} diff --git a/include/Swiften/Elements/PubSubItem.h b/include/Swiften/Elements/PubSubItem.h new file mode 100644 index 00000000..554b7a76 --- /dev/null +++ b/include/Swiften/Elements/PubSubItem.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include + +namespace Swift { + class PubSubItem : public Payload { + public: + PubSubItem(const std::string &body = ""); + + const std::string& getData() const { return body_; } + + void setData(const std::string& body) { + body_ = body; + } + + const std::string& getId() const { return id; } + + void setId(const std::string& id) { + this->id = id; + } + + private: + std::string body_; + std::string id; + }; +} diff --git a/include/Swiften/Elements/PubSubPayload.cpp b/include/Swiften/Elements/PubSubPayload.cpp new file mode 100644 index 00000000..663e8eb7 --- /dev/null +++ b/include/Swiften/Elements/PubSubPayload.cpp @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +namespace Swift { + +PubSubPayload::PubSubPayload() { +} + +} diff --git a/include/Swiften/Elements/PubSubPayload.h b/include/Swiften/Elements/PubSubPayload.h new file mode 100644 index 00000000..61ccdfa8 --- /dev/null +++ b/include/Swiften/Elements/PubSubPayload.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include + +namespace Swift { + class PubSubPayload : public Payload { + public: + PubSubPayload(); + + const std::vector > getPayloads() const { + return payloads; + } + + template + const std::vector > getPayloads() const { + std::vector > matched_payloads; + for (std::vector >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) { + boost::shared_ptr result = boost::dynamic_pointer_cast(*i); + if (result) { + matched_payloads.push_back(result); + } + } + + return matched_payloads; + + } + + template + const boost::shared_ptr getPayload() const { + boost::shared_ptr result; + for (std::vector >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) { + result = boost::dynamic_pointer_cast(*i); + if (result) { + return result; + } + } + + return result; + } + + private: + std::vector > payloads; + }; +} diff --git a/include/Swiften/Elements/PubSubPublishPayload.cpp b/include/Swiften/Elements/PubSubPublishPayload.cpp new file mode 100644 index 00000000..dec34e92 --- /dev/null +++ b/include/Swiften/Elements/PubSubPublishPayload.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +namespace Swift { + +PubSubPublishPayload::PubSubPublishPayload(const std::string &node) : + node(node) { + + } + +} diff --git a/include/Swiften/Elements/PubSubPublishPayload.h b/include/Swiften/Elements/PubSubPublishPayload.h new file mode 100644 index 00000000..7505ca58 --- /dev/null +++ b/include/Swiften/Elements/PubSubPublishPayload.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include +#include + +namespace Swift { + class PubSubPublishPayload : public Payload { + public: + enum Type { None, Pending, Subscribed, Unconfigured }; + + PubSubPublishPayload(const std::string &node = ""); + + void setNode(const std::string &node) { + this->node = node; + } + + const std::string &getNode() const { + return node; + } + + void addItem(const boost::shared_ptr &item) { + items.push_back(item); + } + + const std::vector > &getItems() const { + return items; + } + + private: + std::string node; + std::vector > items; + }; +} diff --git a/include/Swiften/Elements/PubSubSubscribePayload.cpp b/include/Swiften/Elements/PubSubSubscribePayload.cpp new file mode 100644 index 00000000..24aa6fd6 --- /dev/null +++ b/include/Swiften/Elements/PubSubSubscribePayload.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +namespace Swift { + +PubSubSubscribePayload::PubSubSubscribePayload(const JID &jid, const std::string &node) : + jid(jid), node(node) { + + } + +} diff --git a/include/Swiften/Elements/PubSubSubscribePayload.h b/include/Swiften/Elements/PubSubSubscribePayload.h new file mode 100644 index 00000000..c65e2b61 --- /dev/null +++ b/include/Swiften/Elements/PubSubSubscribePayload.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PubSubSubscribePayload : public Payload { + public: + PubSubSubscribePayload(const JID &jid, const std::string &node = ""); + + void setJID(const JID &jid) { + this->jid = jid; + } + + const JID &getJID() const { + return jid; + } + + void setNode(const std::string &node) { + this->node = node; + } + + const std::string &getNode() const { + return node; + } + + private: + JID jid; + std::string node; + }; +} diff --git a/include/Swiften/Elements/PubSubSubscriptionPayload.cpp b/include/Swiften/Elements/PubSubSubscriptionPayload.cpp new file mode 100644 index 00000000..293505ec --- /dev/null +++ b/include/Swiften/Elements/PubSubSubscriptionPayload.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +namespace Swift { + +PubSubSubscriptionPayload::PubSubSubscriptionPayload(const JID &jid, const std::string &node) : + jid(jid), node(node), type(None) { + + } + +} diff --git a/include/Swiften/Elements/PubSubSubscriptionPayload.h b/include/Swiften/Elements/PubSubSubscriptionPayload.h new file mode 100644 index 00000000..7e4e4154 --- /dev/null +++ b/include/Swiften/Elements/PubSubSubscriptionPayload.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PubSubSubscriptionPayload : public Payload { + public: + enum Type { None, Pending, Subscribed, Unconfigured }; + + PubSubSubscriptionPayload(const JID &jid, const std::string &node = ""); + + void setJID(const JID &jid) { + this->jid = jid; + } + + const JID &getJID() const { + return jid; + } + + void setNode(const std::string &node) { + this->node = node; + } + + const std::string &getNode() const { + return node; + } + + void setId(const std::string &id) { + this->id = id; + } + + const std::string &getId() const { + return id; + } + + void setType(const Type &type) { + this->type = type; + } + + const Type &getType() const { + return type; + } + + private: + JID jid; + std::string node; + std::string id; + Type type; + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp new file mode 100644 index 00000000..85702537 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include +#include +#include +#include +#include + +namespace Swift { + +PubSubItemSerializer::PubSubItemSerializer() : GenericPayloadSerializer() { +} + +std::string PubSubItemSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement item("item"); + if (!payload->getId().empty()) { + item.setAttribute("id", payload->getId()); + } + + boost::shared_ptr body(new XMLElement("body", "http://www.w3.org/1999/xhtml")); + body->addNode(boost::shared_ptr(new XMLRawTextNode(payload->getData()))); + item.addNode(body); + + return item.serialize(); +} + +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h new file mode 100644 index 00000000..a75c4969 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class PubSubItemSerializer : public GenericPayloadSerializer { + public: + PubSubItemSerializer(); + + virtual std::string serializePayload(boost::shared_ptr item) const; + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.cpp new file mode 100644 index 00000000..9706d681 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include +#include +#include +#include +#include +#include + +namespace Swift { + +PubSubPayloadSerializer::PubSubPayloadSerializer(PayloadSerializerCollection *serializers) + : GenericPayloadSerializer(), + serializers(serializers) { +} + +std::string PubSubPayloadSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement pubsub("pubsub", "http://jabber.org/protocol/pubsub"); + + if (!payload->getPayloads().empty()) { + foreach(boost::shared_ptr subPayload, payload->getPayloads()) { + PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload); + if (serializer) { + pubsub.addNode(boost::shared_ptr(new XMLRawTextNode(serializer->serialize(subPayload)))); + } + } + } + + return pubsub.serialize(); +} + +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h b/include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h new file mode 100644 index 00000000..0f8f251a --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubPayloadSerializer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class PayloadSerializerCollection; + + class PubSubPayloadSerializer : public GenericPayloadSerializer { + public: + PubSubPayloadSerializer(PayloadSerializerCollection *serializers); + + virtual std::string serializePayload(boost::shared_ptr item) const; + private: + PayloadSerializerCollection *serializers; + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp new file mode 100644 index 00000000..1f87c246 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include +#include +#include +#include +#include +#include + +namespace Swift { + +PubSubPublishPayloadSerializer::PubSubPublishPayloadSerializer(PayloadSerializerCollection *serializers) + : GenericPayloadSerializer(), + serializers(serializers) { +} + +std::string PubSubPublishPayloadSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement publish("publish"); + + if (!payload->getNode().empty()) { + publish.setAttribute("node", payload->getNode()); + } + + if (!payload->getItems().empty()) { + foreach(boost::shared_ptr subPayload, payload->getItems()) { + PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload); + if (serializer) { + publish.addNode(boost::shared_ptr(new XMLRawTextNode(serializer->serialize(subPayload)))); + } + } + } + + return publish.serialize(); +} + +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h b/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h new file mode 100644 index 00000000..ae290559 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class PayloadSerializerCollection; + + class PubSubPublishPayloadSerializer : public GenericPayloadSerializer { + public: + PubSubPublishPayloadSerializer(PayloadSerializerCollection *serializers); + + virtual std::string serializePayload(boost::shared_ptr item) const; + private: + PayloadSerializerCollection *serializers; + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.cpp new file mode 100644 index 00000000..f6a96626 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.cpp @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include +#include +#include +#include +#include +#include + +namespace Swift { + +PubSubSubscribePayloadSerializer::PubSubSubscribePayloadSerializer() + : GenericPayloadSerializer() { +} + +std::string PubSubSubscribePayloadSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement subscribe("subscribe"); + + if (!payload->getJID().isValid()) { + subscribe.setAttribute("jid", payload->getJID().toBare().toString()); + } + + if (!payload->getNode().empty()) { + subscribe.setAttribute("node", payload->getNode()); + } + + return subscribe.serialize(); +} + +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h new file mode 100644 index 00000000..327703be --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscribePayloadSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class PubSubSubscribePayloadSerializer : public GenericPayloadSerializer { + public: + PubSubSubscribePayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr item) const; + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.cpp new file mode 100644 index 00000000..02a634a1 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include +#include +#include +#include +#include +#include + +namespace Swift { + +PubSubSubscriptionPayloadSerializer::PubSubSubscriptionPayloadSerializer() + : GenericPayloadSerializer() { +} + +std::string PubSubSubscriptionPayloadSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement subscription("subscription"); + + if (!payload->getJID().isValid()) { + subscription.setAttribute("jid", payload->getJID().toBare().toString()); + } + + if (!payload->getNode().empty()) { + subscription.setAttribute("node", payload->getNode()); + } + + switch (payload->getType()) { + case PubSubSubscriptionPayload::None: + subscription.setAttribute("subscription", "none"); + break; + case PubSubSubscriptionPayload::Subscribed: + subscription.setAttribute("subscription", "subscribed"); + break; + case PubSubSubscriptionPayload::Unconfigured: + subscription.setAttribute("subscription", "unconfigured"); + break; + case PubSubSubscriptionPayload::Pending: + subscription.setAttribute("subscription", "pending"); + break; + } + + return subscription.serialize(); +} + +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h new file mode 100644 index 00000000..0e06a34b --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubSubscriptionPayloadSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class PubSubSubscriptionPayloadSerializer : public GenericPayloadSerializer { + public: + PubSubSubscriptionPayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr item) const; + }; +} diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index cc57d216..c473966b 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -33,12 +33,12 @@ incoming_dir=/var/spool/sms/incoming #backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] -#type = sqlite3 # or "none" without database backend -#database = test.sql -#prefix=icq -type = mysql # or "none" without database backend....................................................................................................................... -database = test -prefix= -user=root -password=yourrootsqlpassword +type = sqlite3 # or "none" without database backend +database = test.sql +prefix=icq +#type = mysql # or "none" without database backend....................................................................................................................... +#database = test +#prefix= +#user=root +#password=yourrootsqlpassword #encryption_key=hanzzik From ff27ec02335268e1476d93c74a7d2836c6252386 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 22 Feb 2012 14:11:57 +0100 Subject: [PATCH 63/74] Fixed compilation with latest Swiften --- include/Swiften/Network/DummyNetworkFactories.cpp | 1 + include/Swiften/Network/DummyNetworkFactories.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/include/Swiften/Network/DummyNetworkFactories.cpp b/include/Swiften/Network/DummyNetworkFactories.cpp index 4c477561..567d467a 100644 --- a/include/Swiften/Network/DummyNetworkFactories.cpp +++ b/include/Swiften/Network/DummyNetworkFactories.cpp @@ -18,6 +18,7 @@ DummyNetworkFactories::DummyNetworkFactories(EventLoop* eventLoop) { domainNameResolver = new PlatformDomainNameResolver(eventLoop); connectionServerFactory = new DummyConnectionServerFactory(eventLoop); m_platformXMLParserFactory = new PlatformXMLParserFactory(); + this->eventLoop = eventLoop; } DummyNetworkFactories::~DummyNetworkFactories() { diff --git a/include/Swiften/Network/DummyNetworkFactories.h b/include/Swiften/Network/DummyNetworkFactories.h index a945cdfa..546cb0cc 100644 --- a/include/Swiften/Network/DummyNetworkFactories.h +++ b/include/Swiften/Network/DummyNetworkFactories.h @@ -41,6 +41,10 @@ namespace Swift { return m_platformXMLParserFactory; } + EventLoop *getEventLoop() const { + return eventLoop; + } + Swift::TLSContextFactory* getTLSContextFactory() const { return 0; } @@ -55,5 +59,6 @@ namespace Swift { ConnectionFactory* connectionFactory; DomainNameResolver* domainNameResolver; ConnectionServerFactory* connectionServerFactory; + EventLoop *eventLoop; }; } From 7c90087b1774bb14fd2f17cb6bbe53d3bc3a7c8d Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 22 Feb 2012 19:23:43 +0100 Subject: [PATCH 64/74] PubSub Parsers --- include/Swiften/Elements/PubSubItem.cpp | 2 +- include/Swiften/Elements/PubSubItem.h | 39 ++++++++++++-- include/Swiften/Elements/PubSubPayload.h | 6 ++- .../Swiften/Elements/PubSubPublishPayload.h | 6 +-- .../Swiften/Elements/PubSubSubscribePayload.h | 2 +- .../Elements/PubSubSubscriptionPayload.h | 2 +- .../PayloadParsers/PubSubItemParser.cpp | 30 +++++++++++ .../Parser/PayloadParsers/PubSubItemParser.h | 24 +++++++++ .../PayloadParsers/PubSubPayloadParser.cpp | 25 +++++++++ .../PayloadParsers/PubSubPayloadParser.h | 24 +++++++++ .../PubSubPublishPayloadParser.cpp | 30 +++++++++++ .../PubSubPublishPayloadParser.h | 24 +++++++++ .../PubSubSubscribePayloadParser.cpp | 32 ++++++++++++ .../PubSubSubscribePayloadParser.h | 24 +++++++++ .../PubSubSubscriptionPayloadParser.cpp | 51 +++++++++++++++++++ .../PubSubSubscriptionPayloadParser.h | 24 +++++++++ .../PubSubItemSerializer.cpp | 15 ++++-- .../PayloadSerializers/PubSubItemSerializer.h | 5 +- .../PubSubPublishPayloadSerializer.cpp | 2 +- 19 files changed, 349 insertions(+), 18 deletions(-) create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubItemParser.h create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.cpp create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.h create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.cpp create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.cpp create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.cpp create mode 100644 include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h diff --git a/include/Swiften/Elements/PubSubItem.cpp b/include/Swiften/Elements/PubSubItem.cpp index e146be9d..730ad89e 100644 --- a/include/Swiften/Elements/PubSubItem.cpp +++ b/include/Swiften/Elements/PubSubItem.cpp @@ -8,7 +8,7 @@ namespace Swift { -PubSubItem::PubSubItem(const std::string &body) : body_(body) { +PubSubItem::PubSubItem() { } } diff --git a/include/Swiften/Elements/PubSubItem.h b/include/Swiften/Elements/PubSubItem.h index 554b7a76..f0b3ef70 100644 --- a/include/Swiften/Elements/PubSubItem.h +++ b/include/Swiften/Elements/PubSubItem.h @@ -14,12 +14,41 @@ namespace Swift { class PubSubItem : public Payload { public: - PubSubItem(const std::string &body = ""); + PubSubItem(); - const std::string& getData() const { return body_; } + void addPayload(boost::shared_ptr payload) { + payloads.push_back(payload); + } - void setData(const std::string& body) { - body_ = body; + const std::vector > getPayloads() const { + return payloads; + } + + template + const std::vector > getPayloads() const { + std::vector > matched_payloads; + for (std::vector >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) { + boost::shared_ptr result = boost::dynamic_pointer_cast(*i); + if (result) { + matched_payloads.push_back(result); + } + } + + return matched_payloads; + + } + + template + const boost::shared_ptr getPayload() const { + boost::shared_ptr result; + for (std::vector >::const_iterator i = payloads.begin(); i != payloads.end(); ++i) { + result = boost::dynamic_pointer_cast(*i); + if (result) { + return result; + } + } + + return result; } const std::string& getId() const { return id; } @@ -29,7 +58,7 @@ namespace Swift { } private: - std::string body_; + std::vector > payloads; std::string id; }; } diff --git a/include/Swiften/Elements/PubSubPayload.h b/include/Swiften/Elements/PubSubPayload.h index 61ccdfa8..46c8b82e 100644 --- a/include/Swiften/Elements/PubSubPayload.h +++ b/include/Swiften/Elements/PubSubPayload.h @@ -16,10 +16,14 @@ namespace Swift { public: PubSubPayload(); + void addPayload(boost::shared_ptr payload) { + payloads.push_back(payload); + } + const std::vector > getPayloads() const { return payloads; } - + template const std::vector > getPayloads() const { std::vector > matched_payloads; diff --git a/include/Swiften/Elements/PubSubPublishPayload.h b/include/Swiften/Elements/PubSubPublishPayload.h index 7505ca58..930cca6b 100644 --- a/include/Swiften/Elements/PubSubPublishPayload.h +++ b/include/Swiften/Elements/PubSubPublishPayload.h @@ -28,16 +28,16 @@ namespace Swift { return node; } - void addItem(const boost::shared_ptr &item) { + void addItem(const boost::shared_ptr &item) { items.push_back(item); } - const std::vector > &getItems() const { + const std::vector > &getItems() const { return items; } private: std::string node; - std::vector > items; + std::vector > items; }; } diff --git a/include/Swiften/Elements/PubSubSubscribePayload.h b/include/Swiften/Elements/PubSubSubscribePayload.h index c65e2b61..f2b011a2 100644 --- a/include/Swiften/Elements/PubSubSubscribePayload.h +++ b/include/Swiften/Elements/PubSubSubscribePayload.h @@ -15,7 +15,7 @@ namespace Swift { class PubSubSubscribePayload : public Payload { public: - PubSubSubscribePayload(const JID &jid, const std::string &node = ""); + PubSubSubscribePayload(const JID &jid = JID(), const std::string &node = ""); void setJID(const JID &jid) { this->jid = jid; diff --git a/include/Swiften/Elements/PubSubSubscriptionPayload.h b/include/Swiften/Elements/PubSubSubscriptionPayload.h index 7e4e4154..c404e6ff 100644 --- a/include/Swiften/Elements/PubSubSubscriptionPayload.h +++ b/include/Swiften/Elements/PubSubSubscriptionPayload.h @@ -17,7 +17,7 @@ namespace Swift { public: enum Type { None, Pending, Subscribed, Unconfigured }; - PubSubSubscriptionPayload(const JID &jid, const std::string &node = ""); + PubSubSubscriptionPayload(const JID &jid = JID(), const std::string &node = ""); void setJID(const JID &jid) { this->jid = jid; diff --git a/include/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp b/include/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp new file mode 100644 index 00000000..8f23c41a --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubItemParser.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void PubSubItemParser::handleTree(ParserElement::ref root) { + std::string id = root->getAttributes().getAttribute("id"); + if (!id.empty()) { + getPayloadInternal()->setId(id); + } + + foreach (ParserElement::ref child, root->getAllChildren()) { + getPayloadInternal()->addPayload(TreeReparser::parseTree(child, factories)); + } +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubItemParser.h b/include/Swiften/Parser/PayloadParsers/PubSubItemParser.h new file mode 100644 index 00000000..9326f92d --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubItemParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PayloadParserFactoryCollection; + class PubSubItemParser : public GenericPayloadTreeParser { + public: + PubSubItemParser(PayloadParserFactoryCollection* collection) : factories(collection) {} + virtual void handleTree(ParserElement::ref root); + private: + PayloadParserFactoryCollection* factories; + }; +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.cpp b/include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.cpp new file mode 100644 index 00000000..c3e151bb --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void PubSubPayloadParser::handleTree(ParserElement::ref root) { + foreach (ParserElement::ref child, root->getAllChildren()) { + getPayloadInternal()->addPayload(TreeReparser::parseTree(child, factories)); + } +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.h b/include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.h new file mode 100644 index 00000000..7bbb688c --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubPayloadParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PayloadParserFactoryCollection; + class PubSubPayloadParser : public GenericPayloadTreeParser { + public: + PubSubPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {} + virtual void handleTree(ParserElement::ref root); + private: + PayloadParserFactoryCollection* factories; + }; +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.cpp b/include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.cpp new file mode 100644 index 00000000..949ceba4 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void PubSubPublishPayloadParser::handleTree(ParserElement::ref root) { + std::string node = root->getAttributes().getAttribute("node"); + if (!node.empty()) { + getPayloadInternal()->setNode(node); + } + + foreach (ParserElement::ref child, root->getAllChildren()) { + getPayloadInternal()->addItem(TreeReparser::parseTree(child, factories)); + } +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h b/include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h new file mode 100644 index 00000000..b0575b72 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubPublishPayloadParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PayloadParserFactoryCollection; + class PubSubPublishPayloadParser : public GenericPayloadTreeParser { + public: + PubSubPublishPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {} + virtual void handleTree(ParserElement::ref root); + private: + PayloadParserFactoryCollection* factories; + }; +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.cpp b/include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.cpp new file mode 100644 index 00000000..b7913d24 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void PubSubSubscribePayloadParser::handleTree(ParserElement::ref root) { + std::string node = root->getAttributes().getAttribute("node"); + if (!node.empty()) { + getPayloadInternal()->setNode(node); + } + + std::string jid = root->getAttributes().getAttribute("jid"); + if (!jid.empty()) { + getPayloadInternal()->setJID(jid); + } + +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h b/include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h new file mode 100644 index 00000000..54a2b05a --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubSubscribePayloadParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PayloadParserFactoryCollection; + class PubSubSubscribePayloadParser : public GenericPayloadTreeParser { + public: + PubSubSubscribePayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {} + virtual void handleTree(ParserElement::ref root); + private: + PayloadParserFactoryCollection* factories; + }; +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.cpp b/include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.cpp new file mode 100644 index 00000000..0c964762 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void PubSubSubscriptionPayloadParser::handleTree(ParserElement::ref root) { + std::string node = root->getAttributes().getAttribute("node"); + if (!node.empty()) { + getPayloadInternal()->setNode(node); + } + + std::string jid = root->getAttributes().getAttribute("jid"); + if (!jid.empty()) { + getPayloadInternal()->setJID(jid); + } + + std::string id = root->getAttributes().getAttribute("subid"); + if (!id.empty()) { + getPayloadInternal()->setId(id); + } + + std::string type = root->getAttributes().getAttribute("subscription"); + if (type == "none") { + getPayloadInternal()->setType(PubSubSubscriptionPayload::None); + } + else if (type == "subscribed") { + getPayloadInternal()->setType(PubSubSubscriptionPayload::Subscribed); + } + else if (type == "pending") { + getPayloadInternal()->setType(PubSubSubscriptionPayload::Pending); + } + else if (type == "unconfigured") { + getPayloadInternal()->setType(PubSubSubscriptionPayload::Unconfigured); + } + +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h b/include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h new file mode 100644 index 00000000..7bd1c2d1 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/PubSubSubscriptionPayloadParser.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PayloadParserFactoryCollection; + class PubSubSubscriptionPayloadParser : public GenericPayloadTreeParser { + public: + PubSubSubscriptionPayloadParser(PayloadParserFactoryCollection* collection) : factories(collection) {} + virtual void handleTree(ParserElement::ref root); + private: + PayloadParserFactoryCollection* factories; + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp index 85702537..47ab6492 100644 --- a/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.cpp @@ -9,10 +9,12 @@ #include #include #include +#include namespace Swift { -PubSubItemSerializer::PubSubItemSerializer() : GenericPayloadSerializer() { +PubSubItemSerializer::PubSubItemSerializer(PayloadSerializerCollection *serializers) : + GenericPayloadSerializer(), serializers(serializers) { } std::string PubSubItemSerializer::serializePayload(boost::shared_ptr payload) const { @@ -21,9 +23,14 @@ std::string PubSubItemSerializer::serializePayload(boost::shared_ptr item.setAttribute("id", payload->getId()); } - boost::shared_ptr body(new XMLElement("body", "http://www.w3.org/1999/xhtml")); - body->addNode(boost::shared_ptr(new XMLRawTextNode(payload->getData()))); - item.addNode(body); + if (!payload->getPayloads().empty()) { + foreach(boost::shared_ptr subPayload, payload->getPayloads()) { + PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload); + if (serializer) { + item.addNode(boost::shared_ptr(new XMLRawTextNode(serializer->serialize(subPayload)))); + } + } + } return item.serialize(); } diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h index a75c4969..795c63ba 100644 --- a/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubItemSerializer.h @@ -10,10 +10,13 @@ #include namespace Swift { + class PayloadSerializerCollection; class PubSubItemSerializer : public GenericPayloadSerializer { public: - PubSubItemSerializer(); + PubSubItemSerializer(PayloadSerializerCollection *serializers); virtual std::string serializePayload(boost::shared_ptr item) const; + private: + PayloadSerializerCollection *serializers; }; } diff --git a/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp index 1f87c246..09cfbb5f 100644 --- a/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp +++ b/include/Swiften/Serializer/PayloadSerializers/PubSubPublishPayloadSerializer.cpp @@ -26,7 +26,7 @@ std::string PubSubPublishPayloadSerializer::serializePayload(boost::shared_ptr

getItems().empty()) { - foreach(boost::shared_ptr subPayload, payload->getItems()) { + foreach(boost::shared_ptr subPayload, payload->getItems()) { PayloadSerializer* serializer = serializers->getPayloadSerializer(subPayload); if (serializer) { publish.addNode(boost::shared_ptr(new XMLRawTextNode(serializer->serialize(subPayload)))); From 197cd61f9552963c1fcc78594a5b4e50a3878f6f Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 25 Feb 2012 07:37:59 +0100 Subject: [PATCH 65/74] Handle skype FULLNAME --- backends/skype/main.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index c82792ce..f9f7b4b6 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -629,6 +629,19 @@ static void handle_skype_message(std::string &message, Skype *sk) { std::vector groups; np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); } + else if (cmd[2] == "FULLNAME") { + std::string st = sk->send_command("GET USER " + cmd[1] + " ONLINESTATUS"); + st = st.substr(st.find("ONLINESTATUS") + 13); + pbnetwork::StatusType status = getStatus(st); + + std::string mood_text = sk->send_command("GET USER " + cmd[1] + " MOOD_TEXT"); + mood_text = mood_text.substr(mood_text.find("MOOD_TEXT") + 10); + + std::string alias = message.substr(message.find("FULLNAME") + 9); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); + } } else if (cmd[0] == "CHATMESSAGE") { if (cmd[3] == "RECEIVED") { From 54dff8d28067599e63b5c2312889a0c13143a571 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 26 Feb 2012 12:40:48 +0100 Subject: [PATCH 66/74] Gateway payload --- include/Swiften/Elements/GatewayPayload.cpp | 16 ++++++ include/Swiften/Elements/GatewayPayload.h | 49 +++++++++++++++++++ .../PayloadParsers/GatewayPayloadParser.cpp | 33 +++++++++++++ .../PayloadParsers/GatewayPayloadParser.h | 21 ++++++++ .../GatewayPayloadSerializer.cpp | 41 ++++++++++++++++ .../GatewayPayloadSerializer.h | 19 +++++++ 6 files changed, 179 insertions(+) create mode 100644 include/Swiften/Elements/GatewayPayload.cpp create mode 100644 include/Swiften/Elements/GatewayPayload.h create mode 100644 include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.cpp create mode 100644 include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.h create mode 100644 include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp create mode 100644 include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h diff --git a/include/Swiften/Elements/GatewayPayload.cpp b/include/Swiften/Elements/GatewayPayload.cpp new file mode 100644 index 00000000..59b6a9f6 --- /dev/null +++ b/include/Swiften/Elements/GatewayPayload.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +namespace Swift { + +GatewayPayload::GatewayPayload(const JID &jid, const std::string &desc, const std::string &prompt) : + jid(jid), desc(desc), prompt(prompt) { + + } + +} diff --git a/include/Swiften/Elements/GatewayPayload.h b/include/Swiften/Elements/GatewayPayload.h new file mode 100644 index 00000000..2f6bbc54 --- /dev/null +++ b/include/Swiften/Elements/GatewayPayload.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class GatewayPayload : public Payload { + public: + GatewayPayload(const JID &jid = JID(), const std::string &desc = "", const std::string &prompt = ""); + + void setJID(const JID &jid) { + this->jid = jid; + } + + const JID &getJID() const { + return jid; + } + + void setDesc(const std::string &desc) { + this->desc = desc; + } + + const std::string &getDesc() const { + return desc; + } + + void setPrompt(const std::string &prompt) { + this->prompt = prompt; + } + + const std::string &getPrompt() const { + return prompt; + } + + private: + JID jid; + std::string desc; + std::string prompt; + }; +} diff --git a/include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.cpp b/include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.cpp new file mode 100644 index 00000000..30437926 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void GatewayPayloadParser::handleTree(ParserElement::ref root) { + foreach (ParserElement::ref child, root->getAllChildren()) { + if (child->getName() == "desc") { + getPayloadInternal()->setDesc(child->getText()); + } + else if (child->getName() == "prompt") { + getPayloadInternal()->setPrompt(child->getText()); + } + else if (child->getName() == "jid") { + getPayloadInternal()->setJID(child->getText()); + } + } +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.h b/include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.h new file mode 100644 index 00000000..db2c5782 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/GatewayPayloadParser.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2012 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class GatewayPayloadParser : public GenericPayloadTreeParser { + public: + GatewayPayloadParser() {} + virtual void handleTree(ParserElement::ref root); + }; +} diff --git a/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp new file mode 100644 index 00000000..8a129376 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#include +#include +#include +#include +#include +#include + +namespace Swift { + +GatewayPayloadSerializer::GatewayPayloadSerializer() + : GenericPayloadSerializer() { +} + +std::string GatewayPayloadSerializer::serializePayload(boost::shared_ptr payload) const { + XMLElement query("query", "jabber:iq:gateway"); + + if (!payload->getJID().isValid()) { + boost::shared_ptr jid(new XMLElement("jid", "", payload->getJID().toBare().toString())); + query.addNode(jid); + } + + if (!payload->getDesc().empty()) { + boost::shared_ptr desc(new XMLElement("desc", "", payload->getDesc())); + query.addNode(desc); + } + + if (!payload->getPrompt().empty()) { + boost::shared_ptr prompt(new XMLElement("prompt", "", payload->getPrompt())); + query.addNode(prompt); + } + + return query.serialize(); +} + +} diff --git a/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h b/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h new file mode 100644 index 00000000..1b64ac17 --- /dev/null +++ b/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2011 Jan Kaluza + * Licensed under the Simplified BSD license. + * See Documentation/Licenses/BSD-simplified.txt for more information. + */ + +#pragma once + +#include +#include + +namespace Swift { + class GatewayPayloadSerializer : public GenericPayloadSerializer { + public: + GatewayPayloadSerializer(); + + virtual std::string serializePayload(boost::shared_ptr item) const; + }; +} From 320738eda85a90c77c4072bd320f6cfd3e6416f8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 26 Feb 2012 14:03:48 +0100 Subject: [PATCH 67/74] Gateway interaction --- ChangeLog | 1 + .../GatewayPayloadSerializer.cpp | 2 +- include/transport/gatewayresponder.h | 43 +++++++++++++ include/transport/usermanager.h | 4 ++ spectrum/src/main.cpp | 4 ++ src/gatewayresponder.cpp | 63 +++++++++++++++++++ src/transport.cpp | 6 ++ 7 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 include/transport/gatewayresponder.h create mode 100644 src/gatewayresponder.cpp diff --git a/ChangeLog b/ChangeLog index 97aaa33c..bc4c7435 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ Version 2.0.0-beta (X-X-X): General: * Added PostreSQL support (thanks to Jadestorm). + * Added XEP-0100 (Gateway interaction) support. * Send presences only "from" bare JID (fixed bug with buddies appearing twice in the roster and potential unregistering issues). * Fixed potential MySQL/SQLite3 deadlocks. diff --git a/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp b/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp index 8a129376..6b7cd9e7 100644 --- a/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp +++ b/include/Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.cpp @@ -20,7 +20,7 @@ GatewayPayloadSerializer::GatewayPayloadSerializer() std::string GatewayPayloadSerializer::serializePayload(boost::shared_ptr payload) const { XMLElement query("query", "jabber:iq:gateway"); - if (!payload->getJID().isValid()) { + if (payload->getJID().isValid()) { boost::shared_ptr jid(new XMLElement("jid", "", payload->getJID().toBare().toString())); query.addNode(jid); } diff --git a/include/transport/gatewayresponder.h b/include/transport/gatewayresponder.h new file mode 100644 index 00000000..1acf4403 --- /dev/null +++ b/include/transport/gatewayresponder.h @@ -0,0 +1,43 @@ +/** + * libtransport -- C++ library for easy XMPP Transports development + * + * Copyright (C) 2011, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#pragma once + +#include +#include "Swiften/Swiften.h" +#include "Swiften/Queries/Responder.h" +#include "Swiften/Elements/GatewayPayload.h" + +namespace Transport { + +class UserManager; + +class GatewayResponder : public Swift::Responder { + public: + GatewayResponder(Swift::IQRouter *router, UserManager *userManager); + ~GatewayResponder(); + + private: + virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + UserManager *m_userManager; +}; + +} \ No newline at end of file diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 290c4235..5ea47d5c 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -104,6 +104,10 @@ class UserManager : public Swift::EntityCapsProvider { return m_userRegistry; } + Component *getComponent() { + return m_component; + } + /// Connects user manually. /// \param user JID of user. void connectUser(const Swift::JID &user); diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index c57573ea..d05bdeb8 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -12,6 +12,7 @@ #include "transport/statsresponder.h" #include "transport/usersreconnecter.h" #include "transport/util.h" +#include "transport/gatewayresponder.h" #include "Swiften/EventLoop/SimpleEventLoop.h" #include #include @@ -421,6 +422,9 @@ int main(int argc, char **argv) StatsResponder statsResponder(&transport, &userManager, &plugin, storageBackend); statsResponder.start(); + GatewayResponder gatewayResponder(transport.getIQRouter(), &userManager); + gatewayResponder.start(); + eventLoop_ = &eventLoop; eventLoop.run(); diff --git a/src/gatewayresponder.cpp b/src/gatewayresponder.cpp new file mode 100644 index 00000000..903c069a --- /dev/null +++ b/src/gatewayresponder.cpp @@ -0,0 +1,63 @@ +/** + * XMPP - libpurple transport + * + * Copyright (C) 2009, Jan Kaluza + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA + */ + +#include "transport/gatewayresponder.h" + +#include +#include +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Elements/RawXMLPayload.h" +#include "Swiften/Swiften.h" +#include "transport/usermanager.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "log4cxx/logger.h" + +using namespace log4cxx; + +using namespace Swift; +using namespace boost; + +namespace Transport { + +static LoggerPtr logger = Logger::getLogger("GatewayResponder"); + +GatewayResponder::GatewayResponder(Swift::IQRouter *router, UserManager *userManager) : Swift::Responder(router) { + m_userManager = userManager; +} + +GatewayResponder::~GatewayResponder() { +} + +bool GatewayResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload) { + sendResponse(from, id, boost::shared_ptr(new GatewayPayload(Swift::JID(), "Enter legacy network contact ID.", "Contact ID"))); + return true; +} + +bool GatewayResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload) { + std::string prompt = payload->getPrompt(); + std::string escaped = Swift::JID::getEscapedNode(prompt); + std::string jid = escaped + "@" + m_userManager->getComponent()->getJID().toBare().toString(); + + sendResponse(from, id, boost::shared_ptr(new GatewayPayload(jid))); + return true; +} + +} diff --git a/src/transport.cpp b/src/transport.cpp index 0d1d06ea..8eab7bf7 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -36,6 +36,8 @@ #include "Swiften/Serializer/PayloadSerializers/XHTMLIMSerializer.h" #include "Swiften/Parser/PayloadParsers/StatsParser.h" #include "Swiften/Serializer/PayloadSerializers/StatsSerializer.h" +#include "Swiften/Parser/PayloadParsers/GatewayPayloadParser.h" +#include "Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h" #include "Swiften/Serializer/PayloadSerializers/SpectrumErrorSerializer.h" #include "transport/BlockParser.h" #include "transport/BlockSerializer.h" @@ -95,6 +97,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_server->addPayloadParserFactory(new GenericPayloadParserFactory("block", "urn:xmpp:block:0")); m_server->addPayloadParserFactory(new GenericPayloadParserFactory("invisible", "urn:xmpp:invisible:0")); m_server->addPayloadParserFactory(new GenericPayloadParserFactory("query", "http://jabber.org/protocol/stats")); + m_server->addPayloadParserFactory(new GenericPayloadParserFactory("query", "jabber:iq:gateway")); m_server->addPayloadSerializer(new Swift::AttentionSerializer()); m_server->addPayloadSerializer(new Swift::XHTMLIMSerializer()); @@ -102,6 +105,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_server->addPayloadSerializer(new Swift::InvisibleSerializer()); m_server->addPayloadSerializer(new Swift::StatsSerializer()); m_server->addPayloadSerializer(new Swift::SpectrumErrorSerializer()); + m_server->addPayloadSerializer(new Swift::GatewayPayloadSerializer()); m_server->onDataRead.connect(boost::bind(&Component::handleDataRead, this, _1)); m_server->onDataWritten.connect(boost::bind(&Component::handleDataWritten, this, _1)); @@ -121,6 +125,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_component->addPayloadParserFactory(new GenericPayloadParserFactory("block", "urn:xmpp:block:0")); m_component->addPayloadParserFactory(new GenericPayloadParserFactory("invisible", "urn:xmpp:invisible:0")); m_component->addPayloadParserFactory(new GenericPayloadParserFactory("query", "http://jabber.org/protocol/stats")); + m_component->addPayloadParserFactory(new GenericPayloadParserFactory("query", "jabber:iq:gateway")); m_component->addPayloadSerializer(new Swift::AttentionSerializer()); m_component->addPayloadSerializer(new Swift::XHTMLIMSerializer()); @@ -128,6 +133,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_component->addPayloadSerializer(new Swift::InvisibleSerializer()); m_component->addPayloadSerializer(new Swift::StatsSerializer()); m_component->addPayloadSerializer(new Swift::SpectrumErrorSerializer()); + m_component->addPayloadSerializer(new Swift::GatewayPayloadSerializer()); m_stanzaChannel = m_component->getStanzaChannel(); m_iqRouter = m_component->getIQRouter(); From 1c99b634a8e9c83e7ca673ca0ff0925e3562e8be Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 26 Feb 2012 15:41:40 +0100 Subject: [PATCH 68/74] Do not send empty name in roster push --- src/networkpluginserver.cpp | 1 + src/rostermanager.cpp | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index a89117b6..bb8eb680 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -195,6 +195,7 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa // Set alias only if it's not empty. Backends are allowed to send empty alias if it has // not changed. if (!payload.alias().empty()) { + LOG4CXX_INFO(logger, "Setting alias to " << payload.alias() << " " << buddy->getAlias()); buddy->setAlias(payload.alias()); } diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 44264588..65135116 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -110,7 +110,12 @@ void RosterManager::sendBuddyRosterPush(Buddy *buddy) { Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload()); Swift::RosterItemPayload item; item.setJID(buddy->getJID().toBare()); - item.setName(buddy->getAlias()); + if (buddy->getAlias().empty()) { + item.setName(buddy->getJID().toBare().toString()); + } + else { + item.setName(buddy->getAlias()); + } item.setGroups(buddy->getGroups()); item.setSubscription(Swift::RosterItemPayload::Both); From 666233737631cd8bb55186087bafb789248b0c60 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 26 Feb 2012 16:14:43 +0100 Subject: [PATCH 69/74] debug --- src/networkpluginserver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index bb8eb680..00b7f9cd 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -479,6 +479,8 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { if (!user) return; + LOG4CXX_INFO(logger, "HANDLE BUDDY CHANGED " << payload.buddyname() << "-" << payload.alias()); + LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(payload.buddyname()); if (buddy) { handleBuddyPayload(buddy, payload); From fbb10606458df2bda74cc0cf63d883a8fd3c384e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 26 Feb 2012 16:55:37 +0100 Subject: [PATCH 70/74] Remove firstSet check --- src/localbuddy.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/localbuddy.cpp b/src/localbuddy.cpp index a12b9ee9..55f7e27c 100644 --- a/src/localbuddy.cpp +++ b/src/localbuddy.cpp @@ -32,11 +32,11 @@ LocalBuddy::~LocalBuddy() { } void LocalBuddy::setAlias(const std::string &alias) { - if (m_firstSet) { - m_firstSet = false; - m_alias = alias; - return; - } +// if (m_firstSet) { +// m_firstSet = false; +// m_alias = alias; +// return; +// } bool changed = m_alias != alias; m_alias = alias; From d6c5afab27269413fc2a1c1f422f7253dc644f42 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 26 Feb 2012 19:37:00 +0100 Subject: [PATCH 71/74] fixed skype buddies parsing --- backends/skype/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index f9f7b4b6..9ede8a7f 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -505,7 +505,7 @@ bool Skype::loadSkypeBuddies() { // online status;friendly name;voicemail;mood // (comma-seperated lines, usernames can have comma's) - for (int i=0; full_friends_list[i] && *full_friends_list[i] != '\0'; i+=8) + for (int i=0; full_friends_list[i] && full_friends_list[i+1] && *full_friends_list[i] != '\0'; i+=8) { std::string buddy = full_friends_list[i]; From 554dddd813d9f81f47ad1d9b1a12fbf9b5f474a9 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 28 Feb 2012 11:01:22 +0100 Subject: [PATCH 72/74] Updated changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index bc4c7435..d0d28034 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Version 2.0.0-beta (X-X-X): +Version 2.0.0-beta (2012-02-28): General: * Added PostreSQL support (thanks to Jadestorm). * Added XEP-0100 (Gateway interaction) support. From 40d67818427287b278b341a16f265f2bfbfbc46f Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 28 Feb 2012 14:44:00 +0100 Subject: [PATCH 73/74] Backend template --- backends/CMakeLists.txt | 2 + backends/template/CMakeLists.txt | 10 ++ backends/template/README | 1 + backends/template/main.cpp | 181 +++++++++++++++++++++++++++++++ 4 files changed, 194 insertions(+) create mode 100644 backends/template/CMakeLists.txt create mode 100644 backends/template/README create mode 100644 backends/template/main.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 543b60b8..cdb2696f 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -9,6 +9,8 @@ if (PROTOBUF_FOUND) ADD_SUBDIRECTORY(smstools3) + ADD_SUBDIRECTORY(template) + if (NOT WIN32) ADD_SUBDIRECTORY(frotz) if (${LIBDBUSGLIB_FOUND}) diff --git a/backends/template/CMakeLists.txt b/backends/template/CMakeLists.txt new file mode 100644 index 00000000..b35d57a3 --- /dev/null +++ b/backends/template/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.c *.cpp) + +ADD_EXECUTABLE(spectrum2_template_backend ${SRC}) + +target_link_libraries(spectrum2_template_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) + +#INSTALL(TARGETS spectrum2_template_backend RUNTIME DESTINATION bin) + diff --git a/backends/template/README b/backends/template/README new file mode 100644 index 00000000..b5b85a34 --- /dev/null +++ b/backends/template/README @@ -0,0 +1 @@ +This is just template for creating new generic spectrum2 backends. It does not do anything! \ No newline at end of file diff --git a/backends/template/main.cpp b/backends/template/main.cpp new file mode 100644 index 00000000..44fc8623 --- /dev/null +++ b/backends/template/main.cpp @@ -0,0 +1,181 @@ +// Transport includes +#include "transport/config.h" +#include "transport/networkplugin.h" + +// Swiften +#include "Swiften/Swiften.h" + +// for signal handler +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" + +// Log4cxx +#include "log4cxx/logger.h" +#include "log4cxx/consoleappender.h" +#include "log4cxx/patternlayout.h" +#include "log4cxx/propertyconfigurator.h" +#include "log4cxx/helpers/properties.h" +#include "log4cxx/helpers/fileinputstream.h" +#include "log4cxx/helpers/transcoder.h" + +// Boost +#include +using namespace boost::filesystem; +using namespace boost::program_options; +using namespace Transport; + +// log4cxx main logger +using namespace log4cxx; +static LoggerPtr logger = log4cxx::Logger::getLogger("Backend Template"); + +// eventloop +Swift::SimpleEventLoop *loop_; + +// Plugin +class TemplatePlugin; +TemplatePlugin * np = NULL; + +class TemplatePlugin : public NetworkPlugin { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; + + TemplatePlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&TemplatePlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); + + LOG4CXX_INFO(logger, "Starting the plugin."); + } + + // NetworkPlugin uses this method to send the data to networkplugin server + void sendData(const std::string &string) { + m_conn->write(Swift::createSafeByteArray(string)); + } + + // This method has to call handleDataRead with all received data from network plugin server + void _handleDataRead(boost::shared_ptr data) { + std::string d(data->begin(), data->end()); + handleDataRead(d); + } + + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + handleConnected(user); + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + LOG4CXX_INFO(logger, "Sending message from " << user << " to " << legacyName << "."); + } + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << "."); + handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + + } + + private: + Config *config; +}; + +static void spectrum_sigchld_handler(int sig) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} + + +int main (int argc, char* argv[]) { + std::string host; + int port; + + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } + + boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + desc.add_options() + ("host,h", value(&host), "host") + ("port,p", value(&port), "port") + ; + try + { + boost::program_options::variables_map vm; + boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::notify(vm); + } + catch (std::runtime_error& e) + { + std::cout << desc << "\n"; + exit(1); + } + catch (...) + { + std::cout << desc << "\n"; + exit(1); + } + + + if (argc < 5) { + return 1; + } + + Config config; + if (!config.load(argv[5])) { + std::cerr << "Can't open " << argv[1] << " configuration file.\n"; + return 1; + } + + if (CONFIG_STRING(&config, "logging.backend_config").empty()) { + LoggerPtr root = log4cxx::Logger::getRootLogger(); +#ifndef _MSC_VER + root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n"))); +#else + root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n"))); +#endif + } + else { + log4cxx::helpers::Properties p; + log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config")); + p.load(istream); + LogString pid, jid; + log4cxx::helpers::Transcoder::decode(boost::lexical_cast(getpid()), pid); + log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid); +#ifdef _MSC_VER + p.setProperty(L"pid", pid); + p.setProperty(L"jid", jid); +#else + p.setProperty("pid", pid); + p.setProperty("jid", jid); +#endif + log4cxx::PropertyConfigurator::configure(p); + } + + Swift::SimpleEventLoop eventLoop; + loop_ = &eventLoop; + np = new TemplatePlugin(&config, &eventLoop, host, port); + loop_->run(); + + return 0; +} From 7292a987c59d7ae79f1e572aab10f73c38f46f8f Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Fri, 2 Mar 2012 08:51:55 +0100 Subject: [PATCH 74/74] First tries of full MUC support --- backends/libpurple/main.cpp | 35 +++++++++++++++++++++++++++++++++++ spectrum/src/sample.cfg | 7 ++++--- src/user.cpp | 4 ++-- 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 86a6f201..cf8d3090 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -915,6 +915,41 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } } + void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &pasword) { + PurpleAccount *account = m_sessions[user]; + if (!account) { + return; + } + + PurpleConnection *gc = purple_account_get_connection(account); + GHashTable *comps = NULL; + + // Check if the PurpleChat is not stored in buddy list + PurpleChat *chat = purple_blist_find_chat(account, room.c_str()); + if (chat) { + comps = purple_chat_get_components(chat); + } + else if (PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults != NULL) { + comps = PURPLE_PLUGIN_PROTOCOL_INFO(gc->prpl)->chat_info_defaults(gc, room.c_str()); + } + + LOG4CXX_INFO(logger, user << ": Joining the room " << room); + if (comps) { + serv_join_chat(gc, comps); + g_hash_table_destroy(comps); + } + } + + void handleLeaveRoomRequest(const std::string &user, const std::string &room) { + PurpleAccount *account = m_sessions[user]; + if (!account) { + return; + } + + PurpleConversation *conv = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, room.c_str(), account); + purple_conversation_destroy(conv); + } + void handleFTStartRequest(const std::string &user, const std::string &buddyName, const std::string &fileName, unsigned long size, unsigned long ftID) { PurpleXfer *xfer = m_unhandledXfers[user + fileName + buddyName]; if (xfer) { diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index c473966b..d0e234e9 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,8 +13,8 @@ admin_password=test #cert=server.pfx #patch to PKCS#12 certificate #cert_password=test #password to that certificate if any users_per_backend=10 -#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend -backend=/home/hanzz/code/libtransport/backends/smstools3/spectrum2_smstools3_backend +backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend +#backend=/home/hanzz/code/libtransport/backends/smstools3/spectrum2_smstools3_backend #backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe #backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend #backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend @@ -22,6 +22,7 @@ backend=/home/hanzz/code/libtransport/backends/smstools3/spectrum2_smstools3_bac protocol=any #protocol=prpl-icq irc_server=irc.freenode.org +working_dir=./ [backend] #default_avatar=catmelonhead.jpg @@ -33,7 +34,7 @@ incoming_dir=/var/spool/sms/incoming #backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] -type = sqlite3 # or "none" without database backend +type = none # or "none" without database backend database = test.sql prefix=icq #type = mysql # or "none" without database backend....................................................................................................................... diff --git a/src/user.cpp b/src/user.cpp index 0467ee86..e94ae872 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -213,8 +213,8 @@ void User::handlePresence(Swift::Presence::ref presence) { bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; if (isMUC) { if (presence->getType() == Swift::Presence::Unavailable) { - LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << presence->getTo().getNode()); std::string room = Buddy::JIDToLegacyName(presence->getTo()); + LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room); onRoomLeft(room); } else { @@ -224,8 +224,8 @@ void User::handlePresence(Swift::Presence::ref presence) { m_readyForConnect = true; onReadyToConnect(); } - LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << presence->getTo().getNode() << " as " << presence->getTo().getResource()); std::string room = Buddy::JIDToLegacyName(presence->getTo()); + LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << room << " as " << presence->getTo().getResource()); std::string password = ""; if (presence->getPayload() != NULL) { password = presence->getPayload()->getPassword() ? *presence->getPayload()->getPassword() : "";