From 02df69b8318f866a70b3991b4bc169e549444156 Mon Sep 17 00:00:00 2001 From: Darchigh Date: Fri, 18 Jan 2013 17:42:19 +0100 Subject: [PATCH 01/57] Make Spectrum2 send full roster after receiving empty RemoteRoster-Payload --- src/rostermanager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 0967fe56..449cd744 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -280,6 +280,15 @@ void RosterManager::handleRemoteRosterResponse(boost::shared_ptrgetJID().toString() << ": This server supports remote roster protoXEP"); m_supportRemoteRoster = true; + + //If we receive empty RosterPayload initiate full RosterPush + if(payload->getItems().empty()){ + LOG4CXX_INFO(logger, "Received empty Roster. Pushing full Roster."); + for(std::map, boost::pool_allocator< std::pair > >::const_iterator c_it = m_buddies.begin(); + c_it != m_buddies.end(); c_it++) { + sendBuddyRosterPush(c_it->second); + } + } return; BOOST_FOREACH(const Swift::RosterItemPayload &item, payload->getItems()) { From 2f46d9f7a3ab814f76dce516bc5592496481ad53 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 22 Jan 2013 09:07:10 +0100 Subject: [PATCH 02/57] Working spectrum2_manager restart and hopefully working backend logging directory creation under unprivileged user --- spectrum/src/sample.cfg | 6 ++-- spectrum_manager/src/main.cpp | 3 ++ src/logging.cpp | 58 +++++++++++++++++++---------------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index d795b60e..75735b97 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,15 +13,15 @@ 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=../..//backends/swiften/spectrum2_swiften_backend +#backend=../..//backends/swiften/spectrum2_swiften_backend #backend=../../backends/twitter/spectrum2_twitter_backend -#backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend +backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend protocol=prpl-jabber #protocol=prpl-msn #protocol=any #protocol=prpl-icq working_dir=./ -portfile=$jid.port +portfile=./$jid.port irc_server=irc.freenode.org [backend] diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index 9f09d2af..58581be2 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -138,6 +138,9 @@ int main(int argc, char **argv) else if (command[0] == "list") { std::vector list = show_list(&config); } + else if (command[0] == "restart") { + return restart_instances(&config); + } else if (command[0] == "server") { Server server(&config); if (server.start() == false) { diff --git a/src/logging.cpp b/src/logging.cpp index b5c080b2..947eb2bb 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -136,30 +136,38 @@ static void initLogging(Config *config, std::string key, bool only_create_dir = p.setProperty("id", id); #endif - std::string dir; + std::vector dirs; BOOST_FOREACH(const log4cxx::LogString &prop, p.propertyNames()) { -// if (boost::ends_with(prop, ".File")) { + if (boost::ends_with(prop, ".File")) { + std::string dir; log4cxx::helpers::Transcoder::encode(p.get(prop), dir); boost::replace_all(dir, "${jid}", jid); boost::replace_all(dir, "${pid}", pid); boost::replace_all(dir, "${id}", id); - break; -// } + dirs.push_back(dir); + } } mode_t old_cmask; - if (!dir.empty()) { - // create directories + // create directories #ifndef WIN32 - old_cmask = umask(0007); + old_cmask = umask(0007); #endif - try { - Transport::Util::createDirectories(config, boost::filesystem::path(dir).parent_path()); - } - catch (const boost::filesystem::filesystem_error &e) { - std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ": " << e.what() << ".\n"; + + BOOST_FOREACH(std::string &dir, dirs) { + if (!dir.empty()) { + try { + Transport::Util::createDirectories(config, boost::filesystem::path(dir).parent_path()); + } + catch (const boost::filesystem::filesystem_error &e) { + std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ": " << e.what() << ".\n"; + } } } +#ifndef WIN32 + umask(old_cmask); +#endif + if (only_create_dir) { return; } @@ -168,24 +176,20 @@ static void initLogging(Config *config, std::string key, bool only_create_dir = // Change owner of main log file #ifndef WIN32 - if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { - struct group *gr; - if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { - std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; + BOOST_FOREACH(std::string &dir, dirs) { + if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { + struct group *gr; + if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; + } + struct passwd *pw; + if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; + } + chown(dir.c_str(), pw->pw_uid, gr->gr_gid); } - struct passwd *pw; - if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { - std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; - } - chown(dir.c_str(), pw->pw_uid, gr->gr_gid); } #endif - -#ifndef WIN32 - if (!dir.empty()) { - umask(old_cmask); - } -#endif } } From 22270d1b616ab3bc7aaa182fcedb6dccecc463bf Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 22 Jan 2013 09:23:02 +0100 Subject: [PATCH 03/57] Remove bad logging messages --- src/userregistry.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/userregistry.cpp b/src/userregistry.cpp index 8d8a3975..2b7e358c 100644 --- a/src/userregistry.cpp +++ b/src/userregistry.cpp @@ -79,9 +79,6 @@ void UserRegistry::stopLogin(const Swift::JID& user, Swift::ServerFromClientSess LOG4CXX_WARN(logger, key << ": Stopping login process (user probably disconnected while logging in), but this is not active session"); } } - else { - LOG4CXX_WARN(logger, key << ": Stopping login process (user probably disconnected while logging in) for invalid user"); - } // ::removeLater can be called only by libtransport, not by Swift and libtransport // takes care about user disconnecting itself, so don't call our signal. @@ -96,9 +93,6 @@ void UserRegistry::onPasswordValid(const Swift::JID &user) { users[key].session->handlePasswordValid(); users.erase(key); } - else { - LOG4CXX_INFO(logger, key << ": onPasswordValid called for invalid user"); - } } void UserRegistry::onPasswordInvalid(const Swift::JID &user, const std::string &error) { @@ -108,9 +102,6 @@ void UserRegistry::onPasswordInvalid(const Swift::JID &user, const std::string & users[key].session->handlePasswordInvalid(error); users.erase(key); } - else { - LOG4CXX_INFO(logger, key << ": onPasswordInvalid called for invalid user"); - } } void UserRegistry::handleRemoveTimeout(const Swift::JID &user) { From 58f50c754489d9712ce0dd6ba0361fc4b4ac9985 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 22 Jan 2013 09:28:26 +0100 Subject: [PATCH 04/57] better error message for server mode --- src/userregistry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/userregistry.cpp b/src/userregistry.cpp index 2b7e358c..c6cbdf32 100644 --- a/src/userregistry.cpp +++ b/src/userregistry.cpp @@ -98,7 +98,7 @@ void UserRegistry::onPasswordValid(const Swift::JID &user) { void UserRegistry::onPasswordInvalid(const Swift::JID &user, const std::string &error) { std::string key = user.toBare().toString(); if (users.find(key) != users.end()) { - LOG4CXX_INFO(logger, key << ": Password is invalid"); + LOG4CXX_INFO(logger, key << ": Password is invalid or there was an error when connecting the legacy network"); users[key].session->handlePasswordInvalid(error); users.erase(key); } From 5a0f94d26e4567ab57c2ee32376a375ab83c3498 Mon Sep 17 00:00:00 2001 From: Darchigh Date: Tue, 22 Jan 2013 09:49:18 +0100 Subject: [PATCH 05/57] Check if just being registered or normal login before doing remoteRosterPush --- src/rostermanager.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 449cd744..daabf440 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -281,12 +281,14 @@ void RosterManager::handleRemoteRosterResponse(boost::shared_ptrgetJID().toString() << ": This server supports remote roster protoXEP"); m_supportRemoteRoster = true; - //If we receive empty RosterPayload initiate full RosterPush - if(payload->getItems().empty()){ - LOG4CXX_INFO(logger, "Received empty Roster. Pushing full Roster."); - for(std::map, boost::pool_allocator< std::pair > >::const_iterator c_it = m_buddies.begin(); - c_it != m_buddies.end(); c_it++) { - sendBuddyRosterPush(c_it->second); + //If we receive empty RosterPayload on login (not register) initiate full RosterPush + if(!m_buddies.empty()){ + if(payload->getItems().empty()){ + LOG4CXX_INFO(logger, "Received empty Roster upon login. Pushing full Roster."); + for(std::map, boost::pool_allocator< std::pair > >::const_iterator c_it = m_buddies.begin(); + c_it != m_buddies.end(); c_it++) { + sendBuddyRosterPush(c_it->second); + } } } return; From 799350e23fbf09f2dd15b1db378e7b898b0d88e8 Mon Sep 17 00:00:00 2001 From: Darchigh Date: Tue, 22 Jan 2013 10:29:36 +0100 Subject: [PATCH 06/57] Small change... --- src/rostermanager.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index daabf440..1cfedd0f 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -282,14 +282,12 @@ void RosterManager::handleRemoteRosterResponse(boost::shared_ptrgetItems().empty()){ + if(!m_buddies.empty() && payload->getItems().empty()){ LOG4CXX_INFO(logger, "Received empty Roster upon login. Pushing full Roster."); for(std::map, boost::pool_allocator< std::pair > >::const_iterator c_it = m_buddies.begin(); c_it != m_buddies.end(); c_it++) { sendBuddyRosterPush(c_it->second); } - } } return; From 943990e76464a78de93590c6183541137898531b Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 22 Jan 2013 11:59:51 +0100 Subject: [PATCH 07/57] Show all resources of particular user when disconnecting to make debugging easier --- src/user.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/user.cpp b/src/user.cpp index a142fefc..442a34a1 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -320,6 +320,21 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { if (presence->getType() == Swift::Presence::Unavailable) { m_conversationManager->removeJID(presence->getFrom()); + + std::string presences; + std::vector ps = m_presenceOracle->getAllPresence(m_jid); + BOOST_FOREACH(Swift::Presence::ref p, ps) { + if (p != presence) { + presences += p->getFrom().toString() + " "; + } + }; + + if (!presences.empty()) { + LOG4CXX_INFO(logger, m_jid.toString() << ": User is still connected from following clients: " << presences); + } + else { + LOG4CXX_INFO(logger, m_jid.toString() << ": Last client disconnected"); + } } From 96aad929c0d2a3e6d7fcac3abd026ceb8382ce4b Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 22 Jan 2013 13:32:03 +0100 Subject: [PATCH 08/57] Communi: Compare lowercased names of channels --- backends/libcommuni/session.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index c8b271f6..64993a6c 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -96,9 +96,9 @@ void MyIrcSession::on_joined(IrcMessage *message) { bool op = 0; std::string nickname = TO_UTF8(m->sender().name()); op = correctNickname(nickname); - getIRCBuddy(TO_UTF8(m->channel()), nickname).setOp(op); - np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix, op, pbnetwork::STATUS_ONLINE); - LOG4CXX_INFO(logger, user << ": " << nickname << " joined " << TO_UTF8(m->channel()) + suffix); + getIRCBuddy(TO_UTF8(m->channel().toLower()), nickname).setOp(op); + np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel().toLower()) + suffix, op, pbnetwork::STATUS_ONLINE); + LOG4CXX_INFO(logger, user << ": " << nickname << " joined " << TO_UTF8(m->channel().toLower()) + suffix); } @@ -107,9 +107,9 @@ void MyIrcSession::on_parted(IrcMessage *message) { bool op = 0; std::string nickname = TO_UTF8(m->sender().name()); op = correctNickname(nickname); - removeIRCBuddy(TO_UTF8(m->channel()), nickname); - LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << TO_UTF8(m->channel()) + suffix); - np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix, op, pbnetwork::STATUS_NONE, TO_UTF8(m->reason())); + removeIRCBuddy(TO_UTF8(m->channel().toLower()), nickname); + LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << TO_UTF8(m->channel().toLower()) + suffix); + np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel().toLower()) + suffix, op, pbnetwork::STATUS_NONE, TO_UTF8(m->reason())); } void MyIrcSession::on_quit(IrcMessage *message) { @@ -172,7 +172,7 @@ void MyIrcSession::on_topicChanged(IrcMessage *message) { correctNickname(nickname); LOG4CXX_INFO(logger, user << ": " << nickname << " topic changed to " << TO_UTF8(m->topic())); - np->handleSubject(user, TO_UTF8(m->channel()) + suffix, TO_UTF8(m->topic()), nickname); + np->handleSubject(user, TO_UTF8(m->channel().toLower()) + suffix, TO_UTF8(m->topic()), nickname); } void MyIrcSession::on_messageReceived(IrcMessage *message) { @@ -190,7 +190,7 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) { msg = QString("/me ") + msg; } - std::string target = TO_UTF8(m->target()); + std::string target = TO_UTF8(m->target().toLower()); LOG4CXX_INFO(logger, user << ": Message from " << target); if (target.find("#") == 0) { std::string nickname = TO_UTF8(m->sender().name()); @@ -229,10 +229,10 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { if (nick.find("/") != std::string::npos) { nick = nick.substr(0, nick.find("/")); } - np->handleSubject(user, TO_UTF8(parameters[1]) + suffix, m_topicData, nick); + np->handleSubject(user, TO_UTF8(parameters[1].toLower()) + suffix, m_topicData, nick); break; case 352: { - channel = parameters[1]; + channel = parameters[1].toLower(); nick = TO_UTF8(parameters[5]); IRCBuddy &buddy = getIRCBuddy(TO_UTF8(channel), nick); @@ -249,7 +249,7 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { break; } case 353: - channel = parameters[2]; + channel = parameters[2].toLower(); members = parameters[3].split(" "); LOG4CXX_INFO(logger, user << ": Received members for " << TO_UTF8(channel) << suffix); @@ -265,7 +265,7 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { break; case 366: // ask /who to get away states - channel = parameters[1]; + channel = parameters[1].toLower(); LOG4CXX_INFO(logger, user << "Asking /who for channel " << TO_UTF8(channel)); sendCommand(IrcCommand::createWho(channel)); break; From 9238df73bd4922df2b79d6b7bc3e94b90f4c8f12 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 22 Jan 2013 21:20:48 +0100 Subject: [PATCH 09/57] Make log4cxx required on linux --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c5e63bc5..60544139 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ option(ENABLE_TWITTER "Build Twitter plugin" ON) option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) option(ENABLE_DOCS "Build Docs" ON) -option(ENABLE_LOG "Build with logging using Log4cxx" ON) +# option(ENABLE_LOG "Build with logging using Log4cxx" ON) option(ENABLE_TESTS "Build Tests using CppUnit" OFF) MACRO(LIST_CONTAINS var value) @@ -225,7 +225,7 @@ if(ENABLE_DOCS) find_package(Doxygen) endif() -if(ENABLE_LOG) +# if(ENABLE_LOG) if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) set(LOG4CXX_FOUND 1) @@ -234,7 +234,7 @@ if(ENABLE_LOG) set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(log4cxx) endif() -endif() +# endif() # FIND CPPUNIT if(ENABLE_TESTS) @@ -423,10 +423,10 @@ if (LOG4CXX_FOUND) ADD_DEFINITIONS(-DWITH_LOG4CXX) else() set(LOG4CXX_LIBRARIES "") - if(ENABLE_LOG) + if (WIN32) message("Log4cxx : no (install log4cxx-devel)") - else(ENABLE_LOG) - message("Log4cxx : no (user disabled)") + else() + message(FATAL_ERROR "Log4cxx : no (install log4cxx-devel)") endif() endif() From cc64a76c8be5f344ab0645e2797e319c0b5b32cc Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 23 Jan 2013 11:29:43 +0100 Subject: [PATCH 10/57] Replace #include "Swiften/Swiften.h" by particular headers. 25% compilation speedup. --- include/transport/adhoccommand.h | 4 +++- include/transport/adhoccommandfactory.h | 1 - include/transport/adhocmanager.h | 5 +++- include/transport/admininterface.h | 3 ++- include/transport/buddy.h | 2 +- include/transport/conversation.h | 1 - include/transport/conversationmanager.h | 3 ++- include/transport/discoitemsresponder.h | 2 +- include/transport/factory.h | 1 - include/transport/gatewayresponder.h | 1 - include/transport/memoryreadbytestream.h | 3 ++- include/transport/mysqlbackend.h | 1 - include/transport/networkpluginserver.h | 4 +++- include/transport/pqxxbackend.h | 1 - include/transport/rostermanager.h | 6 ++++- include/transport/rosterresponder.h | 3 ++- include/transport/rosterstorage.h | 4 +++- include/transport/settingsadhoccommand.h | 1 - include/transport/sqlite3backend.h | 1 - include/transport/statsresponder.h | 1 - include/transport/threadpool.h | 2 +- include/transport/transport.h | 30 ++++++++++++++---------- include/transport/user.h | 3 ++- include/transport/usermanager.h | 6 ++++- include/transport/userregistration.h | 3 ++- include/transport/userregistry.h | 4 +++- include/transport/usersreconnecter.h | 3 ++- include/transport/vcardresponder.h | 4 +++- spectrum/src/main.cpp | 1 + src/blockresponder.cpp | 1 - src/blockresponder.h | 2 +- src/buddy.cpp | 2 ++ src/conversation.cpp | 5 ++++ src/discoinforesponder.cpp | 2 +- src/discoinforesponder.h | 3 ++- src/discoitemsresponder.cpp | 1 - src/filetransfermanager.cpp | 1 + src/gatewayresponder.cpp | 1 - src/networkpluginserver.cpp | 8 ++++++- src/presenceoracle.cpp | 2 +- src/rostermanager.cpp | 3 +++ src/rosterresponder.cpp | 1 - src/rosterstorage.cpp | 2 ++ src/statsresponder.cpp | 1 - src/storagebackend.cpp | 2 +- src/storageresponder.cpp | 4 +++- src/storageresponder.h | 2 +- src/tests/userregistry.cpp | 2 ++ src/transport.cpp | 2 +- src/user.cpp | 1 - src/usermanager.cpp | 3 ++- src/userregistration.cpp | 3 +++ src/userregistry.cpp | 1 - src/usersreconnecter.cpp | 3 ++- src/vcardresponder.cpp | 1 - 55 files changed, 104 insertions(+), 59 deletions(-) diff --git a/include/transport/adhoccommand.h b/include/transport/adhoccommand.h index 24dbe8e6..e1734b12 100644 --- a/include/transport/adhoccommand.h +++ b/include/transport/adhoccommand.h @@ -23,7 +23,9 @@ #include #include #include -#include "Swiften/Swiften.h" + +#include "Swiften/Elements/FormField.h" +#include "Swiften/Elements/Command.h" namespace Transport { diff --git a/include/transport/adhoccommandfactory.h b/include/transport/adhoccommandfactory.h index 93c9d4a5..859421c5 100644 --- a/include/transport/adhoccommandfactory.h +++ b/include/transport/adhoccommandfactory.h @@ -24,7 +24,6 @@ #include #include #include "transport/adhoccommand.h" -#include "Swiften/Swiften.h" namespace Transport { diff --git a/include/transport/adhocmanager.h b/include/transport/adhocmanager.h index 8b418640..b8f77f87 100644 --- a/include/transport/adhocmanager.h +++ b/include/transport/adhocmanager.h @@ -23,7 +23,10 @@ #include #include #include -#include "Swiften/Swiften.h" + +#include "Swiften/Queries/Responder.h" +#include "Swiften/Elements/Command.h" +#include "Swiften/Network/Timer.h" namespace Transport { diff --git a/include/transport/admininterface.h b/include/transport/admininterface.h index 48f85dc1..3ab03941 100644 --- a/include/transport/admininterface.h +++ b/include/transport/admininterface.h @@ -22,7 +22,8 @@ #include #include -#include "Swiften/Swiften.h" + +#include "Swiften/Elements/Message.h" namespace Transport { diff --git a/include/transport/buddy.h b/include/transport/buddy.h index e11ed425..06792dc8 100644 --- a/include/transport/buddy.h +++ b/include/transport/buddy.h @@ -23,8 +23,8 @@ #include #include #include "transport/transport.h" +#include "Swiften/Elements/VCard.h" -#include "Swiften/Swiften.h" namespace Transport { diff --git a/include/transport/conversation.h b/include/transport/conversation.h index 121794d6..eb2885f8 100644 --- a/include/transport/conversation.h +++ b/include/transport/conversation.h @@ -24,7 +24,6 @@ #include #include "transport/transport.h" -#include "Swiften/Swiften.h" #include "Swiften/Elements/Message.h" namespace Transport { diff --git a/include/transport/conversationmanager.h b/include/transport/conversationmanager.h index 0ef2842f..7aa606bf 100644 --- a/include/transport/conversationmanager.h +++ b/include/transport/conversationmanager.h @@ -23,7 +23,8 @@ #include #include #include -#include "Swiften/Swiften.h" + +#include "Swiften/Elements/Message.h" namespace Transport { diff --git a/include/transport/discoitemsresponder.h b/include/transport/discoitemsresponder.h index ddc1a2af..ff12cdcf 100644 --- a/include/transport/discoitemsresponder.h +++ b/include/transport/discoitemsresponder.h @@ -21,9 +21,9 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/GetResponder.h" #include "Swiften/Elements/DiscoItems.h" +#include "Swiften/Elements/CapsInfo.h" namespace Transport { diff --git a/include/transport/factory.h b/include/transport/factory.h index 0c4595d7..7df6e252 100644 --- a/include/transport/factory.h +++ b/include/transport/factory.h @@ -24,7 +24,6 @@ #include #include "transport/transport.h" -#include "Swiften/Swiften.h" #include "Swiften/Elements/Message.h" #include "transport/conversation.h" #include "transport/buddy.h" diff --git a/include/transport/gatewayresponder.h b/include/transport/gatewayresponder.h index 8cefedbe..59b765ea 100644 --- a/include/transport/gatewayresponder.h +++ b/include/transport/gatewayresponder.h @@ -21,7 +21,6 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/Responder.h" #include "Swiften/Elements/GatewayPayload.h" diff --git a/include/transport/memoryreadbytestream.h b/include/transport/memoryreadbytestream.h index 0f423a55..cb36389f 100644 --- a/include/transport/memoryreadbytestream.h +++ b/include/transport/memoryreadbytestream.h @@ -22,7 +22,8 @@ #include #include -#include "Swiften/Swiften.h" + +#include "Swiften/FileTransfer/ReadBytestream.h" namespace Transport { diff --git a/include/transport/mysqlbackend.h b/include/transport/mysqlbackend.h index eeb0a65f..60733240 100644 --- a/include/transport/mysqlbackend.h +++ b/include/transport/mysqlbackend.h @@ -24,7 +24,6 @@ #include #include -#include "Swiften/Swiften.h" #include "transport/storagebackend.h" #include "transport/config.h" #include "mysql.h" diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index b5aa0b71..322e2048 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -21,11 +21,13 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Presence/PresenceOracle.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Network/BoostConnectionServer.h" #include "Swiften/Network/Connection.h" +#include "Swiften/Elements/ChatState.h" +#include "Swiften/Elements/RosterItemPayload.h" +#include "Swiften/Elements/VCard.h" #include "storagebackend.h" #include "transport/filetransfermanager.h" diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index bf5abf25..5ec0c409 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -24,7 +24,6 @@ #include #include -#include "Swiften/Swiften.h" #include "transport/storagebackend.h" #include "transport/config.h" #include diff --git a/include/transport/rostermanager.h b/include/transport/rostermanager.h index fd649b57..fbd652ff 100644 --- a/include/transport/rostermanager.h +++ b/include/transport/rostermanager.h @@ -25,8 +25,12 @@ #include #include #include -#include "Swiften/Swiften.h" // #include "rosterstorage.h" +#include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Queries/GenericRequest.h" +#include "Swiften/Roster/SetRosterRequest.h" +#include "Swiften/Elements/Presence.h" +#include "Swiften/Network/Timer.h" namespace Transport { diff --git a/include/transport/rosterresponder.h b/include/transport/rosterresponder.h index f716ddcd..4aaa2138 100644 --- a/include/transport/rosterresponder.h +++ b/include/transport/rosterresponder.h @@ -21,10 +21,11 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/Responder.h" #include "Swiften/Elements/RosterPayload.h" +#include + namespace Transport { class UserManager; diff --git a/include/transport/rosterstorage.h b/include/transport/rosterstorage.h index 726425c4..21703442 100644 --- a/include/transport/rosterstorage.h +++ b/include/transport/rosterstorage.h @@ -22,7 +22,9 @@ #include #include -#include "Swiften/Swiften.h" +#include + +#include "Swiften/Network/Timer.h" namespace Transport { diff --git a/include/transport/settingsadhoccommand.h b/include/transport/settingsadhoccommand.h index 3a2450a1..02eff3d9 100644 --- a/include/transport/settingsadhoccommand.h +++ b/include/transport/settingsadhoccommand.h @@ -23,7 +23,6 @@ #include #include #include -#include "Swiften/Swiften.h" #include "transport/adhoccommand.h" #include "transport/adhoccommandfactory.h" diff --git a/include/transport/sqlite3backend.h b/include/transport/sqlite3backend.h index d654ffa6..3c6411ca 100644 --- a/include/transport/sqlite3backend.h +++ b/include/transport/sqlite3backend.h @@ -24,7 +24,6 @@ #include #include -#include "Swiften/Swiften.h" #include "transport/storagebackend.h" #include "transport/config.h" #include "sqlite3.h" diff --git a/include/transport/statsresponder.h b/include/transport/statsresponder.h index ecdd331f..8f7fd8b6 100644 --- a/include/transport/statsresponder.h +++ b/include/transport/statsresponder.h @@ -21,7 +21,6 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/SetResponder.h" #include "Swiften/Elements/StatsPayload.h" diff --git a/include/transport/threadpool.h b/include/transport/threadpool.h index 6f498afa..27cb1a08 100644 --- a/include/transport/threadpool.h +++ b/include/transport/threadpool.h @@ -7,7 +7,7 @@ #include #include #include "transport/logging.h" -#include "Swiften/Swiften.h" +#include "Swiften/EventLoop/EventLoop.h" /* diff --git a/include/transport/transport.h b/include/transport/transport.h index c69ca396..b27ddd37 100644 --- a/include/transport/transport.h +++ b/include/transport/transport.h @@ -21,7 +21,6 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Server/Server.h" #include "Swiften/Disco/GetDiscoInfoRequest.h" #include "Swiften/Disco/EntityCapsManager.h" @@ -32,6 +31,8 @@ #include "Swiften/Server/UserRegistry.h" #include "Swiften/Base/SafeByteArray.h" #include "Swiften/Jingle/JingleSessionManager.h" +#include "Swiften/Component/ComponentError.h" +#include "Swiften/Component/Component.h" #include #include "transport/config.h" @@ -40,12 +41,6 @@ #include namespace Transport { - // typedef enum { CLIENT_FEATURE_ROSTERX = 2, - // CLIENT_FEATURE_XHTML_IM = 4, - // CLIENT_FEATURE_FILETRANSFER = 8, - // CLIENT_FEATURE_CHATSTATES = 16 - // } SpectrumImportantFeatures; - // class StorageBackend; class Factory; class UserRegistry; @@ -68,7 +63,9 @@ namespace Transport { /// - service.server /// - service.port /// - service.server_mode + /// \param factories Swift::NetworkFactories. /// \param factory Transport Abstract factory used to create basic transport structures. + /// \param userRegistery UserRegistry class instance. It's needed only when running transport in server-mode. Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, Config *config, Factory *factory, Transport::UserRegistry *userRegistry = NULL); /// Component destructor. @@ -96,9 +93,13 @@ namespace Transport { /// \return True if the component is in server mode. bool inServerMode() { return m_server != NULL; } - /// Connects the Jabber server. - + /// Starts the Component. + + /// In server-mode, it starts listening on particular port for new client connections. + /// In gateway-mode, it connects the XMPP server. void start(); + + /// Stops the component. void stop(); /// Returns Jabber ID of this transport. @@ -139,14 +140,17 @@ namespace Transport { /// This signal is emitted when presence from XMPP user is received. /// It's emitted only for presences addressed to transport itself - /// (for example to="j2j.domain.tld"). - /// \param presence presence data + /// (for example to="j2j.domain.tld") and for presences comming to + /// MUC (for example to="#chat%irc.freenode.org@irc.domain.tld") + /// \param presence Presence. boost::signal onUserPresenceReceived; + /// Component class asks the XMPP clients automatically for their capabilities. + /// This signal is emitted when capabilities have been received or changed. + /// \param jid JID of the client for which we received capabilities + /// \param info disco#info with response. boost::signal info)> onUserDiscoInfoReceived; -// boost::signal info, Swift::ErrorPayload::ref error, const Swift::JID& jid)> onDiscoInfoResponse; - private: void handleConnected(); void handleConnectionError(const Swift::ComponentError &error); diff --git a/include/transport/user.h b/include/transport/user.h index f7752f07..580fda41 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -21,12 +21,13 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Disco/EntityCapsManager.h" #include "Swiften/Disco/EntityCapsProvider.h" #include "storagebackend.h" #include #include "Swiften/Elements/SpectrumErrorPayload.h" +#include "Swiften/Network/Timer.h" +#include "Swiften/Network/Connection.h" namespace Transport { diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 38a5c7bc..4ccefb53 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -22,8 +22,12 @@ #include #include -#include "Swiften/Swiften.h" #include "transport/userregistry.h" +#include "Swiften/Elements/Message.h" +#include "Swiften/Elements/Presence.h" +#include "Swiften/Disco/EntityCapsProvider.h" +#include "Swiften/Elements/DiscoInfo.h" +#include "Swiften/Network/Timer.h" namespace Transport { diff --git a/include/transport/userregistration.h b/include/transport/userregistration.h index 2e9b6136..1c994423 100644 --- a/include/transport/userregistration.h +++ b/include/transport/userregistration.h @@ -20,9 +20,10 @@ #pragma once -#include "Swiften/Swiften.h" #include "Swiften/Queries/Responder.h" #include "Swiften/Elements/InBandRegistrationPayload.h" +#include "Swiften/Elements/RosterPayload.h" +#include namespace Transport { diff --git a/include/transport/userregistry.h b/include/transport/userregistry.h index 0b6cac14..58590a01 100644 --- a/include/transport/userregistry.h +++ b/include/transport/userregistry.h @@ -22,8 +22,10 @@ #include #include -#include "Swiften/Swiften.h" #include "Swiften/Server/UserRegistry.h" +#include "Swiften/Network/NetworkFactories.h" +#include "Swiften/Network/Timer.h" +#include "Swiften/Network/TimerFactory.h" #include "transport/config.h" namespace Transport { diff --git a/include/transport/usersreconnecter.h b/include/transport/usersreconnecter.h index 52497e64..0c813b0c 100644 --- a/include/transport/usersreconnecter.h +++ b/include/transport/usersreconnecter.h @@ -23,7 +23,8 @@ #include #include #include -#include "Swiften/Swiften.h" + +#include "Swiften/Network/Timer.h" namespace Transport { diff --git a/include/transport/vcardresponder.h b/include/transport/vcardresponder.h index 156a95e4..852500e2 100644 --- a/include/transport/vcardresponder.h +++ b/include/transport/vcardresponder.h @@ -21,9 +21,11 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/Responder.h" #include "Swiften/Elements/VCard.h" +#include "Swiften/Network/NetworkFactories.h" +#include "Swiften/Network/Timer.h" +#include namespace Transport { diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index a024138e..176c618d 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -17,6 +17,7 @@ #include "transport/adhocmanager.h" #include "transport/settingsadhoccommand.h" #include "Swiften/EventLoop/SimpleEventLoop.h" +#include "Swiften/Network/BoostNetworkFactories.h" #include #include #ifndef WIN32 diff --git a/src/blockresponder.cpp b/src/blockresponder.cpp index 708fec43..6a5ad41c 100644 --- a/src/blockresponder.cpp +++ b/src/blockresponder.cpp @@ -24,7 +24,6 @@ #include #include "Swiften/Queries/IQRouter.h" #include "transport/BlockPayload.h" -#include "Swiften/Swiften.h" #include "transport/usermanager.h" #include "transport/user.h" #include "transport/buddy.h" diff --git a/src/blockresponder.h b/src/blockresponder.h index 8f77bea8..ed415502 100644 --- a/src/blockresponder.h +++ b/src/blockresponder.h @@ -21,9 +21,9 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/SetResponder.h" #include "transport/BlockPayload.h" +#include namespace Transport { diff --git a/src/buddy.cpp b/src/buddy.cpp index eb5388f5..300053cf 100644 --- a/src/buddy.cpp +++ b/src/buddy.cpp @@ -26,6 +26,8 @@ #include "transport/usermanager.h" #include "transport/discoitemsresponder.h" +#include "Swiften/Elements/VCardUpdate.h" + namespace Transport { Buddy::Buddy(RosterManager *rosterManager, long id, BuddyFlag flags) : m_id(id), m_flags(flags), m_rosterManager(rosterManager), diff --git a/src/conversation.cpp b/src/conversation.cpp index 1a8b8383..6074fc78 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -26,6 +26,11 @@ #include "transport/buddy.h" #include "transport/rostermanager.h" +#include "Swiften/Elements/MUCItem.h" +#include "Swiften/Elements/MUCOccupant.h" +#include "Swiften/Elements/MUCUserPayload.h" +#include "Swiften/Elements/Delay.h" + namespace Transport { Conversation::Conversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMUC) : m_conversationManager(conversationManager) { diff --git a/src/discoinforesponder.cpp b/src/discoinforesponder.cpp index 15ce1544..448ec17d 100644 --- a/src/discoinforesponder.cpp +++ b/src/discoinforesponder.cpp @@ -26,9 +26,9 @@ #include "Swiften/Disco/DiscoInfoResponder.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Elements/DiscoInfo.h" -#include "Swiften/Swiften.h" #include "transport/config.h" #include "transport/logging.h" +#include "Swiften/Disco/CapsInfoGenerator.h" using namespace Swift; using namespace boost; diff --git a/src/discoinforesponder.h b/src/discoinforesponder.h index 0ce5883b..33dfe6b8 100644 --- a/src/discoinforesponder.h +++ b/src/discoinforesponder.h @@ -21,7 +21,8 @@ #pragma once #include -#include "Swiften/Swiften.h" +#include +#include #include "Swiften/Queries/GetResponder.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Elements/CapsInfo.h" diff --git a/src/discoitemsresponder.cpp b/src/discoitemsresponder.cpp index 72ac8390..90c153ea 100644 --- a/src/discoitemsresponder.cpp +++ b/src/discoitemsresponder.cpp @@ -23,7 +23,6 @@ #include #include #include "Swiften/Queries/IQRouter.h" -#include "Swiften/Swiften.h" #include "transport/transport.h" #include "transport/logging.h" #include "discoinforesponder.h" diff --git a/src/filetransfermanager.cpp b/src/filetransfermanager.cpp index 73c08a86..dd893fb1 100644 --- a/src/filetransfermanager.cpp +++ b/src/filetransfermanager.cpp @@ -24,6 +24,7 @@ #include "transport/user.h" #include "transport/buddy.h" #include "transport/logging.h" +#include "Swiften/Network/ConnectionServerFactory.h" namespace Transport { diff --git a/src/gatewayresponder.cpp b/src/gatewayresponder.cpp index 5a268312..1306a9da 100644 --- a/src/gatewayresponder.cpp +++ b/src/gatewayresponder.cpp @@ -24,7 +24,6 @@ #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" diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 2493d630..dd4ced39 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -34,18 +34,24 @@ #include "transport/logging.h" #include "transport/admininterface.h" #include "blockresponder.h" -#include "Swiften/Swiften.h" #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Elements/StreamError.h" #include "Swiften/Network/BoostConnectionServer.h" +#include "Swiften/Network/ConnectionServerFactory.h" #include "Swiften/Elements/AttentionPayload.h" #include "Swiften/Elements/XHTMLIMPayload.h" +#include "Swiften/Elements/Delay.h" +#include "Swiften/Elements/DeliveryReceipt.h" +#include "Swiften/Elements/DeliveryReceiptRequest.h" #include "Swiften/Elements/InvisiblePayload.h" #include "Swiften/Elements/SpectrumErrorPayload.h" #include "transport/protocol.pb.h" #include "transport/util.h" #include "transport/discoitemsresponder.h" +#include "boost/date_time/posix_time/posix_time.hpp" +#include "boost/signal.hpp" + #include "utf8.h" #include diff --git a/src/presenceoracle.cpp b/src/presenceoracle.cpp index a846a061..49284321 100644 --- a/src/presenceoracle.cpp +++ b/src/presenceoracle.cpp @@ -19,7 +19,7 @@ */ #include "transport/presenceoracle.h" -#include "Swiften/Swiften.h" +#include "Swiften/Elements/MUCPayload.h" #include diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 1cfedd0f..8e6dcbef 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -30,7 +30,10 @@ #include "Swiften/Elements/RosterPayload.h" #include "Swiften/Elements/RosterItemPayload.h" #include "Swiften/Elements/RosterItemExchangePayload.h" +#include "Swiften/Elements/Nickname.h" +#include "Swiften/Queries/IQRouter.h" #include +#include #include #include diff --git a/src/rosterresponder.cpp b/src/rosterresponder.cpp index 6bc496c1..109f30c5 100644 --- a/src/rosterresponder.cpp +++ b/src/rosterresponder.cpp @@ -23,7 +23,6 @@ #include #include #include "Swiften/Queries/IQRouter.h" -#include "Swiften/Swiften.h" #include "transport/user.h" #include "transport/usermanager.h" #include "transport/rostermanager.h" diff --git a/src/rosterstorage.cpp b/src/rosterstorage.cpp index 34a40b3a..eacc205d 100644 --- a/src/rosterstorage.cpp +++ b/src/rosterstorage.cpp @@ -24,6 +24,8 @@ #include "transport/storagebackend.h" #include "transport/logging.h" +#include "Swiften/Network/NetworkFactories.h" + DEFINE_LOGGER(logger, "RosterStorage"); namespace Transport { diff --git a/src/statsresponder.cpp b/src/statsresponder.cpp index 4ba24e71..faed68b0 100644 --- a/src/statsresponder.cpp +++ b/src/statsresponder.cpp @@ -24,7 +24,6 @@ #include #include "Swiften/Queries/IQRouter.h" #include "transport/BlockPayload.h" -#include "Swiften/Swiften.h" #include "transport/usermanager.h" #include "transport/user.h" #include "transport/buddy.h" diff --git a/src/storagebackend.cpp b/src/storagebackend.cpp index ce27dfae..7714df36 100644 --- a/src/storagebackend.cpp +++ b/src/storagebackend.cpp @@ -4,8 +4,8 @@ #include "transport/sqlite3backend.h" #include "transport/mysqlbackend.h" #include "transport/pqxxbackend.h" +#include "Swiften/StringCodecs/Base64.h" -#include "Swiften/Swiften.h" namespace Transport { diff --git a/src/storageresponder.cpp b/src/storageresponder.cpp index 1b3d2aa9..607dca20 100644 --- a/src/storageresponder.cpp +++ b/src/storageresponder.cpp @@ -24,7 +24,9 @@ #include #include "Swiften/Queries/IQRouter.h" #include "Swiften/Elements/RawXMLPayload.h" -#include "Swiften/Swiften.h" +#include "Swiften/Elements/Storage.h" +#include "Swiften/Elements/Storage.h" +#include "Swiften/Serializer/PayloadSerializers/StorageSerializer.h" #include "transport/usermanager.h" #include "transport/user.h" #include "transport/logging.h" diff --git a/src/storageresponder.h b/src/storageresponder.h index 0bf033cb..c92691ba 100644 --- a/src/storageresponder.h +++ b/src/storageresponder.h @@ -21,9 +21,9 @@ #pragma once #include -#include "Swiften/Swiften.h" #include "Swiften/Queries/Responder.h" #include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Elements/PrivateStorage.h" namespace Transport { diff --git a/src/tests/userregistry.cpp b/src/tests/userregistry.cpp index 9b5a7aa0..7e567cfd 100644 --- a/src/tests/userregistry.cpp +++ b/src/tests/userregistry.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include using namespace Transport; diff --git a/src/transport.cpp b/src/transport.cpp index 7bd92b4d..16e2de68 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -51,7 +51,7 @@ #include "transport/BlockSerializer.h" #include "Swiften/Parser/PayloadParsers/InvisibleParser.h" #include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.h" -#include "Swiften/Swiften.h" +#include "Swiften/Parser/GenericPayloadParserFactory.h" using namespace Swift; using namespace boost; diff --git a/src/user.cpp b/src/user.cpp index 442a34a1..0046ae30 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -26,7 +26,6 @@ #include "transport/conversationmanager.h" #include "transport/presenceoracle.h" #include "transport/logging.h" -#include "Swiften/Swiften.h" #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Elements/StreamError.h" #include "Swiften/Elements/MUCPayload.h" diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 61872258..eb091156 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -29,9 +29,10 @@ #include "transport/discoitemsresponder.h" #include "storageresponder.h" -#include "Swiften/Swiften.h" #include "Swiften/Server/ServerStanzaChannel.h" #include "Swiften/Elements/StreamError.h" +#include "Swiften/Elements/MUCPayload.h" +#include "Swiften/Elements/ChatState.h" #ifndef __FreeBSD__ #include "malloc.h" #endif diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 174587fd..75f2d942 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -26,6 +26,9 @@ #include "transport/user.h" #include "transport/logging.h" #include "Swiften/Elements/ErrorPayload.h" +#include "Swiften/EventLoop/SimpleEventLoop.h" +#include "Swiften/Network/BoostNetworkFactories.h" +#include "Swiften/Client/Client.h" #include #include #include diff --git a/src/userregistry.cpp b/src/userregistry.cpp index c6cbdf32..a740e898 100644 --- a/src/userregistry.cpp +++ b/src/userregistry.cpp @@ -20,7 +20,6 @@ #include #include -#include "Swiften/Swiften.h" #include "Swiften/Server/UserRegistry.h" #include "transport/userregistry.h" #include "transport/logging.h" diff --git a/src/usersreconnecter.cpp b/src/usersreconnecter.cpp index ada0283a..1ba6cfff 100644 --- a/src/usersreconnecter.cpp +++ b/src/usersreconnecter.cpp @@ -23,11 +23,12 @@ #include #include #include "Swiften/Queries/IQRouter.h" -#include "Swiften/Swiften.h" #include "transport/storagebackend.h" #include "transport/transport.h" #include "transport/logging.h" +#include "Swiften/Network/NetworkFactories.h" + using namespace Swift; using namespace boost; diff --git a/src/vcardresponder.cpp b/src/vcardresponder.cpp index 214e94e2..f216c92a 100644 --- a/src/vcardresponder.cpp +++ b/src/vcardresponder.cpp @@ -23,7 +23,6 @@ #include #include #include "Swiften/Queries/IQRouter.h" -#include "Swiften/Swiften.h" #include "transport/user.h" #include "transport/usermanager.h" #include "transport/rostermanager.h" From 1af263f488e879e8f07d55d2e99c6a03c81f7acb Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 23 Jan 2013 19:41:56 +0100 Subject: [PATCH 11/57] make enum for Participant.flags --- include/transport/conversation.h | 17 ++++++++++++----- include/transport/protocol.proto | 10 ++++++++++ src/conversation.cpp | 4 ++-- src/networkpluginserver.cpp | 2 +- 4 files changed, 25 insertions(+), 8 deletions(-) diff --git a/include/transport/conversation.h b/include/transport/conversation.h index eb2885f8..cda549cb 100644 --- a/include/transport/conversation.h +++ b/include/transport/conversation.h @@ -33,15 +33,22 @@ class ConversationManager; /// Represents one XMPP-Legacy network conversation. class Conversation { public: + typedef enum { + PARTICIPANT_FLAG_NONE = 0, + PARTICIPANT_FLAG_MODERATOR = 1, + PARTICIPANT_FLAG_CONFLICT = 2, + PARTICIPANT_FLAG_BANNED = 4, + PARTICIPANT_FLAG_NOT_AUTHORIZED = 8, + PARTICIPANT_FLAG_ME = 16, + PARTICIPANT_FLAG_KICKED = 32 + } ParticipantFlag; + typedef struct _Participant { - int flag; + ParticipantFlag flag; int status; std::string statusMessage; } Participant; - /// Type of participants in MUC rooms. - enum ParticipantFlag {None, Moderator}; - /// Creates new conversation. /// \param conversationManager ConversationManager associated with this Conversation. @@ -70,7 +77,7 @@ class Conversation { /// \param status Current status of this participant. /// \param statusMessage Current status message of this participant. /// \param newname If participant was renamed, this variable contains his new name. - void handleParticipantChanged(const std::string &nickname, int flag, int status = Swift::StatusShow::None, const std::string &statusMessage = "", const std::string &newname = ""); + void handleParticipantChanged(const std::string &nickname, ParticipantFlag flag, int status = Swift::StatusShow::None, const std::string &statusMessage = "", const std::string &newname = ""); /// Sets XMPP user nickname in MUC rooms. diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 316b164e..8eafcde8 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -86,6 +86,16 @@ message RoomList { repeated string name = 2; } +enum ParticipantFlag { + PARTICIPANT_FLAG_NONE = 0; + PARTICIPANT_FLAG_MODERATOR = 1; + PARTICIPANT_FLAG_CONFLICT = 2; + PARTICIPANT_FLAG_BANNED = 4; + PARTICIPANT_FLAG_NOT_AUTHORIZED = 8; + PARTICIPANT_FLAG_ME = 16; + PARTICIPANT_FLAG_KICKED = 32; +} + message Participant { required string userName = 1; required string room = 2; diff --git a/src/conversation.cpp b/src/conversation.cpp index 6074fc78..44af07b4 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -242,7 +242,7 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int item.affiliation = Swift::MUCOccupant::Member; item.role = Swift::MUCOccupant::Participant; - if (flag & Moderator) { + if (flag & PARTICIPANT_FLAG_MODERATOR) { item.affiliation = Swift::MUCOccupant::Admin; item.role = Swift::MUCOccupant::Moderator; } @@ -260,7 +260,7 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int return presence; } -void Conversation::handleParticipantChanged(const std::string &nick, int flag, int status, const std::string &statusMessage, const std::string &newname) { +void Conversation::handleParticipantChanged(const std::string &nick, Conversation::ParticipantFlag flag, int status, const std::string &statusMessage, const std::string &newname) { Swift::Presence::ref presence = generatePresence(nick, flag, status, statusMessage, newname); if (presence->getType() == Swift::Presence::Unavailable) { diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index dd4ced39..bb51b73e 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -625,7 +625,7 @@ void NetworkPluginServer::handleParticipantChangedPayload(const std::string &dat return; } - conv->handleParticipantChanged(payload.nickname(), payload.flag(), payload.status(), payload.statusmessage(), payload.newname()); + conv->handleParticipantChanged(payload.nickname(), (Conversation::ParticipantFlag) payload.flag(), payload.status(), payload.statusmessage(), payload.newname()); } void NetworkPluginServer::handleRoomChangedPayload(const std::string &data) { From 65ad5a210697f9e497ba1511bde24433b9bbee05 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 24 Jan 2013 08:35:24 +0100 Subject: [PATCH 12/57] Communi: Log 4xx errors and forward 433, 436 and 464 to XMPP client --- backends/libcommuni/session.cpp | 20 ++++++++++++ src/conversation.cpp | 29 +++++++++++++---- src/tests/conversationmanager.cpp | 52 +++++++++++++++++++++++++++---- src/tests/user.cpp | 2 +- 4 files changed, 90 insertions(+), 13 deletions(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 64993a6c..203a748a 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -272,6 +272,22 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { case 432: np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname"); break; + case 433: + for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { + np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_CONFLICT); + } + np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Nickname is already in use"); + break; + case 436: + for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { + np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_CONFLICT); + } + np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Nickname collision KILL"); + case 464: + for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { + np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_NOT_AUTHORIZED); + } + np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Password incorrect"); case 321: m_rooms.clear(); m_names.clear(); @@ -287,6 +303,10 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { break; } + if (m->code() >= 400 && m->code() < 500) { + LOG4CXX_INFO(logger, user << ": Error message received: " << message->toData().data()); + } + //qDebug() << "numeric message received:" << receiver() << origin << code << params; } diff --git a/src/conversation.cpp b/src/conversation.cpp index 44af07b4..c9be3d3d 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -30,6 +30,7 @@ #include "Swiften/Elements/MUCOccupant.h" #include "Swiften/Elements/MUCUserPayload.h" #include "Swiften/Elements/Delay.h" +#include "Swiften/Elements/MUCPayload.h" namespace Transport { @@ -230,13 +231,29 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int Swift::MUCUserPayload *p = new Swift::MUCUserPayload (); if (m_nickname == nickname) { - Swift::MUCUserPayload::StatusCode c; - c.code = 110; - p->addStatusCode(c); - m_sentInitialPresence = true; + if (flag & PARTICIPANT_FLAG_CONFLICT) { + delete p; + presence->setType(Swift::Presence::Error); + presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); + presence->addPayload(boost::shared_ptr(new Swift::ErrorPayload(Swift::ErrorPayload::Conflict))); + return presence; + } + else if (flag & PARTICIPANT_FLAG_NOT_AUTHORIZED) { + delete p; + presence->setType(Swift::Presence::Error); + presence->addPayload(boost::shared_ptr(new Swift::MUCPayload())); + presence->addPayload(boost::shared_ptr(new Swift::ErrorPayload(Swift::ErrorPayload::NotAuthorized, Swift::ErrorPayload::Auth))); + return presence; + } + else { + Swift::MUCUserPayload::StatusCode c; + c.code = 110; + p->addStatusCode(c); + m_sentInitialPresence = true; + } } - + Swift::MUCItem item; item.affiliation = Swift::MUCOccupant::Member; @@ -254,7 +271,7 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int p->addStatusCode(c); presence->setType(Swift::Presence::Unavailable); } - + p->addItem(item); presence->addPayload(boost::shared_ptr(p)); return presence; diff --git a/src/tests/conversationmanager.cpp b/src/tests/conversationmanager.cpp index 5c9851ec..cf3caf3d 100644 --- a/src/tests/conversationmanager.cpp +++ b/src/tests/conversationmanager.cpp @@ -35,6 +35,8 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST(handleParticipantChangedTwoResources); CPPUNIT_TEST(handlePMFromXMPP); CPPUNIT_TEST(handleGroupchatRemoved); + CPPUNIT_TEST(handleNicknameConflict); + CPPUNIT_TEST(handleNotAuthorized); CPPUNIT_TEST_SUITE_END(); public: @@ -115,7 +117,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); // this user presence - status code 110 - conv->handleParticipantChanged("nickname", 1, Swift::StatusShow::Away, "my status message"); + conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_MODERATOR, Swift::StatusShow::Away, "my status message"); loop->processEvents(); CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); @@ -472,7 +474,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe conv->addJID("user@localhost/resource"); // normal presence - conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message"); + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message"); loop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); @@ -487,7 +489,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe received.clear(); // this user presence - status code 110 - conv->handleParticipantChanged("nickname", 1, Swift::StatusShow::Away, "my status message"); + conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_MODERATOR, Swift::StatusShow::Away, "my status message"); loop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); @@ -503,7 +505,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe received.clear(); // renamed - status code 303 - conv->handleParticipantChanged("anotheruser", 1, Swift::StatusShow::Away, "my status message", "hanzz"); + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_MODERATOR, Swift::StatusShow::Away, "my status message", "hanzz"); loop->processEvents(); CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); @@ -530,7 +532,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe conv->addJID("user@localhost/resource2"); // normal presence - conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message"); + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message"); loop->processEvents(); CPPUNIT_ASSERT_EQUAL(1, (int) received2.size()); @@ -551,7 +553,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe conv->setNickname("nickname"); conv->setJID("user@localhost/resource"); - conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message"); + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message"); loop->processEvents(); received.clear(); @@ -593,6 +595,44 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(332, getStanza(received[0])->getPayload()->getStatusCodes()[0].code); } + void handleNicknameConflict() { + User *user = userManager->getUser("user@localhost"); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true); + + conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); + conv->setNickname("nickname"); + conv->addJID("user@localhost/resource"); + + // normal presence + conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_CONFLICT, Swift::StatusShow::Away, "my status message"); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Error, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(Swift::ErrorPayload::Conflict, getStanza(received[0])->getPayload()->getCondition()); + } + + void handleNotAuthorized() { + User *user = userManager->getUser("user@localhost"); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true); + + conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); + conv->setNickname("nickname"); + conv->addJID("user@localhost/resource"); + + // normal presence + conv->handleParticipantChanged("nickname", Conversation::PARTICIPANT_FLAG_NOT_AUTHORIZED, Swift::StatusShow::Away, "my status message"); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Error, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(Swift::ErrorPayload::NotAuthorized, getStanza(received[0])->getPayload()->getCondition()); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION (ConversationManagerTest); diff --git a/src/tests/user.cpp b/src/tests/user.cpp index 0575f979..d3e58e3b 100644 --- a/src/tests/user.cpp +++ b/src/tests/user.cpp @@ -170,7 +170,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // Add 1 participant Conversation *conv = user->getConversationManager()->getConversation("#room"); - conv->handleParticipantChanged("anotheruser", 0, Swift::StatusShow::Away, "my status message"); + conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message"); // Connect 2nd resource connectSecondResource(); From f464b404e2f83e60a360839dc9985922cc43ef0c Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 24 Jan 2013 20:24:13 +0100 Subject: [PATCH 13/57] Do not normalize nicknames for MUCs --- backends/libpurple/main.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index b232f8bf..526e1a67 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -908,10 +908,6 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char // std::string msg = striped; // g_free(striped); - std::string w = purple_normalize_wrapped(account, who); - size_t pos = w.find("/"); - if (pos != std::string::npos) - w.erase((int) pos, w.length() - (int) pos); // Escape HTML characters. char *newline = purple_strdup_withhtml_wrapped(msg); @@ -948,11 +944,15 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char // LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "'"); if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) { + std::string w = purple_normalize_wrapped(account, who); + size_t pos = w.find("/"); + if (pos != std::string::npos) + w.erase((int) pos, w.length() - (int) pos); np->handleMessage(np->m_accounts[account], w, message_, "", xhtml_, timestamp); } else { - LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << w); - np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, w, xhtml_, timestamp); + LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << who); + np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, who, xhtml_, timestamp); } } From 1b49b0cf36af265af36cfb28f00d1088fb5dc52a Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 25 Jan 2013 08:05:46 +0100 Subject: [PATCH 14/57] Fixed leaving the room even when its name doesn't start with '#' --- include/transport/usermanager.h | 1 + src/presenceoracle.cpp | 45 ++++++++++---------- src/tests/conversationmanager.cpp | 28 ++++++------- src/tests/user.cpp | 69 ++++++++++++++----------------- src/transport.cpp | 3 +- src/user.cpp | 19 +++++---- src/usermanager.cpp | 19 +++++++++ 7 files changed, 97 insertions(+), 87 deletions(-) diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 4ccefb53..b0fd7605 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -137,6 +137,7 @@ class UserManager : public Swift::EntityCapsProvider { void handleProbePresence(Swift::Presence::ref presence); void handleErrorPresence(Swift::Presence::ref presence); void handleSubscription(Swift::Presence::ref presence); + void handleMUCPresence(Swift::Presence::ref presence); void handleRemoveTimeout(const std::string jid, User *user, bool reconnect); void handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr info); void addUser(User *user); diff --git a/src/presenceoracle.cpp b/src/presenceoracle.cpp index 49284321..f84b0a55 100644 --- a/src/presenceoracle.cpp +++ b/src/presenceoracle.cpp @@ -52,9 +52,8 @@ void PresenceOracle::clearPresences(const Swift::JID& bareJID) { void PresenceOracle::handleIncomingPresence(Presence::ref presence) { // ignore presences for some contact, we're checking only presences for the transport itself here. - bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; // filter out login/logout presence spam - if (!presence->getTo().getNode().empty() && isMUC == false) + if (!presence->getTo().getNode().empty()) return; JID bareJID(presence->getFrom().toBare()); @@ -62,29 +61,27 @@ void PresenceOracle::handleIncomingPresence(Presence::ref presence) { } else { Presence::ref passedPresence = presence; - if (!isMUC) { - 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); - 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; + 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); + 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); } } diff --git a/src/tests/conversationmanager.cpp b/src/tests/conversationmanager.cpp index cf3caf3d..b8f2eb4e 100644 --- a/src/tests/conversationmanager.cpp +++ b/src/tests/conversationmanager.cpp @@ -345,17 +345,17 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe injectPresence(response); loop->processEvents(); - CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(3, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[1]))->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[1]))->getTo().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received[1]))->getFrom().toString()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[2]))); - CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[2]))->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast(getStanza(received[2]))->getBody()); CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[2]))->getTo().toString()); CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received[2]))->getFrom().toString()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[3]))); - CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast(getStanza(received[3]))->getBody()); - CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[3]))->getTo().toString()); - CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received[3]))->getFrom().toString()); - } void handleGroupchatMessagesBouncerLeave() { @@ -410,17 +410,17 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe injectPresence(response); loop->processEvents(); - CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(3, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[1]))->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[1]))->getTo().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received[1]))->getFrom().toString()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[2]))); - CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[2]))->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast(getStanza(received[2]))->getBody()); CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[2]))->getTo().toString()); CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received[2]))->getFrom().toString()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[3]))); - CPPUNIT_ASSERT_EQUAL(std::string("hi there2!"), dynamic_cast(getStanza(received[3]))->getBody()); - CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[3]))->getTo().toString()); - CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received[3]))->getFrom().toString()); - } void handleGroupchatMessagesTwoResources() { diff --git a/src/tests/user.cpp b/src/tests/user.cpp index d3e58e3b..8c58c468 100644 --- a/src/tests/user.cpp +++ b/src/tests/user.cpp @@ -125,7 +125,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { User *user = userManager->getUser("user@localhost"); Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); Swift::MUCPayload *payload = new Swift::MUCPayload(); @@ -134,11 +134,8 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { injectPresence(response); loop->processEvents(); - // no presence received in server mode, just disco#info - CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); - CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); - - CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(std::string("room"), room); CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); @@ -147,7 +144,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { roomPassword = ""; // simulate that backend joined the room - TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "room", true); conv->addJID("user@localhost/resource"); user->getConversationManager()->addConversation(conv); @@ -156,8 +153,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { loop->processEvents(); // no presence received in server mode, just disco#info - CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); - CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); CPPUNIT_ASSERT_EQUAL(std::string(""), room); CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); @@ -169,14 +165,14 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { User *user = userManager->getUser("user@localhost"); // Add 1 participant - Conversation *conv = user->getConversationManager()->getConversation("#room"); + Conversation *conv = user->getConversationManager()->getConversation("room"); conv->handleParticipantChanged("anotheruser", Conversation::PARTICIPANT_FLAG_NONE, Swift::StatusShow::Away, "my status message"); // Connect 2nd resource connectSecondResource(); received2.clear(); Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource2"); Swift::MUCPayload *payload = new Swift::MUCPayload(); @@ -189,19 +185,19 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); - CPPUNIT_ASSERT_EQUAL(2, (int) received2.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received2[1]))); - CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received2[1]))->getShow()); - CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast(getStanza(received2[1]))->getTo().toString()); - CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost/anotheruser"), dynamic_cast(getStanza(received2[1]))->getFrom().toString()); - CPPUNIT_ASSERT(getStanza(received2[1])->getPayload()); - CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received2[1])->getPayload()->getItems()[0].affiliation); - CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received2[1])->getPayload()->getItems()[0].role); + CPPUNIT_ASSERT_EQUAL(1, (int) received2.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received2[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received2[0]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource2"), dynamic_cast(getStanza(received2[0]))->getTo().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("room@localhost/anotheruser"), dynamic_cast(getStanza(received2[0]))->getFrom().toString()); + CPPUNIT_ASSERT(getStanza(received2[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Member, *getStanza(received2[0])->getPayload()->getItems()[0].affiliation); + CPPUNIT_ASSERT_EQUAL(Swift::MUCOccupant::Participant, *getStanza(received2[0])->getPayload()->getItems()[0].role); } void handlePresenceLeaveRoom() { Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); response->setType(Swift::Presence::Unavailable); @@ -213,7 +209,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); - CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("room"), room); CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); } @@ -224,7 +220,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // User is still connected from resource2, so he should not leave the room Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); response->setType(Swift::Presence::Unavailable); @@ -243,7 +239,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // disconnect also from resource // User is still connected from resource2, so he should not leave the room response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource2"); response->setType(Swift::Presence::Unavailable); @@ -255,7 +251,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); - CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("room"), room); CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); } @@ -278,7 +274,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); - Conversation *conv = user->getConversationManager()->getConversation("#room"); + Conversation *conv = user->getConversationManager()->getConversation("room"); CPPUNIT_ASSERT_EQUAL(1, (int) conv->getJIDs().size()); CPPUNIT_ASSERT_EQUAL(Swift::JID("user@localhost/resource2"), conv->getJIDs().front()); } @@ -287,7 +283,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { User *user = userManager->getUser("user@localhost"); user->addUserSetting("stay_connected", "1"); Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); response->setType(Swift::Presence::Unavailable); @@ -312,7 +308,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // User is still connected from resource2, so he should not leave the room Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); response->setType(Swift::Presence::Unavailable); @@ -332,7 +328,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // disconnect also from resource // User is still connected from resource2, so he should not leave the room response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource2"); response->setType(Swift::Presence::Unavailable); @@ -368,7 +364,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); - Conversation *conv = user->getConversationManager()->getConversation("#room"); + Conversation *conv = user->getConversationManager()->getConversation("room"); CPPUNIT_ASSERT_EQUAL(1, (int) conv->getJIDs().size()); CPPUNIT_ASSERT_EQUAL(Swift::JID("user@localhost/resource2"), conv->getJIDs().front()); } @@ -377,12 +373,12 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { User *user = userManager->getUser("user@localhost"); handlePresenceJoinRoom(); - CPPUNIT_ASSERT(user->getConversationManager()->getConversation("#room")); + CPPUNIT_ASSERT(user->getConversationManager()->getConversation("room")); received.clear(); handlePresenceLeaveRoom(); - CPPUNIT_ASSERT(!user->getConversationManager()->getConversation("#room")); + CPPUNIT_ASSERT(!user->getConversationManager()->getConversation("room")); } void handleDisconnected() { @@ -427,7 +423,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { user->setConnected(false); Swift::Presence::ref response = Swift::Presence::create(); - response->setTo("#room@localhost/hanzz"); + response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); Swift::MUCPayload *payload = new Swift::MUCPayload(); @@ -436,16 +432,13 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { injectPresence(response); loop->processEvents(); - // no presence received in server mode, just disco#info - CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); - CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); - + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); CPPUNIT_ASSERT_EQUAL(std::string(""), room); CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); user->setConnected(true); - CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("room"), room); CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); } @@ -460,7 +453,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { received.clear(); user->setConnected(true); - CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("room"), room); CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); diff --git a/src/transport.cpp b/src/transport.cpp index 16e2de68..9c7172be 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -275,9 +275,8 @@ void Component::handleDataWritten(const Swift::SafeByteArray &data) { } void Component::handlePresence(Swift::Presence::ref presence) { - bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; // filter out login/logout presence spam - if (!presence->getTo().getNode().empty() && isMUC == false) + if (!presence->getTo().getNode().empty()) return; // filter out bad presences diff --git a/src/user.cpp b/src/user.cpp index 0046ae30..eb79cbb1 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -194,11 +194,6 @@ void User::setCacheMessages(bool cacheMessages) { } void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { - - int currentResourcesCount = m_presenceOracle->getAllPresence(m_jid).size(); - - m_conversationManager->resetResources(); - LOG4CXX_INFO(logger, "PRESENCE " << presence->getFrom().toString() << " " << presence->getTo().toString()); if (!m_connected) { // we are not connected to legacy network, so we should do it when disco#info arrive :) @@ -230,8 +225,9 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { } } - bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; - if (isMUC) { + + if (!presence->getTo().getNode().empty()) { + bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; if (presence->getType() == Swift::Presence::Unavailable) { std::string room = Buddy::JIDToLegacyName(presence->getTo()); Conversation *conv = m_conversationManager->getConversation(room); @@ -259,7 +255,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { } } } - else { + else if (isMUC) { // force connection to legacy network to let backend to handle auto-join on connect. if (!m_readyForConnect) { LOG4CXX_INFO(logger, m_jid.toString() << ": Ready to be connected to legacy network"); @@ -316,7 +312,12 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { } return; } - + + int currentResourcesCount = m_presenceOracle->getAllPresence(m_jid).size(); + + m_conversationManager->resetResources(); + + if (presence->getType() == Swift::Presence::Unavailable) { m_conversationManager->removeJID(presence->getFrom()); diff --git a/src/usermanager.cpp b/src/usermanager.cpp index eb091156..b40c5695 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -400,6 +400,7 @@ void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) { break; case Swift::Presence::Available: case Swift::Presence::Unavailable: + handleMUCPresence(presence); break; case Swift::Presence::Probe: handleProbePresence(presence); @@ -412,6 +413,24 @@ void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) { }; } +void UserManager::handleMUCPresence(Swift::Presence::ref presence) { + // Don't let RosterManager to handle presences for us + if (presence->getTo().getNode().empty()) { + return; + } + + if (presence->getType() == Swift::Presence::Available) { + handlePresence(presence); + } + else if (presence->getType() == Swift::Presence::Unavailable) { + std::string userkey = presence->getFrom().toBare().toString(); + User *user = getUser(userkey); + if (user) { + user->handlePresence(presence); + } + } +} + void UserManager::handleProbePresence(Swift::Presence::ref presence) { // Don't let RosterManager to handle presences for us if (presence->getTo().getNode().empty()) { From 739d5cf87f5ef00b79afd364d53fce1f4e943760 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 25 Jan 2013 12:47:41 +0100 Subject: [PATCH 15/57] Communi:Do not disconnect on error 433 --- backends/libcommuni/session.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 203a748a..4f5b4cfd 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -276,7 +276,9 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_CONFLICT); } - np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Nickname is already in use"); + if (suffix.empty()) { + np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Nickname is already in use"); + } break; case 436: for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { @@ -287,7 +289,9 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { np->handleParticipantChanged(user, TO_UTF8(nickName()), it->second->getChannel() + suffix, pbnetwork::PARTICIPANT_FLAG_NOT_AUTHORIZED); } - np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Password incorrect"); + if (suffix.empty()) { + np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Password incorrect"); + } case 321: m_rooms.clear(); m_names.clear(); From 505ea8301ce863a8661c9fb93df8a016ced6ba7d Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 25 Jan 2013 13:26:49 +0100 Subject: [PATCH 16/57] Fixed adding/removing contacts in gateway mode --- backends/libpurple/main.cpp | 1 + include/transport/networkpluginserver.h | 2 ++ src/networkpluginserver.cpp | 32 +++++++++++++++++++++++++ src/rostermanager.cpp | 1 + src/tests/user.cpp | 7 +++--- src/user.cpp | 3 +++ 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 526e1a67..4695389d 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -549,6 +549,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } purple_blist_add_buddy_wrapped(buddy, NULL, group ,NULL); purple_account_add_buddy_wrapped(account, buddy); + LOG4CXX_INFO(logger, "Adding new buddy " << buddyName.c_str() << " to legacy network roster"); } } } diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 322e2048..2aea0fc9 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -127,6 +127,8 @@ class NetworkPluginServer { void handleBuddyUpdated(Buddy *buddy, const Swift::RosterItemPayload &item); void handleBuddyRemoved(Buddy *buddy); void handleBuddyAdded(Buddy *buddy, const Swift::RosterItemPayload &item); + void handleUserBuddyAdded(User *user, Buddy *buddy); + void handleUserBuddyRemoved(User *user, Buddy *buddy); void handleBlockToggled(Buddy *buddy); diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index bb51b73e..019cfa6d 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -1253,6 +1253,9 @@ void NetworkPluginServer::handleUserCreated(User *user) { user->onPresenceChanged.connect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1)); user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4)); user->onRoomLeft.connect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1)); + + user->getRosterManager()->onBuddyAdded.connect(boost::bind(&NetworkPluginServer::handleUserBuddyAdded, this, user, _1)); + user->getRosterManager()->onBuddyRemoved.connect(boost::bind(&NetworkPluginServer::handleUserBuddyRemoved, this, user, _1)); } void NetworkPluginServer::handleUserReadyToConnect(User *user) { @@ -1358,6 +1361,9 @@ void NetworkPluginServer::handleUserDestroyed(User *user) { user->onRoomJoined.disconnect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4)); user->onRoomLeft.disconnect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1)); + user->getRosterManager()->onBuddyAdded.disconnect(boost::bind(&NetworkPluginServer::handleUserBuddyAdded, this, user, _1)); + user->getRosterManager()->onBuddyRemoved.disconnect(boost::bind(&NetworkPluginServer::handleUserBuddyRemoved, this, user, _1)); + pbnetwork::Logout logout; logout.set_user(user->getJID().toBare()); logout.set_legacyname(userInfo.uin); @@ -1538,6 +1544,32 @@ void NetworkPluginServer::handleBuddyAdded(Buddy *buddy, const Swift::RosterItem handleBuddyUpdated(buddy, item); } +void NetworkPluginServer::handleUserBuddyAdded(User *user, Buddy *b) { + pbnetwork::Buddy buddy; + buddy.set_username(user->getJID().toBare()); + buddy.set_buddyname(b->getName()); + buddy.set_alias(b->getAlias()); + BOOST_FOREACH(const std::string &g, b->getGroups()) { + buddy.add_group(g); + } + buddy.set_status(pbnetwork::STATUS_NONE); + + std::string message; + buddy.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED); + + Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } + send(c->connection, message); +} + +void NetworkPluginServer::handleUserBuddyRemoved(User *user, Buddy *b) { + handleBuddyRemoved(b); +} + void NetworkPluginServer::handleBlockToggled(Buddy *b) { User *user = b->getRosterManager()->getUser(); diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 8e6dcbef..a8b5b550 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -502,6 +502,7 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { buddy = m_component->getFactory()->createBuddy(this, buddyInfo); setBuddy(buddy); onBuddyAdded(buddy); + LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received for new buddy " << buddyInfo.legacyName << " => adding to legacy network"); response->setType(Swift::Presence::Subscribed); break; case Swift::Presence::Unsubscribe: diff --git a/src/tests/user.cpp b/src/tests/user.cpp index 8c58c468..932827a0 100644 --- a/src/tests/user.cpp +++ b/src/tests/user.cpp @@ -196,6 +196,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { } void handlePresenceLeaveRoom() { + received.clear(); Swift::Presence::ref response = Swift::Presence::create(); response->setTo("room@localhost/hanzz"); response->setFrom("user@localhost/resource"); @@ -209,9 +210,9 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); - CPPUNIT_ASSERT_EQUAL(std::string("room"), room); - CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); - CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); +// CPPUNIT_ASSERT_EQUAL(std::string("room"), room); +// CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); +// CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); } void handlePresenceLeaveRoomTwoResources() { diff --git a/src/user.cpp b/src/user.cpp index eb79cbb1..43234bcf 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -237,6 +237,9 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { return; } } + else { + return; + } if (getUserSetting("stay_connected") != "1") { LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room); From d54aac14c8f0c8c68f937b1dfb1970f4594947bc Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 25 Jan 2013 17:55:52 +0100 Subject: [PATCH 17/57] Cache nodes in libpurple backend --- backends/libpurple/main.cpp | 62 +++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 4695389d..7ceedad6 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -90,6 +90,14 @@ struct FTData { bool paused; }; +struct NodeCache { + PurpleAccount *account; + std::map nodes; + int timer; +}; + +bool caching = true; + static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotifyUserInfo *user_info); static gboolean ft_ui_ready(void *data) { @@ -356,6 +364,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void handleLogoutRequest(const std::string &user, const std::string &legacyName) { PurpleAccount *account = m_sessions[user]; if (account) { + if (account->ui_data) { + NodeCache *cache = (NodeCache *) account->ui_data; + purple_timeout_remove_wrapped(cache->timer); + delete cache; + account->ui_data = NULL; + } if (purple_account_get_int_wrapped(account, "version", 0) != 0) { std::string data = stringOf(purple_account_get_int_wrapped(account, "version", 0)); g_file_set_contents ("gfire.cfg", data.c_str(), data.size(), NULL); @@ -805,12 +819,56 @@ static std::vector getGroups(PurpleBuddy *m_buddy) { return groups; } -static void buddyListNewNode(PurpleBlistNode *node) { +void buddyListNewNode(PurpleBlistNode *node); + +static gboolean new_node_cache(void *data) { + NodeCache *cache = (NodeCache *) data; + caching = false; + for (std::map::const_iterator it = cache->nodes.begin(); it != cache->nodes.end(); it++) { + buddyListNewNode(it->first); + } + caching = true; + + cache->account->ui_data = NULL; + delete cache; + + return FALSE; +} + +static void buddyNodeRemoved(PurpleBuddyList *list, PurpleBlistNode *node) { if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node)) return; PurpleBuddy *buddy = (PurpleBuddy *) node; PurpleAccount *account = purple_buddy_get_account_wrapped(buddy); + if (!account->ui_data) { + return; + } + + NodeCache *cache = (NodeCache *) account->ui_data; + cache->nodes.erase(node); +} + +void buddyListNewNode(PurpleBlistNode *node) { + if (!PURPLE_BLIST_NODE_IS_BUDDY_WRAPPED(node)) + return; + PurpleBuddy *buddy = (PurpleBuddy *) node; + PurpleAccount *account = purple_buddy_get_account_wrapped(buddy); + + if (caching) { + if (!account->ui_data) { + NodeCache *cache = new NodeCache; + cache->account = account; + cache->timer = purple_timeout_add_wrapped(400, new_node_cache, cache); + account->ui_data = (void *) cache; + } + + NodeCache *cache = (NodeCache *) account->ui_data; + cache->nodes[node] = 1; + return; + } + + std::vector groups = getGroups(buddy); LOG4CXX_INFO(logger, "Buddy updated " << np->m_accounts[account] << " " << purple_buddy_get_name_wrapped(buddy) << " " << getAlias(buddy) << " group (" << groups.size() << ")=" << groups[0]); @@ -886,7 +944,7 @@ static PurpleBlistUiOps blistUiOps = buddyListNewNode, NULL, buddyListUpdate, - NULL, //NodeRemoved, + buddyNodeRemoved, NULL, NULL, NULL, // buddyListAddBuddy, From 4bef6fe8cfb63b5f596054cd678f01da4bc08f69 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 26 Jan 2013 12:17:16 +0100 Subject: [PATCH 18/57] Communi: handle also '%', '~' and '&' prefix --- backends/libcommuni/session.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 4f5b4cfd..c13297ff 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -86,6 +86,9 @@ bool MyIrcSession::correctNickname(std::string &nickname) { switch(nickname.at(0)) { case '@': nickname = nickname.substr(1); flags = 1; break; case '+': nickname = nickname.substr(1); break; + case '~': nickname = nickname.substr(1); break; + case '&': nickname = nickname.substr(1); break; + case '%': nickname = nickname.substr(1); break; default: break; } return flags; From 711c1674fe9d84a200bc4310b7f2970b9d8e4855 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 26 Jan 2013 15:22:25 +0100 Subject: [PATCH 19/57] Send 'http://jabber.org/protocol/muc' if MUC is supported by backend --- backends/libcommuni/ircnetworkplugin.cpp | 1 + backends/libpurple/main.cpp | 9 +++++++++ include/transport/networkplugin.h | 4 +++- plugin/cpp/networkplugin.cpp | 3 +++ src/config.cpp | 1 + src/discoinforesponder.cpp | 25 +++++++++++++----------- src/discoinforesponder.h | 2 +- 7 files changed, 32 insertions(+), 13 deletions(-) diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index 2eea86cb..4996a874 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -56,6 +56,7 @@ void IRCNetworkPlugin::readData() { if (m_servers.empty()) { NetworkPlugin::PluginConfig cfg; cfg.setNeedRegistration(false); + cfg.setSupportMUC(true); sendConfig(cfg); } } diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 4695389d..36e2df3f 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -43,6 +43,7 @@ DEFINE_LOGGER(logger, "backend"); int main_socket; static int writeInput; +bool firstPing = true; using namespace Transport; @@ -1656,6 +1657,14 @@ static void transportDataReceived(gpointer data, gint source, PurpleInputConditi exit(errno); } std::string d = std::string(buffer, n); + + if (firstPing) { + firstPing = false; + NetworkPlugin::PluginConfig cfg; + cfg.setSupportMUC(true); + np->sendConfig(cfg); + } + np->handleDataRead(d); } else { diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index c8e238c6..eece2e81 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -39,16 +39,18 @@ class NetworkPlugin { class PluginConfig { public: - PluginConfig() : m_needPassword(true), m_needRegistration(false) {} + PluginConfig() : m_needPassword(true), m_needRegistration(false), m_supportMUC(false) {} virtual ~PluginConfig() {} void setNeedRegistration(bool needRegistration = false) { m_needRegistration = needRegistration; } void setNeedPassword(bool needPassword = true) { m_needPassword = needPassword; } + void setSupportMUC(bool supportMUC = true) { m_supportMUC = supportMUC; } void setExtraFields(const std::vector &fields) { m_extraFields = fields; } private: bool m_needPassword; bool m_needRegistration; + bool m_supportMUC; std::vector m_extraFields; friend class NetworkPlugin; diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index 06393bf4..773c47ff 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -71,6 +71,9 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) { data += std::string("extraField=") + (*it) + "\n"; } + data += "[features]\n"; + data += std::string("muc=") + (cfg.m_supportMUC ? "1" : "0") + "\n"; + pbnetwork::BackendConfig m; m.set_config(data); diff --git a/src/config.cpp b/src/config.cpp index a30a01e1..1a5902e4 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -314,6 +314,7 @@ void Config::updateBackendConfig(const std::string &backendConfig) { ("registration.needRegistration", value()->default_value(false), "") ("registration.extraField", value >()->multitoken(), "") ("features.receipts", value()->default_value(false), "") + ("features.muc", value()->default_value(false), "") ; std::stringstream ifs(backendConfig); diff --git a/src/discoinforesponder.cpp b/src/discoinforesponder.cpp index 448ec17d..d3ea87da 100644 --- a/src/discoinforesponder.cpp +++ b/src/discoinforesponder.cpp @@ -39,28 +39,31 @@ namespace Transport { DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) : Swift::GetResponder(router) { m_config = config; - m_config->onBackendConfigUpdated.connect(boost::bind(&DiscoInfoResponder::updateBuddyFeatures, this)); + m_config->onBackendConfigUpdated.connect(boost::bind(&DiscoInfoResponder::updateFeatures, this)); m_buddyInfo = NULL; m_transportInfo.addIdentity(DiscoInfo::Identity(CONFIG_STRING(m_config, "identity.name"), CONFIG_STRING(m_config, "identity.category"), CONFIG_STRING(m_config, "identity.type"))); - std::list features; - features.push_back("jabber:iq:register"); - features.push_back("jabber:iq:gateway"); - features.push_back("jabber:iq:private"); - features.push_back("http://jabber.org/protocol/disco#info"); - features.push_back("http://jabber.org/protocol/commands"); - setTransportFeatures(features); - - updateBuddyFeatures(); + updateFeatures(); } DiscoInfoResponder::~DiscoInfoResponder() { delete m_buddyInfo; } -void DiscoInfoResponder::updateBuddyFeatures() { +void DiscoInfoResponder::updateFeatures() { + std::list features2; + features2.push_back("jabber:iq:register"); + features2.push_back("jabber:iq:gateway"); + features2.push_back("jabber:iq:private"); + features2.push_back("http://jabber.org/protocol/disco#info"); + features2.push_back("http://jabber.org/protocol/commands"); + if (CONFIG_BOOL_DEFAULTED(m_config, "features.muc", false)) { + features2.push_back("http://jabber.org/protocol/muc"); + } + setTransportFeatures(features2); + std::list features; features.push_back("http://jabber.org/protocol/disco#items"); features.push_back("http://jabber.org/protocol/disco#info"); diff --git a/src/discoinforesponder.h b/src/discoinforesponder.h index 33dfe6b8..08b0656e 100644 --- a/src/discoinforesponder.h +++ b/src/discoinforesponder.h @@ -52,7 +52,7 @@ class DiscoInfoResponder : public Swift::GetResponder { private: virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); - void updateBuddyFeatures(); + void updateFeatures(); Swift::DiscoInfo m_transportInfo; Swift::DiscoInfo *m_buddyInfo; From f9eb932dbc9d8342cce3def3d4877dee12b84d22 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 26 Jan 2013 15:35:15 +0100 Subject: [PATCH 20/57] send empty name if we receive it from backend --- src/rostermanager.cpp | 7 +------ src/tests/rostermanager.cpp | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index a8b5b550..f9c47e77 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -154,12 +154,7 @@ void RosterManager::sendBuddyRosterPush(Buddy *buddy) { Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload()); Swift::RosterItemPayload item; item.setJID(buddy->getJID().toBare()); - if (buddy->getAlias().empty()) { - item.setName(buddy->getJID().toBare().toString()); - } - else { - item.setName(buddy->getAlias()); - } + item.setName(buddy->getAlias()); item.setGroups(buddy->getGroups()); item.setSubscription(Swift::RosterItemPayload::Both); diff --git a/src/tests/rostermanager.cpp b/src/tests/rostermanager.cpp index 35d2d444..b9df7a0f 100644 --- a/src/tests/rostermanager.cpp +++ b/src/tests/rostermanager.cpp @@ -23,6 +23,7 @@ using namespace Transport; class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(RosterManagerTest); CPPUNIT_TEST(setBuddy); + CPPUNIT_TEST(setBuddyNoAlias); CPPUNIT_TEST(sendCurrentPresences); CPPUNIT_TEST(sendUnavailablePresences); CPPUNIT_TEST(sendCurrentPresence); @@ -72,6 +73,25 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { } + void setBuddyNoAlias() { + User *user = userManager->getUser("user@localhost"); + CPPUNIT_ASSERT(user); + + std::vector grp; + grp.push_back("group1"); + LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1", "", grp, BUDDY_JID_ESCAPING); + user->getRosterManager()->setBuddy(buddy); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + + Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload(); + CPPUNIT_ASSERT(payload1); + CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size()); + Swift::RosterItemPayload item = payload1->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("buddy1"), Buddy::JIDToLegacyName(item.getJID())); + CPPUNIT_ASSERT_EQUAL(std::string(""), item.getName()); + } + void setBuddy() { add2Buddies(); CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); From d615da6e28e20cce0ba4faf1feb20de8565fa149 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 26 Jan 2013 17:09:07 +0100 Subject: [PATCH 21/57] include time.h --- include/transport/adhoccommand.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/transport/adhoccommand.h b/include/transport/adhoccommand.h index e1734b12..df38d913 100644 --- a/include/transport/adhoccommand.h +++ b/include/transport/adhoccommand.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "Swiften/Elements/FormField.h" #include "Swiften/Elements/Command.h" From d068cb63efae197ecfe63e8e0bd9e7dead461f34 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 27 Jan 2013 11:01:49 +0100 Subject: [PATCH 22/57] Skype: forward authorization request from skype to XMPP --- backends/skype/main.cpp | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 1b09ef78..656ce2f3 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -202,6 +202,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { Skype *skype = m_sessions[user]; if (skype) { skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 1"); + skype->send_command("SET USER " + buddyName + " ISAUTHORIZED FALSE"); } } @@ -695,20 +696,9 @@ static void handle_skype_message(std::string &message, Skype *sk) { std::vector groups; np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); } - //TODO: handle RECEIVEDAUTHREQUEST and reply it with: -// void -// skype_auth_allow(gpointer sender) -// { -// skype_send_message("SET USER %s ISAUTHORIZED TRUE", sender); -// g_free(sender); -// } -// -// void -// skype_auth_deny(gpointer sender) -// { -// skype_send_message("SET USER %s ISAUTHORIZED FALSE", sender); -// g_free(sender); -// } + else if(cmd[2] == "RECEIVEDAUTHREQUEST") { + np->handleAuthorization(sk->getUser(), cmd[1]); + } } else if (cmd[0] == "CHATMESSAGE") { if (cmd[3] == "RECEIVED") { From 0ccf0b0c47e80e0d462ce2c601f7bf32947c54a0 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 27 Jan 2013 11:48:58 +0100 Subject: [PATCH 23/57] Swiften: working adding/removing contacts --- backends/swiften/main.cpp | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 97368436..a9f9a757 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -226,12 +226,45 @@ class SwiftenPlugin : 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/Updated buddy " << buddyName << "."); -// handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); + boost::shared_ptr client = m_users[user]; + if (client) { + LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << "."); + if (!client->getRoster()->containsJID(buddyName)) { + Swift::RosterItemPayload item; + item.setName(alias); + item.setJID(buddyName); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + client->getSubscriptionManager()->requestSubscription(buddyName); + } + else { + Swift::JID contact(buddyName); + Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact)); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + + } } void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { - + boost::shared_ptr client = m_users[user]; + if (client) { + Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } } private: From f5e0acc528a875521fdc24a351d7c72559ba3e3a Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 27 Jan 2013 14:15:55 +0100 Subject: [PATCH 24/57] Send non-escaped JID in gateway responder if jid_escaping is disabled --- src/gatewayresponder.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gatewayresponder.cpp b/src/gatewayresponder.cpp index 1306a9da..fa29711e 100644 --- a/src/gatewayresponder.cpp +++ b/src/gatewayresponder.cpp @@ -52,7 +52,14 @@ bool GatewayResponder::handleGetRequest(const Swift::JID& from, const Swift::JID 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); + if (!CONFIG_BOOL_DEFAULTED(m_userManager->getComponent()->getConfig(), "service.jid_escaping", true)) { + escaped = prompt; + if (escaped.find_last_of("@") != std::string::npos) { + escaped.replace(escaped.find_last_of("@"), 1, "%"); + } + } // This code is here to workaround Gajim (and probably other clients bug too) bug // https://trac.gajim.org/ticket/7277 if (prompt.find("\\40") != std::string::npos) { From 0185f94872997abd123a963ee8e20b11bfe2bb82 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 27 Jan 2013 18:13:25 +0100 Subject: [PATCH 25/57] Swiften backend: support MUC --- backends/swiften/main.cpp | 141 +++++++++++++++++++++++++++++- include/transport/networkplugin.h | 2 +- include/transport/protocol.proto | 1 + plugin/cpp/networkplugin.cpp | 3 +- src/conversation.cpp | 6 +- src/networkpluginserver.cpp | 14 ++- 6 files changed, 161 insertions(+), 6 deletions(-) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index a9f9a757..93137352 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -3,6 +3,8 @@ #include "transport/networkplugin.h" #include "transport/logging.h" +#include "boost/date_time/posix_time/posix_time.hpp" + // Swiften #include "Swiften/Swiften.h" @@ -32,7 +34,83 @@ Swift::SimpleEventLoop *loop_; // Plugins class SwiftenPlugin; -SwiftenPlugin *np = NULL; +NetworkPlugin *np = NULL; + +class MUCController { + public: + MUCController(const std::string &user, boost::shared_ptr client, const std::string &room, const std::string &nickname, const std::string &password) { + m_user = user; + m_room = room; + muc = client->getMUCManager()->createMUC(room); + if (!password.empty()) { + muc->setPassword(password); + } + + muc->onJoinComplete.connect(boost::bind(&MUCController::handleJoinComplete, this, _1)); + muc->onJoinFailed.connect(boost::bind(&MUCController::handleJoinFailed, this, _1)); + muc->onOccupantJoined.connect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); + muc->onOccupantPresenceChange.connect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1)); + muc->onOccupantLeft.connect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); + muc->onOccupantRoleChanged.connect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3)); + muc->onOccupantAffiliationChanged.connect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3)); + + muc->joinAs(nickname); + } + + virtual ~MUCController() { + muc->onJoinComplete.disconnect(boost::bind(&MUCController::handleJoinComplete, this, _1)); + muc->onJoinFailed.disconnect(boost::bind(&MUCController::handleJoinFailed, this, _1)); + muc->onOccupantJoined.disconnect(boost::bind(&MUCController::handleOccupantJoined, this, _1)); + muc->onOccupantPresenceChange.disconnect(boost::bind(&MUCController::handleOccupantPresenceChange, this, _1)); + muc->onOccupantLeft.disconnect(boost::bind(&MUCController::handleOccupantLeft, this, _1, _2, _3)); + muc->onOccupantRoleChanged.disconnect(boost::bind(&MUCController::handleOccupantRoleChanged, this, _1, _2, _3)); + muc->onOccupantAffiliationChanged.disconnect(boost::bind(&MUCController::handleOccupantAffiliationChanged, this, _1, _2, _3)); + } + + const std::string &getNickname() { + //return muc->getCurrentNick(); + return m_nick; + } + + void handleOccupantJoined(const Swift::MUCOccupant& occupant) { + np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE); + } + + void handleOccupantLeft(const Swift::MUCOccupant& occupant, Swift::MUC::LeavingType type, const std::string& reason) { + np->handleParticipantChanged(m_user, occupant.getNick(), m_room, occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_NONE); + } + + void handleOccupantPresenceChange(boost::shared_ptr presence) { + const Swift::MUCOccupant& occupant = muc->getOccupant(presence->getFrom().getResource()); + np->handleParticipantChanged(m_user, presence->getFrom().getResource(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, (pbnetwork::StatusType) presence->getShow(), presence->getStatus()); + } + + void handleOccupantRoleChanged(const std::string& nick, const Swift::MUCOccupant& occupant, const Swift::MUCOccupant::Role& oldRole) { + + } + + void handleOccupantAffiliationChanged(const std::string& nick, const Swift::MUCOccupant::Affiliation& affiliation, const Swift::MUCOccupant::Affiliation& oldAffiliation) { +// np->handleParticipantChanged(m_user, occupant->getNick(), m_room, (int) occupant.getRole() == Swift::MUCOccupant::Moderator, pbnetwork::STATUS_ONLINE); + } + + void handleJoinComplete(const std::string& nick) { + m_nick = nick; + } + + void handleJoinFailed(boost::shared_ptr error) { + + } + + void part() { + muc->part(); + } + + private: + Swift::MUC::ref muc; + std::string m_user; + std::string m_room; + std::string m_nick; +}; class SwiftenPlugin : public NetworkPlugin { public: @@ -106,6 +184,7 @@ class SwiftenPlugin : public NetworkPlugin { client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); m_users.erase(user); + m_mucs.erase(user); } #ifndef WIN32 @@ -136,6 +215,11 @@ class SwiftenPlugin : public NetworkPlugin { } void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) { + boost::shared_ptr client = m_users[user]; + if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { + return; + } + LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); std::string message = presence->getStatus(); @@ -160,7 +244,22 @@ class SwiftenPlugin : public NetworkPlugin { std::string body = message->getBody(); boost::shared_ptr client = m_users[user]; if (client) { - handleMessage(user, message->getFrom().toBare().toString(), body, "", ""); + if (message->getType() == Swift::Message::Groupchat) { + boost::shared_ptr delay = message->getPayload(); + std::string timestamp = ""; + if (delay) { + timestamp = boost::posix_time::to_iso_string(delay->getStamp()); + } + handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", timestamp); + } + else { + if (client->getMUCRegistry()->isMUC(message->getFrom().toBare())) { + handleMessage(user, message->getFrom().toBare().toString(), body, message->getFrom().getResource(), "", "", false, true); + } + else { + handleMessage(user, message->getFrom().toBare().toString(), body, "", ""); + } + } } } @@ -199,6 +298,8 @@ class SwiftenPlugin : public NetworkPlugin { client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); client->disconnect(); + m_mucs.erase(user); + m_users.erase(user); } } @@ -210,6 +311,11 @@ class SwiftenPlugin : public NetworkPlugin { message->setTo(Swift::JID(legacyName)); message->setFrom(client->getJID()); message->setBody(msg); + if (client->getMUCRegistry()->isMUC(legacyName)) { + message->setType(Swift::Message::Groupchat); + boost::shared_ptr muc = m_mucs[user][legacyName]; + handleMessage(user, legacyName, msg, muc->getNickname(), xhtml); + } client->sendMessage(message); } @@ -267,9 +373,40 @@ class SwiftenPlugin : public NetworkPlugin { } } + void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { + boost::shared_ptr client = m_users[user]; + if (client) { + if (client->getMUCRegistry()->isMUC(room)) { + return; + } + + boost::shared_ptr muc = boost::shared_ptr( new MUCController(user, client, room, nickname, password)); + m_mucs[user][room] = muc; + } + } + + void handleLeaveRoomRequest(const std::string &user, const std::string &room) { + boost::shared_ptr client = m_users[user]; + if (client) { + if (!client->getMUCRegistry()->isMUC(room)) { + return; + } + + boost::shared_ptr muc = m_mucs[user][room]; + if (!muc) { + m_mucs[user].erase(room); + return; + } + + muc->part(); + m_mucs[user].erase(room); + } + } + private: Config *config; std::map > m_users; + std::map > > m_mucs; }; #ifndef WIN32 diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index eece2e81..279a3c5d 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -113,7 +113,7 @@ class NetworkPlugin { /// \param message Plain text message. /// \param nickname Nickname of buddy in room. Empty if it's normal chat message. /// \param xhtml XHTML message. - void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = "", const std::string ×tamp = "", bool headline = false); + void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = "", const std::string ×tamp = "", bool headline = false, bool pm = false); void handleMessageAck(const std::string &user, const std::string &legacyName, const std::string &id); diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 8eafcde8..796b656c 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -72,6 +72,7 @@ message ConversationMessage { optional string timestamp = 6; optional bool headline = 7; optional string id = 8; + optional bool pm = 9; } message Room { diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index 773c47ff..45e39e99 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -85,7 +85,7 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) { send(message); } -void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml, const std::string ×tamp, bool headline) { +void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml, const std::string ×tamp, bool headline, bool pm) { pbnetwork::ConversationMessage m; m.set_username(user); m.set_buddyname(legacyName); @@ -94,6 +94,7 @@ void NetworkPlugin::handleMessage(const std::string &user, const std::string &le m.set_xhtml(xhtml); m.set_timestamp(timestamp); m.set_headline(headline); + m.set_pm(pm); std::string message; m.SerializeToString(&message); diff --git a/src/conversation.cpp b/src/conversation.cpp index c9be3d3d..4073d8e6 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -130,7 +130,11 @@ void Conversation::handleMessage(boost::shared_ptr &message, con message->setFrom(Swift::JID(n, m_conversationManager->getComponent()->getJID().toBare(), "user")); } else { - message->setFrom(Swift::JID(m_room, m_conversationManager->getComponent()->getJID().toBare(), n)); + std::string legacyName = m_room; + if (legacyName.find_last_of("@") != std::string::npos) { + legacyName.replace(legacyName.find_last_of("@"), 1, "%"); // OK + } + message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n)); } } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 019cfa6d..85747b23 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -686,7 +686,6 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool msg->addPayload(delay); } - NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname()); // We can't create Conversation for payload with nickname, because this means the message is from room, @@ -695,6 +694,19 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool return; } + if (conv && payload.pm()) { + conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname() + "/" + payload.nickname()); + if (!conv) { + conv = new NetworkConversation(user->getConversationManager(), payload.nickname()); + std::string name = payload.buddyname(); + conv->setRoom(name); + conv->setNickname(payload.buddyname() + "/" + payload.nickname()); + + user->getConversationManager()->addConversation(conv); + conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2)); + } + } + // Create new Conversation if it does not exist if (!conv) { conv = new NetworkConversation(user->getConversationManager(), payload.buddyname()); From 6b10147edbcd1ade91810288da8cf2f2683a0d0e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 28 Jan 2013 07:56:36 +0100 Subject: [PATCH 26/57] replace all % to @ --- src/usermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usermanager.cpp b/src/usermanager.cpp index b40c5695..23ffa53d 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -230,7 +230,7 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { res.password = ""; res.uin = presence->getFrom().getNode(); res.jid = userkey; - if (res.uin.find_last_of("%") != std::string::npos) { // OK + while (res.uin.find_last_of("%") != std::string::npos) { // OK res.uin.replace(res.uin.find_last_of("%"), 1, "@"); // OK } if (m_storageBackend) { From ff6448bcd32f63496ec35511e8a932236b1f6018 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 28 Jan 2013 08:03:14 +0100 Subject: [PATCH 27/57] Communi: initBackendLogging before QCoreApplication --- backends/libcommuni/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/libcommuni/main.cpp b/backends/libcommuni/main.cpp index 99b3bc58..d2013b50 100644 --- a/backends/libcommuni/main.cpp +++ b/backends/libcommuni/main.cpp @@ -33,10 +33,10 @@ int main (int argc, char* argv[]) { return 1; } - QCoreApplication app(argc, argv); - Logging::initBackendLogging(cfg); + QCoreApplication app(argc, argv); + Swift::QtEventLoop eventLoop; From 2fbd27919c143f43925e54a7121441636cce1196 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 28 Jan 2013 16:34:15 +0100 Subject: [PATCH 28/57] Do not try to delete m_proxy if it does not exist --- backends/skype/main.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 656ce2f3..6e700132 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -606,10 +606,12 @@ bool Skype::loadSkypeBuddies() { void Skype::logout() { if (m_pid != 0) { - send_command("SET USERSTATUS INVISIBLE"); - send_command("SET USERSTATUS OFFLINE"); - sleep(2); - g_object_unref(m_proxy); + if (m_proxy) { + send_command("SET USERSTATUS INVISIBLE"); + send_command("SET USERSTATUS OFFLINE"); + sleep(2); + g_object_unref(m_proxy); + } LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)"); kill((int) m_pid, SIGTERM); // Give skype a chance From b90a91ac7883f56ab18288c10a5d1b1e2c01787b Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 28 Jan 2013 17:04:55 +0100 Subject: [PATCH 29/57] different default for skype backend --- spectrum/src/sample2.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index cc0a7aef..6cad8d9d 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_libcommuni_backend # For skype: -#backend=/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 -a -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 a2c36650deed71db1f9d21d3ae893c3a95f18681 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Tue, 29 Jan 2013 11:24:18 +0400 Subject: [PATCH 30/57] libpurple backend: handle Display name vcard field --- backends/libpurple/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 36e2df3f..1de35fbc 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -1101,7 +1101,7 @@ static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotif else if (label=="Nickname" || label == "Nick") { nickname = purple_notify_user_info_entry_get_value_wrapped(vcardEntry); } - else if (label=="Full Name") { + else if (label=="Full Name" || label == "Display name") { fullName = purple_notify_user_info_entry_get_value_wrapped(vcardEntry); } else { From b0069b4b179c9bb97f6e3ea6421eefb8e9e048e7 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 29 Jan 2013 15:02:16 +0100 Subject: [PATCH 31/57] Twitter: Set buddy before sending DirectMessageRequest --- backends/twitter/TwitterPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index b0ffba6f..fa777960 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -274,7 +274,7 @@ void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std: } else { - std::string buddy; + std::string buddy = legacyName; if(userdb[user].twitterMode == CHATROOM) buddy = legacyName.substr(legacyName.find("/") + 1); if(legacyName != "twitter") { tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, buddy, message, From 22eb281dd4b12e29319f37d4adff4443e382d762 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 29 Jan 2013 17:27:41 +0100 Subject: [PATCH 32/57] Skype: initial support for custom groups --- backends/skype/main.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 6e700132..6386a632 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -100,6 +100,7 @@ class Skype { int m_timer; int m_counter; int fd_output; + std::map m_groups; }; class SpectrumNetworkPlugin : public NetworkPlugin { @@ -702,6 +703,32 @@ static void handle_skype_message(std::string &message, Skype *sk) { np->handleAuthorization(sk->getUser(), cmd[1]); } } + else if (cmd[0] == "GROUP") { + if (cmd[2] == "DISPLAYNAME") { + //GROUP 810 DISPLAYNAME My Friends + std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); + std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); + try { + users = GET_RESPONSE_DATA(users, "USERS"); + } + catch (std::out_of_range& oor) { + return; + } + + std::vector data; + boost::split(data, users, boost::is_any_of(",")); + BOOST_FOREACH(std::string u, data) { + GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + groups.push_back(grp); + np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); + } + } + } else if (cmd[0] == "CHATMESSAGE") { if (cmd[3] == "RECEIVED") { GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY"); From 88c5bce5babe13e60f442b04321072dfa64bf8c3 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 30 Jan 2013 10:35:01 +0100 Subject: [PATCH 33/57] Ask for groups after we receive NROFUSERS, not before --- backends/skype/main.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 6386a632..82ecb06d 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -704,9 +704,32 @@ static void handle_skype_message(std::string &message, Skype *sk) { } } else if (cmd[0] == "GROUP") { - if (cmd[2] == "DISPLAYNAME") { - //GROUP 810 DISPLAYNAME My Friends - std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); +// if (cmd[2] == "DISPLAYNAME") { +// //GROUP 810 DISPLAYNAME My Friends +// std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); +// std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); +// try { +// users = GET_RESPONSE_DATA(users, "USERS"); +// } +// catch (std::out_of_range& oor) { +// return; +// } +// +// std::vector data; +// boost::split(data, users, boost::is_any_of(",")); +// BOOST_FOREACH(std::string u, data) { +// GET_PROPERTY(alias, "USER", u, "FULLNAME"); +// GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); +// GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); +// pbnetwork::StatusType status = getStatus(st); +// +// std::vector groups; +// groups.push_back(grp); +// np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); +// } +// } + if (cmd[2] == "NROFUSERS" && cmd[3] != "0") { + GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME"); std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); try { users = GET_RESPONSE_DATA(users, "USERS"); @@ -718,9 +741,9 @@ static void handle_skype_message(std::string &message, Skype *sk) { std::vector data; boost::split(data, users, boost::is_any_of(",")); BOOST_FOREACH(std::string u, data) { - GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + GET_PROPERTY(alias, "USER", u, "FULLNAME"); + GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); + GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); pbnetwork::StatusType status = getStatus(st); std::vector groups; From ac2fd6dbfb75ac8010fdff1122cfccfefd30d9dc Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 30 Jan 2013 17:29:08 +0100 Subject: [PATCH 34/57] Skype: Try to read avatars from main.db sqlite3 database --- backends/skype/main.cpp | 59 ++++++++++++++++++++++++++++++++++++++++- src/sqlite3backend.cpp | 1 + 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 82ecb06d..49966325 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -22,6 +22,8 @@ #endif #include +#include "sqlite3.h" + DEFINE_LOGGER(logger, "backend"); @@ -39,6 +41,34 @@ class SpectrumNetworkPlugin; } + +// Prepare the SQL statement +#define PREP_STMT(sql, str) \ + if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ + LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \ + sql = NULL; \ + } + +// Finalize the prepared statement +#define FINALIZE_STMT(prep) \ + if(prep != NULL) { \ + sqlite3_finalize(prep); \ + } + +#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ + int STATEMENT##_id = 1;\ + int STATEMENT##_id_get = 0;\ + (void)STATEMENT##_id_get; + +#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) +#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) +#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; +#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) +#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) +#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) +#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ + LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ + } SpectrumNetworkPlugin *np; @@ -277,7 +307,34 @@ class SpectrumNetworkPlugin : public NetworkPlugin { g_free(filename); } g_free(username); - + + if (photo.empty()) { + sqlite3 *db; + std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.db"; + if (sqlite3_open(db_path.c_str(), &db)) { + sqlite3_close(db); + } + else { + sqlite3_stmt *stmt; + PREP_STMT(stmt, "SELECT avatar_image FROM Contacts WHERE skypename=?"); + if (stmt) { + BEGIN(stmt); + BIND_STR(stmt, name); + if(sqlite3_step(stmt) == SQLITE_ROW) { + int size = sqlite3_column_bytes(stmt, 0); + const void *data = sqlite3_column_blob(stmt, 0); + photo = std::string((const char *)data, size); + } + + int ret; + while((ret = sqlite3_step(stmt)) == SQLITE_ROW) { + } + FINALIZE_STMT(stmt); + } + sqlite3_close(db); + } + } + std::string alias = ""; std::cout << skype->getUsername() << " " << name << "\n"; if (skype->getUsername() == name) { diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index b7e839bb..4290d9cf 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -55,6 +55,7 @@ #define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; #define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) #define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) +#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) #define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db)));\ } From 8b225b590ada5dadfa16cc94998d98f2496d8f61 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 30 Jan 2013 18:15:10 +0100 Subject: [PATCH 35/57] Skype: log sqlite3 related errors --- backends/skype/main.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 49966325..2ac4d727 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -311,8 +311,10 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (photo.empty()) { sqlite3 *db; std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.db"; + LOG4CXX_INFO(logger, "Opening database " << db_path); if (sqlite3_open(db_path.c_str(), &db)) { sqlite3_close(db); + LOG4CXX_ERROR(logger, "Can't open database"); } else { sqlite3_stmt *stmt; @@ -325,12 +327,19 @@ class SpectrumNetworkPlugin : public NetworkPlugin { const void *data = sqlite3_column_blob(stmt, 0); photo = std::string((const char *)data, size); } + else { + LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); + } int ret; while((ret = sqlite3_step(stmt)) == SQLITE_ROW) { } FINALIZE_STMT(stmt); } + else { + LOG4CXX_ERROR(logger, "Can't created prepared statement"); + LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); + } sqlite3_close(db); } } From df369e65d8f012b5e0356fe185be16d9e437d366 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 30 Jan 2013 18:59:14 +0100 Subject: [PATCH 36/57] libtransport: support service.server also in server-mode --- include/Swiften/Server/Server.cpp | 11 +++++++++-- include/Swiften/Server/Server.h | 3 ++- spectrum/src/sample2.cfg | 2 +- src/tests/userregistry.cpp | 2 +- src/transport.cpp | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/Swiften/Server/Server.cpp b/include/Swiften/Server/Server.cpp index 3cc63428..afd239de 100644 --- a/include/Swiften/Server/Server.cpp +++ b/include/Swiften/Server/Server.cpp @@ -38,6 +38,7 @@ Server::Server( NetworkFactories* networkFactories, UserRegistry *userRegistry, const JID& jid, + const std::string &address, int port) : userRegistry_(userRegistry), port_(port), @@ -45,7 +46,8 @@ Server::Server( networkFactories_(networkFactories), stopping(false), selfJID(jid), - stanzaChannel_(){ + stanzaChannel_(), + address_(address){ stanzaChannel_ = new ServerStanzaChannel(); iqRouter_ = new IQRouter(stanzaChannel_); tlsFactory = NULL; @@ -63,7 +65,12 @@ void Server::start() { if (serverFromClientConnectionServer) { return; } - serverFromClientConnectionServer = networkFactories_->getConnectionServerFactory()->createConnectionServer(port_); + if (address_ == "0.0.0.0") { + serverFromClientConnectionServer = networkFactories_->getConnectionServerFactory()->createConnectionServer(port_); + } + else { + serverFromClientConnectionServer = networkFactories_->getConnectionServerFactory()->createConnectionServer(Swift::HostAddress(address_), port_); + } serverFromClientConnectionServerSignalConnections.push_back( serverFromClientConnectionServer->onNewConnection.connect( boost::bind(&Server::handleNewClientConnection, this, _1))); diff --git a/include/Swiften/Server/Server.h b/include/Swiften/Server/Server.h index f3d70060..b32ae463 100644 --- a/include/Swiften/Server/Server.h +++ b/include/Swiften/Server/Server.h @@ -35,7 +35,7 @@ namespace Swift { class Server : public Entity { public: - Server(EventLoop* eventLoop, NetworkFactories* networkFactories, UserRegistry *userRegistry, const JID& jid, int port); + Server(EventLoop* eventLoop, NetworkFactories* networkFactories, UserRegistry *userRegistry, const JID& jid, const std::string &address, int port); ~Server(); void start(); @@ -86,5 +86,6 @@ namespace Swift { TLSServerContextFactory *tlsFactory; CertificateWithKey::ref cert; PlatformXMLParserFactory *parserFactory_; + std::string address_; }; } diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 6cad8d9d..5a91d5b8 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -14,7 +14,7 @@ jid = localhost password = secret # XMPP server to which Spectrum connects in gateway mode. -# In server mode, this option is ignored. +# To bind to all ipv4 interfaces, use server=0.0.0.0 server = 127.0.0.1 # XMPP server port. diff --git a/src/tests/userregistry.cpp b/src/tests/userregistry.cpp index 7e567cfd..83fb21a1 100644 --- a/src/tests/userregistry.cpp +++ b/src/tests/userregistry.cpp @@ -36,7 +36,7 @@ class UserRegistryTest : public CPPUNIT_NS :: TestFixture { userRegistry->onConnectUser.connect(bind(&UserRegistryTest::handleConnectUser, this, _1)); userRegistry->onDisconnectUser.connect(bind(&UserRegistryTest::handleDisconnectUser, this, _1)); - server = new Swift::Server(loop, factories, userRegistry, "localhost", 5222); + server = new Swift::Server(loop, factories, userRegistry, "localhost", "0.0.0.0", 5222); server->start(); connectionServer = server->getConnectionServer(); diff --git a/src/transport.cpp b/src/transport.cpp index 9c7172be..a98f101a 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -80,7 +80,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, if (CONFIG_BOOL(m_config, "service.server_mode")) { LOG4CXX_INFO(logger, "Creating component in server mode on port " << CONFIG_INT(m_config, "service.port")); - m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_INT(m_config, "service.port")); + m_server = new Swift::Server(loop, m_factories, m_userRegistry, m_jid, CONFIG_STRING(m_config, "service.server"), CONFIG_INT(m_config, "service.port")); if (!CONFIG_STRING(m_config, "service.cert").empty()) { #ifndef _WIN32 //TODO: fix From 14b08332f610f32509bc6028198979d47d5fbd9e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 30 Jan 2013 19:17:54 +0100 Subject: [PATCH 37/57] Skype: First byte in avatar_image is 0... --- 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 2ac4d727..5d603d36 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -325,7 +325,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if(sqlite3_step(stmt) == SQLITE_ROW) { int size = sqlite3_column_bytes(stmt, 0); const void *data = sqlite3_column_blob(stmt, 0); - photo = std::string((const char *)data, size); + photo = std::string((const char *)data + 1, size - 1); } else { LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); From d85474b70b00341d1e64cad667fff624770fd071 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 31 Jan 2013 18:39:04 +0100 Subject: [PATCH 38/57] support specifying jids in munin script --- munin/spectrum2_ | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/munin/spectrum2_ b/munin/spectrum2_ index d0dc7a36..b2cd9f0c 100755 --- a/munin/spectrum2_ +++ b/munin/spectrum2_ @@ -21,10 +21,9 @@ # You have to configure the plugin to run as user and group "spectrum". # # By default, the plugin monitors all instances configured in a config-file -# in /etc/spectrum. If you use a different directory, you can specify the -# environment-variable "base". If you do not want to monitor all instances, -# you can give an explicit listing of the corresponding configuration files -# with the environment variable "cfgs". +# in /etc/spectrum2/transports. If you do not want to monitor all instances, +# you can give an explicit listing of the corresponding instances +# with the environment variable "jids". # # Here is an example of a configuration. Note again that you can ommit both # env.cfgs and env.base: @@ -32,8 +31,7 @@ # [spectrum_*] # user spectrum # group spectrum -# env.cfgs xmpp.example.com.cfg,irc.example.com.cfg -# env.base /etc/spectrum +# env.jids xmpp.example.com,irc.example.com # # Author: # Mathias Ertl @@ -94,9 +92,16 @@ def handle_field( string ): # get runtime variables suffix = sys.argv[0].partition('_')[2] verbose = os.environ.get( 'verbose' ) -proc = Popen(['spectrum2_manager', 'list'], stdout=PIPE, stderr=PIPE) -out, err = proc.communicate() -jids = out.split('\n')[:-1] + +jids = [] + +base = os.environ.get( 'base', '/etc/spectrum' ) +if 'jids' in os.environ.keys(): + jids = os.environ.get( 'cfgs' ).split(',') +else: + proc = Popen(['spectrum2_manager', 'list'], stdout=PIPE, stderr=PIPE) + out, err = proc.communicate() + jids = out.split('\n')[:-1] # set variables based on wildcard if suffix == 'uptime': From 4c1fcb4344e389b818038c6f1a317adcb7a7d35e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 31 Jan 2013 19:12:00 +0100 Subject: [PATCH 39/57] Show better log in case of ENOENT error returned by backend --- src/networkpluginserver.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 85747b23..6f50b04f 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -352,6 +352,10 @@ void NetworkPluginServer::start() { } else { LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status) << ", possible error: " << strerror(WEXITSTATUS(status))); + if (WEXITSTATUS(status) == ENOENT) { + LOG4CXX_ERROR(logger, "This usually means the path to backend executable defined in config file as '[service] backend=\"...\"' is wrong or the executable does not exists."); + } + } LOG4CXX_ERROR(logger, "Check backend log for more details"); continue; From a6296517aa0d07ab335071ceb0c8695d3ac414a2 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 1 Feb 2013 11:38:39 +0100 Subject: [PATCH 40/57] Fixed jids option in munin plugin --- munin/spectrum2_ | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/munin/spectrum2_ b/munin/spectrum2_ index b2cd9f0c..df43dc86 100755 --- a/munin/spectrum2_ +++ b/munin/spectrum2_ @@ -97,7 +97,7 @@ jids = [] base = os.environ.get( 'base', '/etc/spectrum' ) if 'jids' in os.environ.keys(): - jids = os.environ.get( 'cfgs' ).split(',') + jids = os.environ.get( 'jids' ).split(',') else: proc = Popen(['spectrum2_manager', 'list'], stdout=PIPE, stderr=PIPE) out, err = proc.communicate() From 1aba0d0d2eed09f657a6a87ab1ff0778721e50de Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sun, 3 Feb 2013 16:10:17 +0400 Subject: [PATCH 41/57] Fixed osx compilation --- CMakeLists.txt | 12 +++++++++++- backends/swiften/main.cpp | 4 ++++ spectrum/src/main.cpp | 4 ++++ spectrum_manager/src/CMakeLists.txt | 5 ++++- src/CMakeLists.txt | 5 ++++- src/memoryusage.cpp | 24 +++++++++++++++++++++--- src/usermanager.cpp | 6 +++++- 7 files changed, 53 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60544139..6a6ba6f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,7 +109,7 @@ endif() # FIND SQLITE3 if (ENABLE_SQLITE3) - if (NOT CMAKE_COMPILER_IS_GNUCXX) + if (MSVC) ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps) else() if (WIN32) @@ -248,6 +248,16 @@ if(ENABLE_TESTS) endif() endif() +if (APPLE) + FIND_LIBRARY(IOKIT_FRAMEWORK IOKit) + FIND_LIBRARY(SECURITY_FRAMEWORK Security) + FIND_LIBRARY(APPKIT_FRAMEWORK AppKit) + FIND_LIBRARY(SYSTEMCONFIGURATION_FRAMEWORK SystemConfiguration) + FIND_LIBRARY(SECURITYINTERFACE_FRAMEWORK SecurityInterface) + MARK_AS_ADVANCED(IOKIT_FRAMEWORK APPKIT_FRAMEWORK SYSTEMCONFIGURATION_FRAMEWORK SECURITY_FRAMEWORK SECURITYINTERFACE_FRAMEWORK) + SET (APPLE_FRAMEWORKS ${IOKIT_FRAMEWORK} ${APPKIT_FRAMEWORK} ${SYSTEMCONFIGURATION_FRAMEWORK} ${SECURITY_FRAMEWORK} ${SECURITYINTERFACE_FRAMEWORK}) +endif() + message(" Supported features") message("-----------------------") diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 93137352..db6ea37b 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -17,9 +17,11 @@ #endif #ifndef __FreeBSD__ +#ifndef __MACH__ // malloc_trim #include "malloc.h" #endif +#endif // Boost #include @@ -189,9 +191,11 @@ class SwiftenPlugin : public NetworkPlugin { #ifndef WIN32 #ifndef __FreeBSD__ +#ifndef __MACH__ // force returning of memory chunks allocated by libxml2 to kernel malloc_trim(0); #endif +#endif #endif } diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 176c618d..ed5d9b51 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -28,8 +28,10 @@ #include #include "libgen.h" #ifndef __FreeBSD__ +#ifndef __MACH__ #include #endif +#endif #else #include #define getpid _getpid @@ -308,10 +310,12 @@ int main(int argc, char **argv) setlocale(LC_ALL, ""); #ifndef WIN32 #ifndef __FreeBSD__ +#ifndef __MACH__ mallopt(M_CHECK_ACTION, 2); mallopt(M_PERTURB, 0xb); #endif #endif +#endif #ifndef WIN32 if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) { diff --git a/spectrum_manager/src/CMakeLists.txt b/spectrum_manager/src/CMakeLists.txt index a9a9ffc6..53b4e41e 100644 --- a/spectrum_manager/src/CMakeLists.txt +++ b/spectrum_manager/src/CMakeLists.txt @@ -7,7 +7,10 @@ ADD_DEPENDENCIES(spectrum2_manager pb) SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) target_link_libraries(spectrum2_manager ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES}) - + +if(APPLE) +target_link_libraries(spectrum2_manager ${APPLE_FRAMEWORKS}) +endif() INSTALL(TARGETS spectrum2_manager RUNTIME DESTINATION bin) INSTALL(FILES diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9053aa4d..3e49efa8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -3,7 +3,7 @@ FILE(GLOB SRC *.cpp *.h) FILE(GLOB_RECURSE SWIFTEN_SRC ../include/Swiften/*.cpp) # Build without openssl on msvc -if (CMAKE_COMPILER_IS_GNUCXX) +if (NOT MSVC) string(REGEX REPLACE "[^;]+;?/Schannel/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") else() string(REGEX REPLACE "[^;]+;?/OpenSSL/[^;]+;?" "" SWIFTEN_SRC "${SWIFTEN_SRC}") @@ -55,6 +55,9 @@ endif() SET_TARGET_PROPERTIES(transport PROPERTIES VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} ) +if (APPLE) + TARGET_LINK_LIBRARIES(transport ${APPLE_FRAMEWORKS}) +endif() INSTALL(TARGETS transport LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries) diff --git a/src/memoryusage.cpp b/src/memoryusage.cpp index d620569b..31ef5f8c 100644 --- a/src/memoryusage.cpp +++ b/src/memoryusage.cpp @@ -29,19 +29,37 @@ #ifndef WIN32 #include #endif -#ifdef BSD +#ifdef __MACH__ +#include +#elif BSD #include #include #include #include #include - #endif namespace Transport { #ifndef WIN32 -#ifdef BSD +#ifdef __MACH__ + +void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) { + + struct task_basic_info t_info; + mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; + + if (KERN_SUCCESS != task_info(mach_task_self(), + TASK_BASIC_INFO, (task_info_t)&t_info, + &t_info_count)) { + vm_usage = 0; + resident_set = 0; + return; + } + vm_usage = t_info.virtual_size; + resident_set = t_info.resident_size; +} +#elif BSD void process_mem_usage(double& vm_usage, double& resident_set, pid_t pid) { int mib[4]; size_t size; diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 23ffa53d..4a36eebf 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -33,9 +33,11 @@ #include "Swiften/Elements/StreamError.h" #include "Swiften/Elements/MUCPayload.h" #include "Swiften/Elements/ChatState.h" -#ifndef __FreeBSD__ +#ifndef __FreeBSD__ +#ifndef __MACH__ #include "malloc.h" #endif +#endif // #include "valgrind/memcheck.h" namespace Transport { @@ -130,9 +132,11 @@ void UserManager::removeUser(User *user, bool onUserBehalf) { delete user; #ifndef WIN32 #ifndef __FreeBSD__ +#ifndef __MACH__ malloc_trim(0); #endif #endif +#endif // VALGRIND_DO_LEAK_CHECK; } From f4996ab8d30512b0a49db98a039b406a1152e623 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Mon, 4 Feb 2013 14:40:15 +0400 Subject: [PATCH 42/57] memory usage on Windows --- include/transport/memoryusage.h | 6 ++---- src/CMakeLists.txt | 2 +- src/admininterface.cpp | 8 -------- src/memoryusage.cpp | 12 ++++++++++++ 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/include/transport/memoryusage.h b/include/transport/memoryusage.h index 563d0e93..605dd157 100644 --- a/include/transport/memoryusage.h +++ b/include/transport/memoryusage.h @@ -24,12 +24,10 @@ #ifndef WIN32 #include "signal.h" +#else +#define pid_t void* #endif namespace Transport { - -#ifndef WIN32 void process_mem_usage(double& shared, double& resident_set, pid_t pid = 0); -#endif - } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3e49efa8..10171852 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,7 @@ endif(PROTOBUF_FOUND) if (WIN32) include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3") - TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY}) + TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${PROTOBUF_LIBRARY} psapi.lib) else() TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY} ${PROTOBUF_LIBRARY}) endif() diff --git a/src/admininterface.cpp b/src/admininterface.cpp index 3b8a40d1..d8591c18 100644 --- a/src/admininterface.cpp +++ b/src/admininterface.cpp @@ -136,10 +136,7 @@ void AdminInterface::handleQuery(Swift::Message::ref message) { else if (message->getBody() == "res_memory") { double shared = 0; double rss = 0; -#ifndef WIN32 process_mem_usage(shared, rss); -#endif - const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { rss += backend->res; @@ -150,10 +147,7 @@ void AdminInterface::handleQuery(Swift::Message::ref message) { else if (message->getBody() == "shr_memory") { double shared = 0; double rss = 0; -#ifndef WIN32 process_mem_usage(shared, rss); -#endif - const std::list &backends = m_server->getBackends(); BOOST_FOREACH(NetworkPluginServer::Backend * backend, backends) { shared += backend->shared; @@ -164,9 +158,7 @@ void AdminInterface::handleQuery(Swift::Message::ref message) { else if (message->getBody() == "used_memory") { double shared = 0; double rss = 0; -#ifndef WIN32 process_mem_usage(shared, rss); -#endif rss -= shared; const std::list &backends = m_server->getBackends(); diff --git a/src/memoryusage.cpp b/src/memoryusage.cpp index 31ef5f8c..6f94743e 100644 --- a/src/memoryusage.cpp +++ b/src/memoryusage.cpp @@ -28,6 +28,9 @@ #include #ifndef WIN32 #include +#else +#include +#include #endif #ifdef __MACH__ #include @@ -138,6 +141,15 @@ void process_mem_usage(double& shared, double& resident_set, pid_t pid) { resident_set = rss * page_size_kb; } #endif /* else BSD */ +#else +#define PSAPI_VERSION 1 +#define pid_t void* + void process_mem_usage(double& shared, double& resident_set, pid_t pid) { + PROCESS_MEMORY_COUNTERS_EX pmc; + GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&pmc, sizeof(pmc)); + shared = (double)pmc.PrivateUsage; + resident_set = (double)pmc.WorkingSetSize; + } #endif /* WIN32 */ } From a0504b709fc79f90912c1dbae88163ecab75b725 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 4 Feb 2013 20:10:36 +0100 Subject: [PATCH 43/57] Swiften: Do not forward MUC message twice to xmpp user --- backends/swiften/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index db6ea37b..9598cc55 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -315,11 +315,11 @@ class SwiftenPlugin : public NetworkPlugin { message->setTo(Swift::JID(legacyName)); message->setFrom(client->getJID()); message->setBody(msg); - if (client->getMUCRegistry()->isMUC(legacyName)) { - message->setType(Swift::Message::Groupchat); - boost::shared_ptr muc = m_mucs[user][legacyName]; - handleMessage(user, legacyName, msg, muc->getNickname(), xhtml); - } +// if (client->getMUCRegistry()->isMUC(legacyName)) { +// message->setType(Swift::Message::Groupchat); +// boost::shared_ptr muc = m_mucs[user][legacyName]; +// handleMessage(user, legacyName, msg, muc->getNickname(), xhtml); +// } client->sendMessage(message); } From 8e28ea2f10e9c2af380fe0f3beba411e553de5c5 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 5 Feb 2013 08:35:49 +0100 Subject: [PATCH 44/57] fix previous commit --- backends/swiften/main.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 9598cc55..1a0bff55 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -315,11 +315,11 @@ class SwiftenPlugin : public NetworkPlugin { message->setTo(Swift::JID(legacyName)); message->setFrom(client->getJID()); message->setBody(msg); -// if (client->getMUCRegistry()->isMUC(legacyName)) { -// message->setType(Swift::Message::Groupchat); -// boost::shared_ptr muc = m_mucs[user][legacyName]; + if (client->getMUCRegistry()->isMUC(legacyName)) { + message->setType(Swift::Message::Groupchat); + boost::shared_ptr muc = m_mucs[user][legacyName]; // handleMessage(user, legacyName, msg, muc->getNickname(), xhtml); -// } + } client->sendMessage(message); } From 362ebaf12fb6e57782dd5a060224d4aeb41c9ccc Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 5 Feb 2013 09:11:04 +0100 Subject: [PATCH 45/57] Swiften: Do not forward presences with MUCPayload or MUCUserPayload. --- backends/swiften/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 1a0bff55..7af2703b 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -224,6 +224,10 @@ class SwiftenPlugin : public NetworkPlugin { return; } + if (presence->getPayload() != NULL || presence->getPayload() != NULL) { + return; + } + LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); std::string message = presence->getStatus(); From 1acaf75c10c15300229f4f94936fae219d39d799 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 5 Feb 2013 09:16:57 +0100 Subject: [PATCH 46/57] Swiften: Remove user only in onDisconnected callback. --- backends/swiften/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 7af2703b..3ccc632e 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -307,7 +307,6 @@ class SwiftenPlugin : public NetworkPlugin { client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); client->disconnect(); m_mucs.erase(user); - m_users.erase(user); } } From 393cf1cc03032c5938bcc57d54659b6aeb415aa3 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 6 Feb 2013 21:57:59 +0100 Subject: [PATCH 47/57] fix autoregistration --- backends/skype/main.cpp | 547 +------------------------------ include/transport/protocol.proto | 4 + src/usermanager.cpp | 4 +- 3 files changed, 19 insertions(+), 536 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 5d603d36..17c5ac6f 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -1,4 +1,6 @@ #include "glib.h" +#include +#include "sqlite3.h" #include #include "transport/config.h" @@ -20,16 +22,15 @@ #ifndef __FreeBSD__ #include "malloc.h" #endif -#include -#include "sqlite3.h" +#include "skype.h" DEFINE_LOGGER(logger, "backend"); using namespace Transport; -class SpectrumNetworkPlugin; +class SkypePlugin; #define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); #define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ @@ -70,7 +71,7 @@ class SpectrumNetworkPlugin; LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ } -SpectrumNetworkPlugin *np; +SkypePlugin *np; int m_sock; static int writeInput; @@ -97,50 +98,14 @@ static pbnetwork::StatusType getStatus(const std::string &st) { return status; } -class Skype { +class SkypePlugin : public NetworkPlugin { public: - Skype(const std::string &user, const std::string &username, const std::string &password); - ~Skype() { LOG4CXX_INFO(logger, "Skype instance desctuctor"); 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; - } - - bool createDBusProxy(); - bool loadSkypeBuddies(); - - int getPid() { - return (int) m_pid; - } - - private: - std::string m_username; - std::string m_password; - GPid m_pid; - DBusGConnection *m_connection; - DBusGProxy *m_proxy; - std::string m_user; - int m_timer; - int m_counter; - int fd_output; - std::map m_groups; -}; - -class SpectrumNetworkPlugin : public NetworkPlugin { - public: - SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { + SkypePlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { this->config = config; LOG4CXX_INFO(logger, "Starting the backend."); } - ~SpectrumNetworkPlugin() { + ~SkypePlugin() { for (std::map::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) { delete (*it).first; } @@ -153,7 +118,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { } LOG4CXX_INFO(logger, "Creating account with name '" << name << "'"); - Skype *skype = new Skype(user, name, password); + Skype *skype = new Skype(this, user, name, password); m_sessions[user] = skype; m_accounts[skype] = user; @@ -391,495 +356,6 @@ 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; - m_timer = -1; - m_counter = 0; -} - - -static gboolean load_skype_buddies(gpointer data) { - Skype *skype = (Skype *) data; - return skype->loadSkypeBuddies(); -} - -bool Skype::createDBusProxy() { - if (m_proxy == NULL) { - LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); - m_counter++; - - 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); - - if (m_counter == 15) { - LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message); - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message); - logout(); - g_error_free(error); - return FALSE; - } - g_error_free(error); - } - - 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); - - 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() { - if (m_username.find("..") == 0 || m_username.find("/") != std::string::npos) { - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Invalid username"); - return; - } - boost::filesystem::remove_all(std::string("/tmp/skype/") + m_username); - - 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); - - sleep(1); - 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; - GError *error = NULL; - bool spawned = 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, - &error); - - if (!spawned) { - LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message) - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance."); - return; - } - - std::string login_data = std::string(m_username + " " + m_password + "\n"); - LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username); - 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 << ": Creating DBUS Connection error: " << error->message); - g_error_free(error); - return; - } - } - - sleep(1); - 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; - std::string b(buffer); - LOG4CXX_WARN(logger, "Skype wrote this on stdout '" << b << "'"); - if (b.find("Incorrect Password") != std::string::npos) { - LOG4CXX_INFO(logger, "Incorrect password, logging out") - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_FAILED, "Incorrect password"); - close(fd_output); - logout(); - return FALSE; - } - } - - std::string re = send_command("NAME Spectrum"); - if (m_counter++ > 15) { - LOG4CXX_ERROR(logger, "Logging out, because we tried to connect the Skype over DBUS 15 times without success"); - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); - close(fd_output); - logout(); - return FALSE; - } - - if (re.empty() || re == "CONNSTATUS OFFLINE" || re == "ERROR 68") { - return TRUE; - } - - close(fd_output); - - if (send_command("PROTOCOL 7") != "PROTOCOL 7") { - LOG4CXX_ERROR(logger, "PROTOCOL 7 failed, logging out"); - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); - logout(); - return FALSE; - } - - np->handleConnected(m_user); - - std::map group_map; - std::string groups = send_command("SEARCH GROUPS CUSTOM"); - if (groups.find(' ') != std::string::npos) { - 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"); - - if (name.find("ERROR") == 0) { - continue; - } - - boost::split(data, name, boost::is_any_of(" ")); - name = GET_RESPONSE_DATA(name, "DISPLAYNAME"); - - std::string users = send_command("GET GROUP " + data[1] + " USERS"); - try { - users = GET_RESPONSE_DATA(users, "USERS"); - } - catch (std::out_of_range& oor) { - continue; - } - 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+1] && *full_friends_list[i] != '\0'; i+=8) - { - std::string buddy = full_friends_list[i]; - - if (buddy[0] == ',') { - buddy.erase(buddy.begin()); - } - - if (buddy.rfind(",") != std::string::npos) { - 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]; - - 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]; - } - - std::vector groups; - if (group_map.find(buddy) != group_map.end()) { - 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"); - send_command("SET USERSTATUS ONLINE"); - return FALSE; -} - -void Skype::logout() { - if (m_pid != 0) { - if (m_proxy) { - send_command("SET USERSTATUS INVISIBLE"); - send_command("SET USERSTATUS OFFLINE"); - sleep(2); - g_object_unref(m_proxy); - } - LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)"); - kill((int) m_pid, SIGTERM); - // Give skype a chance - sleep(2); - LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)"); - kill((int) m_pid, SIGKILL); - 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]; - - LOG4CXX_INFO(logger, "Sending: '" << message << "'"); - 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); - return ""; - } else { - LOG4CXX_INFO(logger, m_username << ": DBUS no response"); - return ""; - } - - } - 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]); - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); - } - } - else if (cmd[2] == "MOOD_TEXT") { - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::string mood_text = GET_RESPONSE_DATA(message, "MOOD_TEXT"); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); - } - else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") { - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); - } - else if (cmd[2] == "FULLNAME") { - GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); - } - else if(cmd[2] == "RECEIVEDAUTHREQUEST") { - np->handleAuthorization(sk->getUser(), cmd[1]); - } - } - else if (cmd[0] == "GROUP") { -// if (cmd[2] == "DISPLAYNAME") { -// //GROUP 810 DISPLAYNAME My Friends -// std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); -// std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); -// try { -// users = GET_RESPONSE_DATA(users, "USERS"); -// } -// catch (std::out_of_range& oor) { -// return; -// } -// -// std::vector data; -// boost::split(data, users, boost::is_any_of(",")); -// BOOST_FOREACH(std::string u, data) { -// GET_PROPERTY(alias, "USER", u, "FULLNAME"); -// GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); -// GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); -// pbnetwork::StatusType status = getStatus(st); -// -// std::vector groups; -// groups.push_back(grp); -// np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); -// } -// } - if (cmd[2] == "NROFUSERS" && cmd[3] != "0") { - GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME"); - std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); - try { - users = GET_RESPONSE_DATA(users, "USERS"); - } - catch (std::out_of_range& oor) { - return; - } - - std::vector data; - boost::split(data, users, boost::is_any_of(",")); - BOOST_FOREACH(std::string u, data) { - GET_PROPERTY(alias, "USER", u, "FULLNAME"); - GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); - GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::vector groups; - groups.push_back(grp); - np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); - } - } - } - else if (cmd[0] == "CHATMESSAGE") { - if (cmd[3] == "RECEIVED") { - GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY"); - GET_PROPERTY(from_handle, "CHATMESSAGE", cmd[1], "FROM_HANDLE"); - - if (from_handle == sk->getUsername()) - return; - - np->handleMessage(sk->getUser(), from_handle, body); - - sk->send_command("SET CHATMESSAGE " + cmd[1] + " SEEN"); - } - } - else if (cmd[0] == "CALL") { - // CALL 884 STATUS RINGING - if (cmd[2] == "STATUS") { - if (cmd[3] == "RINGING" || cmd[3] == "MISSED") { - // handle only incoming calls - GET_PROPERTY(type, "CALL", cmd[1], "TYPE"); - if (type.find("INCOMING") != 0) { - return; - } - - GET_PROPERTY(from, "CALL", cmd[1], "PARTNER_HANDLE"); - GET_PROPERTY(dispname, "CALL", cmd[1], "PARTNER_DISPNAME"); - - if (cmd[3] == "RINGING") { - np->handleMessage(sk->getUser(), from, "User " + dispname + " is calling you."); - } - else { - np->handleMessage(sk->getUser(), from, "You have missed call from user " + dispname + "."); - } - } - } - } -} - -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; @@ -968,6 +444,7 @@ int main(int argc, char **argv) { Logging::initBackendLogging(cfg); g_type_init(); + m_sock = create_socket(host.c_str(), port); @@ -978,7 +455,9 @@ int main(int argc, char **argv) { 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(cfg, host, port); + dbus_threads_init_default(); + + np = new SkypePlugin(cfg, host, port); GMainLoop *m_loop; m_loop = g_main_loop_new(NULL, FALSE); diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 796b656c..4e47ea6a 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -95,6 +95,10 @@ enum ParticipantFlag { PARTICIPANT_FLAG_NOT_AUTHORIZED = 8; PARTICIPANT_FLAG_ME = 16; PARTICIPANT_FLAG_KICKED = 32; + PARTICIPANT_FLAG_VISITOR = 64; + PARTICIPANT_FLAG_MEMBER = 128; + PARTICIPANT_FLAG_ADMIN = 256; + PARTICIPANT_FLAG_OWNER = 512; } message Participant { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 4a36eebf..2d9a5fbf 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -252,8 +252,8 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { // We allow auto_register feature in gateway-mode. This allows IRC user to register // the transport just by joining the room. if (!m_component->inServerMode()) { - if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") || - !CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) { + if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") + /*!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true)*/)) { res.password = ""; res.jid = userkey; From 255cc8416c6bd55c9d5acd16827529865789d460 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 6 Feb 2013 22:15:35 +0100 Subject: [PATCH 48/57] Revert "fix autoregistration" This reverts commit 393cf1cc03032c5938bcc57d54659b6aeb415aa3. --- backends/skype/main.cpp | 547 ++++++++++++++++++++++++++++++- include/transport/protocol.proto | 4 - src/usermanager.cpp | 4 +- 3 files changed, 536 insertions(+), 19 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 17c5ac6f..5d603d36 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -1,6 +1,4 @@ #include "glib.h" -#include -#include "sqlite3.h" #include #include "transport/config.h" @@ -22,15 +20,16 @@ #ifndef __FreeBSD__ #include "malloc.h" #endif +#include -#include "skype.h" +#include "sqlite3.h" DEFINE_LOGGER(logger, "backend"); using namespace Transport; -class SkypePlugin; +class SpectrumNetworkPlugin; #define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); #define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ @@ -71,7 +70,7 @@ class SkypePlugin; LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ } -SkypePlugin *np; +SpectrumNetworkPlugin *np; int m_sock; static int writeInput; @@ -98,14 +97,50 @@ static pbnetwork::StatusType getStatus(const std::string &st) { return status; } -class SkypePlugin : public NetworkPlugin { +class Skype { public: - SkypePlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { + Skype(const std::string &user, const std::string &username, const std::string &password); + ~Skype() { LOG4CXX_INFO(logger, "Skype instance desctuctor"); 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; + } + + bool createDBusProxy(); + bool loadSkypeBuddies(); + + int getPid() { + return (int) m_pid; + } + + private: + std::string m_username; + std::string m_password; + GPid m_pid; + DBusGConnection *m_connection; + DBusGProxy *m_proxy; + std::string m_user; + int m_timer; + int m_counter; + int fd_output; + std::map m_groups; +}; + +class SpectrumNetworkPlugin : public NetworkPlugin { + public: + SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { this->config = config; LOG4CXX_INFO(logger, "Starting the backend."); } - ~SkypePlugin() { + ~SpectrumNetworkPlugin() { for (std::map::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) { delete (*it).first; } @@ -118,7 +153,7 @@ class SkypePlugin : public NetworkPlugin { } LOG4CXX_INFO(logger, "Creating account with name '" << name << "'"); - Skype *skype = new Skype(this, user, name, password); + Skype *skype = new Skype(user, name, password); m_sessions[user] = skype; m_accounts[skype] = user; @@ -356,6 +391,495 @@ class SkypePlugin : 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; + m_timer = -1; + m_counter = 0; +} + + +static gboolean load_skype_buddies(gpointer data) { + Skype *skype = (Skype *) data; + return skype->loadSkypeBuddies(); +} + +bool Skype::createDBusProxy() { + if (m_proxy == NULL) { + LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); + m_counter++; + + 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); + + if (m_counter == 15) { + LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message); + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message); + logout(); + g_error_free(error); + return FALSE; + } + g_error_free(error); + } + + 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); + + 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() { + if (m_username.find("..") == 0 || m_username.find("/") != std::string::npos) { + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Invalid username"); + return; + } + boost::filesystem::remove_all(std::string("/tmp/skype/") + m_username); + + 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); + + sleep(1); + 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; + GError *error = NULL; + bool spawned = 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, + &error); + + if (!spawned) { + LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message) + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance."); + return; + } + + std::string login_data = std::string(m_username + " " + m_password + "\n"); + LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username); + 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 << ": Creating DBUS Connection error: " << error->message); + g_error_free(error); + return; + } + } + + sleep(1); + 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; + std::string b(buffer); + LOG4CXX_WARN(logger, "Skype wrote this on stdout '" << b << "'"); + if (b.find("Incorrect Password") != std::string::npos) { + LOG4CXX_INFO(logger, "Incorrect password, logging out") + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_FAILED, "Incorrect password"); + close(fd_output); + logout(); + return FALSE; + } + } + + std::string re = send_command("NAME Spectrum"); + if (m_counter++ > 15) { + LOG4CXX_ERROR(logger, "Logging out, because we tried to connect the Skype over DBUS 15 times without success"); + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); + close(fd_output); + logout(); + return FALSE; + } + + if (re.empty() || re == "CONNSTATUS OFFLINE" || re == "ERROR 68") { + return TRUE; + } + + close(fd_output); + + if (send_command("PROTOCOL 7") != "PROTOCOL 7") { + LOG4CXX_ERROR(logger, "PROTOCOL 7 failed, logging out"); + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); + logout(); + return FALSE; + } + + np->handleConnected(m_user); + + std::map group_map; + std::string groups = send_command("SEARCH GROUPS CUSTOM"); + if (groups.find(' ') != std::string::npos) { + 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"); + + if (name.find("ERROR") == 0) { + continue; + } + + boost::split(data, name, boost::is_any_of(" ")); + name = GET_RESPONSE_DATA(name, "DISPLAYNAME"); + + std::string users = send_command("GET GROUP " + data[1] + " USERS"); + try { + users = GET_RESPONSE_DATA(users, "USERS"); + } + catch (std::out_of_range& oor) { + continue; + } + 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+1] && *full_friends_list[i] != '\0'; i+=8) + { + std::string buddy = full_friends_list[i]; + + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + + if (buddy.rfind(",") != std::string::npos) { + 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]; + + 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]; + } + + std::vector groups; + if (group_map.find(buddy) != group_map.end()) { + 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"); + send_command("SET USERSTATUS ONLINE"); + return FALSE; +} + +void Skype::logout() { + if (m_pid != 0) { + if (m_proxy) { + send_command("SET USERSTATUS INVISIBLE"); + send_command("SET USERSTATUS OFFLINE"); + sleep(2); + g_object_unref(m_proxy); + } + LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)"); + kill((int) m_pid, SIGTERM); + // Give skype a chance + sleep(2); + LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)"); + kill((int) m_pid, SIGKILL); + 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]; + + LOG4CXX_INFO(logger, "Sending: '" << message << "'"); + 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); + return ""; + } else { + LOG4CXX_INFO(logger, m_username << ": DBUS no response"); + return ""; + } + + } + 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]); + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); + } + } + else if (cmd[2] == "MOOD_TEXT") { + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::string mood_text = GET_RESPONSE_DATA(message, "MOOD_TEXT"); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); + } + else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") { + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); + } + else if (cmd[2] == "FULLNAME") { + GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); + } + else if(cmd[2] == "RECEIVEDAUTHREQUEST") { + np->handleAuthorization(sk->getUser(), cmd[1]); + } + } + else if (cmd[0] == "GROUP") { +// if (cmd[2] == "DISPLAYNAME") { +// //GROUP 810 DISPLAYNAME My Friends +// std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); +// std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); +// try { +// users = GET_RESPONSE_DATA(users, "USERS"); +// } +// catch (std::out_of_range& oor) { +// return; +// } +// +// std::vector data; +// boost::split(data, users, boost::is_any_of(",")); +// BOOST_FOREACH(std::string u, data) { +// GET_PROPERTY(alias, "USER", u, "FULLNAME"); +// GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); +// GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); +// pbnetwork::StatusType status = getStatus(st); +// +// std::vector groups; +// groups.push_back(grp); +// np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); +// } +// } + if (cmd[2] == "NROFUSERS" && cmd[3] != "0") { + GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME"); + std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); + try { + users = GET_RESPONSE_DATA(users, "USERS"); + } + catch (std::out_of_range& oor) { + return; + } + + std::vector data; + boost::split(data, users, boost::is_any_of(",")); + BOOST_FOREACH(std::string u, data) { + GET_PROPERTY(alias, "USER", u, "FULLNAME"); + GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); + GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + groups.push_back(grp); + np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); + } + } + } + else if (cmd[0] == "CHATMESSAGE") { + if (cmd[3] == "RECEIVED") { + GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY"); + GET_PROPERTY(from_handle, "CHATMESSAGE", cmd[1], "FROM_HANDLE"); + + if (from_handle == sk->getUsername()) + return; + + np->handleMessage(sk->getUser(), from_handle, body); + + sk->send_command("SET CHATMESSAGE " + cmd[1] + " SEEN"); + } + } + else if (cmd[0] == "CALL") { + // CALL 884 STATUS RINGING + if (cmd[2] == "STATUS") { + if (cmd[3] == "RINGING" || cmd[3] == "MISSED") { + // handle only incoming calls + GET_PROPERTY(type, "CALL", cmd[1], "TYPE"); + if (type.find("INCOMING") != 0) { + return; + } + + GET_PROPERTY(from, "CALL", cmd[1], "PARTNER_HANDLE"); + GET_PROPERTY(dispname, "CALL", cmd[1], "PARTNER_DISPNAME"); + + if (cmd[3] == "RINGING") { + np->handleMessage(sk->getUser(), from, "User " + dispname + " is calling you."); + } + else { + np->handleMessage(sk->getUser(), from, "You have missed call from user " + dispname + "."); + } + } + } + } +} + +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; @@ -444,7 +968,6 @@ int main(int argc, char **argv) { Logging::initBackendLogging(cfg); g_type_init(); - m_sock = create_socket(host.c_str(), port); @@ -455,9 +978,7 @@ int main(int argc, char **argv) { channel = g_io_channel_unix_new(m_sock); g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy); - dbus_threads_init_default(); - - np = new SkypePlugin(cfg, host, port); + np = new SpectrumNetworkPlugin(cfg, host, port); GMainLoop *m_loop; m_loop = g_main_loop_new(NULL, FALSE); diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 4e47ea6a..796b656c 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -95,10 +95,6 @@ enum ParticipantFlag { PARTICIPANT_FLAG_NOT_AUTHORIZED = 8; PARTICIPANT_FLAG_ME = 16; PARTICIPANT_FLAG_KICKED = 32; - PARTICIPANT_FLAG_VISITOR = 64; - PARTICIPANT_FLAG_MEMBER = 128; - PARTICIPANT_FLAG_ADMIN = 256; - PARTICIPANT_FLAG_OWNER = 512; } message Participant { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 2d9a5fbf..4a36eebf 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -252,8 +252,8 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { // We allow auto_register feature in gateway-mode. This allows IRC user to register // the transport just by joining the room. if (!m_component->inServerMode()) { - if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") - /*!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true)*/)) { + if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") || + !CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) { res.password = ""; res.jid = userkey; From f2b00dd7da8f01d354e0a951979464ad124c8cfa Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 6 Feb 2013 22:16:04 +0100 Subject: [PATCH 49/57] fix autoregistration --- src/usermanager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 4a36eebf..2d9a5fbf 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -252,8 +252,8 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { // We allow auto_register feature in gateway-mode. This allows IRC user to register // the transport just by joining the room. if (!m_component->inServerMode()) { - if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") || - !CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) { + if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") + /*!CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true)*/)) { res.password = ""; res.jid = userkey; From 052df6134f85ca7df7f760d686a054783b67e346 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 7 Feb 2013 11:28:42 +0100 Subject: [PATCH 50/57] Do not create blist.xml --- backends/libpurple/main.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 1de35fbc..976f9baa 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -881,6 +881,23 @@ static void NodeRemoved(PurpleBlistNode *node, void *data) { // PurpleBuddy *buddy = (PurpleBuddy *) node; } +static void buddyListSaveNode(PurpleBlistNode *node) { + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) + return; + +} + +static void buddyListNewNode(PurpleBlistNode *node) { + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) + return; + +} + +static void buddyListRemoveNode(PurpleBlistNode *node) { + if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) + return; +} + static PurpleBlistUiOps blistUiOps = { NULL, @@ -893,9 +910,9 @@ static PurpleBlistUiOps blistUiOps = NULL, // buddyListAddBuddy, NULL, NULL, - NULL, //buddyListSaveNode, - NULL, //buddyListRemoveNode, - NULL, //buddyListSaveAccount, + buddyListSaveNode, + buddyListRemoveNode, + buddyListSaveAccount, NULL }; From 0dd7c411c7bf2914397edc20d8ea852ae83c5122 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 7 Feb 2013 11:57:25 +0100 Subject: [PATCH 51/57] Remove duplicated buddyListNewNode method --- backends/libpurple/main.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index a3e0dd36..e8004dfb 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -945,10 +945,7 @@ static void buddyListSaveNode(PurpleBlistNode *node) { } -static void buddyListNewNode(PurpleBlistNode *node) { - if (!PURPLE_BLIST_NODE_IS_BUDDY(node)) - return; - +static void buddyListSaveAccount(PurpleAccount *account) { } static void buddyListRemoveNode(PurpleBlistNode *node) { From 7a3c38c46d32e8cb7d5095e3267ce8e28c53040f Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 7 Feb 2013 14:57:23 +0100 Subject: [PATCH 52/57] Skype: split skype backend into more files --- backends/skype/main.cpp | 929 +-------------------------------- backends/skype/skype.cpp | 609 +++++++++++++++++++++ backends/skype/skype.h | 82 +++ backends/skype/skypeplugin.cpp | 390 ++++++++++++++ backends/skype/skypeplugin.h | 74 +++ 5 files changed, 1171 insertions(+), 913 deletions(-) create mode 100644 backends/skype/skype.cpp create mode 100644 backends/skype/skype.h create mode 100644 backends/skype/skypeplugin.cpp create mode 100644 backends/skype/skypeplugin.h diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 5d603d36..1516dc10 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -1,4 +1,6 @@ #include "glib.h" +#include +#include "sqlite3.h" #include #include "transport/config.h" @@ -20,866 +22,15 @@ #ifndef __FreeBSD__ #include "malloc.h" #endif -#include -#include "sqlite3.h" +#include "skype.h" +#include "skypeplugin.h" DEFINE_LOGGER(logger, "backend"); using namespace Transport; -class SpectrumNetworkPlugin; - -#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); -#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ - try {\ - VAR = GET_RESPONSE_DATA(VAR, PROP);\ - }\ - catch (std::out_of_range& oor) {\ - VAR="";\ - } - - - -// Prepare the SQL statement -#define PREP_STMT(sql, str) \ - if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ - LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \ - sql = NULL; \ - } - -// Finalize the prepared statement -#define FINALIZE_STMT(prep) \ - if(prep != NULL) { \ - sqlite3_finalize(prep); \ - } - -#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ - int STATEMENT##_id = 1;\ - int STATEMENT##_id_get = 0;\ - (void)STATEMENT##_id_get; - -#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) -#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) -#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; -#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) -#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) -#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) -#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ - LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ - } - -SpectrumNetworkPlugin *np; - -int m_sock; -static int writeInput; - -static std::string host; -static int port = 10000; - -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() { LOG4CXX_INFO(logger, "Skype instance desctuctor"); 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; - } - - bool createDBusProxy(); - bool loadSkypeBuddies(); - - int getPid() { - return (int) m_pid; - } - - private: - std::string m_username; - std::string m_password; - GPid m_pid; - DBusGConnection *m_connection; - DBusGProxy *m_proxy; - std::string m_user; - int m_timer; - int m_counter; - int fd_output; - std::map m_groups; -}; - -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() { - 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; - if (name.find("skype.") == 0 || name.find("prpl-skype.") == 0) { - 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 handleMemoryUsage(double &res, double &shared) { - res = 0; - shared = 0; - for(std::map::const_iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { - Skype *skype = it->second; - if (skype) { - double r; - double s; - process_mem_usage(s, r, skype->getPid()); - res += r; - shared += s; - } - } - } - - void handleLogoutRequest(const std::string &user, const std::string &legacyName) { - Skype *skype = m_sessions[user]; - if (skype) { - LOG4CXX_INFO(logger, "User wants to logout, logging out"); - skype->logout(); - Logging::shutdownLogging(); - 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 handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { - Skype *skype = m_sessions[user]; - if (skype) { - skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 2 Please authorize me"); - skype->send_command("SET USER " + buddyName + " ISAUTHORIZED TRUE"); - } - } - - void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { - Skype *skype = m_sessions[user]; - if (skype) { - skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 1"); - skype->send_command("SET USER " + buddyName + " ISAUTHORIZED FALSE"); - } - } - - void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = "") { - 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); - - if (photo.empty()) { - sqlite3 *db; - std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.db"; - LOG4CXX_INFO(logger, "Opening database " << db_path); - if (sqlite3_open(db_path.c_str(), &db)) { - sqlite3_close(db); - LOG4CXX_ERROR(logger, "Can't open database"); - } - else { - sqlite3_stmt *stmt; - PREP_STMT(stmt, "SELECT avatar_image FROM Contacts WHERE skypename=?"); - if (stmt) { - BEGIN(stmt); - BIND_STR(stmt, name); - if(sqlite3_step(stmt) == SQLITE_ROW) { - int size = sqlite3_column_bytes(stmt, 0); - const void *data = sqlite3_column_blob(stmt, 0); - photo = std::string((const char *)data + 1, size - 1); - } - else { - LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); - } - - int ret; - while((ret = sqlite3_step(stmt)) == SQLITE_ROW) { - } - FINALIZE_STMT(stmt); - } - else { - LOG4CXX_ERROR(logger, "Can't created prepared statement"); - LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); - } - sqlite3_close(db); - } - } - - std::string alias = ""; - std::cout << skype->getUsername() << " " << name << "\n"; - if (skype->getUsername() == name) { - alias = skype->send_command("GET PROFILE FULLNAME"); - alias = GET_RESPONSE_DATA(alias, "FULLNAME") - } - 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 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; - m_timer = -1; - m_counter = 0; -} - - -static gboolean load_skype_buddies(gpointer data) { - Skype *skype = (Skype *) data; - return skype->loadSkypeBuddies(); -} - -bool Skype::createDBusProxy() { - if (m_proxy == NULL) { - LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); - m_counter++; - - 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); - - if (m_counter == 15) { - LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message); - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message); - logout(); - g_error_free(error); - return FALSE; - } - g_error_free(error); - } - - 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); - - 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() { - if (m_username.find("..") == 0 || m_username.find("/") != std::string::npos) { - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Invalid username"); - return; - } - boost::filesystem::remove_all(std::string("/tmp/skype/") + m_username); - - 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); - - sleep(1); - 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; - GError *error = NULL; - bool spawned = 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, - &error); - - if (!spawned) { - LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message) - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance."); - return; - } - - std::string login_data = std::string(m_username + " " + m_password + "\n"); - LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username); - 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 << ": Creating DBUS Connection error: " << error->message); - g_error_free(error); - return; - } - } - - sleep(1); - 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; - std::string b(buffer); - LOG4CXX_WARN(logger, "Skype wrote this on stdout '" << b << "'"); - if (b.find("Incorrect Password") != std::string::npos) { - LOG4CXX_INFO(logger, "Incorrect password, logging out") - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_FAILED, "Incorrect password"); - close(fd_output); - logout(); - return FALSE; - } - } - - std::string re = send_command("NAME Spectrum"); - if (m_counter++ > 15) { - LOG4CXX_ERROR(logger, "Logging out, because we tried to connect the Skype over DBUS 15 times without success"); - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); - close(fd_output); - logout(); - return FALSE; - } - - if (re.empty() || re == "CONNSTATUS OFFLINE" || re == "ERROR 68") { - return TRUE; - } - - close(fd_output); - - if (send_command("PROTOCOL 7") != "PROTOCOL 7") { - LOG4CXX_ERROR(logger, "PROTOCOL 7 failed, logging out"); - np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); - logout(); - return FALSE; - } - - np->handleConnected(m_user); - - std::map group_map; - std::string groups = send_command("SEARCH GROUPS CUSTOM"); - if (groups.find(' ') != std::string::npos) { - 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"); - - if (name.find("ERROR") == 0) { - continue; - } - - boost::split(data, name, boost::is_any_of(" ")); - name = GET_RESPONSE_DATA(name, "DISPLAYNAME"); - - std::string users = send_command("GET GROUP " + data[1] + " USERS"); - try { - users = GET_RESPONSE_DATA(users, "USERS"); - } - catch (std::out_of_range& oor) { - continue; - } - 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+1] && *full_friends_list[i] != '\0'; i+=8) - { - std::string buddy = full_friends_list[i]; - - if (buddy[0] == ',') { - buddy.erase(buddy.begin()); - } - - if (buddy.rfind(",") != std::string::npos) { - 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]; - - 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]; - } - - std::vector groups; - if (group_map.find(buddy) != group_map.end()) { - 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"); - send_command("SET USERSTATUS ONLINE"); - return FALSE; -} - -void Skype::logout() { - if (m_pid != 0) { - if (m_proxy) { - send_command("SET USERSTATUS INVISIBLE"); - send_command("SET USERSTATUS OFFLINE"); - sleep(2); - g_object_unref(m_proxy); - } - LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)"); - kill((int) m_pid, SIGTERM); - // Give skype a chance - sleep(2); - LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)"); - kill((int) m_pid, SIGKILL); - 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]; - - LOG4CXX_INFO(logger, "Sending: '" << message << "'"); - 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); - return ""; - } else { - LOG4CXX_INFO(logger, m_username << ": DBUS no response"); - return ""; - } - - } - 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]); - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); - } - } - else if (cmd[2] == "MOOD_TEXT") { - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::string mood_text = GET_RESPONSE_DATA(message, "MOOD_TEXT"); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); - } - else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") { - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], "", groups, status, mood_text); - } - else if (cmd[2] == "FULLNAME") { - GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); - GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); - GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::vector groups; - np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); - } - else if(cmd[2] == "RECEIVEDAUTHREQUEST") { - np->handleAuthorization(sk->getUser(), cmd[1]); - } - } - else if (cmd[0] == "GROUP") { -// if (cmd[2] == "DISPLAYNAME") { -// //GROUP 810 DISPLAYNAME My Friends -// std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); -// std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); -// try { -// users = GET_RESPONSE_DATA(users, "USERS"); -// } -// catch (std::out_of_range& oor) { -// return; -// } -// -// std::vector data; -// boost::split(data, users, boost::is_any_of(",")); -// BOOST_FOREACH(std::string u, data) { -// GET_PROPERTY(alias, "USER", u, "FULLNAME"); -// GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); -// GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); -// pbnetwork::StatusType status = getStatus(st); -// -// std::vector groups; -// groups.push_back(grp); -// np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); -// } -// } - if (cmd[2] == "NROFUSERS" && cmd[3] != "0") { - GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME"); - std::string users = sk->send_command("GET GROUP " + cmd[1] + " USERS"); - try { - users = GET_RESPONSE_DATA(users, "USERS"); - } - catch (std::out_of_range& oor) { - return; - } - - std::vector data; - boost::split(data, users, boost::is_any_of(",")); - BOOST_FOREACH(std::string u, data) { - GET_PROPERTY(alias, "USER", u, "FULLNAME"); - GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); - GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); - pbnetwork::StatusType status = getStatus(st); - - std::vector groups; - groups.push_back(grp); - np->handleBuddyChanged(sk->getUser(), u, alias, groups, status, mood_text); - } - } - } - else if (cmd[0] == "CHATMESSAGE") { - if (cmd[3] == "RECEIVED") { - GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY"); - GET_PROPERTY(from_handle, "CHATMESSAGE", cmd[1], "FROM_HANDLE"); - - if (from_handle == sk->getUsername()) - return; - - np->handleMessage(sk->getUser(), from_handle, body); - - sk->send_command("SET CHATMESSAGE " + cmd[1] + " SEEN"); - } - } - else if (cmd[0] == "CALL") { - // CALL 884 STATUS RINGING - if (cmd[2] == "STATUS") { - if (cmd[3] == "RINGING" || cmd[3] == "MISSED") { - // handle only incoming calls - GET_PROPERTY(type, "CALL", cmd[1], "TYPE"); - if (type.find("INCOMING") != 0) { - return; - } - - GET_PROPERTY(from, "CALL", cmd[1], "PARTNER_HANDLE"); - GET_PROPERTY(dispname, "CALL", cmd[1], "PARTNER_DISPNAME"); - - if (cmd[3] == "RINGING") { - np->handleMessage(sk->getUser(), from, "User " + dispname + " is calling you."); - } - else { - np->handleMessage(sk->getUser(), from, "You have missed call from user " + dispname + "."); - } - } - } - } -} - -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; @@ -896,68 +47,24 @@ static void spectrum_sigchld_handler(int sig) } } -static int create_socket(const 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 - Logging::shutdownLogging(); - 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"); - Logging::shutdownLogging(); - exit(errno); - } - std::string d = std::string(buffer, n); - np->handleDataRead(d); - return TRUE; -} - -static void io_destroy(gpointer data) { - Logging::shutdownLogging(); - exit(1); -} - static void log_glib_error(const gchar *string) { LOG4CXX_ERROR(logger, "GLIB ERROR:" << string); } int main(int argc, char **argv) { #ifndef WIN32 - signal(SIGPIPE, SIG_IGN); + signal(SIGPIPE, SIG_IGN); - if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { - std::cout << "SIGCHLD handler can't be set\n"; - return -1; - } + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } #endif + std::string host; + int port = 10000; + + std::string error; Config *cfg = Config::createFromArgs(argc, argv, error, host, port); if (cfg == NULL) { @@ -969,16 +76,11 @@ int main(int argc, char **argv) { g_type_init(); - m_sock = create_socket(host.c_str(), port); - g_set_printerr_handler(log_glib_error); - GIOChannel *channel; - 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); + dbus_threads_init_default(); - np = new SpectrumNetworkPlugin(cfg, host, port); + SkypePlugin *np = new SkypePlugin(cfg, host, port); GMainLoop *m_loop; m_loop = g_main_loop_new(NULL, FALSE); @@ -987,4 +89,5 @@ int main(int argc, char **argv) { g_main_loop_run(m_loop); } + return 0; } diff --git a/backends/skype/skype.cpp b/backends/skype/skype.cpp new file mode 100644 index 00000000..050e9722 --- /dev/null +++ b/backends/skype/skype.cpp @@ -0,0 +1,609 @@ +/** + * 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 + */ + +#include "skype.h" +#include "skypeplugin.h" + +#include "transport/config.h" +#include "transport/logging.h" +#include "transport/transport.h" +#include "transport/usermanager.h" +#include "transport/memoryusage.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 +#include "sys/wait.h" +#include "sys/signal.h" +// #include "valgrind/memcheck.h" +#ifndef __FreeBSD__ +#include "malloc.h" +#endif + + +#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); +#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ + try {\ + VAR = GET_RESPONSE_DATA(VAR, PROP);\ + }\ + catch (std::out_of_range& oor) {\ + VAR="";\ + } + + + +// Prepare the SQL statement +#define PREP_STMT(sql, str) \ + if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ + LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \ + sql = NULL; \ + } + +// Finalize the prepared statement +#define FINALIZE_STMT(prep) \ + if(prep != NULL) { \ + sqlite3_finalize(prep); \ + } + +#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ + int STATEMENT##_id = 1;\ + int STATEMENT##_id_get = 0;\ + (void)STATEMENT##_id_get; + +#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) +#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) +#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; +#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) +#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) +#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) +#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ + LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ + } + +DEFINE_LOGGER(logger, "Skype"); + +Skype::Skype(SkypePlugin *np, 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; + m_np = np; +} + +static gboolean load_skype_buddies(gpointer data) { + Skype *skype = (Skype *) data; + return skype->loadSkypeBuddies(); +} + +static gboolean create_dbus_proxy(gpointer data) { + Skype *skype = (Skype *) data; + return skype->createDBusProxy(); +} + +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; +} + +DBusHandlerResult skype_notify_handler(DBusConnection *connection, DBusMessage *message, gpointer data) { + Skype *skype = (Skype *) data; + return skype->dbusMessageReceived(connection, message); +} + +void Skype::login() { + // Do not allow usernames with unsecure symbols + if (m_username.find("..") == 0 || m_username.find("/") != std::string::npos) { + m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Invalid username"); + return; + } + + std::string db_path = createSkypeDirectory(); + + bool spawned = spawnSkype(db_path); + if (!spawned) { + m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance."); + return; + } + + + 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 << ": Creating DBUS Connection error: " << error->message); + g_error_free(error); + return; + } + } + + m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this); +} + +bool Skype::createDBusProxy() { + if (m_proxy == NULL) { + LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); + m_counter++; + + 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); + + if (m_counter == 15) { + LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message); + m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message); + logout(); + g_error_free(error); + return FALSE; + } + g_error_free(error); + } + + 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); + + m_counter = 0; + m_timer = g_timeout_add_seconds(1, load_skype_buddies, this); + return FALSE; + } + return TRUE; + } + return FALSE; +} + +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; + std::string b(buffer); + LOG4CXX_WARN(logger, "Skype wrote this on stdout '" << b << "'"); + if (b.find("Incorrect Password") != std::string::npos) { + LOG4CXX_INFO(logger, "Incorrect password, logging out") + m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_FAILED, "Incorrect password"); + close(fd_output); + logout(); + return FALSE; + } + } + + std::string re = send_command("NAME Spectrum"); + if (m_counter++ > 15) { + LOG4CXX_ERROR(logger, "Logging out, because we tried to connect the Skype over DBUS 15 times without success"); + m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); + close(fd_output); + logout(); + return FALSE; + } + + if (re.empty() || re == "CONNSTATUS OFFLINE" || re == "ERROR 68") { + return TRUE; + } + + close(fd_output); + + if (send_command("PROTOCOL 7") != "PROTOCOL 7") { + LOG4CXX_ERROR(logger, "PROTOCOL 7 failed, logging out"); + m_np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Skype is not ready. This issue have been logged and admins will check it and try to fix it soon."); + logout(); + return FALSE; + } + + m_np->handleConnected(m_user); + + std::map group_map; + std::string groups = send_command("SEARCH GROUPS CUSTOM"); + if (groups.find(' ') != std::string::npos) { + 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"); + + if (name.find("ERROR") == 0) { + continue; + } + + boost::split(data, name, boost::is_any_of(" ")); + name = GET_RESPONSE_DATA(name, "DISPLAYNAME"); + + std::string users = send_command("GET GROUP " + data[1] + " USERS"); + try { + users = GET_RESPONSE_DATA(users, "USERS"); + } + catch (std::out_of_range& oor) { + continue; + } + 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+1] && *full_friends_list[i] != '\0'; i+=8) + { + std::string buddy = full_friends_list[i]; + + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + + if (buddy.rfind(",") != std::string::npos) { + 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]; + + 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]; + } + + std::vector groups; + if (group_map.find(buddy) != group_map.end()) { + groups.push_back(group_map[buddy]); + } + m_np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); + } + } + g_strfreev(full_friends_list); + + send_command("SET AUTOAWAY OFF"); + send_command("SET USERSTATUS ONLINE"); + return FALSE; +} + +void Skype::logout() { + if (m_pid != 0) { + if (m_proxy) { + send_command("SET USERSTATUS INVISIBLE"); + send_command("SET USERSTATUS OFFLINE"); + sleep(2); + g_object_unref(m_proxy); + } + LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)"); + kill((int) m_pid, SIGTERM); + // Give skype a chance + sleep(2); + LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)"); + kill((int) m_pid, SIGKILL); + 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]; + + LOG4CXX_INFO(logger, "Sending: '" << message << "'"); + 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); + return ""; + } else { + LOG4CXX_INFO(logger, m_username << ": DBUS no response"); + return ""; + } + + } + if (str != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS:'" << str << "'"); + } + return str ? std::string(str) : std::string(); +} + +void Skype::handleSkypeMessage(std::string &message) { + std::vector cmd; + boost::split(cmd, message, boost::is_any_of(" ")); + + if (cmd[0] == "USER") { + if (cmd[1] == getUsername()) { + return; + } + + if (cmd[2] == "ONLINESTATUS") { + if (cmd[3] == "SKYPEOUT" || cmd[3] == "UNKNOWN") { + return; + } + else { + pbnetwork::StatusType status = getStatus(cmd[3]); + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); + + std::vector groups; + m_np->handleBuddyChanged(getUser(), cmd[1], alias, groups, status, mood_text); + } + } + else if (cmd[2] == "MOOD_TEXT") { + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::string mood_text = GET_RESPONSE_DATA(message, "MOOD_TEXT"); + + std::vector groups; + m_np->handleBuddyChanged(getUser(), cmd[1], "", groups, status, mood_text); + } + else if (cmd[2] == "BUDDYSTATUS" && cmd[3] == "3") { + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + m_np->handleBuddyChanged(getUser(), cmd[1], "", groups, status, mood_text); + } + else if (cmd[2] == "FULLNAME") { + GET_PROPERTY(alias, "USER", cmd[1], "FULLNAME"); + GET_PROPERTY(mood_text, "USER", cmd[1], "MOOD_TEXT"); + GET_PROPERTY(st, "USER", cmd[1], "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + m_np->handleBuddyChanged(getUser(), cmd[1], alias, groups, status, mood_text); + } + else if(cmd[2] == "RECEIVEDAUTHREQUEST") { + m_np->handleAuthorization(getUser(), cmd[1]); + } + } + else if (cmd[0] == "GROUP") { +// if (cmd[2] == "DISPLAYNAME") { +// //GROUP 810 DISPLAYNAME My Friends +// std::string grp = GET_RESPONSE_DATA(message, "DISPLAYNAME"); +// std::string users = send_command("GET GROUP " + cmd[1] + " USERS"); +// try { +// users = GET_RESPONSE_DATA(users, "USERS"); +// } +// catch (std::out_of_range& oor) { +// return; +// } +// +// std::vector data; +// boost::split(data, users, boost::is_any_of(",")); +// BOOST_FOREACH(std::string u, data) { +// GET_PROPERTY(alias, "USER", u, "FULLNAME"); +// GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); +// GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); +// pbnetwork::StatusType status = getStatus(st); +// +// std::vector groups; +// groups.push_back(grp); +// m_np->handleBuddyChanged(getUser(), u, alias, groups, status, mood_text); +// } +// } + if (cmd[2] == "NROFUSERS" && cmd[3] != "0") { + GET_PROPERTY(grp, "GROUP", cmd[1], "DISPLAYNAME"); + std::string users = send_command("GET GROUP " + cmd[1] + " USERS"); + try { + users = GET_RESPONSE_DATA(users, "USERS"); + } + catch (std::out_of_range& oor) { + return; + } + + std::vector data; + boost::split(data, users, boost::is_any_of(",")); + BOOST_FOREACH(std::string u, data) { + GET_PROPERTY(alias, "USER", u, "FULLNAME"); + GET_PROPERTY(mood_text, "USER", u, "MOOD_TEXT"); + GET_PROPERTY(st, "USER", u, "ONLINESTATUS"); + pbnetwork::StatusType status = getStatus(st); + + std::vector groups; + groups.push_back(grp); + m_np->handleBuddyChanged(getUser(), u, alias, groups, status, mood_text); + } + } + } + else if (cmd[0] == "CHATMESSAGE") { + if (cmd[3] == "RECEIVED") { + GET_PROPERTY(body, "CHATMESSAGE", cmd[1], "BODY"); + GET_PROPERTY(from_handle, "CHATMESSAGE", cmd[1], "FROM_HANDLE"); + + if (from_handle == getUsername()) + return; + + m_np->handleMessage(getUser(), from_handle, body); + + send_command("SET CHATMESSAGE " + cmd[1] + " SEEN"); + } + } + else if (cmd[0] == "CALL") { + // CALL 884 STATUS RINGING + if (cmd[2] == "STATUS") { + if (cmd[3] == "RINGING" || cmd[3] == "MISSED") { + // handle only incoming calls + GET_PROPERTY(type, "CALL", cmd[1], "TYPE"); + if (type.find("INCOMING") != 0) { + return; + } + + GET_PROPERTY(from, "CALL", cmd[1], "PARTNER_HANDLE"); + GET_PROPERTY(dispname, "CALL", cmd[1], "PARTNER_DISPNAME"); + + if (cmd[3] == "RINGING") { + m_np->handleMessage(getUser(), from, "User " + dispname + " is calling you."); + } + else { + m_np->handleMessage(getUser(), from, "You have missed call from user " + dispname + "."); + } + } + } + } +} + +DBusHandlerResult Skype::dbusMessageReceived(DBusConnection *connection, DBusMessage *message) { + 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); + handleSkypeMessage(m); + } while(dbus_message_iter_has_next(&iterator) && dbus_message_iter_next(&iterator)); + + dbus_message_unref(message); + + return DBUS_HANDLER_RESULT_HANDLED; +} + +std::string Skype::createSkypeDirectory() { + std::string tmpdir = std::string("/tmp/skype/") + m_username; + + // This should not be needed anymore... + // boost::filesystem::remove_all(std::string("/tmp/skype/") + m_username); + + boost::filesystem::path path(tmpdir); + if (!boost::filesystem::exists(path)) { + boost::filesystem::create_directories(path); + boost::filesystem::path path2(tmpdir + "/" + 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(tmpdir + "/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(tmpdir + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL); + + return tmpdir; +} + +bool Skype::spawnSkype(const std::string &db_path) { + 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; + GError *error = NULL; + bool spawned = 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, + &error); + + if (!spawned) { + LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message) + return false; + } + + std::string login_data = std::string(m_username + " " + m_password + "\n"); + LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username); + write(fd, login_data.c_str(), login_data.size()); + close(fd); + + fcntl (fd_output, F_SETFL, O_NONBLOCK); + + free(db); + + return true; +} diff --git a/backends/skype/skype.h b/backends/skype/skype.h new file mode 100644 index 00000000..ec22b335 --- /dev/null +++ b/backends/skype/skype.h @@ -0,0 +1,82 @@ +/** + * 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 "glib.h" +#include +#include "sqlite3.h" +#include +#include + +class SkypePlugin; + +class Skype { + public: + Skype(SkypePlugin *np, const std::string &user, const std::string &username, const std::string &password); + + virtual ~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; + } + + int getPid() { + return (int) m_pid; + } + + public: // but do not use them, should be used only internally + bool createDBusProxy(); + + bool loadSkypeBuddies(); + + void handleSkypeMessage(std::string &message); + + DBusHandlerResult dbusMessageReceived(DBusConnection *connection, DBusMessage *message); + + private: + std::string createSkypeDirectory(); + bool spawnSkype(const std::string &db_path); + + std::string m_username; + std::string m_password; + GPid m_pid; + DBusGConnection *m_connection; + DBusGProxy *m_proxy; + std::string m_user; + int m_timer; + int m_counter; + int fd_output; + std::map m_groups; + SkypePlugin *m_np; +}; + diff --git a/backends/skype/skypeplugin.cpp b/backends/skype/skypeplugin.cpp new file mode 100644 index 00000000..9ef2867b --- /dev/null +++ b/backends/skype/skypeplugin.cpp @@ -0,0 +1,390 @@ +/** + * 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 + */ + +#include "skypeplugin.h" +#include "skype.h" + +#include "transport/config.h" +#include "transport/logging.h" +#include "transport/transport.h" +#include "transport/usermanager.h" +#include "transport/memoryusage.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 +#include "sys/wait.h" +#include "sys/signal.h" +// #include "valgrind/memcheck.h" +#ifndef __FreeBSD__ +#include "malloc.h" +#endif + +#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); +#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ + try {\ + VAR = GET_RESPONSE_DATA(VAR, PROP);\ + }\ + catch (std::out_of_range& oor) {\ + VAR="";\ + } + + + +// Prepare the SQL statement +#define PREP_STMT(sql, str) \ + if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ + LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \ + sql = NULL; \ + } + +// Finalize the prepared statement +#define FINALIZE_STMT(prep) \ + if(prep != NULL) { \ + sqlite3_finalize(prep); \ + } + +#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ + int STATEMENT##_id = 1;\ + int STATEMENT##_id_get = 0;\ + (void)STATEMENT##_id_get; + +#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) +#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) +#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; +#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) +#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) +#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) +#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ + LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ + } + +using namespace Transport; + +DEFINE_LOGGER(logger, "SkypePlugin"); + +static int m_sock; + +static gboolean transportDataReceived(GIOChannel *source, GIOCondition condition, gpointer data) { + SkypePlugin *np = (SkypePlugin *) 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"); + Logging::shutdownLogging(); + exit(errno); + } + std::string d = std::string(buffer, n); + np->handleDataRead(d); + return TRUE; +} + +static int create_socket(const 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 + Logging::shutdownLogging(); + 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 void io_destroy(gpointer data) { + Logging::shutdownLogging(); + exit(1); +} + +SkypePlugin::SkypePlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + LOG4CXX_INFO(logger, "Starting the backend."); + + m_sock = create_socket(host.c_str(), port); + GIOChannel *channel; + 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, this, io_destroy); +} + +SkypePlugin::~SkypePlugin() { + for (std::map::iterator it = m_accounts.begin(); it != m_accounts.end(); it++) { + delete (*it).first; + } +} + +void SkypePlugin::handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + std::string name = legacyName; + if (name.find("skype.") == 0 || name.find("prpl-skype.") == 0) { + name = name.substr(name.find(".") + 1); + } + LOG4CXX_INFO(logger, "Creating account with name '" << name << "'"); + + Skype *skype = new Skype(this, user, name, password); + m_sessions[user] = skype; + m_accounts[skype] = user; + + skype->login(); +} + +void SkypePlugin::handleMemoryUsage(double &res, double &shared) { + res = 0; + shared = 0; + for(std::map::const_iterator it = m_sessions.begin(); it != m_sessions.end(); it++) { + Skype *skype = it->second; + if (skype) { + double r; + double s; + process_mem_usage(s, r, skype->getPid()); + res += r; + shared += s; + } + } +} + +void SkypePlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) { + Skype *skype = m_sessions[user]; + if (skype) { + LOG4CXX_INFO(logger, "User wants to logout, logging out"); + skype->logout(); + Logging::shutdownLogging(); + exit(1); + } +} + +void SkypePlugin::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 SkypePlugin::handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + Skype *skype = m_sessions[user]; + if (skype) { + skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 2 Please authorize me"); + skype->send_command("SET USER " + buddyName + " ISAUTHORIZED TRUE"); + } +} + +void SkypePlugin::handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + Skype *skype = m_sessions[user]; + if (skype) { + skype->send_command("SET USER " + buddyName + " BUDDYSTATUS 1"); + skype->send_command("SET USER " + buddyName + " ISAUTHORIZED FALSE"); + } +} + +void SkypePlugin::handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml, const std::string &id) { + Skype *skype = m_sessions[user]; + if (skype) { + skype->send_command("MESSAGE " + legacyName + " " + message); + } + +} + +void SkypePlugin::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); + + if (photo.empty()) { + sqlite3 *db; + std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.db"; + LOG4CXX_INFO(logger, "Opening database " << db_path); + if (sqlite3_open(db_path.c_str(), &db)) { + sqlite3_close(db); + LOG4CXX_ERROR(logger, "Can't open database"); + } + else { + sqlite3_stmt *stmt; + PREP_STMT(stmt, "SELECT avatar_image FROM Contacts WHERE skypename=?"); + if (stmt) { + BEGIN(stmt); + BIND_STR(stmt, name); + if(sqlite3_step(stmt) == SQLITE_ROW) { + int size = sqlite3_column_bytes(stmt, 0); + const void *data = sqlite3_column_blob(stmt, 0); + photo = std::string((const char *)data + 1, size - 1); + } + else { + LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); + } + + int ret; + while((ret = sqlite3_step(stmt)) == SQLITE_ROW) { + } + FINALIZE_STMT(stmt); + } + else { + LOG4CXX_ERROR(logger, "Can't created prepared statement"); + LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); + } + sqlite3_close(db); + } + } + + std::string alias; + std::cout << skype->getUsername() << " " << name << "\n"; + if (skype->getUsername() == name) { + alias = skype->send_command("GET PROFILE FULLNAME"); + alias = GET_RESPONSE_DATA(alias, "FULLNAME") + } + handleVCard(user, id, legacyName, "", alias, photo); + } +} + +void SkypePlugin::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 SkypePlugin::handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname) { +} + +void SkypePlugin::handleBuddyBlockToggled(const std::string &user, const std::string &buddyName, bool blocked) { + +} + +void SkypePlugin::handleTypingRequest(const std::string &user, const std::string &buddyName) { + +} + +void SkypePlugin::handleTypedRequest(const std::string &user, const std::string &buddyName) { + +} + +void SkypePlugin::handleStoppedTypingRequest(const std::string &user, const std::string &buddyName) { + +} + +void SkypePlugin::handleAttentionRequest(const std::string &user, const std::string &buddyName, const std::string &message) { + +} + diff --git a/backends/skype/skypeplugin.h b/backends/skype/skypeplugin.h new file mode 100644 index 00000000..782814bc --- /dev/null +++ b/backends/skype/skypeplugin.h @@ -0,0 +1,74 @@ +/** + * 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 "glib.h" +#include +#include "sqlite3.h" +#include +#include +#include "transport/networkplugin.h" +#include "transport/config.h" + +class Skype; + +class SkypePlugin : public Transport::NetworkPlugin { + public: + SkypePlugin(Transport::Config *config, const std::string &host, int port); + + virtual ~SkypePlugin(); + + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password); + + void handleMemoryUsage(double &res, double &shared); + + void handleLogoutRequest(const std::string &user, const std::string &legacyName); + + void handleStatusChangeRequest(const std::string &user, int status, const std::string &statusMessage); + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups); + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups); + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "", const std::string &id = ""); + + void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id); + + void sendData(const std::string &string); + + void handleVCardUpdatedRequest(const std::string &user, const std::string &p, const std::string &nickname); + + 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; + Transport::Config *config; + +}; From 0b87eda8069455132f52719d8cc657df66d98786 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 7 Feb 2013 15:21:25 +0100 Subject: [PATCH 53/57] Skype: move sqlite3 db stuff into skypedb.cpp --- backends/skype/skype.cpp | 39 ----------- backends/skype/skype.h | 9 +++ backends/skype/skypedb.cpp | 115 +++++++++++++++++++++++++++++++++ backends/skype/skypedb.h | 33 ++++++++++ backends/skype/skypeplugin.cpp | 45 +------------ 5 files changed, 159 insertions(+), 82 deletions(-) create mode 100644 backends/skype/skypedb.cpp create mode 100644 backends/skype/skypedb.h diff --git a/backends/skype/skype.cpp b/backends/skype/skype.cpp index 050e9722..9f054efe 100644 --- a/backends/skype/skype.cpp +++ b/backends/skype/skype.cpp @@ -42,45 +42,6 @@ #endif -#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); -#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ - try {\ - VAR = GET_RESPONSE_DATA(VAR, PROP);\ - }\ - catch (std::out_of_range& oor) {\ - VAR="";\ - } - - - -// Prepare the SQL statement -#define PREP_STMT(sql, str) \ - if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ - LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \ - sql = NULL; \ - } - -// Finalize the prepared statement -#define FINALIZE_STMT(prep) \ - if(prep != NULL) { \ - sqlite3_finalize(prep); \ - } - -#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ - int STATEMENT##_id = 1;\ - int STATEMENT##_id_get = 0;\ - (void)STATEMENT##_id_get; - -#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) -#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) -#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; -#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) -#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) -#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) -#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ - LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ - } - DEFINE_LOGGER(logger, "Skype"); Skype::Skype(SkypePlugin *np, const std::string &user, const std::string &username, const std::string &password) { diff --git a/backends/skype/skype.h b/backends/skype/skype.h index ec22b335..9b321bc5 100644 --- a/backends/skype/skype.h +++ b/backends/skype/skype.h @@ -26,6 +26,15 @@ #include #include +#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); +#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ + try {\ + VAR = GET_RESPONSE_DATA(VAR, PROP);\ + }\ + catch (std::out_of_range& oor) {\ + VAR="";\ + } + class SkypePlugin; class Skype { diff --git a/backends/skype/skypedb.cpp b/backends/skype/skypedb.cpp new file mode 100644 index 00000000..4daf44ee --- /dev/null +++ b/backends/skype/skypedb.cpp @@ -0,0 +1,115 @@ +/** + * 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 + */ + +#include "skypedb.h" + +#include "transport/config.h" +#include "transport/logging.h" +#include "transport/transport.h" +#include "transport/usermanager.h" +#include "transport/memoryusage.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 +#include "sys/wait.h" +#include "sys/signal.h" +// #include "valgrind/memcheck.h" +#ifndef __FreeBSD__ +#include "malloc.h" +#endif + +// Prepare the SQL statement +#define PREP_STMT(sql, str) \ + if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ + LOG4CXX_ERROR(logger, str<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); \ + sql = NULL; \ + } + +// Finalize the prepared statement +#define FINALIZE_STMT(prep) \ + if(prep != NULL) { \ + sqlite3_finalize(prep); \ + } + +#define BEGIN(STATEMENT) sqlite3_reset(STATEMENT);\ + int STATEMENT##_id = 1;\ + int STATEMENT##_id_get = 0;\ + (void)STATEMENT##_id_get; + +#define BIND_INT(STATEMENT, VARIABLE) sqlite3_bind_int(STATEMENT, STATEMENT##_id++, VARIABLE) +#define BIND_STR(STATEMENT, VARIABLE) sqlite3_bind_text(STATEMENT, STATEMENT##_id++, VARIABLE.c_str(), -1, SQLITE_STATIC) +#define RESET_GET_COUNTER(STATEMENT) STATEMENT##_id_get = 0; +#define GET_INT(STATEMENT) sqlite3_column_int(STATEMENT, STATEMENT##_id_get++) +#define GET_STR(STATEMENT) (const char *) sqlite3_column_text(STATEMENT, STATEMENT##_id_get++) +#define GET_BLOB(STATEMENT) (const void *) sqlite3_column_blob(STATEMENT, STATEMENT##_id_get++) +#define EXECUTE_STATEMENT(STATEMENT, NAME) if(sqlite3_step(STATEMENT) != SQLITE_DONE) {\ + LOG4CXX_ERROR(logger, NAME<< (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db)));\ + } + +using namespace Transport; + +DEFINE_LOGGER(logger, "SkypeDB"); + +namespace SkypeDB { + +bool getAvatar(const std::string &db_path, const std::string &name, std::string &photo) { + bool ret = false; + sqlite3 *db; + LOG4CXX_INFO(logger, "Opening database " << db_path); + if (sqlite3_open(db_path.c_str(), &db)) { + sqlite3_close(db); + LOG4CXX_ERROR(logger, "Can't open database"); + } + else { + sqlite3_stmt *stmt; + PREP_STMT(stmt, "SELECT avatar_image FROM Contacts WHERE skypename=?"); + if (stmt) { + BEGIN(stmt); + BIND_STR(stmt, name); + if(sqlite3_step(stmt) == SQLITE_ROW) { + int size = sqlite3_column_bytes(stmt, 0); + const void *data = sqlite3_column_blob(stmt, 0); + photo = std::string((const char *)data + 1, size - 1); + ret = true; + } + else { + LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); + } + + int ret; + while((ret = sqlite3_step(stmt)) == SQLITE_ROW) { + } + FINALIZE_STMT(stmt); + } + else { + LOG4CXX_ERROR(logger, "Can't created prepared statement"); + LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); + } + sqlite3_close(db); + } + return ret; +} + +} diff --git a/backends/skype/skypedb.h b/backends/skype/skypedb.h new file mode 100644 index 00000000..d0ba9f27 --- /dev/null +++ b/backends/skype/skypedb.h @@ -0,0 +1,33 @@ +/** + * 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 "glib.h" +#include +#include "sqlite3.h" +#include +#include + +namespace SkypeDB { + bool getAvatar(const std::string &db, const std::string &name, std::string &avatar); + +} + diff --git a/backends/skype/skypeplugin.cpp b/backends/skype/skypeplugin.cpp index 9ef2867b..61a38c5c 100644 --- a/backends/skype/skypeplugin.cpp +++ b/backends/skype/skypeplugin.cpp @@ -20,6 +20,7 @@ #include "skypeplugin.h" #include "skype.h" +#include "skypedb.h" #include "transport/config.h" #include "transport/logging.h" @@ -41,17 +42,6 @@ #include "malloc.h" #endif -#define GET_RESPONSE_DATA(RESP, DATA) ((RESP.find(std::string(DATA) + " ") != std::string::npos) ? RESP.substr(RESP.find(DATA) + strlen(DATA) + 1) : ""); -#define GET_PROPERTY(VAR, OBJ, WHICH, PROP) std::string VAR = sk->send_command(std::string("GET ") + OBJ + " " + WHICH + " " + PROP); \ - try {\ - VAR = GET_RESPONSE_DATA(VAR, PROP);\ - }\ - catch (std::out_of_range& oor) {\ - VAR="";\ - } - - - // Prepare the SQL statement #define PREP_STMT(sql, str) \ if(sqlite3_prepare_v2(db, std::string(str).c_str(), -1, &sql, NULL)) { \ @@ -314,39 +304,8 @@ void SkypePlugin::handleVCardRequest(const std::string &user, const std::string g_free(username); if (photo.empty()) { - sqlite3 *db; std::string db_path = std::string("/tmp/skype/") + skype->getUsername() + "/" + skype->getUsername() + "/main.db"; - LOG4CXX_INFO(logger, "Opening database " << db_path); - if (sqlite3_open(db_path.c_str(), &db)) { - sqlite3_close(db); - LOG4CXX_ERROR(logger, "Can't open database"); - } - else { - sqlite3_stmt *stmt; - PREP_STMT(stmt, "SELECT avatar_image FROM Contacts WHERE skypename=?"); - if (stmt) { - BEGIN(stmt); - BIND_STR(stmt, name); - if(sqlite3_step(stmt) == SQLITE_ROW) { - int size = sqlite3_column_bytes(stmt, 0); - const void *data = sqlite3_column_blob(stmt, 0); - photo = std::string((const char *)data + 1, size - 1); - } - else { - LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); - } - - int ret; - while((ret = sqlite3_step(stmt)) == SQLITE_ROW) { - } - FINALIZE_STMT(stmt); - } - else { - LOG4CXX_ERROR(logger, "Can't created prepared statement"); - LOG4CXX_ERROR(logger, (sqlite3_errmsg(db) == NULL ? "" : sqlite3_errmsg(db))); - } - sqlite3_close(db); - } + SkypeDB::getAvatar(db_path, name, photo); } std::string alias; From 4f9457bdd83a2794e72f93567b0847ab244b7d7f Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 9 Feb 2013 11:09:38 +0100 Subject: [PATCH 54/57] Added testing swiften_raw backend which just changes to/from attributes and forwards unchanged stanzas --- backends/CMakeLists.txt | 1 + include/transport/conversation.h | 2 + include/transport/localbuddy.h | 2 + include/transport/networkplugin.h | 8 +- include/transport/networkpluginserver.h | 21 +++- include/transport/protocol.proto | 1 + include/transport/transport.h | 10 +- include/transport/user.h | 1 + plugin/cpp/networkplugin.cpp | 10 ++ src/buddy.cpp | 8 +- src/config.cpp | 1 + src/conversation.cpp | 83 +++++++------ src/networkpluginserver.cpp | 156 ++++++++++++++++++++++++ src/tests/networkpluginserver.cpp | 12 ++ src/transport.cpp | 29 +++++ src/user.cpp | 3 + 16 files changed, 307 insertions(+), 41 deletions(-) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 6bb81a77..6dcfb900 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -9,6 +9,7 @@ if (PROTOBUF_FOUND) if (ENABLE_SWIFTEN) ADD_SUBDIRECTORY(swiften) + ADD_SUBDIRECTORY(swiften_raw) endif() ADD_SUBDIRECTORY(template) diff --git a/include/transport/conversation.h b/include/transport/conversation.h index cda549cb..78aa5266 100644 --- a/include/transport/conversation.h +++ b/include/transport/conversation.h @@ -70,6 +70,8 @@ class Conversation { /// \param nickname For MUC conversation this is nickname of room participant who sent this message. void handleMessage(boost::shared_ptr &message, const std::string &nickname = ""); + void handleRawMessage(boost::shared_ptr &message); + /// Handles participant change in MUC. /// \param nickname Nickname of participant which changed. diff --git a/include/transport/localbuddy.h b/include/transport/localbuddy.h index 5e80fb10..69c5c153 100644 --- a/include/transport/localbuddy.h +++ b/include/transport/localbuddy.h @@ -65,6 +65,8 @@ class LocalBuddy : public Buddy { std::string m_statusMessage; std::string m_iconHash; Swift::StatusShow m_status; + + friend class NetworkPluginServer; }; } diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 279a3c5d..7afe3358 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -39,18 +39,20 @@ class NetworkPlugin { class PluginConfig { public: - PluginConfig() : m_needPassword(true), m_needRegistration(false), m_supportMUC(false) {} + PluginConfig() : m_needPassword(true), m_needRegistration(false), m_supportMUC(false), m_rawXML(false) {} virtual ~PluginConfig() {} void setNeedRegistration(bool needRegistration = false) { m_needRegistration = needRegistration; } void setNeedPassword(bool needPassword = true) { m_needPassword = needPassword; } void setSupportMUC(bool supportMUC = true) { m_supportMUC = supportMUC; } void setExtraFields(const std::vector &fields) { m_extraFields = fields; } + void setRawXML(bool rawXML = false) { m_rawXML = rawXML; } private: bool m_needPassword; bool m_needRegistration; bool m_supportMUC; + bool m_rawXML; std::vector m_extraFields; friend class NetworkPlugin; @@ -67,6 +69,8 @@ class NetworkPlugin { void sendConfig(const PluginConfig &cfg); + void sendRawXML(std::string &xml); + /// Call this function when legacy network buddy changed. /// \param user XMPP JID of user for which this event occurs. You can get it from NetworkPlugin::handleLoginRequest(). (eg. "user%gmail.com@xmpp.domain.tld") /// \param buddyName Name of legacy network buddy. (eg. "user2@gmail.com") @@ -245,6 +249,8 @@ class NetworkPlugin { virtual void handleFTPauseRequest(unsigned long ftID) {} virtual void handleFTContinueRequest(unsigned long ftID) {} + virtual void handleRawXML(const std::string &xml) {} + virtual void handleMemoryUsage(double &res, double &shared) {res = 0; shared = 0;} virtual void handleExitRequest() { exit(1); } diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 2aea0fc9..44a20b26 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -28,6 +28,11 @@ #include "Swiften/Elements/ChatState.h" #include "Swiften/Elements/RosterItemPayload.h" #include "Swiften/Elements/VCard.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "Swiften/Serializer/PayloadSerializers/FullPayloadSerializerCollection.h" +#include "Swiften/Parser/XMPPParser.h" +#include "Swiften/Parser/XMPPParserClient.h" +#include "Swiften/Serializer/XMPPSerializer.h" #include "storagebackend.h" #include "transport/filetransfermanager.h" @@ -47,7 +52,7 @@ class DummyReadBytestream; class AdminInterface; class DiscoItemsResponder; -class NetworkPluginServer { +class NetworkPluginServer : Swift::XMPPParserClient { public: struct Backend { int pongReceived; @@ -116,6 +121,7 @@ class NetworkPluginServer { void handleQueryPayload(Backend *b, const std::string &payload); void handleBackendConfigPayload(const std::string &payload); void handleRoomListPayload(const std::string &payload); + void handleRawXML(const std::string &xml); void handleUserCreated(User *user); void handleRoomJoined(User *user, const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password); @@ -149,6 +155,14 @@ class NetworkPluginServer { Backend *getFreeClient(bool acceptUsers = true, bool longRun = false, bool check = false); void connectWaitingUsers(); void loginDelayFinished(); + void handleRawIQReceived(boost::shared_ptr iq); + void handleRawPresenceReceived(boost::shared_ptr presence); + + void handleStreamStart(const Swift::ProtocolHeader&) {} + + void handleElement(boost::shared_ptr element); + + void handleStreamEnd() {} UserManager *m_userManager; VCardResponder *m_vcardResponder; @@ -171,6 +185,11 @@ class NetworkPluginServer { bool m_startingBackend; DiscoItemsResponder *m_discoItemsResponder; time_t m_lastLogin; + Swift::XMPPParser *m_xmppParser; + Swift::FullPayloadParserFactoryCollection m_collection; + Swift::XMPPSerializer *m_serializer; + Swift::FullPayloadSerializerCollection m_collection2; + std::map m_id2resource; }; } diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 796b656c..4a5b8f00 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -180,6 +180,7 @@ message WrapperMessage { TYPE_QUERY = 31; TYPE_ROOM_LIST = 32; TYPE_CONV_MESSAGE_ACK = 33; + TYPE_RAW_XML = 34; } required Type type = 1; optional bytes payload = 2; diff --git a/include/transport/transport.h b/include/transport/transport.h index b27ddd37..51f69018 100644 --- a/include/transport/transport.h +++ b/include/transport/transport.h @@ -30,9 +30,11 @@ #include "Swiften/Network/BoostIOServiceThread.h" #include "Swiften/Server/UserRegistry.h" #include "Swiften/Base/SafeByteArray.h" +#include "Swiften/Queries/IQHandler.h" #include "Swiften/Jingle/JingleSessionManager.h" #include "Swiften/Component/ComponentError.h" #include "Swiften/Component/Component.h" +#include "Swiften/Queries/IQHandler.h" #include #include "transport/config.h" @@ -52,7 +54,7 @@ namespace Transport { /// /// In server mode it represents Jabber server to which users can connect and use /// it as transport. - class Component { + class Component : Swift::IQHandler { public: /// Creates new Component instance. @@ -151,6 +153,8 @@ namespace Transport { /// \param info disco#info with response. boost::signal info)> onUserDiscoInfoReceived; + boost::signal)> onRawIQReceived; + private: void handleConnected(); void handleConnectionError(const Swift::ComponentError &error); @@ -162,6 +166,9 @@ namespace Transport { void handleDiscoInfoResponse(boost::shared_ptr info, Swift::ErrorPayload::ref error, const Swift::JID& jid); void handleCapsChanged(const Swift::JID& jid); + void handleBackendConfigChanged(); + bool handleIQ(boost::shared_ptr); + Swift::NetworkFactories *m_factories; Swift::Component *m_component; Swift::Server *m_server; @@ -181,6 +188,7 @@ namespace Transport { Swift::JID m_jid; Factory *m_factory; Swift::EventLoop *m_loop; + bool m_rawXML; friend class User; friend class UserRegistration; diff --git a/include/transport/user.h b/include/transport/user.h index 580fda41..ad259142 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -133,6 +133,7 @@ class User : public Swift::EntityCapsProvider { boost::signal onReadyToConnect; boost::signal onPresenceChanged; + boost::signal onRawPresenceReceived; boost::signal onRoomJoined; boost::signal onRoomLeft; boost::signal onDisconnected; diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index 45e39e99..fb660b1f 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -73,6 +73,7 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) { data += "[features]\n"; data += std::string("muc=") + (cfg.m_supportMUC ? "1" : "0") + "\n"; + data += std::string("rawxml=") + (cfg.m_rawXML ? "1" : "0") + "\n"; pbnetwork::BackendConfig m; m.set_config(data); @@ -85,6 +86,12 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) { send(message); } +void NetworkPlugin::sendRawXML(std::string &xml) { + WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML); + + send(xml); +} + void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml, const std::string ×tamp, bool headline, bool pm) { pbnetwork::ConversationMessage m; m.set_username(user); @@ -647,6 +654,9 @@ void NetworkPlugin::handleDataRead(std::string &data) { case pbnetwork::WrapperMessage_Type_TYPE_EXIT: handleExitRequest(); break; + case pbnetwork::WrapperMessage_Type_TYPE_RAW_XML: + handleRawXML(wrapper.payload()); + break; default: return; } diff --git a/src/buddy.cpp b/src/buddy.cpp index 300053cf..4c112052 100644 --- a/src/buddy.cpp +++ b/src/buddy.cpp @@ -103,15 +103,19 @@ Swift::Presence::ref Buddy::generatePresenceStanza(int features, bool only_new) } Swift::Presence::ref presence = Swift::Presence::create(); - presence->setFrom(m_jid); presence->setTo(m_rosterManager->getUser()->getJID().toBare()); presence->setType(Swift::Presence::Available); if (!statusMessage.empty()) presence->setStatus(statusMessage); - if (s.getType() == Swift::StatusShow::None) + if (s.getType() == Swift::StatusShow::None) { presence->setType(Swift::Presence::Unavailable); + presence->setFrom(Swift::JID(m_jid.getNode(), m_jid.getDomain())); + } + else { + presence->setFrom(m_jid); + } presence->setShow(s.getType()); if (presence->getType() != Swift::Presence::Unavailable) { diff --git a/src/config.cpp b/src/config.cpp index 1a5902e4..f1a476ae 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -315,6 +315,7 @@ void Config::updateBackendConfig(const std::string &backendConfig) { ("registration.extraField", value >()->multitoken(), "") ("features.receipts", value()->default_value(false), "") ("features.muc", value()->default_value(false), "") + ("features.rawxml", value()->default_value(false), "") ; std::stringstream ifs(backendConfig); diff --git a/src/conversation.cpp b/src/conversation.cpp index 4073d8e6..7f4fe73c 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -39,6 +39,10 @@ Conversation::Conversation(ConversationManager *conversationManager, const std:: m_muc = isMUC; m_jid = m_conversationManager->getUser()->getJID().toBare(); m_sentInitialPresence = false; + + if (CONFIG_BOOL_DEFAULTED(conversationManager->getComponent()->getConfig(), "features.rawxml", false)) { + m_sentInitialPresence = true; + } } Conversation::~Conversation() { @@ -82,6 +86,47 @@ void Conversation::setRoom(const std::string &room) { m_legacyName = m_room + "/" + m_legacyName; } +void Conversation::handleRawMessage(boost::shared_ptr &message) { + if (message->getType() != Swift::Message::Groupchat) { + if (m_conversationManager->getComponent()->inServerMode() && m_conversationManager->getUser()->shouldCacheMessages()) { + boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time(); + boost::shared_ptr delay(boost::make_shared()); + delay->setStamp(timestamp); + message->addPayload(delay); + m_cachedMessages.push_back(message); + if (m_cachedMessages.size() > 100) { + m_cachedMessages.pop_front(); + } + } + else { + m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); + } + } + else { + if (m_jids.empty()) { + boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time(); + boost::shared_ptr delay(boost::make_shared()); + delay->setStamp(timestamp); + message->addPayload(delay); + m_cachedMessages.push_back(message); + if (m_cachedMessages.size() > 100) { + m_cachedMessages.pop_front(); + } + } + else { + BOOST_FOREACH(const Swift::JID &jid, m_jids) { + message->setTo(jid); + // Subject has to be sent after our own presence (the one with code 110) + if (!message->getSubject().empty() && m_sentInitialPresence == false) { + m_subject = message; + return; + } + m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); + } + } + } +} + void Conversation::handleMessage(boost::shared_ptr &message, const std::string &nickname) { if (m_muc) { message->setType(Swift::Message::Groupchat); @@ -137,20 +182,6 @@ void Conversation::handleMessage(boost::shared_ptr &message, con message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n)); } } - - if (m_conversationManager->getComponent()->inServerMode() && m_conversationManager->getUser()->shouldCacheMessages()) { - boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time(); - boost::shared_ptr delay(boost::make_shared()); - delay->setStamp(timestamp); - message->addPayload(delay); - m_cachedMessages.push_back(message); - if (m_cachedMessages.size() > 100) { - m_cachedMessages.pop_front(); - } - } - else { - m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); - } } else { std::string legacyName = m_legacyName; @@ -164,29 +195,9 @@ void Conversation::handleMessage(boost::shared_ptr &message, con } message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n)); - - if (m_jids.empty()) { - boost::posix_time::ptime timestamp = boost::posix_time::second_clock::universal_time(); - boost::shared_ptr delay(boost::make_shared()); - delay->setStamp(timestamp); - message->addPayload(delay); - m_cachedMessages.push_back(message); - if (m_cachedMessages.size() > 100) { - m_cachedMessages.pop_front(); - } - } - else { - BOOST_FOREACH(const Swift::JID &jid, m_jids) { - message->setTo(jid); - // Subject has to be sent after our own presence (the one with code 110) - if (!message->getSubject().empty() && m_sentInitialPresence == false) { - m_subject = message; - return; - } - m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); - } - } } + + handleRawMessage(message); } void Conversation::sendParticipants(const Swift::JID &to) { diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 6f50b04f..3b189abb 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -269,11 +269,16 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U m_adminInterface = NULL; m_startingBackend = false; m_lastLogin = 0; + m_xmppParser = new Swift::XMPPParser(this, &m_collection, component->getNetworkFactories()->getXMLParserFactory()); + m_xmppParser->parse(""); + m_serializer = new Swift::XMPPSerializer(&m_collection2, Swift::ClientStreamType); m_discoItemsResponder = discoItemsResponder; m_component->m_factory = new NetworkFactory(this); m_userManager->onUserCreated.connect(boost::bind(&NetworkPluginServer::handleUserCreated, this, _1)); m_userManager->onUserDestroyed.connect(boost::bind(&NetworkPluginServer::handleUserDestroyed, this, _1)); + m_component->onRawIQReceived.connect(boost::bind(&NetworkPluginServer::handleRawIQReceived, this, _1)); + m_pingTimer = component->getNetworkFactories()->getTimerFactory()->createTimer(20000); m_pingTimer->onTick.connect(boost::bind(&NetworkPluginServer::pingTimeout, this)); m_pingTimer->start(); @@ -987,6 +992,133 @@ void NetworkPluginServer::handleRoomListPayload(const std::string &data) { } } +void NetworkPluginServer::handleElement(boost::shared_ptr element) { + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + User *user = m_userManager->getUser(stanza->getTo().toBare()); + if (!user) + return; + + Swift::JID originalJID = stanza->getFrom(); + LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(stanza->getFrom().toBare()); + if (buddy) { + const Swift::JID &jid = buddy->getJID(); + if (stanza->getFrom().getResource().empty()) { + stanza->setFrom(Swift::JID(jid.getNode(), jid.getDomain())); + } + else { + stanza->setFrom(Swift::JID(jid.getNode(), jid.getDomain(), stanza->getFrom().getResource())); + } + } + else { + std::string name = stanza->getFrom().toBare(); + if (CONFIG_BOOL_DEFAULTED(m_config, "service.jid_escaping", true)) { + name = Swift::JID::getEscapedNode(name); + } + else { + if (name.find_last_of("@") != std::string::npos) { + name.replace(name.find_last_of("@"), 1, "%"); + } + } + if (stanza->getFrom().getResource().empty()) { + stanza->setFrom(Swift::JID(name, m_component->getJID().toString())); + } + else { + stanza->setFrom(Swift::JID(name, m_component->getJID().toString(), stanza->getFrom().getResource())); + } + } + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(originalJID.toBare()); + if (conv) { + conv->handleRawMessage(message); + return; + } + + m_component->getStanzaChannel()->sendMessage(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + m_component->getStanzaChannel()->sendPresence(presence); + if (buddy) { + buddy->m_statusMessage = presence->getStatus(); + buddy->m_status = Swift::StatusShow(presence->getShow()); + } + + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + if (m_id2resource.find(stanza->getTo().toBare().toString() + stanza->getID()) != m_id2resource.end()) { + iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), m_id2resource[stanza->getTo().toBare().toString() + stanza->getID()])); + m_id2resource.erase(stanza->getTo().toBare().toString() + stanza->getID()); + } + m_component->getIQRouter()->sendIQ(iq); + return; + } +} + +void NetworkPluginServer::handleRawXML(const std::string &xml) { + m_xmppParser->parse(xml); +} + +void NetworkPluginServer::handleRawPresenceReceived(boost::shared_ptr presence) { + User *user = m_userManager->getUser(presence->getFrom().toBare()); + if (!user) + return; + + Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } + + Swift::JID legacyname = Swift::JID(Buddy::JIDToLegacyName(presence->getTo())); + if (!presence->getTo().getResource().empty()) { + presence->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain(), presence->getTo().getResource())); + } + else { + presence->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain())); + } + + std::string xml = safeByteArrayToString(m_serializer->serializeElement(presence)); + WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML); + send(c->connection, xml); +} + +void NetworkPluginServer::handleRawIQReceived(boost::shared_ptr iq) { + User *user = m_userManager->getUser(iq->getFrom().toBare()); + if (!user) + return; + + Backend *c = (Backend *) user->getData(); + if (!c) { + return; + } + + if (iq->getType() == Swift::IQ::Get) { + m_id2resource[iq->getFrom().toBare().toString() + iq->getID()] = iq->getFrom().getResource(); + } + + Swift::JID legacyname = Swift::JID(Buddy::JIDToLegacyName(iq->getTo())); + if (!iq->getTo().getResource().empty()) { + iq->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain(), iq->getTo().getResource())); + } + else { + iq->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain())); + } + + std::string xml = safeByteArrayToString(m_serializer->serializeElement(iq)); + WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML); + send(c->connection, xml); +} + void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptr data) { // Append data to buffer c->data.insert(c->data.end(), data->begin(), data->end()); @@ -1098,6 +1230,9 @@ void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptronReadyToConnect.connect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user)); user->onPresenceChanged.connect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1)); + user->onRawPresenceReceived.connect(boost::bind(&NetworkPluginServer::handleRawPresenceReceived, this, _1)); user->onRoomJoined.connect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4)); user->onRoomLeft.connect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1)); @@ -1374,6 +1510,7 @@ void NetworkPluginServer::handleUserDestroyed(User *user) { user->onReadyToConnect.disconnect(boost::bind(&NetworkPluginServer::handleUserReadyToConnect, this, user)); user->onPresenceChanged.disconnect(boost::bind(&NetworkPluginServer::handleUserPresenceChanged, this, user, _1)); + user->onRawPresenceReceived.disconnect(boost::bind(&NetworkPluginServer::handleRawPresenceReceived, this, _1)); user->onRoomJoined.disconnect(boost::bind(&NetworkPluginServer::handleRoomJoined, this, user, _1, _2, _3, _4)); user->onRoomLeft.disconnect(boost::bind(&NetworkPluginServer::handleRoomLeft, this, user, _1)); @@ -1406,6 +1543,25 @@ void NetworkPluginServer::handleUserDestroyed(User *user) { void NetworkPluginServer::handleMessageReceived(NetworkConversation *conv, boost::shared_ptr &msg) { conv->getConversationManager()->getUser()->updateLastActivity(); + + if (CONFIG_BOOL_DEFAULTED(m_config, "features.rawxml", false)) { + Backend *c = (Backend *) conv->getConversationManager()->getUser()->getData(); + if (!c) { + return; + } + Swift::JID legacyname = Swift::JID(Buddy::JIDToLegacyName(msg->getTo())); + if (!msg->getTo().getResource().empty()) { + msg->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain(), msg->getTo().getResource())); + } + else { + msg->setTo(Swift::JID(legacyname.getNode(), legacyname.getDomain())); + } + std::string xml = safeByteArrayToString(m_serializer->serializeElement(msg)); + WRAP(xml, pbnetwork::WrapperMessage_Type_TYPE_RAW_XML); + send(c->connection, xml); + return; + } + boost::shared_ptr statePayload = msg->getPayload(); if (statePayload) { pbnetwork::WrapperMessage_Type type = pbnetwork::WrapperMessage_Type_TYPE_BUDDY_CHANGED; diff --git a/src/tests/networkpluginserver.cpp b/src/tests/networkpluginserver.cpp index 6d941cd8..3b2fd5f8 100644 --- a/src/tests/networkpluginserver.cpp +++ b/src/tests/networkpluginserver.cpp @@ -53,6 +53,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST(handleBuddyChangedPayloadUserContactInRoster); CPPUNIT_TEST(handleMessageHeadline); CPPUNIT_TEST(handleConvMessageAckPayload); + CPPUNIT_TEST(handleRawXML); CPPUNIT_TEST(benchmarkHandleBuddyChangedPayload); CPPUNIT_TEST_SUITE_END(); @@ -196,6 +197,17 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); } + void handleRawXML() { + User *user = userManager->getUser("user@localhost"); + + std::string xml = ""; + + serv->handleRawXML(xml); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40domain.tld@localhost"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); + } + void handleMessageHeadline() { User *user = userManager->getUser("user@localhost"); diff --git a/src/transport.cpp b/src/transport.cpp index a98f101a..18fc4830 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -52,6 +52,9 @@ #include "Swiften/Parser/PayloadParsers/InvisibleParser.h" #include "Swiften/Serializer/PayloadSerializers/InvisibleSerializer.h" #include "Swiften/Parser/GenericPayloadParserFactory.h" +#include "Swiften/Queries/IQRouter.h" +#include "Swiften/Elements/RosterPayload.h" +#include "Swiften/Elements/InBandRegistrationPayload.h" using namespace Swift; using namespace boost; @@ -67,9 +70,11 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_server = NULL; m_reconnectCount = 0; m_config = config; + m_config->onBackendConfigUpdated.connect(boost::bind(&Component::handleBackendConfigChanged, this)); m_factory = factory; m_loop = loop; m_userRegistry = userRegistry; + m_rawXML = false; m_jid = Swift::JID(CONFIG_STRING(m_config, "service.jid")); @@ -177,6 +182,30 @@ Component::~Component() { } } +bool Component::handleIQ(boost::shared_ptr iq) { + if (!m_rawXML) { + return false; + } + + if (iq->getPayload() != NULL) { return false; } + if (iq->getPayload() != NULL) { return false; } + if (iq->getPayload() != NULL) { return false; } + + if (iq->getTo().getNode().empty()) { + return false; + } + + onRawIQReceived(iq); + return true; +} + +void Component::handleBackendConfigChanged() { + if (!m_rawXML && CONFIG_BOOL_DEFAULTED(m_config, "features.rawxml", false)) { + m_rawXML = true; + m_iqRouter->addHandler(this); + } +} + Swift::StanzaChannel *Component::getStanzaChannel() { return m_stanzaChannel; } diff --git a/src/user.cpp b/src/user.cpp index 43234bcf..9afab31a 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -243,6 +243,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { if (getUserSetting("stay_connected") != "1") { LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room); + onRawPresenceReceived(presence); onRoomLeft(room); BOOST_FOREACH(Swift::Presence::ref &p, m_joinedRooms) { @@ -284,6 +285,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { } if (forceJoin) { + onRawPresenceReceived(presence); onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password); } return; @@ -311,6 +313,7 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { conv->setNickname(presence->getTo().getResource()); conv->addJID(presence->getFrom()); + onRawPresenceReceived(presence); onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password); } return; From d3387ffd20f1bb549bd8f17691c8691a955f4df8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 9 Feb 2013 11:19:40 +0100 Subject: [PATCH 55/57] added missing files --- backends/swiften_raw/CMakeLists.txt | 14 + backends/swiften_raw/main.cpp | 427 ++++++++++++++++++++++++++++ 2 files changed, 441 insertions(+) create mode 100644 backends/swiften_raw/CMakeLists.txt create mode 100644 backends/swiften_raw/main.cpp diff --git a/backends/swiften_raw/CMakeLists.txt b/backends/swiften_raw/CMakeLists.txt new file mode 100644 index 00000000..ccd50e8e --- /dev/null +++ b/backends/swiften_raw/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.cpp) + +ADD_EXECUTABLE(spectrum2_swiften_raw_backend ${SRC}) + +IF (NOT WIN32) +target_link_libraries(spectrum2_swiften_raw_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +else() +target_link_libraries(spectrum2_swiften_raw_backend transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +endif() + +INSTALL(TARGETS spectrum2_swiften_raw_backend RUNTIME DESTINATION bin) + diff --git a/backends/swiften_raw/main.cpp b/backends/swiften_raw/main.cpp new file mode 100644 index 00000000..9f164a81 --- /dev/null +++ b/backends/swiften_raw/main.cpp @@ -0,0 +1,427 @@ +// Transport includes +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "transport/logging.h" + +#include "boost/date_time/posix_time/posix_time.hpp" + +// Swiften +#include "Swiften/Swiften.h" + +#ifndef WIN32 +// for signal handler +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" +#endif + +#ifndef __FreeBSD__ +#ifndef __MACH__ +// malloc_trim +#include "malloc.h" +#endif +#endif + +// Boost +#include +using namespace boost::filesystem; +using namespace boost::program_options; +using namespace Transport; + +DEFINE_LOGGER(logger, "Swiften"); +DEFINE_LOGGER(logger_xml, "backend.xml"); + +// eventloop +Swift::SimpleEventLoop *loop_; + +// Plugins +class SwiftenPlugin; +NetworkPlugin *np = NULL; +Swift::XMPPSerializer *serializer; + +class ForwardIQHandler : public Swift::IQHandler { + public: + std::map m_id2resource; + + ForwardIQHandler(NetworkPlugin *np, const std::string &user) { + m_np = np; + m_user = user; + } + + bool handleIQ(boost::shared_ptr iq) { + if (iq->getPayload() != NULL) { + return false; + } + if (iq->getType() == Swift::IQ::Get) { + m_id2resource[iq->getID()] = iq->getFrom().getResource(); + } + + iq->setTo(m_user); + std::string xml = safeByteArrayToString(serializer->serializeElement(iq)); + m_np->sendRawXML(xml); + return true; + } + + private: + NetworkPlugin *m_np; + std::string m_user; + +}; + +class SwiftenPlugin : public NetworkPlugin, Swift::XMPPParserClient { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; + bool m_firstPing; + + Swift::FullPayloadSerializerCollection collection; + Swift::XMPPParser *m_xmppParser; + Swift::FullPayloadParserFactoryCollection m_collection2; + + SwiftenPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + m_firstPing = true; + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&SwiftenPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); + + serializer = new Swift::XMPPSerializer(&collection, Swift::ClientStreamType); + m_xmppParser = new Swift::XMPPParser(this, &m_collection2, m_factories->getXMLParserFactory()); + m_xmppParser->parse(""); + + 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) { + if (m_firstPing) { + m_firstPing = false; + NetworkPlugin::PluginConfig cfg; + cfg.setRawXML(true); + sendConfig(cfg); + } + std::string d(data->begin(), data->end()); + handleDataRead(d); + } + + void handleStreamStart(const Swift::ProtocolHeader&) {} + + void handleElement(boost::shared_ptr element) { + boost::shared_ptr stanza = boost::dynamic_pointer_cast(element); + if (!stanza) { + return; + } + + std::string user = stanza->getFrom().toBare(); + + boost::shared_ptr client = m_users[user]; + if (!client) + return; + + stanza->setFrom(client->getJID()); + + boost::shared_ptr message = boost::dynamic_pointer_cast(stanza); + if (message) { + client->sendMessage(message); + return; + } + + boost::shared_ptr presence = boost::dynamic_pointer_cast(stanza); + if (presence) { + client->sendPresence(presence); + return; + } + + boost::shared_ptr iq = boost::dynamic_pointer_cast(stanza); + if (iq) { + if (m_handlers[user]->m_id2resource.find(stanza->getID()) != m_handlers[user]->m_id2resource.end()) { + iq->setTo(Swift::JID(iq->getTo().getNode(), iq->getTo().getDomain(), m_handlers[user]->m_id2resource[stanza->getID()])); + m_handlers[user]->m_id2resource.erase(stanza->getID()); + } + client->getIQRouter()->sendIQ(iq); + return; + } + } + + void handleStreamEnd() {} + + void handleRawXML(const std::string &xml) { + m_xmppParser->parse(xml); + } + + void handleSwiftDisconnected(const std::string &user, const boost::optional &error) { + std::string message = ""; + bool reconnect = false; + if (error) { + switch(error->getType()) { + case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break; + case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break; + case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break; + case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break; + case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break; + case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break; + case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break; + case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break; + case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break; + case Swift::ClientError::NoSupportedAuthMechanismsError: message = ("Authentication mechanisms not supported"); break; + case Swift::ClientError::UnexpectedElementError: message = ("Unexpected response"); break; + case Swift::ClientError::ResourceBindError: message = ("Error binding resource"); break; + case Swift::ClientError::SessionStartError: message = ("Error starting session"); break; + case Swift::ClientError::StreamError: message = ("Stream error"); break; + case Swift::ClientError::TLSError: message = ("Encryption error"); break; + case Swift::ClientError::ClientCertificateLoadError: message = ("Error loading certificate (Invalid password?)"); break; + case Swift::ClientError::ClientCertificateError: message = ("Certificate not authorized"); break; + + case Swift::ClientError::UnknownCertificateError: message = ("Unknown certificate"); break; + case Swift::ClientError::CertificateExpiredError: message = ("Certificate has expired"); break; + case Swift::ClientError::CertificateNotYetValidError: message = ("Certificate is not yet valid"); break; + case Swift::ClientError::CertificateSelfSignedError: message = ("Certificate is self-signed"); break; + case Swift::ClientError::CertificateRejectedError: message = ("Certificate has been rejected"); break; + case Swift::ClientError::CertificateUntrustedError: message = ("Certificate is not trusted"); break; + case Swift::ClientError::InvalidCertificatePurposeError: message = ("Certificate cannot be used for encrypting your connection"); break; + case Swift::ClientError::CertificatePathLengthExceededError: message = ("Certificate path length constraint exceeded"); break; + case Swift::ClientError::InvalidCertificateSignatureError: message = ("Invalid certificate signature"); break; + case Swift::ClientError::InvalidCAError: message = ("Invalid Certificate Authority"); break; + case Swift::ClientError::InvalidServerIdentityError: message = ("Certificate does not match the host identity"); break; + } + } + LOG4CXX_INFO(logger, user << ": Disconnected " << message); + handleDisconnected(user, reconnect ? 0 : 3, message); + + boost::shared_ptr client = m_users[user]; + if (client) { + client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); + client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + m_users.erase(user); + m_handlers.erase(user); + } + +#ifndef WIN32 +#ifndef __FreeBSD__ +#ifndef __MACH__ + // force returning of memory chunks allocated by libxml2 to kernel + malloc_trim(0); +#endif +#endif +#endif + } + + void handleSwiftConnected(const std::string &user) { + LOG4CXX_INFO(logger, user << ": Connected to XMPP server."); + handleConnected(user); + m_users[user]->requestRoster(); + Swift::Presence::ref response = Swift::Presence::create(); + response->setFrom(m_users[user]->getJID()); + m_users[user]->sendPresence(response); + } + + void handleSwiftRosterReceived(const std::string &user) { + Swift::PresenceOracle *oracle = m_users[user]->getPresenceOracle(); + BOOST_FOREACH(const Swift::XMPPRosterItem &item, m_users[user]->getRoster()->getItems()) { + Swift::Presence::ref lastPresence = oracle->getLastPresence(item.getJID()); + pbnetwork::StatusType status = lastPresence ? ((pbnetwork::StatusType) lastPresence->getShow()) : pbnetwork::STATUS_NONE; + handleBuddyChanged(user, item.getJID().toBare().toString(), + item.getName(), item.getGroups(), status); + } + } + + void handleSwiftPresenceChanged(const std::string &user, Swift::Presence::ref presence) { +// boost::shared_ptr client = m_users[user]; +// if (client->getMUCRegistry()->isMUC(presence->getFrom().toBare())) { +// return; +// } +// +// if (presence->getPayload() != NULL || presence->getPayload() != NULL) { +// return; +// } +// +// LOG4CXX_INFO(logger, user << ": " << presence->getFrom().toBare().toString() << " presence changed"); +// +// std::string message = presence->getStatus(); +// std::string photo = ""; +// +// boost::shared_ptr update = presence->getPayload(); +// if (update) { +// photo = update->getPhotoHash(); +// } +// +// boost::optional item = m_users[user]->getRoster()->getItem(presence->getFrom()); +// if (item) { +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), item->getName(), item->getGroups(), (pbnetwork::StatusType) presence->getShow(), message, photo); +// } +// else { +// std::vector groups; +// handleBuddyChanged(user, presence->getFrom().toBare().toString(), presence->getFrom().toBare(), groups, (pbnetwork::StatusType) presence->getShow(), message, photo); +// } + presence->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(presence)); + sendRawXML(xml); + } + + void handleSwiftMessageReceived(const std::string &user, Swift::Message::ref message) { + message->setTo(user); + std::string xml = safeByteArrayToString(serializer->serializeElement(message)); + sendRawXML(xml); + } + + void handleSwiftenDataRead(const Swift::SafeByteArray &data) { + std::string d = safeByteArrayToString(data); + if (!boost::starts_with(d, " client = boost::make_shared(Swift::JID(legacyName), password, m_factories); + m_users[user] = client; + client->setAlwaysTrustCertificates(); + client->onConnected.connect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); + client->onDisconnected.connect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.connect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + client->getRoster()->onInitialRosterPopulated.connect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); + client->getPresenceOracle()->onPresenceChange.connect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->onDataRead.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataRead, this, _1)); + client->onDataWritten.connect(boost::bind(&SwiftenPlugin::handleSwiftenDataWritten, this, _1)); + Swift::ClientOptions opt; + opt.allowPLAINWithoutTLS = true; + client->connect(opt); + + boost::shared_ptr handler = boost::make_shared(this, user); + client->getIQRouter()->addHandler(handler); + m_handlers[user] = handler; + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + boost::shared_ptr client = m_users[user]; + if (client) { + client->onConnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftConnected, this, user)); +// client->onDisconnected.disconnect(boost::bind(&SwiftenPlugin::handleSwiftDisconnected, this, user, _1)); + client->onMessageReceived.disconnect(boost::bind(&SwiftenPlugin::handleSwiftMessageReceived, this, user, _1)); + client->getRoster()->onInitialRosterPopulated.disconnect(boost::bind(&SwiftenPlugin::handleSwiftRosterReceived, this, user)); + client->getPresenceOracle()->onPresenceChange.disconnect(boost::bind(&SwiftenPlugin::handleSwiftPresenceChanged, this, user, _1)); + client->disconnect(); + } + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &xhtml = "", const std::string &id = "") { + } + + void handleVCardRequest(const std::string &user, const std::string &legacyName, unsigned int id) { + } + + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + boost::shared_ptr client = m_users[user]; + if (client) { + LOG4CXX_INFO(logger, user << ": Added/Updated buddy " << buddyName << "."); + if (!client->getRoster()->containsJID(buddyName) || client->getRoster()->getSubscriptionStateForJID(buddyName) != Swift::RosterItemPayload::Both) { + Swift::RosterItemPayload item; + item.setName(alias); + item.setJID(buddyName); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + client->getSubscriptionManager()->requestSubscription(buddyName); + } + else { + Swift::JID contact(buddyName); + Swift::RosterItemPayload item(contact, alias, client->getRoster()->getSubscriptionStateForJID(contact)); + item.setGroups(groups); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + + } + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + boost::shared_ptr client = m_users[user]; + if (client) { + Swift::RosterItemPayload item(buddyName, "", Swift::RosterItemPayload::Remove); + boost::shared_ptr roster(new Swift::RosterPayload()); + roster->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(roster, client->getIQRouter()); +// request->onResponse.connect(boost::bind(&RosterController::handleRosterSetError, this, _1, roster)); + request->send(); + } + } + + 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; + std::map > m_users; + std::map > m_handlers; +}; + +#ifndef WIN32 +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); + } +} +#endif + + +int main (int argc, char* argv[]) { + std::string host; + int port; + +#ifndef WIN32 + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } +#endif + + std::string error; + Config *cfg = Config::createFromArgs(argc, argv, error, host, port); + if (cfg == NULL) { + std::cerr << error; + return 1; + } + + Logging::initBackendLogging(cfg); + + Swift::SimpleEventLoop eventLoop; + loop_ = &eventLoop; + np = new SwiftenPlugin(cfg, &eventLoop, host, port); + loop_->run(); + + return 0; +} From 6f9fbae0907a499538074fbbdec5d74cb6aa1136 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 9 Feb 2013 16:28:22 +0100 Subject: [PATCH 56/57] Twitter: remove user from database even when he logged out before sending #pin --- backends/twitter/TwitterPlugin.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index fa777960..96ca53ea 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -156,10 +156,13 @@ void TwitterPlugin::handleLoginRequest(const std::string &user, const std::strin // User logging out void TwitterPlugin::handleLogoutRequest(const std::string &user, const std::string &legacyName) { - if(onlineUsers.count(user)) { + if (userdb.count(user)) { delete userdb[user].sessions; userdb[user].sessions = NULL; userdb[user].connectionState = DISCONNECTED; + } + + if(onlineUsers.count(user)) { onlineUsers.erase(user); } } From 57a728834db61fd80b38c4f4f895ff8b688f0789 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 9 Feb 2013 23:10:01 +0100 Subject: [PATCH 57/57] Twitter: better help --- backends/twitter/Requests/HelpMessageRequest.cpp | 13 +++++++++---- backends/twitter/Requests/HelpMessageRequest.h | 4 +++- backends/twitter/Requests/PINExchangeProcess.cpp | 1 + backends/twitter/TwitterPlugin.cpp | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/backends/twitter/Requests/HelpMessageRequest.cpp b/backends/twitter/Requests/HelpMessageRequest.cpp index 53ee3692..da7dfc76 100644 --- a/backends/twitter/Requests/HelpMessageRequest.cpp +++ b/backends/twitter/Requests/HelpMessageRequest.cpp @@ -3,16 +3,21 @@ DEFINE_LOGGER(logger, "HelpMessageRequest") void HelpMessageRequest::run() { helpMsg = helpMsg - + "\n******************************HELP************************************\n" - + "#status ==> Update your status\n" + + "You will receive tweets of people you follow from this contact." + + "Following commands can be used to manage your Twitter account:" + "#timeline [username] ==> Retrieve 's timeline; Default - own timeline\n" + + "#status ==> Update your status\n" + "@ ==> Send a directed message to the user \n" + "#retweet ==> Retweet the tweet having id \n" + "#follow ==> Follow user \n" + "#unfollow ==> Stop Following user \n" - + "#mode [012] ==> Switch mode to 0(single), 1(multiple) or 2(chatroom)\n" + + "#mode [01] ==> Switch mode to 0(single), 1(multiple). See below\n" + "#help ==> Print this help message\n" - + "************************************************************************\n"; + + "************************************************************************\n" + + "There are 3 ways how to use the gateway:\n" + + "Mode 0 - There is twitter.com contact in your roster and all Twitter messages are forwaded using this contact.\n" + + "Mode 1 - Same as Mode 0, but the people you follow are displayed in your roster. You will receive/send directed messages using those contacts.\n" + + "Joining the #twitter@" + jid + " room - You can join mentioned room and see people you follow there as well as the tweets they post. Private messages in that room are mapped to Twitter direct messages."; } void HelpMessageRequest::finalize() diff --git a/backends/twitter/Requests/HelpMessageRequest.h b/backends/twitter/Requests/HelpMessageRequest.h index 14188eb3..c0d86d2b 100644 --- a/backends/twitter/Requests/HelpMessageRequest.h +++ b/backends/twitter/Requests/HelpMessageRequest.h @@ -14,13 +14,15 @@ using namespace Transport; class HelpMessageRequest : public Thread { std::string user; + std::string jid; std::string helpMsg; boost::function callBack; public: - HelpMessageRequest(const std::string &_user, boost::function cb) { + HelpMessageRequest(const std::string &_user, const std::string &jid, boost::function cb) { user = _user; callBack = cb; + this->jid = jid; } void run(); diff --git a/backends/twitter/Requests/PINExchangeProcess.cpp b/backends/twitter/Requests/PINExchangeProcess.cpp index dc6b756a..51c87aee 100644 --- a/backends/twitter/Requests/PINExchangeProcess.cpp +++ b/backends/twitter/Requests/PINExchangeProcess.cpp @@ -39,6 +39,7 @@ void PINExchangeProcess::finalize() } np->pinExchangeComplete(user, OAuthAccessTokenKey, OAuthAccessTokenSecret); np->handleMessage(user, "twitter.com", "PIN is OK. You are now authorized."); + np->handleMessage(user, "twitter.com", "Send '#help' (without the quotes) to see how to use this transport."); LOG4CXX_INFO(logger, user << ": Sent PIN " << data << " and obtained Access Token"); } } diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index 96ca53ea..6d5c5e69 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -215,7 +215,7 @@ void TwitterPlugin::handleMessageSendRequest(const std::string &user, const std: if(cmd == "#pin") tp->runAsThread(new PINExchangeProcess(np, userdb[user].sessions, user, data)); else if(cmd == "#help") - tp->runAsThread(new HelpMessageRequest(user, boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2))); + tp->runAsThread(new HelpMessageRequest(user, CONFIG_STRING(config, "service.jid"), boost::bind(&TwitterPlugin::helpMessageResponse, this, _1, _2))); else if(cmd[0] == '@') { std::string username = cmd.substr(1); tp->runAsThread(new DirectMessageRequest(userdb[user].sessions, user, username, data,