From 20ba88890d2a10e9c912e3a88d4db805a275e08b Mon Sep 17 00:00:00 2001 From: Dominik Date: Fri, 27 Jan 2012 15:11:24 +0100 Subject: [PATCH 01/41] - registration with local user accounts stub --- src/config.cpp | 2 ++ src/userregistration.cpp | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/config.cpp b/src/config.cpp index c5ca48b5..d456024f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -87,6 +87,8 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.username_label", value()->default_value("Legacy network username:"), "Label for username field") ("registration.username_mask", value()->default_value(""), "Username mask") ("registration.encoding", value()->default_value("utf8"), "Default encoding in registration form") + ("registration.require_local_account", value()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.") + ("registration.local_username_label", value()->default_value("Local username:"), "Label for local usernme field") ("database.type", value()->default_value("none"), "Database type.") ("database.database", value()->default_value(""), "Database used to store data") ("database.server", value()->default_value("localhost"), "Database server.") diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 9160465f..6d3e9fd5 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -241,6 +241,20 @@ bool UserRegistration::handleGetRequest(const Swift::JID& from, const Swift::JID boolean->setLabel((("Remove your registration"))); boolean->setValue(0); form->addField(boolean); + } else { + if (CONFIG_BOOL(m_config,"registration.require_local_account")) { + std::string localUsernameField = CONFIG_STRING(m_config, "registration.local_username_label"); + TextSingleFormField::ref local_username = TextSingleFormField::create(); + local_username->setName("local_username"); + local_username->setLabel((localUsernameField)); + local_username->setRequired(true); + form->addField(local_username); + TextPrivateFormField::ref local_password = TextPrivateFormField::create(); + local_password->setName("local_password"); + local_password->setLabel((("Local Password"))); + local_password->setRequired(true); + form->addField(local_password); + } } reg->setForm(form); @@ -273,6 +287,8 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID std::string encoding; std::string language; + std::string local_username(""); + std::string local_password(""); Form::ref form = payload->getForm(); if (form) { @@ -290,6 +306,13 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID else if (textSingle->getName() == "password") { payload->setPassword(textSingle->getValue()); } + else if (textSingle->getName() == "local_username") { + local_username = textSingle->getValue(); + } + // Pidgin sends it as textSingle, not sure why... + else if (textSingle->getName() == "local_password") { + local_password = textSingle->getValue(); + } continue; } @@ -298,6 +321,9 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID if (textPrivate->getName() == "password") { payload->setPassword(textPrivate->getValue()); } + else if (textPrivate->getName() == "local_password") { + local_password = textPrivate->getValue(); + } continue; } @@ -327,6 +353,22 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID return true; } + if (CONFIG_BOOL(m_config,"registration.require_local_account")) { + /* if (!local_username || !local_password) { + sendResponse(from, id, InBandRegistrationPayload::ref()); + return true + } else */ if (local_username == "" || local_password == "") { + sendResponse(from, id, InBandRegistrationPayload::ref()); + return true; + } else if (local_username != "heinz" || local_password != "heinz") { + // TODO: Check local password and username + sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Modify); + return true; + } + } + + printf("here\n"); + if (!payload->getUsername() || !payload->getPassword()) { sendError(from, id, ErrorPayload::NotAcceptable, ErrorPayload::Modify); return true; From 7619b9e2b2cbd4c6416fcf75f8fed575bb0dc444 Mon Sep 17 00:00:00 2001 From: Dominik Date: Fri, 27 Jan 2012 18:33:18 +0100 Subject: [PATCH 02/41] - check local_username against configured server - TODO: improve really crappy and hacky Swiften password check solution --- spectrum/src/sample2.cfg | 17 +++++++++++++++++ src/config.cpp | 2 ++ src/userregistration.cpp | 34 ++++++++++++++++++++++++++++++++-- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index d2de8992..508395e9 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -95,3 +95,20 @@ type = none # Prefix used for tables #prefix = jabber_ + +[registration] +# Enable public registrations +enable_public_registration=1 + +# Text to display upon user registration form +username_label=Jabber JID (e.g. user@server.tld): +instructions=Enter your remote jabber JID and password as well as your local username and password + +# If True a local jabber account on is needed +# for transport registration, the idea is to enable public registration +# from other servers, but only for users, who have already local accounts +require_local_account=1 +local_username_label=Local username (without @server.tld): +local_account_server=localhost +local_account_server_timeout=10000 + diff --git a/src/config.cpp b/src/config.cpp index d456024f..91e5ed67 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -89,6 +89,8 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.encoding", value()->default_value("utf8"), "Default encoding in registration form") ("registration.require_local_account", value()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.") ("registration.local_username_label", value()->default_value("Local username:"), "Label for local usernme field") + ("registration.local_account_server", value()->default_value("localhost"), "The server on which the local accounts will be checked for validity") + ("registration.local_account_server_timeout", value()->default_value(10000), "Timeout when checking local user on local_account_server (msecs)") ("database.type", value()->default_value("none"), "Database type.") ("database.database", value()->default_value(""), "Database used to store data") ("database.server", value()->default_value("localhost"), "Database server.") diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 6d3e9fd5..d5d7d611 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -26,6 +26,8 @@ #include "transport/user.h" #include "Swiften/Elements/ErrorPayload.h" #include +#include +#include #include "log4cxx/logger.h" using namespace Swift; @@ -360,8 +362,36 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID } else */ if (local_username == "" || local_password == "") { sendResponse(from, id, InBandRegistrationPayload::ref()); return true; - } else if (local_username != "heinz" || local_password != "heinz") { - // TODO: Check local password and username + } + Swift::logging = true; + bool validLocal = false; + std::string localLookupServer = CONFIG_STRING(m_config, "registration.local_account_server"); + std::string localLookupJID = local_username + std::string("@") + localLookupServer; + SimpleEventLoop localLookupEventLoop; + BoostNetworkFactories localLookupNetworkFactories(&localLookupEventLoop); + Client localLookupClient(localLookupJID, local_password, &localLookupNetworkFactories); + + // TODO: this is neccessary on my server ... but should maybe omitted + localLookupClient.setAlwaysTrustCertificates(); + localLookupClient.connect(); + + class SimpleLoopRunner { + public: + SimpleLoopRunner() {}; + + static void run(SimpleEventLoop * loop) { + loop->run(); + }; + }; + + // TODO: Really ugly and hacky solution, any other ideas more than welcome! + boost::thread thread(boost::bind(&(SimpleLoopRunner::run), &localLookupEventLoop)); + thread.timed_join(boost::posix_time::millisec(CONFIG_INT(m_config, "registration.local_account_server_timeout"))); + localLookupEventLoop.stop(); + thread.join(); + validLocal = localLookupClient.isAvailable(); + localLookupClient.disconnect(); + if (!validLocal) { sendError(from, id, ErrorPayload::NotAuthorized, ErrorPayload::Modify); return true; } From daf9143bf26005fe951de79a989d865a564da151 Mon Sep 17 00:00:00 2001 From: Dominik Date: Fri, 27 Jan 2012 18:41:47 +0100 Subject: [PATCH 03/41] - forgot to disable logging --- src/userregistration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/userregistration.cpp b/src/userregistration.cpp index d5d7d611..f7de616e 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -363,7 +363,7 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID sendResponse(from, id, InBandRegistrationPayload::ref()); return true; } - Swift::logging = true; +// Swift::logging = true; bool validLocal = false; std::string localLookupServer = CONFIG_STRING(m_config, "registration.local_account_server"); std::string localLookupJID = local_username + std::string("@") + localLookupServer; From 099857ad59ce9a2579b716a3fc73095f6fe396bc Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 14 Feb 2012 21:48:07 +0100 Subject: [PATCH 04/41] smstools3 backend - not working so far --- backends/CMakeLists.txt | 2 + backends/smstools3/CMakeLists.txt | 10 ++ backends/smstools3/main.cpp | 246 ++++++++++++++++++++++++++++++ 3 files changed, 258 insertions(+) create mode 100644 backends/smstools3/CMakeLists.txt create mode 100644 backends/smstools3/main.cpp diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index b8278015..c0e3d527 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -7,6 +7,8 @@ if (PROTOBUF_FOUND) ADD_SUBDIRECTORY(libcommuni) endif() +#ADD_SUBDIRECTORY(smstools3) + if (NOT WIN32) ADD_SUBDIRECTORY(frotz) # ADD_SUBDIRECTORY(skype) diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt new file mode 100644 index 00000000..c410cee6 --- /dev/null +++ b/backends/smstools3/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required(VERSION 2.6) + +FILE(GLOB SRC *.c *.cpp) + +ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC}) + +target_link_libraries(spectrum2_smstools3_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) + +INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin) + diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp new file mode 100644 index 00000000..60d1e1e3 --- /dev/null +++ b/backends/smstools3/main.cpp @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2008-2009 J-P Nurmi jpnurmi@gmail.com + * + * This example is free, and not covered by LGPL license. There is no + * restriction applied to their modification, redistribution, using and so on. + * You can study them, modify them, use them in your own program - either + * completely or partially. By using it you may give me some credits in your + * program, but you don't have to. + */ + +#include "transport/config.h" +#include "transport/networkplugin.h" +#include "Swiften/Swiften.h" +#include +#include "unistd.h" +#include "signal.h" +#include "sys/wait.h" +#include "sys/signal.h" +#include +#include + +Swift::SimpleEventLoop *loop_; + +#include "log4cxx/logger.h" +#include "log4cxx/consoleappender.h" +#include "log4cxx/patternlayout.h" +#include "log4cxx/propertyconfigurator.h" +#include "log4cxx/helpers/properties.h" +#include "log4cxx/helpers/fileinputstream.h" +#include "log4cxx/helpers/transcoder.h" +#include +#include + +using namespace boost::filesystem; + +using namespace boost::program_options; +using namespace Transport; + +using namespace log4cxx; + +class SMSNetworkPlugin; +SMSNetworkPlugin * np = NULL; + +class SMSNetworkPlugin : public NetworkPlugin { + public: + Swift::BoostNetworkFactories *m_factories; + Swift::BoostIOServiceThread m_boostIOServiceThread; + boost::shared_ptr m_conn; + Swift::Timer::ref m_timer; + + SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { + this->config = config; + m_factories = new Swift::BoostNetworkFactories(loop); + m_conn = m_factories->getConnectionFactory()->createConnection(); + m_conn->onDataRead.connect(boost::bind(&SMSNetworkPlugin::_handleDataRead, this, _1)); + m_conn->connect(Swift::HostAddressPort(Swift::HostAddress(host), port)); +// m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1)); +// m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this)); + + m_timer = m_factories->getTimerFactory()->createTimer(5000); + m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); + m_timer->start(); + } + + + void handleSMS(const std::string &sms) { + std::ifstream t(sms.c_str()); + std::string str; + + t.seekg(0, std::ios::end); + str.reserve(t.tellg()); + t.seekg(0, std::ios::beg); + + str.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + + std::string to = ""; + std::string msg = ""; + while(str.find("\n") != std::string::npos) { + std::string line = str.substr(0, str.find("\n")); + if (line.find("To: ") == 0) { + to = line.substr(strlen("To: ")); + } + else if (line.empty()) { + msg = str; + break; + } + str = str.substr(str.find("\n") + 1); + } + + } + + void handleSMSDir() { + path p(config->getUnregistered().find("backend.incoming_dir")->second); + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + + try { + if (is_regular(itr->path())) { + handleSMS(itr->path().string()); + remove(itr->path()); + } + } + catch (const filesystem_error& ex) { + + } + } + m_timer->start(); + } + + void sendData(const std::string &string) { + m_conn->write(Swift::createSafeByteArray(string)); + } + + void _handleDataRead(boost::shared_ptr data) { + std::string d(data->begin(), data->end()); + handleDataRead(d); + } + + void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + np->handleConnected(user); +// std::vector groups; +// groups.push_back("ZCode"); +// np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE); + } + + void handleLogoutRequest(const std::string &user, const std::string &legacyName) { + } + + void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + + } + + void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { + } + + void handleLeaveRoomRequest(const std::string &user, const std::string &room) { + } + + + private: + + Config *config; +}; + +static void spectrum_sigchld_handler(int sig) +{ + int status; + pid_t pid; + + do { + pid = waitpid(-1, &status, WNOHANG); + } while (pid != 0 && pid != (pid_t)-1); + + if ((pid == (pid_t) - 1) && (errno != ECHILD)) { + char errmsg[BUFSIZ]; + snprintf(errmsg, BUFSIZ, "Warning: waitpid() returned %d", pid); + perror(errmsg); + } +} + + +int main (int argc, char* argv[]) { + std::string host; + int port; + + if (signal(SIGCHLD, spectrum_sigchld_handler) == SIG_ERR) { + std::cout << "SIGCHLD handler can't be set\n"; + return -1; + } + + boost::program_options::options_description desc("Usage: spectrum [OPTIONS] \nAllowed options"); + desc.add_options() + ("host,h", value(&host), "host") + ("port,p", value(&port), "port") + ; + try + { + boost::program_options::variables_map vm; + boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm); + boost::program_options::notify(vm); + } + catch (std::runtime_error& e) + { + std::cout << desc << "\n"; + exit(1); + } + catch (...) + { + std::cout << desc << "\n"; + exit(1); + } + + + if (argc < 5) { + return 1; + } + +// QStringList channels; +// for (int i = 3; i < argc; ++i) +// { +// channels.append(argv[i]); +// } +// +// MyIrcSession session; +// session.setNick(argv[2]); +// session.setAutoJoinChannels(channels); +// session.connectToServer(argv[1], 6667); + + Config config; + if (!config.load(argv[5])) { + std::cerr << "Can't open " << argv[1] << " configuration file.\n"; + return 1; + } + + if (CONFIG_STRING(&config, "logging.backend_config").empty()) { + LoggerPtr root = log4cxx::Logger::getRootLogger(); +#ifndef _MSC_VER + root->addAppender(new ConsoleAppender(new PatternLayout("%d %-5p %c: %m%n"))); +#else + root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n"))); +#endif + } + else { + log4cxx::helpers::Properties p; + log4cxx::helpers::FileInputStream *istream = new log4cxx::helpers::FileInputStream(CONFIG_STRING(&config, "logging.backend_config")); + p.load(istream); + LogString pid, jid; + log4cxx::helpers::Transcoder::decode(boost::lexical_cast(getpid()), pid); + log4cxx::helpers::Transcoder::decode(CONFIG_STRING(&config, "service.jid"), jid); +#ifdef _MSC_VER + p.setProperty(L"pid", pid); + p.setProperty(L"jid", jid); +#else + p.setProperty("pid", pid); + p.setProperty("jid", jid); +#endif + log4cxx::PropertyConfigurator::configure(p); + } + + Swift::SimpleEventLoop eventLoop; + loop_ = &eventLoop; + np = new SMSNetworkPlugin(&config, &eventLoop, host, port); + loop_->run(); + + return 0; +} From db6f7e6c8f8692d8ef69a032c95dc07fcff91aac Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 15 Feb 2012 20:48:51 +0100 Subject: [PATCH 05/41] sending sms works --- backends/CMakeLists.txt | 2 +- backends/smstools3/main.cpp | 22 ++++++++++++++++++++-- spectrum/src/sample.cfg | 4 +++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index c0e3d527..be7163c5 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -7,7 +7,7 @@ if (PROTOBUF_FOUND) ADD_SUBDIRECTORY(libcommuni) endif() -#ADD_SUBDIRECTORY(smstools3) + ADD_SUBDIRECTORY(smstools3) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 60d1e1e3..bc02c24a 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -87,6 +87,8 @@ class SMSNetworkPlugin : public NetworkPlugin { str = str.substr(str.find("\n") + 1); } + std::cout << "INCOMING SMS '" << to << "' '" << msg << "'\n"; + } void handleSMSDir() { @@ -97,7 +99,7 @@ class SMSNetworkPlugin : public NetworkPlugin { try { if (is_regular(itr->path())) { handleSMS(itr->path().string()); - remove(itr->path()); +// remove(itr->path()); } } catch (const filesystem_error& ex) { @@ -107,6 +109,22 @@ class SMSNetworkPlugin : public NetworkPlugin { m_timer->start(); } + void sendSMS(const std::string &to, const std::string &msg) { + std::string data = "To: " + to + "\n"; + data += "\n"; + data += msg; + + std::string bucket = "abcdefghijklmnopqrstuvwxyz"; + std::string uuid; + for (int i = 0; i < 10; i++) { + uuid += bucket[rand() % bucket.size()]; + } + std::ofstream myfile; + myfile.open (std::string("/var/spool/sms/outgoing/spectrum." + uuid).c_str()); + myfile << data; + myfile.close(); + } + void sendData(const std::string &string) { m_conn->write(Swift::createSafeByteArray(string)); } @@ -127,7 +145,7 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { - + sendSMS(legacyName, message); } void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index fcb060d3..10850f05 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,7 +13,8 @@ admin_password=test #cert=server.pfx #patch to PKCS#12 certificate #cert_password=test #password to that certificate if any users_per_backend=10 -backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend +#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend +backend=/home/hanzz/code/libtransport/backends/smstools3/spectrum2_smstools3_backend #backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe #backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend #backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend @@ -25,6 +26,7 @@ irc_server=irc.freenode.org [backend] #default_avatar=catmelonhead.jpg #no_vcard_fetch=true +incoming_dir=/var/spool/sms/incoming [logging] #config=logging.cfg # log4cxx/log4j logging configuration file From d8e60cea9507daf5485ee1627446497c7c1169f8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 15 Feb 2012 21:13:14 +0100 Subject: [PATCH 06/41] Join the database from sms backend --- backends/smstools3/main.cpp | 76 +++++++++++++++++++++++++++++++++++++ spectrum/src/sample.cfg | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index bc02c24a..919480ec 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -10,6 +10,10 @@ #include "transport/config.h" #include "transport/networkplugin.h" +#include "transport/sqlite3backend.h" +#include "transport/mysqlbackend.h" +#include "transport/pqxxbackend.h" +#include "transport/storagebackend.h" #include "Swiften/Swiften.h" #include #include "unistd.h" @@ -40,6 +44,7 @@ using namespace log4cxx; class SMSNetworkPlugin; SMSNetworkPlugin * np = NULL; +StorageBackend *storageBackend; class SMSNetworkPlugin : public NetworkPlugin { public: @@ -135,6 +140,18 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { + UserInfo info; + if (!storageBackend->getUser(user, info)) { + handleDisconnected(user, 0, "Not registered user."); + return; + } + std::list roster; + storageBackend->getBuddies(info.id, roster); + + BOOST_FOREACH(BuddyInfo &b, roster) { + handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE); + } + np->handleConnected(user); // std::vector groups; // groups.push_back("ZCode"); @@ -154,6 +171,14 @@ class SMSNetworkPlugin : public NetworkPlugin { void handleLeaveRoomRequest(const std::string &user, const std::string &room) { } + void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); + } + + void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::vector &groups) { + + } + private: @@ -255,6 +280,57 @@ int main (int argc, char* argv[]) { log4cxx::PropertyConfigurator::configure(p); } +#ifdef WITH_SQLITE + if (CONFIG_STRING(&config, "database.type") == "sqlite3") { + storageBackend = new SQLite3Backend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "sqlite3") { + std::cerr << "Spectrum2 is not compiled with mysql backend.\n"; + return -2; + } +#endif + +#ifdef WITH_MYSQL + if (CONFIG_STRING(&config, "database.type") == "mysql") { + storageBackend = new MySQLBackend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "mysql") { + std::cerr << "Spectrum2 is not compiled with mysql backend.\n"; + return -2; + } +#endif + +#ifdef WITH_PQXX + if (CONFIG_STRING(&config, "database.type") == "pqxx") { + storageBackend = new PQXXBackend(&config); + if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + } +#else + if (CONFIG_STRING(&config, "database.type") == "pqxx") { + std::cerr << "Spectrum2 is not compiled with pqxx backend.\n"; + return -2; + } +#endif + + if (CONFIG_STRING(&config, "database.type") != "mysql" && CONFIG_STRING(&config, "database.type") != "sqlite3" + && CONFIG_STRING(&config, "database.type") != "pqxx" && CONFIG_STRING(&config, "database.type") != "none") { + std::cerr << "Unknown storage backend " << CONFIG_STRING(&config, "database.type") << "\n"; + return -2; + } + Swift::SimpleEventLoop eventLoop; loop_ = &eventLoop; np = new SMSNetworkPlugin(&config, &eventLoop, host, port); diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 10850f05..85f88d37 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -33,6 +33,6 @@ incoming_dir=/var/spool/sms/incoming #backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] -type = none # or "none" without database backend +type = sqlite3 # or "none" without database backend database = test.sql prefix=icq From 57963cf18ec01b4998765f292001cd207e0cc2b1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 15 Feb 2012 22:31:08 +0100 Subject: [PATCH 07/41] working smstools3 with basic pairing --- backends/smstools3/main.cpp | 48 +++++++++++++++++++++++++++++++------ spectrum/src/sample.cfg | 12 +++++++--- src/mysqlbackend.cpp | 10 +++++--- src/sqlite3backend.cpp | 2 ++ 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 919480ec..892a37f9 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -42,6 +42,8 @@ using namespace Transport; using namespace log4cxx; +#define INTERNAL_USER "/sms@backend@internal@user" + class SMSNetworkPlugin; SMSNetworkPlugin * np = NULL; StorageBackend *storageBackend; @@ -52,6 +54,7 @@ class SMSNetworkPlugin : public NetworkPlugin { Swift::BoostIOServiceThread m_boostIOServiceThread; boost::shared_ptr m_conn; Swift::Timer::ref m_timer; + int m_internalUser; SMSNetworkPlugin(Config *config, Swift::SimpleEventLoop *loop, const std::string &host, int port) : NetworkPlugin() { this->config = config; @@ -65,6 +68,13 @@ class SMSNetworkPlugin : public NetworkPlugin { m_timer = m_factories->getTimerFactory()->createTimer(5000); m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); m_timer->start(); + + UserInfo info; + info.jid = INTERNAL_USER; + info.password = ""; + storageBackend->setUser(info); + storageBackend->getUser(INTERNAL_USER, info); + m_internalUser = info.id; } @@ -78,21 +88,32 @@ class SMSNetworkPlugin : public NetworkPlugin { str.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - std::string to = ""; + std::string from = ""; std::string msg = ""; while(str.find("\n") != std::string::npos) { std::string line = str.substr(0, str.find("\n")); - if (line.find("To: ") == 0) { - to = line.substr(strlen("To: ")); + if (line.find("From: ") == 0) { + from = line.substr(strlen("From: ")); } else if (line.empty()) { - msg = str; + msg = str.substr(1); break; } str = str.substr(str.find("\n") + 1); } - std::cout << "INCOMING SMS '" << to << "' '" << msg << "'\n"; + std::list roster; + storageBackend->getBuddies(m_internalUser, roster); + + std::string to; + BOOST_FOREACH(BuddyInfo &b, roster) { + if (b.legacyName == from) { + to = b.alias; + } + } + + handleMessage(to, from, msg); + std::cout << "INCOMING SMS '" << from << "' '" << to << "' '" << msg << "'\n"; } @@ -104,7 +125,7 @@ class SMSNetworkPlugin : public NetworkPlugin { try { if (is_regular(itr->path())) { handleSMS(itr->path().string()); -// remove(itr->path()); + remove(itr->path()); } } catch (const filesystem_error& ex) { @@ -162,7 +183,20 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { - sendSMS(legacyName, message); + std::string n = legacyName; + if (n.find("+") == 0) { + n = n.substr(1); + } + + BuddyInfo info; + info.legacyName = n; + info.alias = user; + info.id = -1; + info.subscription = "both"; + info.flags = 0; + storageBackend->addBuddy(m_internalUser, info); + + sendSMS(n, message); } void handleJoinRoomRequest(const std::string &user, const std::string &room, const std::string &nickname, const std::string &password) { diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 85f88d37..cc57d216 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -33,6 +33,12 @@ incoming_dir=/var/spool/sms/incoming #backend_config=/home/hanzz/code/libtransport/spectrum/src/backend-logging.cfg # log4cxx/log4j logging configuration file for backends [database] -type = sqlite3 # or "none" without database backend -database = test.sql -prefix=icq +#type = sqlite3 # or "none" without database backend +#database = test.sql +#prefix=icq +type = mysql # or "none" without database backend....................................................................................................................... +database = test +prefix= +user=root +password=yourrootsqlpassword +#encryption_key=hanzzik diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 4bc2eec4..1af53c3a 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -470,7 +470,7 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { long id = (long) mysql_insert_id(&m_conn); // INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) - if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { + if (buddyInfo.settings.find("icon_hash") != buddyInfo.settings.end() && !buddyInfo.settings.find("icon_hash")->second.s.empty()) { *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); } @@ -597,6 +597,10 @@ void MySQLBackend::getUserSetting(long id, const std::string &variable, int &typ else { *m_getUserSetting >> type >> value; } + + while (m_getUserSetting->fetch() == 0) { + + } } void MySQLBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { @@ -606,11 +610,11 @@ void MySQLBackend::updateUserSetting(long id, const std::string &variable, const } void MySQLBackend::beginTransaction() { - exec("START TRANSACTION;"); + //exec("START TRANSACTION;"); } void MySQLBackend::commitTransaction() { - exec("COMMIT;"); + //exec("COMMIT;"); } } diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index ad03bf23..ea869275 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -111,6 +111,8 @@ bool SQLite3Backend::connect() { return false; } + sqlite3_busy_timeout(m_db, 1500); + if (createDatabase() == false) return false; From a67bc0fa96a538343236b538df9ab9c26aab938e Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 08:45:18 +0100 Subject: [PATCH 08/41] SMSTools3 backend logging --- backends/smstools3/main.cpp | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index 892a37f9..fb5a791b 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -42,6 +42,8 @@ using namespace Transport; using namespace log4cxx; +static LoggerPtr logger = log4cxx::Logger::getLogger("SMSNetworkPlugin"); + #define INTERNAL_USER "/sms@backend@internal@user" class SMSNetworkPlugin; @@ -65,6 +67,8 @@ class SMSNetworkPlugin : public NetworkPlugin { // m_conn->onConnectFinished.connect(boost::bind(&FrotzNetworkPlugin::_handleConnected, this, _1)); // m_conn->onDisconnected.connect(boost::bind(&FrotzNetworkPlugin::handleDisconnected, this)); + LOG4CXX_INFO(logger, "Starting the plugin."); + m_timer = m_factories->getTimerFactory()->createTimer(5000); m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); m_timer->start(); @@ -79,6 +83,7 @@ class SMSNetworkPlugin : public NetworkPlugin { void handleSMS(const std::string &sms) { + LOG4CXX_INFO(logger, "Handling SMS " << sms << ".") std::ifstream t(sms.c_str()); std::string str; @@ -112,13 +117,22 @@ class SMSNetworkPlugin : public NetworkPlugin { } } - handleMessage(to, from, msg); - std::cout << "INCOMING SMS '" << from << "' '" << to << "' '" << msg << "'\n"; + if (to.empty()) { + LOG4CXX_WARN(logger, "Received SMS from " << from << ", but this number is not associated with any XMPP user."); + } + LOG4CXX_INFO(logger, "Forwarding SMS from " << from << " to " << to << "."); + handleMessage(to, from, msg); } void handleSMSDir() { - path p(config->getUnregistered().find("backend.incoming_dir")->second); + std::string dir = "/var/spool/sms/incoming/"; + if (config->getUnregistered().find("backend.incoming_dir") != config->getUnregistered().end()) { + dir = config->getUnregistered().find("backend.incoming_dir")->second; + } + LOG4CXX_INFO(logger, "Checking directory " << dir << " for incoming SMS."); + + path p(dir); directory_iterator end_itr; for (directory_iterator itr(p); itr != end_itr; ++itr) { @@ -129,7 +143,7 @@ class SMSNetworkPlugin : public NetworkPlugin { } } catch (const filesystem_error& ex) { - + LOG4CXX_ERROR(logger, "Error when removing the SMS: " << ex.what() << "."); } } m_timer->start(); @@ -196,6 +210,7 @@ class SMSNetworkPlugin : public NetworkPlugin { info.flags = 0; storageBackend->addBuddy(m_internalUser, info); + LOG4CXX_INFO(logger, "Sending SMS from " << user << " to " << n << "."); sendSMS(n, message); } @@ -206,6 +221,7 @@ class SMSNetworkPlugin : public NetworkPlugin { } void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::vector &groups) { + LOG4CXX_INFO(logger, user << ": Added buddy " << buddyName << "."); handleBuddyChanged(user, buddyName, alias, groups, pbnetwork::STATUS_ONLINE); } From 1be2472596ac1ac0f414e3af830112ce992be649 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 09:18:29 +0100 Subject: [PATCH 09/41] more comments --- CMakeLists.txt | 2 +- backends/smstools3/main.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f4802e1..261af42c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,7 +38,7 @@ set(Boost_USE_STATIC_LIBS ON) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) endif() -find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) +find_package(Boost COMPONENTS program_options date_time system filesystem regex signals REQUIRED) message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") diff --git a/backends/smstools3/main.cpp b/backends/smstools3/main.cpp index fb5a791b..1b0bb044 100644 --- a/backends/smstools3/main.cpp +++ b/backends/smstools3/main.cpp @@ -73,6 +73,11 @@ class SMSNetworkPlugin : public NetworkPlugin { m_timer->onTick.connect(boost::bind(&SMSNetworkPlugin::handleSMSDir, this)); m_timer->start(); + // We're reusing our database model here. Buddies of user with JID INTERNAL_USER are there + // to match received GSM messages from number N with the XMPP users who sent message to number N. + // BuddyName = GSM number + // Alias = XMPP user JID to which the messages from this number is sent to. + // TODO: This should be per Modem!!! UserInfo info; info.jid = INTERNAL_USER; info.password = ""; @@ -150,10 +155,12 @@ class SMSNetworkPlugin : public NetworkPlugin { } void sendSMS(const std::string &to, const std::string &msg) { + // TODO: Probably std::string data = "To: " + to + "\n"; data += "\n"; data += msg; + // generate random string here... std::string bucket = "abcdefghijklmnopqrstuvwxyz"; std::string uuid; for (int i = 0; i < 10; i++) { @@ -183,25 +190,25 @@ class SMSNetworkPlugin : public NetworkPlugin { std::list roster; storageBackend->getBuddies(info.id, roster); + // Send available presence to every number in the roster. BOOST_FOREACH(BuddyInfo &b, roster) { handleBuddyChanged(user, b.legacyName, b.alias, b.groups, pbnetwork::STATUS_ONLINE); } np->handleConnected(user); -// std::vector groups; -// groups.push_back("ZCode"); -// np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE); } void handleLogoutRequest(const std::string &user, const std::string &legacyName) { } void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &xhtml = "") { + // Remove trailing +, because smstools doesn't use it in "From: " field for received messages. std::string n = legacyName; if (n.find("+") == 0) { n = n.substr(1); } + // Create GSM Number - XMPP user pair to match the potential response and send it to the proper JID. BuddyInfo info; info.legacyName = n; info.alias = user; From 2442a31dfd32d9b4fbfe643100aa38fa01624e00 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 10:26:47 +0100 Subject: [PATCH 10/41] Find dbus --- CMakeLists.txt | 12 ++ backends/CMakeLists.txt | 2 +- backends/skype/CMakeLists.txt | 6 +- backends/skype/geventloop.cpp | 248 --------------------------- backends/skype/geventloop.h | 33 ---- backends/skype/main.cpp | 4 +- backends/skype/spectrumeventloop.cpp | 90 ---------- backends/skype/spectrumeventloop.h | 49 ------ cmake_modules/dbusConfig.cmake | 53 ++++++ 9 files changed, 68 insertions(+), 429 deletions(-) delete mode 100644 backends/skype/geventloop.cpp delete mode 100644 backends/skype/geventloop.h delete mode 100644 backends/skype/spectrumeventloop.cpp delete mode 100644 backends/skype/spectrumeventloop.h create mode 100644 cmake_modules/dbusConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 261af42c..e798a842 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,9 @@ find_package(event) set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(pqxx) +set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(dbus) + find_package(Doxygen) INCLUDE(FindQt4) @@ -146,12 +149,21 @@ if (PROTOBUF_FOUND) endif() message("Frotz plugin : yes") + message("SMSTools3 plugin : yes") + + if(${LIBDBUSGLIB_FOUND}) + message("Skype plugin : yes") + include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + else() + message("Skype plugin : no (install dbus-glib-devel)") + endif() else() message("Network plugins : no (install libprotobuf-dev)") message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") message("IRC plugin : no (install libircclient-qt and libprotobuf-dev)") message("Frotz plugin : no (install libprotobuf-dev)") + message("SMSTools3 plugin : no (install libprotobuf-dev)") endif() if (LOG4CXX_FOUND) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index be7163c5..2bb2c447 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -11,7 +11,7 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) -# ADD_SUBDIRECTORY(skype) + ADD_SUBDIRECTORY(skype) endif() endif() diff --git a/backends/skype/CMakeLists.txt b/backends/skype/CMakeLists.txt index fa6e9266..4e611208 100644 --- a/backends/skype/CMakeLists.txt +++ b/backends/skype/CMakeLists.txt @@ -1,13 +1,9 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp) - -include_directories(/usr/include/dbus-1.0/) -include_directories(/usr/lib/dbus-1.0/include/) -include_directories(/usr/lib64/dbus-1.0/include/) ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) -target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread dbus-glib-1 dbus-1 gobject-2.0 transport-plugin) +target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES} transport-plugin) INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) diff --git a/backends/skype/geventloop.cpp b/backends/skype/geventloop.cpp deleted file mode 100644 index d00d7a56..00000000 --- a/backends/skype/geventloop.cpp +++ /dev/null @@ -1,248 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "geventloop.h" -#ifdef _WIN32 -#include "win32/win32dep.h" -#endif -#ifdef WITH_LIBEVENT -#include "event.h" -#endif - -typedef struct _PurpleIOClosure { - PurpleInputFunction function; - guint result; - gpointer data; -#ifdef WITH_LIBEVENT - GSourceFunc function2; - struct timeval timeout; - struct event evfifo; -#endif -} PurpleIOClosure; - -static gboolean io_invoke(GIOChannel *source, - GIOCondition condition, - gpointer data) -{ - PurpleIOClosure *closure = (PurpleIOClosure* )data; - PurpleInputCondition purple_cond = (PurpleInputCondition)0; - - int tmp = 0; - if (condition & READ_COND) - { - tmp |= PURPLE_INPUT_READ; - purple_cond = (PurpleInputCondition)tmp; - } - if (condition & WRITE_COND) - { - tmp |= PURPLE_INPUT_WRITE; - purple_cond = (PurpleInputCondition)tmp; - } - - closure->function(closure->data, g_io_channel_unix_get_fd(source), purple_cond); - - return TRUE; -} - -static void io_destroy(gpointer data) -{ - g_free(data); -} - -static guint input_add(gint fd, - PurpleInputCondition condition, - PurpleInputFunction function, - gpointer data) -{ - PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = (GIOCondition)0; - closure->function = function; - closure->data = data; - - int tmp = 0; - if (condition & PURPLE_INPUT_READ) - { - tmp |= READ_COND; - cond = (GIOCondition)tmp; - } - if (condition & PURPLE_INPUT_WRITE) - { - tmp |= WRITE_COND; - cond = (GIOCondition)tmp; - } - -#ifdef WIN32 - channel = wpurple_g_io_channel_win32_new_socket(fd); -#else - channel = g_io_channel_unix_new(fd); -#endif - closure->result = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, - io_invoke, closure, io_destroy); - - g_io_channel_unref(channel); - return closure->result; -} - -static PurpleEventLoopUiOps eventLoopOps = -{ - g_timeout_add, - g_source_remove, - input_add, - g_source_remove, - NULL, -#if GLIB_CHECK_VERSION(2,14,0) - g_timeout_add_seconds, -#else - NULL, -#endif - - NULL, - NULL, - NULL -}; - -#ifdef WITH_LIBEVENT - -static GHashTable *events = NULL; -static unsigned long id = 0; - -static void event_io_destroy(gpointer data) -{ - PurpleIOClosure *closure = (PurpleIOClosure* )data; - event_del(&closure->evfifo); - g_free(data); -} - -static void event_io_invoke(int fd, short event, void *data) -{ - PurpleIOClosure *closure = (PurpleIOClosure* )data; - PurpleInputCondition purple_cond = (PurpleInputCondition)0; - int tmp = 0; - if (event & EV_READ) - { - tmp |= PURPLE_INPUT_READ; - purple_cond = (PurpleInputCondition)tmp; - } - if (event & EV_WRITE) - { - tmp |= PURPLE_INPUT_WRITE; - purple_cond = (PurpleInputCondition)tmp; - } - if (event & EV_TIMEOUT) - { -// tmp |= PURPLE_INPUT_WRITE; -// purple_cond = (PurpleInputCondition)tmp; - if (closure->function2(closure->data)) - evtimer_add(&closure->evfifo, &closure->timeout); -// else -// event_io_destroy(data); - return; - } - - closure->function(closure->data, fd, purple_cond); -} - -static gboolean event_input_remove(guint handle) -{ - PurpleIOClosure *closure = (PurpleIOClosure *) g_hash_table_lookup(events, &handle); - if (closure) - event_io_destroy(closure); - return TRUE; -} - -static guint event_input_add(gint fd, - PurpleInputCondition condition, - PurpleInputFunction function, - gpointer data) -{ - PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); - GIOChannel *channel; - GIOCondition cond = (GIOCondition)0; - closure->function = function; - closure->data = data; - - int tmp = EV_PERSIST; - if (condition & PURPLE_INPUT_READ) - { - tmp |= EV_READ; - } - if (condition & PURPLE_INPUT_WRITE) - { - tmp |= EV_WRITE; - } - - event_set(&closure->evfifo, fd, tmp, event_io_invoke, closure); - event_add(&closure->evfifo, NULL); - - int *f = (int *) g_malloc(sizeof(int)); - *f = id; - id++; - g_hash_table_replace(events, f, closure); - - return *f; -} - -static guint event_timeout_add (guint interval, GSourceFunc function, gpointer data) { - struct timeval timeout; - PurpleIOClosure *closure = g_new0(PurpleIOClosure, 1); - closure->function2 = function; - closure->data = data; - - timeout.tv_sec = interval/1000; - timeout.tv_usec = (interval%1000)*1000; - evtimer_set(&closure->evfifo, event_io_invoke, closure); - evtimer_add(&closure->evfifo, &timeout); - closure->timeout = timeout; - - guint *f = (guint *) g_malloc(sizeof(guint)); - *f = id; - id++; - g_hash_table_replace(events, f, closure); - return *f; -} - -static PurpleEventLoopUiOps libEventLoopOps = -{ - event_timeout_add, - event_input_remove, - event_input_add, - event_input_remove, - NULL, -// #if GLIB_CHECK_VERSION(2,14,0) -// g_timeout_add_seconds, -// #else - NULL, -// #endif - - NULL, - NULL, - NULL -}; - -#endif /* WITH_LIBEVENT*/ - -PurpleEventLoopUiOps * getEventLoopUiOps(void){ - return &eventLoopOps; -#ifdef WITH_LIBEVENT - events = g_hash_table_new_full(g_int_hash, g_int_equal, g_free, NULL); - return &libEventLoopOps; -#endif -} diff --git a/backends/skype/geventloop.h b/backends/skype/geventloop.h deleted file mode 100644 index 3febd65e..00000000 --- a/backends/skype/geventloop.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef _HI_EVENTLOOP_H -#define _HI_EVENTLOOP_H - -#include -#include "purple.h" -#include "eventloop.h" - -#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) -#define WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL) - -PurpleEventLoopUiOps * getEventLoopUiOps(void); - -#endif diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 5a135410..17f10bd9 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -12,9 +12,7 @@ #include "transport/rostermanager.h" #include "transport/conversation.h" #include "transport/networkplugin.h" -#include "spectrumeventloop.h" #include -#include "geventloop.h" #include "log4cxx/logger.h" #include "log4cxx/consoleappender.h" #include "log4cxx/patternlayout.h" @@ -773,7 +771,7 @@ int main(int argc, char **argv) { GIOChannel *channel; - GIOCondition cond = (GIOCondition) READ_COND; + GIOCondition cond = (GIOCondition) G_IO_IN; channel = g_io_channel_unix_new(m_sock); g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, cond, transportDataReceived, NULL, io_destroy); diff --git a/backends/skype/spectrumeventloop.cpp b/backends/skype/spectrumeventloop.cpp deleted file mode 100644 index 20286e58..00000000 --- a/backends/skype/spectrumeventloop.cpp +++ /dev/null @@ -1,90 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "spectrumeventloop.h" -#include "glib.h" - -#include - -#ifdef WITH_LIBEVENT -#include -#endif - - -using namespace Swift; - -// Fires the event's callback and frees the event -static gboolean processEvent(void *data) { - Event *ev = (Event *) data; - ev->callback(); - delete ev; - return FALSE; -} - -SpectrumEventLoop::SpectrumEventLoop() : m_isRunning(false) { - m_loop = NULL; - if (true) { - m_loop = g_main_loop_new(NULL, FALSE); - } -#ifdef WITH_LIBEVENT - else { - /*struct event_base *base = (struct event_base *)*/ - event_init(); - } -#endif -} - -SpectrumEventLoop::~SpectrumEventLoop() { - stop(); -} - -void SpectrumEventLoop::run() { - m_isRunning = true; - if (m_loop) { - g_main_loop_run(m_loop); - } -#ifdef WITH_LIBEVENT - else { - event_loop(0); - } -#endif -} - -void SpectrumEventLoop::stop() { - std::cout << "stopped loop\n"; - if (!m_isRunning) - return; - if (m_loop) { - g_main_loop_quit(m_loop); - g_main_loop_unref(m_loop); - m_loop = NULL; - } -#ifdef WITH_LIBEVENT - else { - event_loopexit(NULL); - } -#endif -} - -void SpectrumEventLoop::post(const Event& event) { - // pass copy of event to main thread - Event *ev = new Event(event.owner, event.callback); - g_timeout_add(0, processEvent, ev); -} diff --git a/backends/skype/spectrumeventloop.h b/backends/skype/spectrumeventloop.h deleted file mode 100644 index 7e811c89..00000000 --- a/backends/skype/spectrumeventloop.h +++ /dev/null @@ -1,49 +0,0 @@ -/** - * XMPP - libpurple transport - * - * Copyright (C) 2009, Jan Kaluza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#ifndef SPECTRUM_EVENT_LOOP_H -#define SPECTRUM_EVENT_LOOP_H - -#include -#include "Swiften/EventLoop/EventLoop.h" -#include "glib.h" - -// Event loop implementation for Spectrum -class SpectrumEventLoop : public Swift::EventLoop { - public: - // Creates event loop according to CONFIG().eventloop settings. - SpectrumEventLoop(); - ~SpectrumEventLoop(); - - // Executes the eventloop. - void run(); - - // Stops tht eventloop. - void stop(); - - // Posts new Swift::Event to main thread. - virtual void post(const Swift::Event& event); - - private: - bool m_isRunning; - GMainLoop *m_loop; -}; - -#endif diff --git a/cmake_modules/dbusConfig.cmake b/cmake_modules/dbusConfig.cmake new file mode 100644 index 00000000..532e37da --- /dev/null +++ b/cmake_modules/dbusConfig.cmake @@ -0,0 +1,53 @@ +# - Try to find LIBDBUS GLIB Bindings +# Find LIBDBUSGLIB headers, libraries and the answer to all questions. +# +# LIBDBUSGLIB_FOUND True if libdbus-glib got found +# LIBDBUSGLIB_INCLUDE_DIRS Location of libdbus-glib headers +# LIBDBUSGLIB_LIBRARIES List of libraries to use libdbus-glib +# +# Copyright (c) 2008 Bjoern Ricks +# +# Redistribution and use is allowed according to the terms of the New +# BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# + +INCLUDE( FindPkgConfig ) + +IF ( LibDbusGlib_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "REQUIRED" ) +ELSE( LibDbusGlib_FIND_REQUIRED ) + SET( _pkgconfig_REQUIRED "" ) +ENDIF ( LibDbusGlib_FIND_REQUIRED ) + +IF ( LIBDBUSGLIB_MIN_VERSION ) + PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1>=${LIBDBUSGLIB_MIN_VERSION} ) +ELSE ( LIBDBUSGLIB_MIN_VERSION ) + PKG_SEARCH_MODULE( LIBDBUSGLIB ${_pkgconfig_REQUIRED} dbus-glib-1 ) +ENDIF ( LIBDBUSGLIB_MIN_VERSION ) + + +IF( NOT LIBDBUSGLIB_FOUND AND NOT PKG_CONFIG_FOUND ) + FIND_PATH( LIBDBUSGLIB_INCLUDE_DIRS dbus/dbus-glib.h PATH_SUFFIXES dbus-1.0 dbus ) + FIND_LIBRARY( LIBDBUSGLIB_LIBRARIES dbus-glib dbus-glib-1) + + # Report results + IF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS ) + SET( LIBDBUSGLIB_FOUND 1 ) + IF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" ) + ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + ELSE ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS ) + IF ( LIBDBUSGLIB_FIND_REQUIRED ) + MESSAGE( SEND_ERROR "Could NOT find libdbus-glib" ) + ELSE ( LIBDBUSGLIB_FIND_REQUIRED ) + IF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + MESSAGE( STATUS "Could NOT find libdbus-glib" ) + ENDIF ( NOT LIBDBUSGLIB_FIND_QUIETLY ) + ENDIF ( LIBDBUSGLIB_FIND_REQUIRED ) + ENDIF ( LIBDBUSGLIB_LIBRARIES AND LIBDBUSGLIB_INCLUDE_DIRS ) +else() + MESSAGE( STATUS "Found libdbus-glib: ${LIBDBUSGLIB_LIBRARIES} ${LIBDBUSGLIB_INCLUDE_DIRS}" ) +ENDIF() + +MARK_AS_ADVANCED( LIBDBUSGLIB_LIBRARIES LIBDBUSGLIB_INCLUDE_DIRS ) \ No newline at end of file From 6dd874964a6100d070a090fc6f8f96c4ef78f0a9 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 16 Feb 2012 11:13:13 +0100 Subject: [PATCH 11/41] Do not build skype if it's not found --- backends/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 2bb2c447..543b60b8 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -11,7 +11,9 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(frotz) - ADD_SUBDIRECTORY(skype) + if (${LIBDBUSGLIB_FOUND}) + ADD_SUBDIRECTORY(skype) + endif() endif() endif() From a9341e05497c195e3918200b330c93ce6422407c Mon Sep 17 00:00:00 2001 From: HanzZ Date: Thu, 16 Feb 2012 23:16:13 +0100 Subject: [PATCH 12/41] Log --- src/networkpluginserver.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index feade943..7a876383 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -257,6 +257,7 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U #endif exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str()); + LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); } NetworkPluginServer::~NetworkPluginServer() { From 5c015b5547db9403cfa4b6174b84d012e6d96466 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 09:43:10 +0100 Subject: [PATCH 13/41] Load SSL related issues --- .../TLS/OpenSSL/OpenSSLServerContext.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp b/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp index ecc60733..ebf798be 100644 --- a/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp +++ b/include/Swiften/TLS/OpenSSL/OpenSSLServerContext.cpp @@ -14,6 +14,13 @@ #include #include +#include "log4cxx/logger.h" +#include "log4cxx/consoleappender.h" +#include "log4cxx/patternlayout.h" +#include "log4cxx/propertyconfigurator.h" +using namespace log4cxx; +static LoggerPtr logger = Logger::getLogger("OpenSSLServerContext"); + #include "Swiften/TLS/OpenSSL/OpenSSLServerContext.h" #include "Swiften/TLS/OpenSSL/OpenSSLCertificate.h" @@ -179,7 +186,7 @@ void OpenSSLServerContext::sendPendingDataToApplication() { bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certificate) { if (certificate.isNull()) { -// std::cout << "error 1\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate can't be loaded."); return false; } @@ -189,7 +196,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi boost::shared_ptr pkcs12(d2i_PKCS12_bio(bio, NULL), PKCS12_free); BIO_free(bio); if (!pkcs12) { -// std::cout << "error 2\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format."); return false; } @@ -199,7 +206,7 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi STACK_OF(X509)* caCertsPtr = 0; int result = PKCS12_parse(pkcs12.get(), reinterpret_cast(vecptr(certificate.getPassword())), &privateKeyPtr, &certPtr, &caCertsPtr); if (result != 1) { -// std::cout << "error 3\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Certificate is not in PKCS#12 format."); return false; } boost::shared_ptr cert(certPtr, X509_free); @@ -208,11 +215,11 @@ bool OpenSSLServerContext::setServerCertificate(const PKCS12Certificate& certifi // Use the key & certificates if (SSL_CTX_use_certificate(context_, cert.get()) != 1) { -// std::cout << "error 4\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this certificate"); return false; } if (SSL_CTX_use_PrivateKey(context_, privateKey.get()) != 1) { -// std::cout << "error 5\n"; + LOG4CXX_ERROR(logger, "TLS WILL NOT WORK: Can't use this private key"); return false; } return true; From 263f0b11d85144e76975823026443eafe4d9649b Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 09:59:38 +0100 Subject: [PATCH 14/41] Call setsid always when spawning backend --- spectrum/src/sample2.cfg | 2 +- src/networkpluginserver.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 508395e9..981124b9 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -41,7 +41,7 @@ users_per_backend=10 backend=/usr/bin/spectrum2_libpurple_backend #backend=/usr/bin/spectrum2_libircclient-qt_backend # For skype: -#backend=/usr/bin/setsid /usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend +#backend=/usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend # Libpurple protocol-id for spectrum_libpurple_backend protocol=prpl-jabber diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 7a876383..756cff77 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -157,6 +157,7 @@ static unsigned long exec_(std::string path, const char *host, const char *port, // fork and exec pid_t pid = fork(); if ( pid == 0 ) { + setsid(); // child process exit(execv(argv[0], argv)); } else if ( pid < 0 ) { From b6811cfe5a8e96061da43a10a39939d0ba4c2897 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 10:38:44 +0100 Subject: [PATCH 15/41] read all data fetched by sqlite3 --- src/sqlite3backend.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index ea869275..c61ca628 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -236,6 +236,8 @@ bool SQLite3Backend::getUser(const std::string &barejid, UserInfo &user) { user.encoding = (const char *) sqlite3_column_text(m_getUser, 4); user.language = (const char *) sqlite3_column_text(m_getUser, 5); user.vip = sqlite3_column_int(m_getUser, 6) != 0; + while((ret = sqlite3_step(m_getUser)) == SQLITE_ROW) { + } return true; } @@ -390,6 +392,9 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { roster.push_back(b); } + while((ret = sqlite3_step(m_getBuddiesSettings)) == SQLITE_ROW) { + } + if (ret != SQLITE_DONE) { LOG4CXX_ERROR(logger, "getBuddies query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); return false; @@ -446,6 +451,10 @@ void SQLite3Backend::getUserSetting(long id, const std::string &variable, int &t type = GET_INT(m_getUserSetting); value = GET_STR(m_getUserSetting); } + + int ret; + while((ret = sqlite3_step(m_getUserSetting)) == SQLITE_ROW) { + } } void SQLite3Backend::updateUserSetting(long id, const std::string &variable, const std::string &value) { From eb3c5880337ca2576d093f1ee8858cda745dd45a Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 10:47:05 +0100 Subject: [PATCH 16/41] Comment out the registration stuff --- spectrum/src/sample2.cfg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 981124b9..3f755c00 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -101,14 +101,14 @@ type = none enable_public_registration=1 # Text to display upon user registration form -username_label=Jabber JID (e.g. user@server.tld): -instructions=Enter your remote jabber JID and password as well as your local username and password +#username_label=Jabber JID (e.g. user@server.tld): +#instructions=Enter your remote jabber JID and password as well as your local username and password # If True a local jabber account on is needed # for transport registration, the idea is to enable public registration # from other servers, but only for users, who have already local accounts -require_local_account=1 -local_username_label=Local username (without @server.tld): -local_account_server=localhost -local_account_server_timeout=10000 +#require_local_account=1 +#local_username_label=Local username (without @server.tld): +#local_account_server=localhost +#local_account_server_timeout=10000 From 56bb259d89e1e6d4e38ecad72d22c72475a66a93 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 10:57:32 +0100 Subject: [PATCH 17/41] ChangeLog update --- ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index 36a65268..ae19ff21 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,11 +1,24 @@ Version 2.0.0-beta (X-X-X): General: + * Fixed potential MySQL/SQLite3 deadlocks. + * Fixed disconnecting in server-mode when client does not send unavailable + presence before disconnection. + * Fixed crash in server-mode when client send its custom jabber:iq:storage + payload. * Fixed registration from Pidgin. * Unsubscribe presence sent to some buddy doesn't disconnect the account. * Remote Roster requests are not sent to resources, but to bare JID. * Added automatic reconnection in case of non-fatal error. * Added more error messages. + Skype: + * Initial support for Skype added, read more on + http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_Skype_backend + + SMSTools3: + * Initial support for SMSTools3, read more on + http://spectrum.im/projects/spectrum/wiki/Spectrum_2_Admin_-_SMSTools3_backend + version 2.0.0 alpha (2011-12-06): General: * First Spectrum 2.0.0 alpha release, check more on From abf7412731ac5fbfd45a79f12e90ed3c197e5a49 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 11:26:46 +0100 Subject: [PATCH 18/41] Set proper default database --- src/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.cpp b/src/config.cpp index 91e5ed67..18434c24 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -92,7 +92,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.local_account_server", value()->default_value("localhost"), "The server on which the local accounts will be checked for validity") ("registration.local_account_server_timeout", value()->default_value(10000), "Timeout when checking local user on local_account_server (msecs)") ("database.type", value()->default_value("none"), "Database type.") - ("database.database", value()->default_value(""), "Database used to store data") + ("database.database", value()->default_value("/var/lib/spectrum2/$jid/database.sql"), "Database used to store data") ("database.server", value()->default_value("localhost"), "Database server.") ("database.user", value()->default_value(""), "Database user.") ("database.password", value()->default_value(""), "Database Password.") From 8d97bbe73ec0fd66a118159cbb64633e3f7cd06e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 11:33:00 +0100 Subject: [PATCH 19/41] Respect default value for database.database --- src/config.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/config.cpp b/src/config.cpp index 18434c24..7088889c 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -111,6 +111,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description bool found_working = false; bool found_pidfile = false; bool found_backend_port = false; + bool found_database = false; std::string jid = ""; BOOST_FOREACH(option &opt, parsed.options) { if (opt.string_key == "service.jid") { @@ -134,6 +135,9 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description else if (opt.string_key == "service.pidfile") { found_pidfile = true; } + else if (opt.string_key == "database.database") { + found_database = true; + } } if (!found_working) { @@ -152,6 +156,11 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description value.push_back(p); parsed.options.push_back(boost::program_options::basic_option("service.backend_port", value)); } + if (!found_database) { + std::vector value; + value.push_back("/var/lib/spectrum2/$jid/database.sql"); + parsed.options.push_back(boost::program_options::basic_option("database.database", value)); + } BOOST_FOREACH(option &opt, parsed.options) { if (opt.unregistered) { From f742dae4624834fb6de966e030ffb44569f2c2eb Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 11:50:33 +0100 Subject: [PATCH 20/41] wait 10s --- backends/skype/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 17f10bd9..095c41a9 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -366,7 +366,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { free(db); - sleep(2); + sleep(10); GError *error = NULL; DBusObjectPathVTable vtable; From 31de3415d2828623d695671dab8415665617ee5e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 14:01:01 +0100 Subject: [PATCH 21/41] Removed big sleep from skype --- backends/skype/main.cpp | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 095c41a9..4b21effe 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -107,6 +107,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { public: SpectrumNetworkPlugin(Config *config, const std::string &host, int port) : NetworkPlugin() { this->config = config; + LOG4CXX_INFO(logger, "Starting the backend."); } ~SpectrumNetworkPlugin() { @@ -118,7 +119,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { std::string name = legacyName; name = name.substr(name.find(".") + 1); - LOG4CXX_INFO(logger, "Creating account with name '" << name); + LOG4CXX_INFO(logger, "Creating account with name '" << name << "'"); Skype *skype = new Skype(user, name, password); m_sessions[user] = skype; @@ -366,8 +367,6 @@ class SpectrumNetworkPlugin : public NetworkPlugin { free(db); - sleep(10); - GError *error = NULL; DBusObjectPathVTable vtable; @@ -376,6 +375,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (m_connection == NULL) { + LOG4CXX_INFO(logger, "Creating DBus connection."); m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (m_connection == NULL && error != NULL) { @@ -387,15 +387,29 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (m_proxy == NULL) { - m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, - "com.Skype.API", - "/com/Skype", - "com.Skype.API", - &error); - if (m_proxy == NULL && error != NULL) - { - LOG4CXX_INFO(logger, m_username << ":" << error->message); - g_error_free(error); + int counter = 0; + while (m_proxy == NULL) { + counter++; + sleep(1); + LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); + m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, + "com.Skype.API", + "/com/Skype", + "com.Skype.API", + &error); + if (m_proxy == NULL && error != NULL) + { + LOG4CXX_INFO(logger, m_username << ":" << error->message); + + if (counter == 15) { + np->handleDisconnected(m_user, 0, error->message); + close(fd_output); + logout(); + g_error_free(error); + break; + } + g_error_free(error); + } } vtable.message_function = &skype_notify_handler; @@ -466,7 +480,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { if (buddy[0] == ',') { buddy.erase(buddy.begin()); } - std::cout << "BUDDY '" << buddy << "'\n"; + LOG4CXX_INFO(logger, "Got buddy " << buddy); std::string st = full_friends_list[i + 5]; pbnetwork::StatusType status = getStatus(st); From 1b8fef4d70b58dfc4f0df21b600d77e21dae43f1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:09:35 +0100 Subject: [PATCH 22/41] Skype backend is now non-blocking --- backends/skype/main.cpp | 494 +++++++++++++++++++++------------------- 1 file changed, 266 insertions(+), 228 deletions(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 4b21effe..a09b0b80 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -94,6 +94,9 @@ class Skype { return m_username; } + bool createDBusProxy(); + bool loadSkypeBuddies(); + private: std::string m_username; std::string m_password; @@ -101,6 +104,9 @@ class Skype { DBusGConnection *m_connection; DBusGProxy *m_proxy; std::string m_user; + int m_timer; + int m_counter; + int fd_output; }; class SpectrumNetworkPlugin : public NetworkPlugin { @@ -296,250 +302,277 @@ class SpectrumNetworkPlugin : public NetworkPlugin { }; - Skype::Skype(const std::string &user, const std::string &username, const std::string &password) { - m_username = username; - m_user = user; - m_password = password; - m_pid = 0; - m_connection = 0; - m_proxy = 0; - } - void Skype::login() { - boost::filesystem::path path(std::string("/tmp/skype/") + m_username); - if (!boost::filesystem::exists(path)) { - boost::filesystem::create_directories(path); - boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username ); - boost::filesystem::create_directories(path2); - } +Skype::Skype(const std::string &user, const std::string &username, const std::string &password) { + m_username = username; + m_user = user; + m_password = password; + m_pid = 0; + m_connection = 0; + m_proxy = 0; + m_timer = -1; + m_counter = 0; +} - std::string shared_xml = "\n" - "(time(NULL)) + ".0\">\n" - "\n" - "2\n" - "en\n" - "\n" - "\n"; - g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL); - std::string config_xml = "\n" - "(time(NULL)) + ".0\">\n" - "\n" - "\n" - "30000000\n" - "300000000\n" - "" + boost::lexical_cast(time(NULL)) + "\n" - "\n" - "\n" - "\n" - "\n" - "Spectrum\n" - "\n" - "\n" - "\n" - "\n"; - g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL); - std::string db_path = std::string("/tmp/skype/") + m_username; - char *db = (char *) malloc(db_path.size() + 1); - strcpy(db, db_path.c_str()); - LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db); - gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0}; +static gboolean load_skype_buddies(gpointer data) { + Skype *skype = (Skype *) data; + return skype->loadSkypeBuddies(); +} - int fd; - int fd_output; - g_spawn_async_with_pipes(NULL, - argv, - NULL /*envp*/, - G_SPAWN_SEARCH_PATH, - NULL /*child_setup*/, - NULL /*user_data*/, - &m_pid /*child_pid*/, - &fd, - NULL, - &fd_output, - NULL /*error*/); - std::string login_data = std::string(m_username + " " + m_password + "\n"); - LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data); - write(fd, login_data.c_str(), login_data.size()); - close(fd); - - fcntl (fd_output, F_SETFL, O_NONBLOCK); +bool Skype::createDBusProxy() { + if (m_proxy == NULL) { + LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); + m_counter++; - free(db); + GError *error = NULL; + m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, "com.Skype.API", "/com/Skype", "com.Skype.API", &error); + if (m_proxy == NULL && error != NULL) { + LOG4CXX_INFO(logger, m_username << ":" << error->message); - GError *error = NULL; - DBusObjectPathVTable vtable; - - //Initialise threading - dbus_threads_init_default(); - - if (m_connection == NULL) - { - LOG4CXX_INFO(logger, "Creating DBus connection."); - m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); - if (m_connection == NULL && error != NULL) - { - LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); - g_error_free(error); - return; - } - } - - if (m_proxy == NULL) - { - int counter = 0; - while (m_proxy == NULL) { - counter++; - sleep(1); - LOG4CXX_INFO(logger, "Creating DBus proxy for com.Skype.Api."); - m_proxy = dbus_g_proxy_new_for_name_owner (m_connection, - "com.Skype.API", - "/com/Skype", - "com.Skype.API", - &error); - if (m_proxy == NULL && error != NULL) - { - LOG4CXX_INFO(logger, m_username << ":" << error->message); - - if (counter == 15) { - np->handleDisconnected(m_user, 0, error->message); - close(fd_output); - logout(); - g_error_free(error); - break; - } - g_error_free(error); - } - } - - vtable.message_function = &skype_notify_handler; - dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this); - } - - int counter = 0; - std::string re = "CONNSTATUS OFFLINE"; - while (re == "CONNSTATUS OFFLINE" || re.empty()) { - sleep(1); - gchar buffer[1024]; - int bytes_read; - bytes_read = read (fd_output, buffer, 1023); - if (bytes_read > 0) { - buffer[bytes_read] = 0; - np->handleDisconnected(m_user, 0, buffer); - close(fd_output); - logout(); - return; - } - re = send_command("NAME Spectrum"); - if (counter++ > 15) - break; - } - - close(fd_output); - - if (send_command("PROTOCOL 7") != "PROTOCOL 7") { - np->handleDisconnected(m_user, 0, "Skype is not ready"); + if (m_counter == 15) { + np->handleDisconnected(m_user, 0, error->message); logout(); - return; + g_error_free(error); + return FALSE; } - - np->handleConnected(m_user); - - std::map group_map; - std::string groups = send_command("SEARCH GROUPS CUSTOM"); - groups = groups.substr(groups.find(' ') + 1); - std::vector grps; - boost::split(grps, groups, boost::is_any_of(",")); - BOOST_FOREACH(std::string grp, grps) { - std::vector data; - std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME"); - boost::split(data, name, boost::is_any_of(" ")); - name = name.substr(name.find("DISPLAYNAME") + 12); - - std::string users = send_command("GET GROUP " + data[1] + " USERS"); - users = name.substr(name.find("USERS") + 6); - boost::split(data, users, boost::is_any_of(",")); - BOOST_FOREACH(std::string u, data) { - group_map[u] = grp; - } - } - - std::string friends = send_command("GET AUTH_CONTACTS_PROFILES"); - - char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0); - if (full_friends_list && full_friends_list[0]) - { - //in the format of: username;full name;phone;office phone;mobile phone; - // online status;friendly name;voicemail;mood - // (comma-seperated lines, usernames can have comma's) - - for (int i=0; full_friends_list[i] && *full_friends_list[i] != '\0'; i+=8) - { - std::string buddy = full_friends_list[i]; - - if (buddy[0] == ',') { - buddy.erase(buddy.begin()); - } - LOG4CXX_INFO(logger, "Got buddy " << buddy); - std::string st = full_friends_list[i + 5]; - - pbnetwork::StatusType status = getStatus(st); - - std::string alias = full_friends_list[i + 6]; - - std::string mood_text = ""; - if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { - mood_text = full_friends_list[i + 8]; - i++; - } - - std::vector groups; - groups.push_back(group_map[buddy]); - np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); - } - } - g_strfreev(full_friends_list); - - send_command("SET AUTOAWAY OFF"); + g_error_free(error); } - void Skype::logout() { - if (m_pid != 0) { - send_command("SET USERSTATUS INVISIBLE"); - send_command("SET USERSTATUS OFFLINE"); - sleep(2); - g_object_unref(m_proxy); - LOG4CXX_INFO(logger, m_username << ": Killing Skype instance"); - kill((int) m_pid, SIGTERM); - m_pid = 0; - } - } + if (m_proxy) { + LOG4CXX_INFO(logger, "Proxy created."); + DBusObjectPathVTable vtable; + vtable.message_function = &skype_notify_handler; + dbus_connection_register_object_path(dbus_g_connection_get_connection(m_connection), "/com/Skype/Client", &vtable, this); - std::string Skype::send_command(const std::string &message) { - GError *error = NULL; - gchar *str = NULL; + m_counter = 0; + m_timer = g_timeout_add_seconds(1, load_skype_buddies, this); + return FALSE; + } + return TRUE; + } + return FALSE; +} + +static gboolean create_dbus_proxy(gpointer data) { + Skype *skype = (Skype *) data; + return skype->createDBusProxy(); +} + +void Skype::login() { + boost::filesystem::path path(std::string("/tmp/skype/") + m_username); + if (!boost::filesystem::exists(path)) { + boost::filesystem::create_directories(path); + boost::filesystem::path path2(std::string("/tmp/skype/") + m_username + "/" + m_username ); + boost::filesystem::create_directories(path2); + } + + std::string shared_xml = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "2\n" + "en\n" + "\n" + "\n"; + g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/shared.xml").c_str(), shared_xml.c_str(), -1, NULL); + + std::string config_xml = "\n" + "(time(NULL)) + ".0\">\n" + "\n" + "\n" + "30000000\n" + "300000000\n" + "" + boost::lexical_cast(time(NULL)) + "\n" + "\n" + "\n" + "\n" + "\n" + "Spectrum\n" + "\n" + "\n" + "\n" + "\n"; + g_file_set_contents(std::string(std::string("/tmp/skype/") + m_username + "/" + m_username +"/config.xml").c_str(), config_xml.c_str(), -1, NULL); + + std::string db_path = std::string("/tmp/skype/") + m_username; + char *db = (char *) malloc(db_path.size() + 1); + strcpy(db, db_path.c_str()); + LOG4CXX_INFO(logger, m_username << ": Spawning new Skype instance dbpath=" << db); + gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0}; + + int fd; + g_spawn_async_with_pipes(NULL, + argv, + NULL /*envp*/, + G_SPAWN_SEARCH_PATH, + NULL /*child_setup*/, + NULL /*user_data*/, + &m_pid /*child_pid*/, + &fd, + NULL, + &fd_output, + NULL /*error*/); + std::string login_data = std::string(m_username + " " + m_password + "\n"); + LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data); + write(fd, login_data.c_str(), login_data.size()); + close(fd); + + fcntl (fd_output, F_SETFL, O_NONBLOCK); + + free(db); + + //Initialise threading + dbus_threads_init_default(); + + if (m_connection == NULL) + { + LOG4CXX_INFO(logger, "Creating DBus connection."); + GError *error = NULL; + m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); + if (m_connection == NULL && error != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + g_error_free(error); + return; + } + } + + m_timer = g_timeout_add_seconds(1, create_dbus_proxy, this); +} + +bool Skype::loadSkypeBuddies() { +// std::string re = "CONNSTATUS OFFLINE"; +// while (re == "CONNSTATUS OFFLINE" || re.empty()) { +// sleep(1); + + gchar buffer[1024]; + int bytes_read = read(fd_output, buffer, 1023); + if (bytes_read > 0) { + buffer[bytes_read] = 0; + np->handleDisconnected(m_user, 0, buffer); + close(fd_output); + logout(); + return FALSE; + } + + std::string re = send_command("NAME Spectrum"); + if (m_counter++ > 15) { + np->handleDisconnected(m_user, 0, ""); + close(fd_output); + logout(); + return FALSE; + } + + if (re.empty() || re == "CONNSTATUS OFFLINE") { + return TRUE; + } + + close(fd_output); + + if (send_command("PROTOCOL 7") != "PROTOCOL 7") { + np->handleDisconnected(m_user, 0, "Skype is not ready"); + logout(); + return FALSE; + } + + np->handleConnected(m_user); + + std::map group_map; + std::string groups = send_command("SEARCH GROUPS CUSTOM"); + groups = groups.substr(groups.find(' ') + 1); + std::vector grps; + boost::split(grps, groups, boost::is_any_of(",")); + BOOST_FOREACH(std::string grp, grps) { + std::vector data; + std::string name = send_command("GET GROUP " + grp + " DISPLAYNAME"); + boost::split(data, name, boost::is_any_of(" ")); + name = name.substr(name.find("DISPLAYNAME") + 12); + + std::string users = send_command("GET GROUP " + data[1] + " USERS"); + users = name.substr(name.find("USERS") + 6); + boost::split(data, users, boost::is_any_of(",")); + BOOST_FOREACH(std::string u, data) { + group_map[u] = grp; + } + } + + std::string friends = send_command("GET AUTH_CONTACTS_PROFILES"); + + char **full_friends_list = g_strsplit((strchr(friends.c_str(), ' ')+1), ";", 0); + if (full_friends_list && full_friends_list[0]) + { + //in the format of: username;full name;phone;office phone;mobile phone; + // online status;friendly name;voicemail;mood + // (comma-seperated lines, usernames can have comma's) + + for (int i=0; full_friends_list[i] && *full_friends_list[i] != '\0'; i+=8) + { + std::string buddy = full_friends_list[i]; + + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + LOG4CXX_INFO(logger, "Got buddy " << buddy); + std::string st = full_friends_list[i + 5]; + + pbnetwork::StatusType status = getStatus(st); + + std::string alias = full_friends_list[i + 6]; + + std::string mood_text = ""; + if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { + mood_text = full_friends_list[i + 8]; + i++; + } + + std::vector groups; + groups.push_back(group_map[buddy]); + np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); + } + } + g_strfreev(full_friends_list); + + send_command("SET AUTOAWAY OFF"); + return FALSE; +} + +void Skype::logout() { + if (m_pid != 0) { + send_command("SET USERSTATUS INVISIBLE"); + send_command("SET USERSTATUS OFFLINE"); + sleep(2); + g_object_unref(m_proxy); + LOG4CXX_INFO(logger, m_username << ": Killing Skype instance"); + kill((int) m_pid, SIGTERM); + m_pid = 0; + } +} + +std::string Skype::send_command(const std::string &message) { + GError *error = NULL; + gchar *str = NULL; // int message_num; // gchar error_return[30]; - - if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID, - G_TYPE_STRING, &str, G_TYPE_INVALID)) + + if (!dbus_g_proxy_call (m_proxy, "Invoke", &error, G_TYPE_STRING, message.c_str(), G_TYPE_INVALID, + G_TYPE_STRING, &str, G_TYPE_INVALID)) + { + if (error && error->message) { - if (error && error->message) - { - LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); - g_error_free(error); - } else { - LOG4CXX_INFO(logger, m_username << ": DBUS no response"); - } - - } - if (str != NULL) - { - LOG4CXX_INFO(logger, m_username << ": DBUS:" << str); - } - return str ? std::string(str) : std::string(); + LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + g_error_free(error); + } else { + LOG4CXX_INFO(logger, m_username << ": DBUS no response"); } + } + if (str != NULL) + { + LOG4CXX_INFO(logger, m_username << ": DBUS:" << str); + } + return str ? std::string(str) : std::string(); +} + static void handle_skype_message(std::string &message, Skype *sk) { std::vector cmd; boost::split(cmd, message, boost::is_any_of(" ")); @@ -696,6 +729,10 @@ static void io_destroy(gpointer data) { exit(1); } +static void log_glib_error(const gchar *string) { + LOG4CXX_ERROR(logger, "GLIB ERROR:" << string); +} + int main(int argc, char **argv) { GError *error = NULL; GOptionContext *context; @@ -783,6 +820,7 @@ int main(int argc, char **argv) { m_sock = create_socket(host, port); + g_set_printerr_handler(log_glib_error); GIOChannel *channel; GIOCondition cond = (GIOCondition) G_IO_IN; From f681cbeba6afc79a53be8b2a8671a1b83c454969 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:31:53 +0100 Subject: [PATCH 23/41] Fixed skype buddy list parsing --- backends/skype/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index a09b0b80..c36b46b8 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -522,7 +522,6 @@ bool Skype::loadSkypeBuddies() { std::string mood_text = ""; if (full_friends_list[i + 8] && *full_friends_list[i + 8] != '\0' && *full_friends_list[i + 8] != ',') { mood_text = full_friends_list[i + 8]; - i++; } std::vector groups; From fd081a77e7b71b0430f2a0cb7f13ef38d0830b36 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:35:39 +0100 Subject: [PATCH 24/41] Fixed skype buddy list parsing --- backends/skype/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index c36b46b8..699a79d2 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -509,6 +509,7 @@ bool Skype::loadSkypeBuddies() { { std::string buddy = full_friends_list[i]; + buddy = buddy.substr(buddy.rfind(",")); if (buddy[0] == ',') { buddy.erase(buddy.begin()); } From 31a19c5f3fb5a541fdd6b55273e45f821c07c94b Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:38:45 +0100 Subject: [PATCH 25/41] Fixed skype buddy list parsing --- backends/skype/main.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 699a79d2..42da9f7b 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -509,10 +509,14 @@ bool Skype::loadSkypeBuddies() { { std::string buddy = full_friends_list[i]; - buddy = buddy.substr(buddy.rfind(",")); if (buddy[0] == ',') { buddy.erase(buddy.begin()); } + + if (buddy.rfind(",") != std::string::npos) { + buddy = buddy.substr(buddy.rfind(",")); + } + LOG4CXX_INFO(logger, "Got buddy " << buddy); std::string st = full_friends_list[i + 5]; From d6353232aefdc98f302465d4001f1742e2308043 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:47:42 +0100 Subject: [PATCH 26/41] Fixed skype buddy list parsing --- backends/skype/main.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 42da9f7b..16614b39 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -517,6 +517,10 @@ bool Skype::loadSkypeBuddies() { buddy = buddy.substr(buddy.rfind(",")); } + if (buddy[0] == ',') { + buddy.erase(buddy.begin()); + } + LOG4CXX_INFO(logger, "Got buddy " << buddy); std::string st = full_friends_list[i + 5]; From cc9d7c7950582b2bf11c4df396bfbf0c97a5463e Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 15:57:40 +0100 Subject: [PATCH 27/41] Forward initial presence to skype --- backends/skype/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 16614b39..d5f6e9d9 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -541,6 +541,7 @@ bool Skype::loadSkypeBuddies() { g_strfreev(full_friends_list); send_command("SET AUTOAWAY OFF"); + send_command("SET USERSTATUS ONLINE"); return FALSE; } From 18ba1b7ac49199ea393f4e8af93d7141ed049e3d Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 16:40:49 +0100 Subject: [PATCH 28/41] Do not send buddies in empty group --- backends/skype/main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index d5f6e9d9..c82792ce 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -534,7 +534,9 @@ bool Skype::loadSkypeBuddies() { } std::vector groups; - groups.push_back(group_map[buddy]); + if (group_map.find(buddy) != group_map.end()) { + groups.push_back(group_map[buddy]); + } np->handleBuddyChanged(m_user, buddy, alias, groups, status, mood_text); } } From acd1c0447f771a06c41e7676091890d14aae71d0 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 16:54:40 +0100 Subject: [PATCH 29/41] Send subscribe presences to bare jid --- src/rostermanager.cpp | 6 +++--- src/usermanager.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 23b19a7f..44264588 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -285,8 +285,8 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { // using roster pushes. if (m_component->inServerMode()) { Swift::Presence::ref response = Swift::Presence::create(); - response->setTo(presence->getFrom()); - response->setFrom(presence->getTo()); + response->setTo(presence->getFrom().toBare()); + response->setFrom(presence->getTo().toBare()); Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo())); if (buddy) { LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received and buddy " << Buddy::JIDToLegacyName(presence->getTo()) << " is already there => answering"); @@ -342,7 +342,7 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { Swift::Presence::ref response = Swift::Presence::create(); Swift::Presence::ref currentPresence; response->setTo(presence->getFrom().toBare()); - response->setFrom(presence->getTo().toBare().toString() + "/bot"); + response->setFrom(presence->getTo().toBare()); Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo())); if (buddy) { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index ccb036f4..08823715 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -306,8 +306,8 @@ void UserManager::handleSubscription(Swift::Presence::ref presence) { // answer to subscibe for transport itself if (presence->getType() == Swift::Presence::Subscribe && presence->getTo().getNode().empty()) { Swift::Presence::ref response = Swift::Presence::create(); - response->setFrom(presence->getTo()); - response->setTo(presence->getFrom()); + response->setFrom(presence->getTo().toBare()); + response->setTo(presence->getFrom().toBare()); response->setType(Swift::Presence::Subscribed); m_component->getStanzaChannel()->sendPresence(response); From 04115c5d99f19b4d9ccf9d2e974a61caf30a4ff4 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Feb 2012 17:41:06 +0100 Subject: [PATCH 30/41] changelog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index ae19ff21..942fdfe4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ Version 2.0.0-beta (X-X-X): General: + * Send presences only "from" bare JID (fixed bug with buddies appearing + twice in the roster and potential unregistering issues). * Fixed potential MySQL/SQLite3 deadlocks. * Fixed disconnecting in server-mode when client does not send unavailable presence before disconnection. From 67d6458a411393969bb105ec03d20bb83161aad4 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Thu, 26 Jan 2012 12:36:15 +0800 Subject: [PATCH 31/41] Downgraded PQXX API used due to the 2.6 series on most modern linux distros. Implemented most of the other functions. --- include/transport/pqxxbackend.h | 3 + src/pqxxbackend.cpp | 109 ++++++++++++++++---------------- 2 files changed, 59 insertions(+), 53 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index e13c6b03..f02d86fc 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -98,6 +98,9 @@ class PQXXBackend : public StorageBackend private: bool exec(const std::string &query, bool show_error = true); bool exec(pqxx::work &txn, const std::string &query, bool show_error = true); + template + std::string quote(pqxx::work &txn, const T &t); + Config *m_config; std::string m_prefix; diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index af0efd36..36953090 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -124,6 +124,11 @@ bool PQXXBackend::createDatabase() { return true; } +template +std::string PQXXBackend::quote(pqxx::work &txn, const T &t) { + return "'" + txn.esc(pqxx::to_string(t)) + "'"; +} + bool PQXXBackend::exec(const std::string &query, bool show_error) { pqxx::work txn(*m_conn); return exec(txn, query, show_error); @@ -148,15 +153,14 @@ void PQXXBackend::setUser(const UserInfo &user) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } pqxx::work txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users SET uin=" + txn.quote(user.uin) + ", password=" + txn.quote(encrypted) + ";" - "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " - "(" + txn.quote(user.jid) + "," - + txn.quote(user.uin) + "," - + txn.quote(encrypted) + "," - + txn.quote(user.language) + "," - + txn.quote(user.encoding) + "," + exec(txn, "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + "(" + quote(txn, user.jid) + "," + + quote(txn, user.uin) + "," + + quote(txn, encrypted) + "," + + quote(txn, user.language) + "," + + quote(txn, user.encoding) + "," + "NOW()," - + txn.quote(user.vip) +")"); + + (user.vip ? "'true'" : "'false'") +")"); } bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { @@ -164,7 +168,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { pqxx::work txn(*m_conn); pqxx::result r = txn.exec("SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=" - + txn.quote(barejid)); + + quote(txn, barejid)); if (r.size() == 0) { return false; @@ -189,7 +193,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { void PQXXBackend::setUserOnline(long id, bool online) { try { pqxx::work txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users SET online=" + txn.quote(online) + ", last_login=NOW() WHERE id=" + txn.quote(id)); + exec(txn, "UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -234,13 +238,13 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { -// "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?" -// std::string groups = Util::serializeGroups(buddyInfo.groups); -// *m_updateBuddy << groups; -// *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; -// *m_updateBuddy << userId << buddyInfo.legacyName; - -// EXEC(m_updateBuddy, updateBuddy(userId, buddyInfo)); + try { + pqxx::work txn(*m_conn); + exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + quote(txn, buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } bool PQXXBackend::getBuddies(long id, std::list &roster) { @@ -317,55 +321,54 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { } bool PQXXBackend::removeUser(long id) { -// *m_removeUser << (int) id; -// EXEC(m_removeUser, removeUser(id)); -// if (!exec_ok) -// return false; + try { + pqxx::work txn(*m_conn); + exec(txn, "DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); + exec(txn, "DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); + exec(txn, "DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); + exec(txn, "DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); -// *m_removeUserSettings << (int) id; -// EXEC(m_removeUserSettings, removeUser(id)); -// if (!exec_ok) -// return false; - -// *m_removeUserBuddies << (int) id; -// EXEC(m_removeUserBuddies, removeUser(id)); -// if (!exec_ok) -// return false; - -// *m_removeUserBuddiesSettings << (int) id; -// EXEC(m_removeUserBuddiesSettings, removeUser(id)); -// if (!exec_ok) -// return false; - - return true; + return true; + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } + return false; } void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { -//// "SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=? AND var=?" -// *m_getUserSetting << id << variable; -// EXEC(m_getUserSetting, getUserSetting(id, variable, type, value)); -// if (m_getUserSetting->fetch() != 0) { -//// "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES (?,?,?,?)" -// *m_setUserSetting << id << variable << type << value; -// EXEC(m_setUserSetting, getUserSetting(id, variable, type, value)); -// } -// else { -// *m_getUserSetting >> type >> value; -// } + try { + pqxx::work txn(*m_conn); + + pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); + if (r.size() == 0) { + exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); + } + else { + type = r[0][0].as(); + value = r[0][0].as(); + } + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { -//// "UPDATE " + m_prefix + "users_settings SET value=? WHERE user_id=? AND var=?" -// *m_updateUserSetting << value << id << variable; -// EXEC(m_updateUserSetting, updateUserSetting(id, variable, value)); + try { + pqxx::work txn(*m_conn); + exec(txn, "UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } void PQXXBackend::beginTransaction() { -// exec("START TRANSACTION;"); + exec("START TRANSACTION;"); } void PQXXBackend::commitTransaction() { -// exec("COMMIT;"); + exec("COMMIT;"); } } From faeb4bd8ef6b293ddaa565165cbfa3a359698432 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Sat, 28 Jan 2012 00:57:13 +0800 Subject: [PATCH 32/41] One more function to go after this. At some future date I'd like to consider if the API provides some better mechanisms, but this'll do for now. --- src/pqxxbackend.cpp | 114 ++++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 61 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 36953090..1194b2ef 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -248,76 +248,67 @@ void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { } bool PQXXBackend::getBuddies(long id, std::list &roster) { -// SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=? ORDER BY id ASC -// *m_getBuddies << id; + try { + pqxx::work txn(*m_conn); -// "SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=? ORDER BY buddy_id ASC" -// *m_getBuddiesSettings << id; + pqxx::result r = txn.exec("SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=" + pqxx::to_string(id) + " ORDER BY id ASC"); + for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { + BuddyInfo b; + std::string group; -// SettingVariableInfo var; -// long buddy_id = -1; -// std::string key; + b.id = r[0][0].as(); + b.legacyName = r[0][1].as(); + b.subscription = r[0][2].as(); + b.alias = r[0][3].as(); + group = r[0][4].as(); + b.flags = r[0][5].as(); -// EXEC(m_getBuddies, getBuddies(id, roster)); -// if (!exec_ok) -// return false; + if (!group.empty()) { + b.groups = Util::deserializeGroups(group); + } -// while (m_getBuddies->fetch() == 0) { -// BuddyInfo b; + roster.push_back(b); + } -// std::string group; -// *m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags; -// if (!group.empty()) { -// b.groups = Util::deserializeGroups(group); -// } + r = txn.exec("SELECT buddy_id, type, var, value FROM " + m_prefix + "buddies_settings WHERE user_id=" + pqxx::to_string(id) + " ORDER BY buddy_id ASC"); + for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { + SettingVariableInfo var; + long buddy_id = -1; + std::string key; + std::string val; -// roster.push_back(b); -// } + buddy_id = r[0][0].as(); + var.type = r[0][1].as(); + key = r[0][2].as(); + val = r[0][3].as(); + switch (var.type) { + case TYPE_BOOLEAN: + var.b = atoi(val.c_str()); + break; + case TYPE_STRING: + var.s = val; + break; + default: + continue; + break; + } -// EXEC(m_getBuddiesSettings, getBuddies(id, roster)); -// if (!exec_ok) -// return false; + BOOST_FOREACH(BuddyInfo &b, roster) { + if (buddy_id == b.id) { + b.settings[key] = var; + break; + } + } + } -// BOOST_FOREACH(BuddyInfo &b, roster) { -// if (buddy_id == b.id) { -//// std::cout << "Adding buddy info setting " << key << "\n"; -// b.settings[key] = var; -// buddy_id = -1; -// } + return true; + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } -// while(buddy_id == -1 && m_getBuddiesSettings->fetch() == 0) { -// std::string val; -// *m_getBuddiesSettings >> buddy_id >> var.type >> key >> val; - -// switch (var.type) { -// case TYPE_BOOLEAN: -// var.b = atoi(val.c_str()); -// break; -// case TYPE_STRING: -// var.s = val; -// break; -// default: -// if (buddy_id == b.id) { -// buddy_id = -1; -// } -// continue; -// break; -// } -// if (buddy_id == b.id) { -//// std::cout << "Adding buddy info setting " << key << "=" << val << "\n"; -// b.settings[key] = var; -// buddy_id = -1; -// } -// } -// } - -// while(m_getBuddiesSettings->fetch() == 0) { -// // TODO: probably remove those settings, because there's no buddy for them. -// // It should not happend, but one never know... -// } - - return true; + return false; } bool PQXXBackend::removeUser(long id) { @@ -329,6 +320,7 @@ bool PQXXBackend::removeUser(long id) { exec(txn, "DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); return true; + } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); } @@ -345,7 +337,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type } else { type = r[0][0].as(); - value = r[0][0].as(); + value = r[0][1].as(); } } catch (std::exception& e) { From 352a15b226ac1f10258212484fbd5ca6c289e503 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Sat, 28 Jan 2012 05:05:18 +0800 Subject: [PATCH 33/41] Finished last postgres function. --- src/pqxxbackend.cpp | 37 +++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 1194b2ef..ae6ddc9d 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -118,7 +118,7 @@ bool PQXXBackend::createDatabase() { "UNIQUE (ver)" ");"); -// exec("INSERT INTO db_version (ver) VALUES ('2');"); + exec("INSERT INTO db_version (ver) VALUES ('1');"); } return true; @@ -218,29 +218,34 @@ bool PQXXBackend::getOnlineUsers(std::vector &users) { } long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { -// "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)" -// std::string groups = Util::serializeGroups(buddyInfo.groups); -// *m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription; -// *m_addBuddy << groups; -// *m_addBuddy << buddyInfo.alias << buddyInfo.flags; + pqxx::work txn(*m_conn); + pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " + + "(" + pqxx::to_string(userId) + "," + + quote(txn, buddyInfo.legacyName) + "," + + quote(txn, buddyInfo.subscription) + "," + + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," + + quote(txn, buddyInfo.alias) + "," + + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); -// EXEC(m_addBuddy, addBuddy(userId, buddyInfo)); + long id = r[0][0].as(); -// long id = (long) mysql_insert_id(&m_conn); + r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string(TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); + if (r.affected_rows() == 0) { + exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + + "(" + pqxx::to_string(userId) + "," + + pqxx::to_string(id) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," + + pqxx::to_string(TYPE_STRING) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); + } -// INSERT OR REPLACE INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES (?, ?, ?, ?, ?) -// if (!buddyInfo.settings.find("icon_hash")->second.s.empty()) { -// *m_updateBuddySetting << userId << id << buddyInfo.settings.find("icon_hash")->first << (int) TYPE_STRING << buddyInfo.settings.find("icon_hash")->second.s << buddyInfo.settings.find("icon_hash")->second.s; -// EXEC(m_updateBuddySetting, addBuddy(userId, buddyInfo)); -// } - - return 0; + return id; } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { pqxx::work txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + quote(txn, buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); From 017935ae158d823aea1dfea713db70820ed67725 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Wed, 15 Feb 2012 23:22:27 +0800 Subject: [PATCH 34/41] Casted TYPE_STRING properly. --- src/pqxxbackend.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index ae6ddc9d..d20bfc95 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -229,13 +229,13 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { long id = r[0][0].as(); - r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string(TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); + r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); if (r.affected_rows() == 0) { exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + "(" + pqxx::to_string(userId) + "," + pqxx::to_string(id) + "," + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," - + pqxx::to_string(TYPE_STRING) + "," + + pqxx::to_string((int)TYPE_STRING) + "," + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); } From 7f13a29090639a9a6d1f2f88924ddf9021b44ed6 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Thu, 16 Feb 2012 01:29:28 +0800 Subject: [PATCH 35/41] Removed auto-transaction postgres handlers in lieu of our own transaction calls. Updated config file to mention postgres. --- include/transport/pqxxbackend.h | 4 ++-- spectrum/src/sample2.cfg | 4 ++-- src/pqxxbackend.cpp | 34 +++++++++++++++++---------------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/include/transport/pqxxbackend.h b/include/transport/pqxxbackend.h index f02d86fc..f571433b 100644 --- a/include/transport/pqxxbackend.h +++ b/include/transport/pqxxbackend.h @@ -97,9 +97,9 @@ class PQXXBackend : public StorageBackend private: bool exec(const std::string &query, bool show_error = true); - bool exec(pqxx::work &txn, const std::string &query, bool show_error = true); + bool exec(pqxx::nontransaction &txn, const std::string &query, bool show_error = true); template - std::string quote(pqxx::work &txn, const T &t); + std::string quote(pqxx::nontransaction &txn, const T &t); Config *m_config; std::string m_prefix; diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 3f755c00..3181a6a1 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -73,11 +73,11 @@ backend_config = /etc/spectrum2/backend-logging.cfg [database] # Database backend type -# "sqlite3", "mysql" or "none" without database backend +# "sqlite3", "mysql", "pqxx", or "none" without database backend type = none # For SQLite3: Full path to database -# For MySQL: name of database +# For MySQL and PostgreSQL: name of database # default database = /var/lib/spectrum2/$jid/database.sql #database = jabber_transport diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index d20bfc95..c6136bd3 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -125,16 +125,16 @@ bool PQXXBackend::createDatabase() { } template -std::string PQXXBackend::quote(pqxx::work &txn, const T &t) { +std::string PQXXBackend::quote(pqxx::nontransaction &txn, const T &t) { return "'" + txn.esc(pqxx::to_string(t)) + "'"; } bool PQXXBackend::exec(const std::string &query, bool show_error) { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); return exec(txn, query, show_error); } -bool PQXXBackend::exec(pqxx::work &txn, const std::string &query, bool show_error) { +bool PQXXBackend::exec(pqxx::nontransaction &txn, const std::string &query, bool show_error) { try { txn.exec(query); txn.commit(); @@ -152,7 +152,7 @@ void PQXXBackend::setUser(const UserInfo &user) { if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " "(" + quote(txn, user.jid) + "," + quote(txn, user.uin) + "," @@ -165,7 +165,7 @@ void PQXXBackend::setUser(const UserInfo &user) { bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=" + quote(txn, barejid)); @@ -192,7 +192,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { void PQXXBackend::setUserOnline(long id, bool online) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); } catch (std::exception& e) { @@ -202,7 +202,7 @@ void PQXXBackend::setUserOnline(long id, bool online) { bool PQXXBackend::getOnlineUsers(std::vector &users) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online=1"); for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { @@ -218,7 +218,7 @@ bool PQXXBackend::getOnlineUsers(std::vector &users) { } long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " + "(" + pqxx::to_string(userId) + "," + quote(txn, buddyInfo.legacyName) + "," @@ -231,7 +231,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); if (r.affected_rows() == 0) { - exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + "(" + pqxx::to_string(userId) + "," + pqxx::to_string(id) + "," + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," @@ -239,12 +239,14 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); } + txn.commit(); + return id; } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { @@ -254,7 +256,7 @@ void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { bool PQXXBackend::getBuddies(long id, std::list &roster) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT id, uin, subscription, nickname, groups, flags FROM " + m_prefix + "buddies WHERE user_id=" + pqxx::to_string(id) + " ORDER BY id ASC"); for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { @@ -318,7 +320,7 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { bool PQXXBackend::removeUser(long id) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); exec(txn, "DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); exec(txn, "DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); @@ -334,11 +336,11 @@ bool PQXXBackend::removeUser(long id) { void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type, std::string &value) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); if (r.size() == 0) { - exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); + txn.exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); } else { type = r[0][0].as(); @@ -352,7 +354,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { try { - pqxx::work txn(*m_conn); + pqxx::nontransaction txn(*m_conn); exec(txn, "UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); } catch (std::exception& e) { @@ -361,7 +363,7 @@ void PQXXBackend::updateUserSetting(long id, const std::string &variable, const } void PQXXBackend::beginTransaction() { - exec("START TRANSACTION;"); + exec("BEGIN;"); } void PQXXBackend::commitTransaction() { From 3f2a5840a5eb702a1659c474b5ad432433cc2445 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Thu, 16 Feb 2012 07:12:09 +0800 Subject: [PATCH 36/41] Cleaned up code a bit, more to come. --- src/pqxxbackend.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index c6136bd3..90818d56 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -99,8 +99,8 @@ bool PQXXBackend::createDatabase() { "language varchar(25) NOT NULL," "encoding varchar(50) NOT NULL default 'utf8'," "last_login timestamp," - "vip boolean NOT NULL default '0'," - "online boolean NOT NULL default '0'," + "vip boolean NOT NULL default 'false'," + "online boolean NOT NULL default 'false'," "PRIMARY KEY (id)," "UNIQUE (jid)" ");"); @@ -153,8 +153,8 @@ void PQXXBackend::setUser(const UserInfo &user) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } pqxx::nontransaction txn(*m_conn); - exec(txn, "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " - "(" + quote(txn, user.jid) + "," + txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + + "(" + quote(txn, user.jid) + "," + quote(txn, user.uin) + "," + quote(txn, encrypted) + "," + quote(txn, user.language) + "," @@ -193,7 +193,7 @@ bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { void PQXXBackend::setUserOnline(long id, bool online) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); + txn.exec("UPDATE " + m_prefix + "users SET online=" + (online ? "'true'" : "'false'") + ", last_login=NOW() WHERE id=" + pqxx::to_string(id)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -203,7 +203,7 @@ void PQXXBackend::setUserOnline(long id, bool online) { bool PQXXBackend::getOnlineUsers(std::vector &users) { try { pqxx::nontransaction txn(*m_conn); - pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online=1"); + pqxx::result r = txn.exec("SELECT jid FROM " + m_prefix + "users WHERE online='true'"); for (pqxx::result::const_iterator it = r.begin(); it != r.end(); it++) { users.push_back((*it)[0].as()); @@ -247,7 +247,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -321,10 +321,10 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { bool PQXXBackend::removeUser(long id) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); - exec(txn, "DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); - exec(txn, "DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); - exec(txn, "DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "users SET id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "buddies SET user_id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "user_settings SET user_id=" + pqxx::to_string(id)); + txn.exec("DELETE FROM " + m_prefix + "buddies_settings SET user_id=" + pqxx::to_string(id)); return true; } @@ -340,7 +340,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type pqxx::result r = txn.exec("SELECT type, value FROM " + m_prefix + "users_settings WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); if (r.size() == 0) { - txn.exec(txn, "INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string(type) + "," + quote(txn, value) + ")"); + txn.exec("INSERT INTO " + m_prefix + "users_settings (user_id, var, type, value) VALUES(" + pqxx::to_string(id) + "," + quote(txn, variable) + "," + pqxx::to_string((int)type) + "," + quote(txn, value) + ")"); } else { type = r[0][0].as(); @@ -355,7 +355,7 @@ void PQXXBackend::getUserSetting(long id, const std::string &variable, int &type void PQXXBackend::updateUserSetting(long id, const std::string &variable, const std::string &value) { try { pqxx::nontransaction txn(*m_conn); - exec(txn, "UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); + txn.exec("UPDATE " + m_prefix + "users_settings SET value=" + quote(txn, value) + " WHERE user_id=" + pqxx::to_string(id) + " AND var=" + quote(txn, variable)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); From 9cf00ddc59a0d16bb9f00881e56da990fad4d2d7 Mon Sep 17 00:00:00 2001 From: Daniel Henninger Date: Sat, 18 Feb 2012 02:49:57 +0800 Subject: [PATCH 37/41] Cleaned up code a bit, primarily adding more exception catching in proper locations. --- src/pqxxbackend.cpp | 80 +++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 90818d56..c2ae4580 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -57,7 +57,14 @@ bool PQXXBackend::connect() { str += CONFIG_STRING(m_config, "database.database") + " "; str += "user=" + CONFIG_STRING(m_config, "database.user") + " "; - m_conn = new pqxx::connection(str); + + try { + m_conn = new pqxx::connection(str); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + return false; + } createDatabase(); @@ -152,15 +159,20 @@ void PQXXBackend::setUser(const UserInfo &user) { if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } - pqxx::nontransaction txn(*m_conn); - txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " - + "(" + quote(txn, user.jid) + "," - + quote(txn, user.uin) + "," - + quote(txn, encrypted) + "," - + quote(txn, user.language) + "," - + quote(txn, user.encoding) + "," - + "NOW()," - + (user.vip ? "'true'" : "'false'") +")"); + try { + pqxx::nontransaction txn(*m_conn); + txn.exec("INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES " + + "(" + quote(txn, user.jid) + "," + + quote(txn, user.uin) + "," + + quote(txn, encrypted) + "," + + quote(txn, user.language) + "," + + quote(txn, user.encoding) + "," + + "NOW()," + + (user.vip ? "'true'" : "'false'") +")"); + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + } } bool PQXXBackend::getUser(const std::string &barejid, UserInfo &user) { @@ -218,30 +230,34 @@ bool PQXXBackend::getOnlineUsers(std::vector &users) { } long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { - pqxx::nontransaction txn(*m_conn); - pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " - + "(" + pqxx::to_string(userId) + "," - + quote(txn, buddyInfo.legacyName) + "," - + quote(txn, buddyInfo.subscription) + "," - + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," - + quote(txn, buddyInfo.alias) + "," - + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); - - long id = r[0][0].as(); - - r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); - if (r.affected_rows() == 0) { - txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + try { + pqxx::nontransaction txn(*m_conn); + pqxx::result r = txn.exec("INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES " + "(" + pqxx::to_string(userId) + "," - + pqxx::to_string(id) + "," - + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," - + pqxx::to_string((int)TYPE_STRING) + "," - + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); + + quote(txn, buddyInfo.legacyName) + "," + + quote(txn, buddyInfo.subscription) + "," + + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," + + quote(txn, buddyInfo.alias) + "," + + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); + + long id = r[0][0].as(); + + r = txn.exec("UPDATE " + m_prefix + "buddies_settings SET var = " + quote(txn, buddyInfo.settings.find("icon_hash")->first) + ", type = " + pqxx::to_string((int)TYPE_STRING) + ", value = " + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + " WHERE user_id = " + pqxx::to_string(userId) + " AND buddy_id = " + pqxx::to_string(id)); + if (r.affected_rows() == 0) { + txn.exec("INSERT INTO " + m_prefix + "buddies_settings (user_id, buddy_id, var, type, value) VALUES " + + "(" + pqxx::to_string(userId) + "," + + pqxx::to_string(id) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->first) + "," + + pqxx::to_string((int)TYPE_STRING) + "," + + quote(txn, buddyInfo.settings.find("icon_hash")->second.s) + ")"); + } + + return id; + } + catch (std::exception& e) { + LOG4CXX_ERROR(logger, e.what()); + return -1; } - - txn.commit(); - - return id; } void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { From 6e4eb0ed6f15c24188d9dc606e3d5e359d160175 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 19 Feb 2012 10:13:51 +0100 Subject: [PATCH 38/41] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 942fdfe4..97aaa33c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ Version 2.0.0-beta (X-X-X): General: + * Added PostreSQL support (thanks to Jadestorm). * Send presences only "from" bare JID (fixed bug with buddies appearing twice in the roster and potential unregistering issues). * Fixed potential MySQL/SQLite3 deadlocks. From 342df599be765f0b16c8dd98e80e1e338d939dd3 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 19 Feb 2012 15:35:18 +0100 Subject: [PATCH 39/41] link libtransport to libtransport-plugin to allow using these two libraries together --- src/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac077b20..dcb192c4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -20,11 +20,11 @@ endif() if (PROTOBUF_FOUND) if (CMAKE_COMPILER_IS_GNUCXX) - ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc) + ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) else(CMAKE_COMPILER_IS_GNUCXX) - ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC} ${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc) + ADD_LIBRARY(transport STATIC ${HEADERS} ${SRC} ${SWIFTEN_SRC}) endif(CMAKE_COMPILER_IS_GNUCXX) - SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) +# SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) ADD_DEPENDENCIES(transport pb) else(PROTOBUF_FOUND) ADD_LIBRARY(transport SHARED ${HEADERS} ${SRC} ${SWIFTEN_SRC}) @@ -35,9 +35,9 @@ if (CMAKE_COMPILER_IS_GNUCXX) endif() if (WIN32) - TARGET_LINK_LIBRARIES(transport ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) + TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) else (WIN32) - TARGET_LINK_LIBRARIES(transport ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) + TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) endif(WIN32) SET_TARGET_PROPERTIES(transport PROPERTIES From e53e622e4d4ebc5c34cf2de49616f7f53bd32972 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 20 Feb 2012 10:39:25 +0100 Subject: [PATCH 40/41] Link only against transport --- backends/frotz/CMakeLists.txt | 2 +- backends/libcommuni/CMakeLists.txt | 2 +- backends/skype/CMakeLists.txt | 2 +- backends/smstools3/CMakeLists.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/frotz/CMakeLists.txt b/backends/frotz/CMakeLists.txt index 7ce14f86..f9bc283a 100644 --- a/backends/frotz/CMakeLists.txt +++ b/backends/frotz/CMakeLists.txt @@ -6,7 +6,7 @@ FILE(GLOB SRC *.c *.cpp) ADD_EXECUTABLE(spectrum2_frotz_backend ${SRC}) -target_link_libraries(spectrum2_frotz_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_frotz_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) INSTALL(TARGETS spectrum2_frotz_backend RUNTIME DESTINATION bin) diff --git a/backends/libcommuni/CMakeLists.txt b/backends/libcommuni/CMakeLists.txt index a2a14730..38e7507b 100644 --- a/backends/libcommuni/CMakeLists.txt +++ b/backends/libcommuni/CMakeLists.txt @@ -4,7 +4,7 @@ FILE(GLOB HEADERS *.h) QT4_WRAP_CPP(SRC ${HEADERS}) ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC}) -target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport-plugin transport pthread) +target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread) INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin) diff --git a/backends/skype/CMakeLists.txt b/backends/skype/CMakeLists.txt index 4e611208..d27b4296 100644 --- a/backends/skype/CMakeLists.txt +++ b/backends/skype/CMakeLists.txt @@ -3,7 +3,7 @@ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(spectrum2_skype_backend ${SRC}) -target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES} transport-plugin) +target_link_libraries(spectrum2_skype_backend ${GLIB2_LIBRARIES} ${EVENT_LIBRARIES} transport pthread ${LIBDBUSGLIB_LIBRARIES}) INSTALL(TARGETS spectrum2_skype_backend RUNTIME DESTINATION bin) diff --git a/backends/smstools3/CMakeLists.txt b/backends/smstools3/CMakeLists.txt index c410cee6..a557e243 100644 --- a/backends/smstools3/CMakeLists.txt +++ b/backends/smstools3/CMakeLists.txt @@ -4,7 +4,7 @@ FILE(GLOB SRC *.c *.cpp) ADD_EXECUTABLE(spectrum2_smstools3_backend ${SRC}) -target_link_libraries(spectrum2_smstools3_backend transport pthread transport-plugin ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +target_link_libraries(spectrum2_smstools3_backend transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) INSTALL(TARGETS spectrum2_smstools3_backend RUNTIME DESTINATION bin) From d0afb12646d78ccf22bd9115112f31bd54392802 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 20 Feb 2012 14:31:23 +0100 Subject: [PATCH 41/41] Fixed zombie process caused by bad waitpid call --- src/networkpluginserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 756cff77..a89117b6 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -175,7 +175,7 @@ static void SigCatcher(int n) { int status; // Read exit code from all children to not have zombies arround // WARNING: Do not put LOG4CXX_ here, because it can lead to deadlock - while ((result = waitpid(0, &status, WNOHANG)) > 0) { + while ((result = waitpid(-1, &status, WNOHANG)) > 0) { if (result != 0) { if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) {