diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a10d6c9..c5e63bc5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ endif() # FIND SQLITE3 if (ENABLE_SQLITE3) if (NOT CMAKE_COMPILER_IS_GNUCXX) - ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3) + ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps) else() if (WIN32) ADD_SUBDIRECTORY(${CMAKE_SOURCE_DIR}/msvc-deps/sqlite3) @@ -214,10 +214,10 @@ set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(dbus) endif() -if(ENABLE_YAHOO2) - set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(yahoo2) -endif() +# if(ENABLE_YAHOO2) +# set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +# find_package(yahoo2) +# endif() ####### Miscallanous ###### @@ -390,16 +390,17 @@ if (PROTOBUF_FOUND) message("Skype plugin : no (does not run on Win32)") endif() - if(YAHOO2_FOUND) - message("Libyahoo2 plugin : yes") - include_directories(${YAHOO2_INCLUDE_DIR}) - else() +# if(YAHOO2_FOUND) +# message("Libyahoo2 plugin : yes") +# include_directories(${YAHOO2_INCLUDE_DIR}) +# else() if(ENABLE_YAHOO2) - message("Libyahoo2 plugin : no (install libyahoo2-devel)") + set(YAHOO2_FOUND 1) + message("Libyahoo2 plugin : yes") else(ENABLE_YAHOO2) message("Libyahoo2 plugin : no (user disabled)") endif() - endif() +# endif() if(ENABLE_SWIFTEN) message("Swiften plugin : yes") diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 04cd980b..b232f8bf 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -339,9 +339,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin { // Enable account + privacy lists purple_account_set_enabled_wrapped(account, "spectrum", TRUE); + +#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 7 if (CONFIG_BOOL(config, "service.enable_privacy_lists")) { purple_account_set_privacy_type_wrapped(account, PURPLE_PRIVACY_DENY_USERS); } +#endif // Set the status const PurpleStatusType *status_type = purple_account_get_status_type_with_primitive_wrapped(account, PURPLE_STATUS_AVAILABLE); @@ -483,7 +486,9 @@ class SpectrumNetworkPlugin : public NetworkPlugin { PurpleAccount *account = m_sessions[user]; if (account) { purple_account_set_alias_wrapped(account, nickname.c_str()); +#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 7 purple_account_set_public_alias_wrapped(account, nickname.c_str(), NULL, NULL); +#endif gssize size = image.size(); // this will be freed by libpurple guchar *photo = (guchar *) g_malloc(size * sizeof(guchar)); @@ -1115,9 +1120,11 @@ static void *notify_user_info(PurpleConnection *gc, const char *who, PurpleNotif if (ownInfo) { const gchar *displayname = purple_connection_get_display_name_wrapped(gc); +#if PURPLE_MAJOR_VERSION >= 2 && PURPLE_MINOR_VERSION >= 7 if (!displayname) { displayname = purple_account_get_name_for_display_wrapped(account); } +#endif if (displayname && nickname.empty()) { nickname = displayname; @@ -1565,7 +1572,7 @@ static bool initPurple() { remove("./blist.xml"); purple_debug_set_ui_ops_wrapped(&debugUiOps); - purple_debug_set_verbose_wrapped(true); +// purple_debug_set_verbose_wrapped(true); purple_core_set_ui_ops_wrapped(&coreUiOps); if (CONFIG_STRING_DEFAULTED(config, "service.eventloop", "") == "libev") { diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index d8bfd295..1b09ef78 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -6,7 +6,6 @@ #include "transport/transport.h" #include "transport/usermanager.h" #include "transport/memoryusage.h" -#include "transport/logger.h" #include "transport/sqlite3backend.h" #include "transport/userregistration.h" #include "transport/user.h" @@ -14,7 +13,6 @@ #include "transport/rostermanager.h" #include "transport/conversation.h" #include "transport/networkplugin.h" -#include "transport/logger.h" #include #include "sys/wait.h" #include "sys/signal.h" @@ -697,6 +695,20 @@ static void handle_skype_message(std::string &message, Skype *sk) { std::vector groups; np->handleBuddyChanged(sk->getUser(), cmd[1], alias, groups, status, mood_text); } + //TODO: handle RECEIVEDAUTHREQUEST and reply it with: +// void +// skype_auth_allow(gpointer sender) +// { +// skype_send_message("SET USER %s ISAUTHORIZED TRUE", sender); +// g_free(sender); +// } +// +// void +// skype_auth_deny(gpointer sender) +// { +// skype_send_message("SET USER %s ISAUTHORIZED FALSE", sender); +// g_free(sender); +// } } else if (cmd[0] == "CHATMESSAGE") { if (cmd[3] == "RECEIVED") { diff --git a/backends/twitter/CMakeLists.txt b/backends/twitter/CMakeLists.txt index 26da4cb7..981e4046 100644 --- a/backends/twitter/CMakeLists.txt +++ b/backends/twitter/CMakeLists.txt @@ -5,6 +5,7 @@ add_executable(spectrum2_twitter_backend ${SRC}) if (NOT WIN32) target_link_libraries(spectrum2_twitter_backend curl transport pthread ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) else () +include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/curl/include") target_link_libraries(spectrum2_twitter_backend libcurl_imp transport ${Boost_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) endif() diff --git a/docs/guide/postgresql.textile b/docs/guide/postgresql.textile index 85d27c0c..a8f5aa1a 100644 --- a/docs/guide/postgresql.textile +++ b/docs/guide/postgresql.textile @@ -1,16 +1,33 @@ h2. 1. Editing the configuration file -To configure Spectrum 2 to use PostgreSQL database, you have to edit following options in database section: +To configure Spectrum 2 to use PostgreSQL database, you have to edit some or more of the following options in database section. Please note that connectionstring overrides everything else (aside from type). |_. Section |_. Key |_. Type |_. Change to value |_. Description | | database| type | string | pqxx | Database type - "none", "mysql", "sqlite3", "pqxx". | | database| database | string | Name of the already create empty database | Database used to store data. | | database| server | string | Database server | Database server. | +| database| port | string | Database port | Database port. | | database| user | string | PostgreSQL user. | PostgreSQL user. | | database| password | string | PostgreSQL Password. | PostgreSQL Password. | | database| prefix | string | | Prefix of tables in database. | +| database| connectionstring | string | Postgres connection string | If you set this, it will ignore all other options above aside from type and prefix. This allows you to set any typical postgres connection string option, separated by spaces (no semicolons). | h2. 2. Creating the database -Spectrum 2 will create the database on the first execution. Once the database is created, you can remove the CREATE TABLE permissions to the PostgreSQL database user you use to connect the SQL. \ No newline at end of file +Spectrum 2 will create the database on the first execution. Once the database is created, you can remove the CREATE TABLE permissions to the PostgreSQL database user you use to connect the SQL. + +h2. 3. Some examples + +Using connectionstring: +[database] +type=pqxx +connectionstring=host=localhost database=spectrum2 user=myuser password=whatever + +Using traditional options: +[database] +type=pqxx +server=localhost +database=spectrum2 +user=myuser +password=whatever diff --git a/include/transport/buddy.h b/include/transport/buddy.h index 35205822..e11ed425 100644 --- a/include/transport/buddy.h +++ b/include/transport/buddy.h @@ -122,10 +122,7 @@ class Buddy { /// so it can be used in JIDs. std::string getSafeName(); - /// This method should be called whenever some information returned by virtual functions changes. - - /// This method sends presence to XMPP user. - void handleBuddyChanged(); + void sendPresence(); /// Handles VCard from legacy network and forwards it to XMPP user. diff --git a/include/transport/localbuddy.h b/include/transport/localbuddy.h index 7a0ff92d..5e80fb10 100644 --- a/include/transport/localbuddy.h +++ b/include/transport/localbuddy.h @@ -45,18 +45,10 @@ class LocalBuddy : public Buddy { return true; } - void setStatus(const Swift::StatusShow &status, const std::string &statusMessage) { - m_status = status; - m_statusMessage = statusMessage; - } + void setStatus(const Swift::StatusShow &status, const std::string &statusMessage); std::string getIconHash() { return m_iconHash; } - void setIconHash(const std::string &iconHash) { - bool changed = m_iconHash != iconHash; - m_iconHash = iconHash; - if (changed) - getRosterManager()->storeBuddy(this); - } + void setIconHash(const std::string &iconHash); std::vector getGroups() { return m_groups; } void setGroups(const std::vector &groups); diff --git a/include/transport/logger.h b/include/transport/logger.h deleted file mode 100644 index ecca0247..00000000 --- a/include/transport/logger.h +++ /dev/null @@ -1,89 +0,0 @@ -/** - * libtransport -- C++ library for easy XMPP Transports development - * - * Copyright (C) 2011, Jan Kaluza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#pragma once - -#include -#include -#include "Swiften/Swiften.h" - -namespace Transport { - -struct UserInfo; -class User; -class UserManager; -class Component; -class StorageBackend; -class UserRegistration; -class RosterManager; -class Buddy; - -/// Basic logging class which logs various data into std::out (standard output). -class Logger -{ - public: - /// Creates new Logger class instance. - /// \param component component instance - Logger(Component *component); - - /// Logger destructor. - ~Logger(); - - /// Starts logging data related to StorageBackend class. - /// \param storage storage class - void setStorageBackend(StorageBackend *storage); - - /// Starts logging data related to UserRegistration class. - /// \param userRegistration userRegistration class - void setUserRegistration(UserRegistration *userRegistration); - - /// Starts logging data related to UserManager class. - /// \param userManager userManager class - void setUserManager(UserManager *userManager); - - /// Starts logging data related to RosterManager class. - /// \param rosterManager rosterManager class - void setRosterManager(RosterManager *rosterManager); - - private: - // Component - void handleConnected(); - void handleConnectionError(const Swift::ComponentError &error); - void handleXMLIn(const std::string &data); - void handleXMLOut(const std::string &data); - - // StorageBackend - void handleStorageError(const std::string &statement, const std::string &error); - - // UserRegistration - void handleUserRegistered(const UserInfo &user); - void handleUserUnregistered(const UserInfo &user); - void handleUserUpdated(const UserInfo &user); - - // UserManager - void handleUserCreated(User *user); - void handleUserDestroyed(User *user); - - // RosterManager - void handleBuddySet(Buddy *buddy); - void handleBuddyUnset(Buddy *buddy); -}; - -} diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 738a0cc8..b5aa0b71 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -136,6 +136,7 @@ class NetworkPluginServer { void handleFTRejected(User *user, const std::string &buddyName, const std::string &fileName, unsigned long size); void handleFTDataNeeded(Backend *b, unsigned long ftid); + void handlePIDTerminated(unsigned long pid); private: void send(boost::shared_ptr &, const std::string &data); @@ -152,6 +153,7 @@ class NetworkPluginServer { Config *m_config; boost::shared_ptr m_server; std::list m_clients; + std::vector m_pids; Swift::Timer::ref m_pingTimer; Swift::Timer::ref m_collectTimer; Swift::Timer::ref m_loginTimer; diff --git a/include/transport/userregistration.h b/include/transport/userregistration.h index 32299f09..2e9b6136 100644 --- a/include/transport/userregistration.h +++ b/include/transport/userregistration.h @@ -71,6 +71,7 @@ class UserRegistration : public Swift::Responder payload); virtual bool handleSetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + void handleRegisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref error, const UserInfo &row); void handleUnregisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref error, const std::string &barejid); Component *m_component; diff --git a/packaging/fedora/spectrum2.spec b/packaging/fedora/spectrum2.spec index 7bae9b13..91b60256 100644 --- a/packaging/fedora/spectrum2.spec +++ b/packaging/fedora/spectrum2.spec @@ -25,7 +25,7 @@ BuildRequires: libidn-devel BuildRequires: expat-devel BuildRequires: avahi-devel BuildRequires: log4cxx-devel -BuildRequires: swiften-devel +#BuildRequires: swiften-devel BuildRequires: libcommuni-devel Requires: libtransport%{?_isa} = %{version}-%{release} diff --git a/spectrum/src/backend-logging.cfg b/spectrum/src/backend-logging.cfg index fcdc906c..1078afe2 100644 --- a/spectrum/src/backend-logging.cfg +++ b/spectrum/src/backend-logging.cfg @@ -1,11 +1,11 @@ log4j.rootLogger=debug, R log4j.appender.R=org.apache.log4j.RollingFileAppender -log4j.appender.R.File=/var/log/spectrum2/${jid}/backends/backend-${pid}.log +log4j.appender.R.File=/var/log/spectrum2/${jid}/backends/backend-${id}.log log4j.appender.R.MaxFileSize=10000KB # Keep one backup file log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout -log4j.appender.R.layout.ConversionPattern=%d %-5p %c: %m%n +log4j.appender.R.layout.ConversionPattern=${pid}: %d %-5p %c: %m%n diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 68389e80..a024138e 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -2,7 +2,6 @@ #include "transport/transport.h" #include "transport/filetransfermanager.h" #include "transport/usermanager.h" -#include "transport/logger.h" #include "transport/sqlite3backend.h" #include "transport/mysqlbackend.h" #include "transport/pqxxbackend.h" @@ -132,6 +131,32 @@ static void daemonize(const char *cwd, const char *lock_file) { } #endif +static void _createDirectories(Transport::Config *config, boost::filesystem::path ph) { + if (ph.empty() || exists(ph)) { + return; + } + + // First create branch, by calling ourself recursively + _createDirectories(config, ph.branch_path()); + + // Now that parent's path exists, create the directory + boost::filesystem::create_directory(ph); + +#ifndef WIN32 + if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { + struct group *gr; + if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; + } + struct passwd *pw; + if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; + } + chown(ph.string().c_str(), pw->pw_uid, gr->gr_gid); + } +#endif +} + int mainloop() { #ifndef WIN32 @@ -217,6 +242,9 @@ int mainloop() { usersReconnecter = new UsersReconnecter(&transport, storageBackend); } + else if (!CONFIG_BOOL(config_, "service.server_mode")) { + LOG4CXX_WARN(logger, "Registrations won't work, you have specified [database] type=none in config file."); + } FileTransferManager ftManager(&transport, &userManager); @@ -398,8 +426,7 @@ int main(int argc, char **argv) // create directories try { - - Transport::Util::createDirectories(&config, CONFIG_STRING(&config, "service.working_dir")); + _createDirectories(&config, boost::filesystem::path(CONFIG_STRING(&config, "service.working_dir"))); } catch (...) { std::cerr << "Can't create service.working_dir directory " << CONFIG_STRING(&config, "service.working_dir") << ".\n"; @@ -451,7 +478,13 @@ int main(int argc, char **argv) // daemonize daemonize(CONFIG_STRING(&config, "service.working_dir").c_str(), CONFIG_STRING(&config, "service.pidfile").c_str()); // removeOldIcons(CONFIG_STRING(&config, "service.working_dir") + "/icons"); - } + } + else { + if ((chdir(CONFIG_STRING(&config, "service.working_dir").c_str())) < 0) { + std::cerr << "Cannot change directory to " << CONFIG_STRING(&config, "service.working_dir") << "\n"; + exit(1); + } + } #endif #ifdef WIN32 if (!run_service_name.empty()) { diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 0da3b1ec..cc0a7aef 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -96,6 +96,10 @@ type = none # Prefix used for tables #prefix = jabber_ +# Connection string (for pqxx only!) +# If you set this, it ignores every other database option except for type and prefix. +#connectionstring = host=localhost user=specturm password=secret + [registration] # Enable public registrations enable_public_registration=1 diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index 94d29345..9f09d2af 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -82,6 +82,7 @@ int main(int argc, char **argv) " spectrum [OPTIONS] \nCommands:\n" " start - start all local Spectrum2 instances\n" " stop - stop all local Spectrum2 instances\n" + " restart - restart all local Spectrum2 instances\n" " status - status of local Spectrum2 instances\n" " - send command to local Spectrum2 instance and print output\n" "Allowed options"); @@ -164,6 +165,9 @@ int main(int argc, char **argv) stop_instances(&config, jid); return 0; } + else if (cmd == "restart") { + return restart_instances(&config, jid); + } ask_local_server(&config, networkFactories, jid, cmd); // std::string message = command; diff --git a/spectrum_manager/src/methods.cpp b/spectrum_manager/src/methods.cpp index a9b56cf4..aabbfee8 100644 --- a/spectrum_manager/src/methods.cpp +++ b/spectrum_manager/src/methods.cpp @@ -276,6 +276,100 @@ void stop_instances(ManagerConfig *config, const std::string &_jid) { } } +int restart_instances(ManagerConfig *config, const std::string &_jid) { + response = ""; + path p(CONFIG_STRING(config, "service.config_directory")); + int rv = 0; + int rc; + + try { + if (!exists(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(6); + } + + if (!is_directory(p)) { + std::cerr << "Config directory " << CONFIG_STRING(config, "service.config_directory") << " does not exist\n"; + exit(7); + } + + std::string spectrum2_binary = searchForBinary("spectrum2"); + if (spectrum2_binary.empty()) { + std::cerr << "spectrum2 binary not found in PATH\n"; + return 8; + } + + directory_iterator end_itr; + for (directory_iterator itr(p); itr != end_itr; ++itr) { + if (is_regular(itr->path()) && extension(itr->path()) == ".cfg") { + Config cfg; + if (cfg.load(itr->path().string()) == false) { + std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; + } + + std::vector vhosts; + if (CONFIG_HAS_KEY(&cfg, "vhosts.vhost")) + vhosts = CONFIG_VECTOR(&cfg, "vhosts.vhost"); + vhosts.push_back(CONFIG_STRING(&cfg, "service.jid")); + + BOOST_FOREACH(std::string &vhost, vhosts) { + Config vhostCfg; + if (vhostCfg.load(itr->path().string(), vhost) == false) { + std::cerr << "Can't load config file " << itr->path().string() << ". Skipping...\n"; + continue; + } + + if (!_jid.empty() && _jid != vhost) { + continue; + } + + int pid = isRunning(CONFIG_STRING(&vhostCfg, "service.pidfile")); + if (pid) { + response ="Stopping " + itr->path().string() + ": "; + std::cout << "Stopping " << itr->path() << ": "; + kill(pid, SIGTERM); + + sleep(1); + int count = 20; + while (kill(pid, 0) == 0 && count != 0) { + std::cout << "."; + sleep(1); + count--; + } + if (count == 0) { + response += "ERROR (timeout)\n"; + std::cout << " ERROR (timeout)\n"; + } + else { + response += "OK\n"; + std::cout << " OK\n"; + + response = "Starting " + itr->path().string() + ": OK\n"; + std::cout << "Starting " << itr->path() << ": OK\n"; + exec_(spectrum2_binary, itr->path().string(), vhost, rc); + if (rv == 0) { + rv = rc; + } + } + + + } + else { + response = "Stopping " + itr->path().string() + ": Not running\n"; + std::cout << "Stopping " << itr->path() << ": Not running\n"; + } + } + } + } + } + catch (const filesystem_error& ex) { + std::cerr << "Filesystem error: " << ex.what() << "\n"; + exit(5); + } + + return rv; +} + int show_status(ManagerConfig *config) { int ret = 0; path p(CONFIG_STRING(config, "service.config_directory")); diff --git a/spectrum_manager/src/methods.h b/spectrum_manager/src/methods.h index 4ee5209f..df21ab47 100644 --- a/spectrum_manager/src/methods.h +++ b/spectrum_manager/src/methods.h @@ -45,6 +45,7 @@ int getPort(const std::string &portfile); int isRunning(const std::string &pidfile); int start_instances(ManagerConfig *config, const std::string &_jid = ""); +int restart_instances(ManagerConfig *config, const std::string &_jid = ""); void stop_instances(ManagerConfig *config, const std::string &_jid = ""); int show_status(ManagerConfig *config); diff --git a/src/buddy.cpp b/src/buddy.cpp index 07d1a76c..eb5388f5 100644 --- a/src/buddy.cpp +++ b/src/buddy.cpp @@ -37,6 +37,13 @@ Buddy::~Buddy() { // m_rosterManager->unsetBuddy(this); } +void Buddy::sendPresence() { + Swift::Presence::ref presence = generatePresenceStanza(255); + if (presence) { + m_rosterManager->getUser()->getComponent()->getStanzaChannel()->sendPresence(presence); + } +} + void Buddy::generateJID() { m_jid = Swift::JID(); m_jid = Swift::JID(getSafeName(), m_rosterManager->getUser()->getComponent()->getJID().toString(), "bot"); @@ -150,13 +157,6 @@ std::string Buddy::getSafeName() { return name; } -void Buddy::handleBuddyChanged() { - Swift::Presence::ref presence = generatePresenceStanza(255); - if (presence) { - m_rosterManager->getUser()->getComponent()->getStanzaChannel()->sendPresence(presence); - } -} - void Buddy::handleVCardReceived(const std::string &id, Swift::VCard::ref vcard) { boost::shared_ptr > request(new Swift::GenericRequest(Swift::IQ::Result, m_rosterManager->getUser()->getJID(), vcard, m_rosterManager->getUser()->getComponent()->getIQRouter())); request->send(); diff --git a/src/config.cpp b/src/config.cpp index 8873c862..a30a01e1 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -363,7 +363,7 @@ Config *Config::createFromArgs(int argc, char **argv, std::string &error, std::s } catch (std::runtime_error& e) { - error = os.str(); + error = std::string(e.what()) + "\n" + os.str(); return NULL; } catch (...) diff --git a/src/localbuddy.cpp b/src/localbuddy.cpp index 7f2d642d..47fe2b7f 100644 --- a/src/localbuddy.cpp +++ b/src/localbuddy.cpp @@ -37,6 +37,24 @@ LocalBuddy::LocalBuddy(RosterManager *rosterManager, long id, const std::string LocalBuddy::~LocalBuddy() { } +void LocalBuddy::setStatus(const Swift::StatusShow &status, const std::string &statusMessage) { + bool changed = ((m_status.getType() != status.getType()) || (m_statusMessage != statusMessage)); + if (changed) { + m_status = status; + m_statusMessage = statusMessage; + sendPresence(); + } +} + +void LocalBuddy::setIconHash(const std::string &iconHash) { + bool changed = m_iconHash != iconHash; + m_iconHash = iconHash; + if (changed) { + getRosterManager()->storeBuddy(this); + sendPresence(); + } +} + bool LocalBuddy::setName(const std::string &name) { if (name == m_name) { return true; diff --git a/src/logger.cpp b/src/logger.cpp deleted file mode 100644 index ab46b204..00000000 --- a/src/logger.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/** - * libtransport -- C++ library for easy XMPP Transports development - * - * Copyright (C) 2011, Jan Kaluza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA - */ - -#include "transport/logger.h" -#include "transport/usermanager.h" -#include "transport/user.h" -#include "transport/transport.h" -#include "transport/storagebackend.h" -#include "transport/userregistration.h" -#include "transport/buddy.h" -#include "transport/rostermanager.h" -#include - -using namespace boost; - -namespace Transport { - -Logger::Logger(Component *component) { - component->onConnected.connect(boost::bind(&Logger::handleConnected, this)); - component->onConnectionError.connect(boost::bind(&Logger::handleConnectionError, this, _1)); - component->onXMLIn.connect(boost::bind(&Logger::handleXMLIn, this, _1)); - component->onXMLOut.connect(boost::bind(&Logger::handleXMLOut, this, _1)); -} - -Logger::~Logger(){ -} - -void Logger::setStorageBackend(StorageBackend *storage) { -// storage->onStorageError.connect(boost::bind(&Logger::handleStorageError, this, _1, _2)); -} - -void Logger::setUserRegistration(UserRegistration *userRegistration) { - userRegistration->onUserRegistered.connect(boost::bind(&Logger::handleUserRegistered, this, _1)); - userRegistration->onUserUnregistered.connect(boost::bind(&Logger::handleUserUnregistered, this, _1)); - userRegistration->onUserUpdated.connect(boost::bind(&Logger::handleUserUpdated, this, _1)); -} - -void Logger::setUserManager(UserManager *userManager) { - userManager->onUserCreated.connect(boost::bind(&Logger::handleUserCreated, this, _1)); - userManager->onUserDestroyed.connect(boost::bind(&Logger::handleUserDestroyed, this, _1)); -} - -void Logger::setRosterManager(RosterManager *rosterManager) { - rosterManager->onBuddySet.connect(boost::bind(&Logger::handleBuddySet, this, _1)); - rosterManager->onBuddyUnset.connect(boost::bind(&Logger::handleBuddyUnset, this, _1)); -} - -void Logger::handleConnected() { - std::cout << "[COMPONENT] Connected to Jabber Server!\n"; -} - -void Logger::handleConnectionError(const Swift::ComponentError &error) { - std::cout << "[COMPONENT] Connection Error!\n"; - switch (error.getType()) { - case Swift::ComponentError::UnknownError: std::cout << "[COMPONENT] Disconnect reason: UnknownError\n"; break; - case Swift::ComponentError::ConnectionError: std::cout << "[COMPONENT] Disconnect reason: ConnectionError\n"; break; - case Swift::ComponentError::ConnectionReadError: std::cout << "[COMPONENT] Disconnect reason: ConnectionReadError\n"; break; - case Swift::ComponentError::ConnectionWriteError: std::cout << "[COMPONENT] Disconnect reason: ConnectionWriteError\n"; break; - case Swift::ComponentError::XMLError: std::cout << "[COMPONENT] Disconnect reason: XMLError\n"; break; - case Swift::ComponentError::AuthenticationFailedError: std::cout << "[COMPONENT] Disconnect reason: AuthenticationFailedError\n"; break; - case Swift::ComponentError::UnexpectedElementError: std::cout << "[COMPONENT] Disconnect reason: UnexpectedElementError\n"; break; - }; -} - -void Logger::handleXMLIn(const std::string &data) { - std::cout << "[XML IN] " << data << "\n"; -} - -void Logger::handleXMLOut(const std::string &data) { - std::cout << "[XML OUT] " << data << "\n"; -} - -void Logger::handleStorageError(const std::string &statement, const std::string &error) { - std::cout << "[SQL ERROR] \"" << error << "\" during statement \"" << statement << "\"\n"; -} - -void Logger::handleUserRegistered(const UserInfo &user) { - std::cout << "[REGISTRATION] User \"" << user.jid << "\" registered as \"" << user.uin << "\"\n"; -} - -void Logger::handleUserUnregistered(const UserInfo &user) { - std::cout << "[REGISTRATION] User \"" << user.jid << "\" unregistered \"" << user.uin << "\"\n"; -} - -void Logger::handleUserUpdated(const UserInfo &user) { - std::cout << "[REGISTRATION] User \"" << user.jid << "\" updated \"" << user.uin << "\"\n"; -} - -void Logger::handleUserCreated(User *user) { - std::cout << "[USERMANAGER] User \"" << user->getJID().toString() << "\" (UIN: \"" << user->getUserInfo().uin << "\") connected and User class has been created\n"; -} - -void Logger::handleUserDestroyed(User *user) { - std::cout << "[USERMANAGER] User \"" << user->getJID().toBare().toString() << "\" (UIN: \"" << user->getUserInfo().uin << "\") disconnected and User class is going to be destroyed\n"; -} - -void Logger::handleBuddySet(Buddy *buddy) { - std::cout << "[ROSTERMANAGER] \"" << buddy->getRosterManager()->getUser()->getJID().toBare().toString() << "\": Buddy \"" << buddy->getSafeName() << "\" (ALIAS: \"" << buddy->getAlias() << "\") has been bound with this user's roster.\n"; -} - -void Logger::handleBuddyUnset(Buddy *buddy) { - std::cout << "[ROSTERMANAGER] \"" << buddy->getRosterManager()->getUser()->getJID().toBare().toString() << "\": Buddy \"" << buddy->getSafeName() << "\" (ALIAS: \"" << buddy->getAlias() << "\") has been unbound with this user's roster.\n"; -} - -} diff --git a/src/logging.cpp b/src/logging.cpp index a7f8478b..b5c080b2 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -91,8 +91,11 @@ static intercept_stream* intercepter_cout; static intercept_stream* intercepter_cerr; -static void initLogging(Config *config, std::string key) { +static void initLogging(Config *config, std::string key, bool only_create_dir = false) { if (CONFIG_STRING(config, key).empty()) { + if (only_create_dir) { + return; + } root = log4cxx::Logger::getRootLogger(); #ifdef _MSC_VER root->addAppender(new ConsoleAppender(new PatternLayout(L"%d %-5p %c: %m%n"))); @@ -119,24 +122,29 @@ static void initLogging(Config *config, std::string key) { } p.load(istream); - LogString pid, jid; + LogString pid, jid, id; log4cxx::helpers::Transcoder::decode(boost::lexical_cast(getpid()), pid); log4cxx::helpers::Transcoder::decode(CONFIG_STRING(config, "service.jid"), jid); + log4cxx::helpers::Transcoder::decode(CONFIG_STRING_DEFAULTED(config, "service.backend_id", ""), id); #ifdef _MSC_VER p.setProperty(L"pid", pid); p.setProperty(L"jid", jid); + p.setProperty(L"id", id); #else p.setProperty("pid", pid); p.setProperty("jid", jid); + p.setProperty("id", id); #endif std::string dir; BOOST_FOREACH(const log4cxx::LogString &prop, p.propertyNames()) { - if (boost::ends_with(prop, ".File")) { +// if (boost::ends_with(prop, ".File")) { log4cxx::helpers::Transcoder::encode(p.get(prop), dir); boost::replace_all(dir, "${jid}", jid); + boost::replace_all(dir, "${pid}", pid); + boost::replace_all(dir, "${id}", id); break; - } +// } } mode_t old_cmask; if (!dir.empty()) { @@ -152,6 +160,10 @@ static void initLogging(Config *config, std::string key) { } } + if (only_create_dir) { + return; + } + log4cxx::PropertyConfigurator::configure(p); // Change owner of main log file @@ -185,6 +197,7 @@ void initBackendLogging(Config *config) { void initMainLogging(Config *config) { initLogging(config, "logging.config"); + initLogging(config, "logging.backend_config", true); } void redirect_stderr() { diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index a012ee87..2493d630 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -71,6 +71,8 @@ static unsigned long bytestream_id; DEFINE_LOGGER(logger, "NetworkPluginServer"); +static NetworkPluginServer *_server; + class NetworkConversation : public Conversation { public: NetworkConversation(ConversationManager *conversationManager, const std::string &legacyName, bool muc = false) : Conversation(conversationManager, legacyName, muc) { @@ -128,7 +130,7 @@ class NetworkFactory : public Factory { wrap.SerializeToString(&MESSAGE); // Executes new backend -static unsigned long exec_(const std::string& exePath, const char *host, const char *port, const char *cmdlineArgs) { +static unsigned long exec_(const std::string& exePath, const char *host, const char *port, const char *log_id, const char *cmdlineArgs) { // BACKEND_ID is replaced with unique ID. The ID is increasing for every backend. std::string finalExePath = boost::replace_all_copy(exePath, "BACKEND_ID", boost::lexical_cast(backend_id++)); @@ -171,7 +173,7 @@ static unsigned long exec_(const std::string& exePath, const char *host, const c return 0; #else // Add host and port. - finalExePath += std::string(" --host ") + host + " --port " + port + " " + cmdlineArgs; + finalExePath += std::string(" --host ") + host + " --port " + port + " --service.backend_id=" + log_id + " " + cmdlineArgs; LOG4CXX_INFO(logger, "Starting new backend " << finalExePath); // Create array of char * from string using -lpopt library @@ -214,6 +216,7 @@ static void SigCatcher(int n) { // WARNING: Do not put LOG4CXX_ here, because it can lead to deadlock while ((result = waitpid(-1, &status, WNOHANG)) > 0) { if (result != 0) { + _server->handlePIDTerminated((unsigned long)result); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { // LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status)); @@ -251,6 +254,7 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa } NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager, DiscoItemsResponder *discoItemsResponder) { + _server = this; m_ftManager = ftManager; m_userManager = userManager; m_config = config; @@ -324,7 +328,7 @@ void NetworkPluginServer::start() { LOG4CXX_INFO(logger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); while (true) { - unsigned long pid = 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->getCommandLineArgs().c_str()); + unsigned long pid = 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(), "1", m_config->getCommandLineArgs().c_str()); LOG4CXX_INFO(logger, "Tried to spawn first backend with pid " << pid); LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); @@ -353,6 +357,8 @@ void NetworkPluginServer::start() { } } + m_pids.push_back(pid); + signal(SIGCHLD, SigCatcher); #endif // quit the while loop @@ -555,7 +561,6 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { LocalBuddy *buddy = (LocalBuddy *) user->getRosterManager()->getBuddy(payload.buddyname()); if (buddy) { handleBuddyPayload(buddy, payload); - buddy->handleBuddyChanged(); } else { if (payload.buddyname() == user->getUserInfo().uin) { @@ -577,10 +582,10 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { return; } - buddy->setStatus(Swift::StatusShow((Swift::StatusShow::Type) payload.status()), payload.statusmessage()); - buddy->setIconHash(payload.iconhash()); buddy->setBlocked(payload.blocked()); user->getRosterManager()->setBuddy(buddy); + buddy->setStatus(Swift::StatusShow((Swift::StatusShow::Type) payload.status()), payload.statusmessage()); + buddy->setIconHash(payload.iconhash()); } } @@ -708,6 +713,10 @@ void NetworkPluginServer::handleConvMessageAckPayload(const std::string &data) { if (!user) return; + if (payload.id().empty()) { + LOG4CXX_WARN(logger, "Received message ack with empty ID, not forwarding to XMPP."); + return; + } boost::shared_ptr msg(new Swift::Message()); msg->addPayload(boost::make_shared(payload.id())); @@ -1656,13 +1665,68 @@ void NetworkPluginServer::sendPing(Backend *c) { // LOG4CXX_INFO(logger, "PING to " << c); } +void NetworkPluginServer::handlePIDTerminated(unsigned long pid) { + std::vector::iterator log_id_it; + log_id_it = std::find(m_pids.begin(), m_pids.end(), pid); + if (log_id_it != m_pids.end()) { + *log_id_it = 0; + } +} + +#ifndef _WIN32 + +static int sig_block_count = 0; +static sigset_t block_mask; + +static void __block_signals ( void ) +{ + static int init_done = 0; + + if ( (sig_block_count++) != 1 ) return; + + if ( init_done == 0 ) { + sigemptyset ( &block_mask ); + sigaddset ( &block_mask, SIGPIPE ); + sigaddset ( &block_mask, SIGHUP ); + sigaddset ( &block_mask, SIGINT ); + sigaddset ( &block_mask, SIGQUIT ); + sigaddset ( &block_mask, SIGTERM ); + sigaddset ( &block_mask, SIGABRT ); + sigaddset ( &block_mask, SIGCHLD ); + init_done = 1; + } + + sigprocmask ( SIG_BLOCK, &block_mask, NULL ); + return; +} + +static void __unblock_signals ( void ) +{ + sigset_t sigset; + + if ( (sig_block_count--) != 0 ) return; + sigprocmask ( SIG_UNBLOCK, &block_mask, NULL ); + + if ( sigpending ( &sigset ) == 0 ) { + if ( sigismember ( &sigset, SIGCHLD ) ) { + raise ( SIGCHLD ); + } + } +} + +#endif + NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUsers, bool longRun, bool check) { NetworkPluginServer::Backend *c = NULL; unsigned long diff = CONFIG_INT(m_config, "service.login_delay"); time_t now = time(NULL); if (diff && (now - m_lastLogin < diff)) { + m_loginTimer->stop(); + m_loginTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer((diff - (now - m_lastLogin)) * 1000); + m_loginTimer->onTick.connect(boost::bind(&NetworkPluginServer::loginDelayFinished, this)); m_loginTimer->start(); + LOG4CXX_INFO(logger, "Postponing login because of service.login_delay setting"); return NULL; } @@ -1676,7 +1740,7 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUser c = *it; // if we're not reusing all backends and backend is full, stop accepting new users on this backend if (!CONFIG_BOOL(m_config, "service.reuse_old_backends")) { - if (c->users.size() + 1 >= CONFIG_INT(m_config, "service.users_per_backend")) { + if (!check && c->users.size() + 1 >= CONFIG_INT(m_config, "service.users_per_backend")) { c->acceptUsers = false; } } @@ -1688,7 +1752,29 @@ NetworkPluginServer::Backend *NetworkPluginServer::getFreeClient(bool acceptUser if (c == NULL && !m_startingBackend) { m_isNextLongRun = longRun; m_startingBackend = true; - 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->getCommandLineArgs().c_str()); + +#ifndef _WIN32 + __block_signals(); +#endif + std::vector::iterator log_id_it; + log_id_it = std::find(m_pids.begin(), m_pids.end(), 0); + std::string log_id = ""; + if (log_id_it == m_pids.end()) { + log_id = boost::lexical_cast(m_pids.size() + 1); + } + else { + log_id = boost::lexical_cast(log_id_it - m_pids.begin() + 1); + } + unsigned long pid = 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(), log_id.c_str(), m_config->getCommandLineArgs().c_str()); + if (log_id_it == m_pids.end()) { + m_pids.push_back(pid); + } + else { + *log_id_it = pid; + } +#ifndef _WIN32 + __unblock_signals(); +#endif } return c; diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index 90fffb87..f9b399d3 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -48,18 +48,34 @@ void PQXXBackend::disconnect() { } bool PQXXBackend::connect() { - LOG4CXX_INFO(logger, "Connecting PostgreSQL server " << CONFIG_STRING(m_config, "database.server") << ", user " << - CONFIG_STRING(m_config, "database.user") << ", database " << CONFIG_STRING(m_config, "database.database") << - ", port " << CONFIG_INT(m_config, "database.port") - ); - - std::string str = "dbname="; - str += CONFIG_STRING(m_config, "database.database") + " "; - - str += "user=" + CONFIG_STRING(m_config, "database.user") + " "; + std::string connection_str; + connection_str = CONFIG_STRING_DEFAULTED(m_config, "database.connectionstring", ""); + if (connection_str.empty()) { + LOG4CXX_INFO(logger, "Connecting PostgreSQL server " << CONFIG_STRING(m_config, "database.server") << ", user " << + CONFIG_STRING(m_config, "database.user") << ", dbname " << CONFIG_STRING(m_config, "database.database") << + ", port " << CONFIG_INT(m_config, "database.port") + ); + connection_str = "dbname="; + connection_str += CONFIG_STRING(m_config, "database.database"); + if (!CONFIG_STRING(m_config, "database.server").empty()) { + connection_str += " host=" + CONFIG_STRING(m_config, "database.server"); + } + if (!CONFIG_STRING(m_config, "database.user").empty()) { + connection_str += " user=" + CONFIG_STRING(m_config, "database.user"); + } + if (!CONFIG_STRING(m_config, "database.password").empty()) { + connection_str += " password=" + CONFIG_STRING(m_config, "database.password"); + } + if (CONFIG_INT(m_config, "database.port") != 0) { + connection_str += " port=" + boost::lexical_cast(CONFIG_INT(m_config, "database.port")); + } + } + else { + LOG4CXX_INFO(logger, "Connecting PostgreSQL server via provided connection string."); + } try { - m_conn = new pqxx::connection(str); + m_conn = new pqxx::connection(connection_str); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 88b69971..0967fe56 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -257,7 +257,10 @@ void RosterManager::storeBuddy(Buddy *buddy) { void RosterManager::handleBuddyRosterPushResponse(Swift::ErrorPayload::ref error, Swift::SetRosterRequest::ref request, const std::string &key) { LOG4CXX_INFO(logger, "handleBuddyRosterPushResponse called for buddy " << key); if (m_buddies[key] != NULL) { - m_buddies[key]->handleBuddyChanged(); + Swift::Presence::ref presence = m_buddies[key]->generatePresenceStanza(255); + if (presence && presence->getType() == Swift::Presence::Available) { + m_component->getStanzaChannel()->sendPresence(presence); + } } else { LOG4CXX_WARN(logger, "handleBuddyRosterPushResponse called for unknown buddy " << key); @@ -577,7 +580,7 @@ void RosterManager::sendCurrentPresences(const Swift::JID &to) { continue; } Swift::Presence::ref presence = buddy->generatePresenceStanza(255); - if (presence) { + if (presence && presence->getType() == Swift::Presence::Available) { presence->setTo(to); m_component->getStanzaChannel()->sendPresence(presence); } @@ -609,7 +612,7 @@ void RosterManager::sendUnavailablePresences(const Swift::JID &to) { continue; } Swift::Presence::ref presence = buddy->generatePresenceStanza(255); - if (presence) { + if (presence && presence->getType() == Swift::Presence::Available) { presence->setTo(to); presence->setType(Swift::Presence::Unavailable); m_component->getStanzaChannel()->sendPresence(presence); diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index c3ce5d31..b7e839bb 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -349,6 +349,7 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { std::string key; int ret; + int ret2 = -10; while((ret = sqlite3_step(m_getBuddies)) == SQLITE_ROW) { BuddyInfo b; RESET_GET_COUNTER(m_getBuddies); @@ -366,7 +367,7 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { buddy_id = -1; } - while(buddy_id == -1 && (ret = sqlite3_step(m_getBuddiesSettings)) == SQLITE_ROW) { + while(buddy_id == -1 && ret2 != SQLITE_DONE && ret2 != SQLITE_ERROR && (ret2 = sqlite3_step(m_getBuddiesSettings)) == SQLITE_ROW) { RESET_GET_COUNTER(m_getBuddiesSettings); buddy_id = GET_INT(m_getBuddiesSettings); @@ -403,12 +404,24 @@ 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; } - if (ret != SQLITE_DONE) { - LOG4CXX_ERROR(logger, "getBuddies query"<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); - return false; + if (ret2 != SQLITE_DONE) { + if (ret2 == SQLITE_ERROR) { + LOG4CXX_ERROR(logger, "getBuddiesSettings query "<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); + return false; + } + + while((ret2 = sqlite3_step(m_getBuddiesSettings)) == SQLITE_ROW) { + } + + if (ret2 != SQLITE_DONE) { + LOG4CXX_ERROR(logger, "getBuddiesSettings query "<< (sqlite3_errmsg(m_db) == NULL ? "" : sqlite3_errmsg(m_db))); + return false; + } } return true; diff --git a/src/tests/basictest.cpp b/src/tests/basictest.cpp index eb02de33..6f3545f6 100644 --- a/src/tests/basictest.cpp +++ b/src/tests/basictest.cpp @@ -258,13 +258,13 @@ void BasicTest::add2Buddies() { std::vector grp; grp.push_back("group1"); LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1", "Buddy 1", grp, BUDDY_JID_ESCAPING); - buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status1"); user->getRosterManager()->setBuddy(buddy); + buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status1"); std::vector grp2; grp2.push_back("group2"); buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy2", "Buddy 2", grp2, BUDDY_JID_ESCAPING); - buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status2"); user->getRosterManager()->setBuddy(buddy); + buddy->setStatus(Swift::StatusShow(Swift::StatusShow::Away), "status2"); } diff --git a/src/tests/localbuddy.cpp b/src/tests/localbuddy.cpp index 3a0ee795..9300c290 100644 --- a/src/tests/localbuddy.cpp +++ b/src/tests/localbuddy.cpp @@ -26,7 +26,7 @@ class LocalBuddyTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(buddyFlagsFromJID); CPPUNIT_TEST(JIDToLegacyName); CPPUNIT_TEST(getSafeName); - CPPUNIT_TEST(handleBuddyChanged); + CPPUNIT_TEST(sendPresence); CPPUNIT_TEST(setAlias); CPPUNIT_TEST_SUITE_END(); @@ -90,7 +90,7 @@ class LocalBuddyTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(BUDDY_NO_FLAG, Buddy::buddyFlagsFromJID("hanzz%test@localhost/bot")); } - void handleBuddyChanged() { + void sendPresence() { User *user = userManager->getUser("user@localhost"); CPPUNIT_ASSERT(user); @@ -101,7 +101,7 @@ class LocalBuddyTest : public CPPUNIT_NS :: TestFixture, public BasicTest { user->getRosterManager()->setBuddy(buddy); received.clear(); - buddy->handleBuddyChanged(); + buddy->sendPresence(); CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[0]))->getShow()); diff --git a/src/tests/networkpluginserver.cpp b/src/tests/networkpluginserver.cpp index e880c2ad..6d941cd8 100644 --- a/src/tests/networkpluginserver.cpp +++ b/src/tests/networkpluginserver.cpp @@ -52,6 +52,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST(handleBuddyChangedPayloadNoEscaping); CPPUNIT_TEST(handleBuddyChangedPayloadUserContactInRoster); CPPUNIT_TEST(handleMessageHeadline); + CPPUNIT_TEST(handleConvMessageAckPayload); CPPUNIT_TEST(benchmarkHandleBuddyChangedPayload); CPPUNIT_TEST_SUITE_END(); @@ -74,6 +75,31 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe tearMeDown(); } + void handleConvMessageAckPayload() { + handleMessageHeadline(); + received.clear(); + User *user = userManager->getUser("user@localhost"); + + pbnetwork::ConversationMessage m; + m.set_username("user@localhost"); + m.set_buddyname("user"); + m.set_message(""); + m.set_nickname(""); + m.set_id("testingid"); + m.set_xhtml(""); + m.set_timestamp(""); + m.set_headline(true); + + std::string message; + m.SerializeToString(&message); + + serv->handleConvMessageAckPayload(message); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))->getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("testingid"), dynamic_cast(getStanza(received[0]))->getPayload()->getReceivedID()); + } + void benchmarkHandleBuddyChangedPayload() { Clock clk; std::vector lst; @@ -81,6 +107,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe pbnetwork::Buddy buddy; buddy.set_username("user@localhost"); buddy.set_buddyname("buddy" + boost::lexical_cast(i) + "@test"); + buddy.set_status((pbnetwork::StatusType) 5); std::string message; buddy.SerializeToString(&message); @@ -118,6 +145,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe pbnetwork::Buddy buddy; buddy.set_username("user@localhost"); buddy.set_buddyname("buddy1@test"); + buddy.set_status(pbnetwork::STATUS_NONE); std::string message; buddy.SerializeToString(&message); @@ -138,6 +166,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe pbnetwork::Buddy buddy; buddy.set_username("user@localhost"); buddy.set_buddyname("buddy1@test"); + buddy.set_status(pbnetwork::STATUS_NONE); std::string message; buddy.SerializeToString(&message); @@ -193,7 +222,6 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT_EQUAL(Swift::Message::Headline, dynamic_cast(getStanza(received[0]))->getType()); - } }; diff --git a/src/tests/rostermanager.cpp b/src/tests/rostermanager.cpp index e9e5f903..35d2d444 100644 --- a/src/tests/rostermanager.cpp +++ b/src/tests/rostermanager.cpp @@ -24,6 +24,7 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(RosterManagerTest); CPPUNIT_TEST(setBuddy); CPPUNIT_TEST(sendCurrentPresences); + CPPUNIT_TEST(sendUnavailablePresences); CPPUNIT_TEST(sendCurrentPresence); CPPUNIT_TEST(sendBuddySubscribePresence); CPPUNIT_TEST(removeBuddy); @@ -73,7 +74,7 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { void setBuddy() { add2Buddies(); - CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload(); CPPUNIT_ASSERT(payload1); @@ -82,7 +83,7 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string("buddy1"), Buddy::JIDToLegacyName(item.getJID())); CPPUNIT_ASSERT_EQUAL(std::string("Buddy 1"), item.getName()); - Swift::RosterPayload::ref payload2 = getStanza(received[1])->getPayload(); + Swift::RosterPayload::ref payload2 = getStanza(received[2])->getPayload(); CPPUNIT_ASSERT(payload2); CPPUNIT_ASSERT_EQUAL(1, (int) payload2->getItems().size()); item = payload2->getItems()[0]; @@ -91,17 +92,17 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { // send responses back injectIQ(Swift::IQ::createResult(getStanza(received[0])->getFrom(), getStanza(received[0])->getTo(), getStanza(received[0])->getID())); - injectIQ(Swift::IQ::createResult(getStanza(received[1])->getFrom(), getStanza(received[1])->getTo(), getStanza(received[1])->getID())); + injectIQ(Swift::IQ::createResult(getStanza(received[2])->getFrom(), getStanza(received[2])->getTo(), getStanza(received[2])->getID())); // we should get presences - CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[2]))); - CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[2]))->getShow()); - CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast(getStanza(received[2]))->getStatus()); + CPPUNIT_ASSERT_EQUAL(6, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[4]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[4]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("status1"), dynamic_cast(getStanza(received[4]))->getStatus()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[3]))); - CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[3]))->getShow()); - CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast(getStanza(received[3]))->getStatus()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[5]))); + CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received[5]))->getShow()); + CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast(getStanza(received[5]))->getStatus()); } void sendCurrentPresences() { @@ -120,6 +121,22 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { } } + void sendUnavailablePresences() { + setBuddy(); + received.clear(); + + User *user = userManager->getUser("user@localhost"); + user->getRosterManager()->sendUnavailablePresences("user@localhost/resource"); + + CPPUNIT_ASSERT_EQUAL(3, (int) received.size()); + + for (int i = 0; i < 3; i++) { + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[i]))); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, dynamic_cast(getStanza(received[i]))->getType()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[i]))->getTo().toString()); + } + } + void sendCurrentPresence() { setBuddy(); received.clear(); @@ -142,7 +159,7 @@ class RosterManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { void removeBuddy() { add2Buddies(); - CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); received.clear(); User *user = userManager->getUser("user@localhost"); diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index dd896309..cbe49747 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -34,6 +34,8 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE_END(); public: + Swift::Presence::ref changedPresence; + void setUp (void) { setMeUp(); } @@ -165,11 +167,18 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); } + void handleUserPresenceChanged(User *user, Swift::Presence::ref presence) { + changedPresence = presence; + } + void connectTwoResources() { connectUser(); add2Buddies(); connectSecondResource(); + User *user = userManager->getUser("user@localhost"); + user->onPresenceChanged.connect(boost::bind(&UserManagerTest::handleUserPresenceChanged, this, user, _1)); + // we should get presences CPPUNIT_ASSERT_EQUAL(4, (int) received2.size()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received2[2]))); @@ -179,6 +188,22 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT(dynamic_cast(getStanza(received2[3]))); CPPUNIT_ASSERT_EQUAL(Swift::StatusShow::Away, dynamic_cast(getStanza(received2[3]))->getShow()); CPPUNIT_ASSERT_EQUAL(std::string("status2"), dynamic_cast(getStanza(received2[3]))->getStatus()); + + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost/resource"); + response->setType(Swift::Presence::Unavailable); + injectPresence(response); + + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Available, changedPresence->getType()); + + Swift::Presence::ref response2 = Swift::Presence::create(); + response2->setTo("localhost"); + response2->setFrom("user@localhost/resource2"); + response2->setType(Swift::Presence::Unavailable); + injectPresence(response2); + + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, changedPresence->getType()); } void disconnectUserBouncer() { @@ -192,7 +217,6 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(1, userManager->getUserCount()); CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT(userManager->getUser("user@localhost")); userManager->removeAllUsers(); diff --git a/src/tests/userregistration.cpp b/src/tests/userregistration.cpp index 1c81aa5b..c2d3de59 100644 --- a/src/tests/userregistration.cpp +++ b/src/tests/userregistration.cpp @@ -26,6 +26,7 @@ class UserRegistrationTest : public CPPUNIT_NS :: TestFixture, public BasicTest CPPUNIT_TEST(getForm); CPPUNIT_TEST(getFormRegistered); CPPUNIT_TEST(registerUser); + CPPUNIT_TEST(registerUserWithoutRR); CPPUNIT_TEST(unregisterUser); CPPUNIT_TEST(unregisterEmptyPayload); CPPUNIT_TEST(registerUserNotify); @@ -96,12 +97,23 @@ class UserRegistrationTest : public CPPUNIT_NS :: TestFixture, public BasicTest CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); - CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[1]))->getType()); + iq = Swift::IQ::createResult(Swift::JID("localhost"), getStanza(received[0])->getTo(), getStanza(received[0])->getID(), boost::shared_ptr(new Swift::RosterPayload())); + received.clear(); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Set, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), getStanza(received[0])->getPayload()->getItems()[0].getJID().toString()); + UserInfo user; CPPUNIT_ASSERT_EQUAL(true, storage->getUser("user@localhost", user)); @@ -109,6 +121,30 @@ class UserRegistrationTest : public CPPUNIT_NS :: TestFixture, public BasicTest CPPUNIT_ASSERT_EQUAL(std::string("password"), user.password); } + void registerUserWithoutRR(){ + Swift::InBandRegistrationPayload *reg = new Swift::InBandRegistrationPayload(); + reg->setUsername("legacyname"); + reg->setPassword("password"); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", boost::shared_ptr(reg)); + iq->setFrom("user@localhost"); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[1]))->getType()); + + iq = Swift::IQ::createError(Swift::JID("localhost"), getStanza(received[0])->getTo(), getStanza(received[0])->getID()); + received.clear(); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, dynamic_cast(getStanza(received[0]))->getType()); + } + void unregisterUser() { registerUser(); received.clear(); @@ -153,17 +189,27 @@ class UserRegistrationTest : public CPPUNIT_NS :: TestFixture, public BasicTest injectIQ(iq); loop->processEvents(); - CPPUNIT_ASSERT_EQUAL(3, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); - CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[1]))->getType()); + + iq = Swift::IQ::createResult(Swift::JID("localhost"), getStanza(received[0])->getTo(), getStanza(received[0])->getID(), boost::shared_ptr(new Swift::RosterPayload())); + received.clear(); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Set, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), getStanza(received[0])->getPayload()->getItems()[0].getJID().toString()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); CPPUNIT_ASSERT_EQUAL(std::string("registered: user@localhost"), dynamic_cast(getStanza(received[1]))->getBody()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[2]))); - CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[2]))->getType()); - UserInfo user; CPPUNIT_ASSERT_EQUAL(true, storage->getUser("user@localhost", user)); @@ -293,12 +339,22 @@ class UserRegistrationTest : public CPPUNIT_NS :: TestFixture, public BasicTest CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); - CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, dynamic_cast(getStanza(received[0]))->getType()); - + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[1]))->getType()); + iq = Swift::IQ::createResult(Swift::JID("localhost"), getStanza(received[0])->getTo(), getStanza(received[0])->getID(), boost::shared_ptr(new Swift::RosterPayload())); + received.clear(); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Set, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), getStanza(received[0])->getPayload()->getItems()[0].getJID().toString()); + UserInfo user; CPPUNIT_ASSERT_EQUAL(true, storage->getUser("user@localhost", user)); diff --git a/src/transport.cpp b/src/transport.cpp index 106f0622..7bd92b4d 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -231,8 +231,12 @@ void Component::handleConnected() { void Component::handleServerStopped(boost::optional e) { if(e != NULL ) { - if(*e == Swift::BoostConnectionServer::Conflict) + if(*e == Swift::BoostConnectionServer::Conflict) { LOG4CXX_INFO(logger, "Port "<< CONFIG_INT(m_config, "service.port") << " already in use! Stopping server.."); + if (CONFIG_INT(m_config, "service.port") == 5347) { + LOG4CXX_INFO(logger, "Port 5347 is usually used for components. You are using server_mode=1. Are you sure you don't want to use server_mode=0 and run spectrum as component?"); + } + } if(*e == Swift::BoostConnectionServer::UnknownError) LOG4CXX_INFO(logger, "Unknown error occured! Stopping server.."); exit(1); diff --git a/src/user.cpp b/src/user.cpp index 82a45bdd..a142fefc 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -348,7 +348,6 @@ void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { m_resources = currentResourcesCount; - // Change legacy network presence if (m_readyForConnect) { Swift::Presence::ref highest = m_presenceOracle->getHighestPriorityPresence(m_jid.toBare()); diff --git a/src/userregistration.cpp b/src/userregistration.cpp index 363812ce..174587fd 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -56,21 +56,11 @@ bool UserRegistration::registerUser(const UserInfo &row) { m_storageBackend->setUser(row); - Swift::Presence::ref response = Swift::Presence::create(); - response->setFrom(m_component->getJID()); - response->setTo(Swift::JID(row.jid)); - response->setType(Swift::Presence::Subscribe); - m_component->getStanzaChannel()->sendPresence(response); + //same as in unregisterUser but here we have to pass UserInfo to handleRegisterRRResponse + AddressedRosterRequest::ref request = AddressedRosterRequest::ref(new AddressedRosterRequest(m_component->getIQRouter(),row.jid)); + request->onResponse.connect(boost::bind(&UserRegistration::handleRegisterRemoteRosterResponse, this, _1, _2, row)); + request->send(); - onUserRegistered(row); - - BOOST_FOREACH(const std::string ¬ify_jid, CONFIG_VECTOR(m_component->getConfig(),"registration.notify_jid")) { - boost::shared_ptr msg(new Swift::Message()); - msg->setBody(std::string("registered: ") + row.jid); - msg->setTo(notify_jid); - msg->setFrom(m_component->getJID()); - m_component->getStanzaChannel()->sendMessage(msg); - } return true; } @@ -91,6 +81,35 @@ bool UserRegistration::unregisterUser(const std::string &barejid) { return true; } +void UserRegistration::handleRegisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref remoteRosterNotSupported /*error*/, const UserInfo &row){ + if (remoteRosterNotSupported || !payload) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setFrom(m_component->getJID()); + response->setTo(Swift::JID(row.jid)); + response->setType(Swift::Presence::Subscribe); + m_component->getStanzaChannel()->sendPresence(response); + } + else{ + Swift::RosterPayload::ref payload = Swift::RosterPayload::ref(new Swift::RosterPayload()); + Swift::RosterItemPayload item; + item.setJID(m_component->getJID()); + item.setSubscription(Swift::RosterItemPayload::Both); + payload->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(payload, row.jid, m_component->getIQRouter()); + request->send(); + } + onUserRegistered(row); + + std::vector const &x = CONFIG_VECTOR(m_component->getConfig(),"registration.notify_jid"); + BOOST_FOREACH(const std::string ¬ify_jid, x) { + boost::shared_ptr msg(new Swift::Message()); + msg->setBody(std::string("registered: ") + row.jid); + msg->setTo(notify_jid); + msg->setFrom(m_component->getJID()); + m_component->getStanzaChannel()->sendMessage(msg); + } +} + void UserRegistration::handleUnregisterRemoteRosterResponse(boost::shared_ptr payload, Swift::ErrorPayload::ref remoteRosterNotSupported /*error*/, const std::string &barejid) { UserInfo userInfo; bool registered = m_storageBackend->getUser(barejid, userInfo); @@ -174,7 +193,8 @@ void UserRegistration::handleUnregisterRemoteRosterResponse(boost::shared_ptrsend(); } - BOOST_FOREACH(const std::string ¬ify_jid, CONFIG_VECTOR(m_component->getConfig(),"registration.notify_jid")) { + std::vector const &x = CONFIG_VECTOR(m_component->getConfig(),"registration.notify_jid"); + BOOST_FOREACH(const std::string ¬ify_jid, x) { boost::shared_ptr msg(new Swift::Message()); msg->setBody(std::string("unregistered: ") + barejid); msg->setTo(notify_jid); @@ -491,6 +511,7 @@ bool UserRegistration::handleSetRequest(const Swift::JID& from, const Swift::JID res.language = language; res.encoding = encoding; res.vip = 0; + res.id = 0; registerUser(res); } else {