diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a10d6c95b71404d92e6accf73f893adc3fa467f..c5e63bc5042469b5075b65d9ee3bec22a54154dc 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 04cd980b588f3b015ec54ce202529ba4a6e1469d..b232f8bfc0c6f5286650ae68b6bb5f7440175287 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 d8bfd2954056b77ec634f8466f2f8bff35d87d29..1b09ef788d11ca11cdd687df33d2ae54dfede028 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 26da4cb7b2864645b819e9d0c1ef0a2bab161b83..981e404634be7bf6d51920dc79c18756275bc956 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 85d27c0c76c0c1d90548202ad8b8373e9686a288..a8f5aa1a23724f84d6e5136f0bc2ceb7d8ebd1ad 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 35205822b3e8a932682aa70b0dbda4160ca84798..e11ed4250576ab8c55ac36fd7b9e2590fc61fd19 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 7a0ff92da8f77916b13b1efc5b1cf8d3e8ea2292..5e80fb10efb80a6b5c20b8f5679a1b98be91bb96 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 ecca0247895e82060511b02968600ab4192d9609..0000000000000000000000000000000000000000 --- 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 738a0cc82c43d23bd7a71b89dfdd0091cd78a4e0..b5aa0b71bdb7be0e1e7443b26f1a5034c8363713 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 32299f09ce0e16cfdfa51a556e324ade07e5ba53..2e9b6136ea47f7b58a3c54d0f27d8aec3859ba73 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 7bae9b13d0e2ec066b7e9cdfcdb8f3a290ff4c5b..91b6025605560cad7f46556f382e8191f1778aa8 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 fcdc906c8bd15387ebe6d4ff7d97cd98c2374b18..1078afe2d6385bcfe8a2f5d2f0a5bf82cd7580b0 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 68389e80864536d4e29cb08ee9b9b6be598ad27c..a024138e97cb5feccab77f381eb2fd75e6ed2878 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 0da3b1ecbbc380ee5d940a93155993c0a79d379b..cc0a7aef8e0d611c4f98a0f23a7415d0a490269a 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 94d2934551d02578c8480e0e8f1df7ce0d3c6e8f..9f09d2aff0703a70a9638a8572b0b1bc99a972ca 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 a9b56cf4f13d95374496e3ac9ad4a80a157cb5c7..aabbfee84ba2967420346509850a41df7330ef05 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 4ee5209f48b9b9a520c0850551be36b1525b07f4..df21ab4733c617c1080f27bf853f33e382c37699 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 07d1a76cd38aae9aec3531ce63131253e37cfef9..eb5388f51bee6bfb2e0edac848710208501c7c13 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 8873c862b04573e656d7fe2cde224f2a5c90460a..a30a01e151fc6f177b36f908081814e23f3d13ad 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 7f2d642d57b6c8f670dd2b97a4a5c218f1b554a2..47fe2b7f9b4224335649cdcc9d19d1ebd478176e 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 ab46b2044e6a8183386c028a90acdd88ccf330f1..0000000000000000000000000000000000000000 --- 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 a7f8478b090172d28f076dfeb8dd0de89c02f510..b5c080b2d9eadf466e60e70ee6fc2e28621c091a 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 a012ee871bce221c7883d6482307f308b21f3021..2493d6309a9583ec9569e2c8e1086bc0e9dffd9d 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 90fffb87b69b48d92bf63bf12d0854a7251a42ef..f9b399d3f8dc81582945f8ed00a294cb6328fee2 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 88b6997131ad7c02605fb9c7b4004216a6e22b09..0967fe567a8c8208b1f1805cebcd07f2c8a036b6 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 c3ce5d3108b4d07c1b9cac3f68d6329ca3291599..b7e839bb2d15994bc43242a04195169b5e20739a 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,13 +404,25 @@ 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))); + 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 eb02de33fdaef9e1c49680bb7ac2aec3c2346532..6f3545f66541c18db07b3d93e0f72bdfd37250ce 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 3a0ee7951b1db940ae0af601b4659cb4437f0504..9300c290a56bf228e80b7309626c621f5ddf911e 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 e880c2ad9af0a724eb7c881ded75e8230664183d..6d941cd84a19b497e78f41da23869e6736b0c17a 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 e9e5f90391140b71d8ed355c7e3996138ec03c91..35d2d444bde875d5a42360c150481d512dd34bbc 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(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_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[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 dd89630975160788b93e11c7737a39e1fc1a48a9..cbe49747df02056f2e0868eb4519643eb0f2a83b 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 1c81aa5b31c549233d2d33893ed8f69a155427a7..c2d3de59482e80994602d9bf6a816efcb890dcae 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 106f062207fc3db7dbc11e43789640b125ba362e..7bd92b4dd5d59bc7bd4330220877a1e39b8f6146 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 82a45bddf81a1942765dba53c4ae44bc6cb64199..a142fefcf4c8685845ae8e8a57178dbc57f228ac 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 363812ce6e057539d370f3e4d744f10ca42196d5..174587fd6c0cfc9f128571b7cc2e3e0f871c1bfb 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); - - onUserRegistered(row); + //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(); - 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 {