diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0adee0ba --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.pb.cc +*.pb.h \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 22029d2a..96be435b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,10 @@ cmake_minimum_required(VERSION 2.6) project(libtransport) +if(NOT LIB_INSTALL_DIR) + set(LIB_INSTALL_DIR "lib") +endif() + set(CMAKE_MODULE_PATH "cmake_modules") set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") diff --git a/ChangeLog b/ChangeLog index 645ca3fa..fe7ded53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -Version 2.0.0-beta2 (2012-XX-XX): +Version 2.0.0-beta2 (2012-03-28): General: * Fixed bug when Roster Item Exchange and subscribe stanzas were sent repeatedly. @@ -6,13 +6,19 @@ Version 2.0.0-beta2 (2012-XX-XX): * Fixed username_mask setting. * Added new fields into statistics (backends_crashed, messages related stats). + * Chatstates are now not counted as incoming messages in stats. * Log4cxx is now optional dependency. Without Log4cxx, Spectrum 2 logs to standard output. * Fixed crash when Log4cxx configuration file didn't exist. * Admin can now see "Admin" contact in server-mode. libpurple: - * Added support for MUC for prpl-jabber protocol. + * Added initial support for MUC for prpl-jabber protocol. + + LibCommuni IRC backend: + * Fixed sending/receiving UTF8 messages. + * Using the [registration] auto_register=1 config option, users don't + have to register manually when connecting IRC network. Skype: * Memory usage statistic now includes the Skype client. @@ -21,6 +27,7 @@ Version 2.0.0-beta2 (2012-XX-XX): * Skype backend includes also Skype client memory usage into the account. * Working buddies adding/removing. * Information about missed call is now forwarded to XMPP user. + * Fixed bug when Skype client instance wasn't killed by backend. Version 2.0.0-beta (2012-02-28): General: diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index d7c9ae9e..74bdec24 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -2,10 +2,13 @@ #include #include +#define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size()) +#define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size()) + IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) { this->config = config; m_socket = new QTcpSocket(); - m_socket->connectToHost(QString::fromStdString(host), port); + m_socket->connectToHost(FROM_UTF8(host), port); connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData())); } @@ -28,8 +31,8 @@ void IRCNetworkPlugin::handleLoginRequest(const std::string &user, const std::st if (CONFIG_BOOL(config, "service.server_mode")) { MyIrcSession *session = new MyIrcSession(user, this); std::string h = user.substr(0, user.find("@")); - session->setNickName(QString::fromStdString(h.substr(0, h.find("%")))); - session->setHost(QString::fromStdString(h.substr(h.find("%") + 1))); + session->setNickName(FROM_UTF8(h.substr(0, h.find("%")))); + session->setHost(FROM_UTF8(h.substr(h.find("%") + 1))); session->setPort(6667); session->open(); std::cout << "CONNECTING IRC NETWORK " << h.substr(h.find("%") + 1) << "\n"; @@ -72,7 +75,7 @@ void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const s } } std::cout << "MESSAGE " << u << " " << r << "\n"; - m_sessions[u]->sendCommand(IrcCommand::createMessage(QString::fromStdString(r), QString::fromStdString(message))); + m_sessions[u]->sendCommand(IrcCommand::createMessage(FROM_UTF8(r), FROM_UTF8(message))); std::cout << "SENT\n"; } @@ -89,8 +92,8 @@ void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std: if (room.find("@") != std::string::npos) { // suffix is %irc.freenode.net to let MyIrcSession return #room%irc.freenode.net MyIrcSession *session = new MyIrcSession(user, this, room.substr(room.find("@"))); - session->setNickName(QString::fromStdString(nickname)); - session->setHost(QString::fromStdString(room.substr(room.find("@") + 1))); + session->setNickName(FROM_UTF8(nickname)); + session->setHost(FROM_UTF8(room.substr(room.find("@") + 1))); session->setPort(6667); session->open(); std::cout << "CONNECTING IRC NETWORK " << room.substr(room.find("@") + 1) << "\n"; @@ -103,10 +106,10 @@ void IRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, const std: } std::cout << "JOINING " << r << "\n"; m_sessions[u]->addAutoJoinChannel(r); - m_sessions[u]->sendCommand(IrcCommand::createJoin(QString::fromStdString(r), QString::fromStdString(password))); + m_sessions[u]->sendCommand(IrcCommand::createJoin(FROM_UTF8(r), FROM_UTF8(password))); m_sessions[u]->rooms += 1; // update nickname, because we have nickname per session, no nickname per room. - handleRoomNicknameChanged(user, r, m_sessions[u]->nickName().toStdString()); + handleRoomNicknameChanged(user, r, TO_UTF8(m_sessions[u]->nickName())); } void IRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) { @@ -120,7 +123,7 @@ void IRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std if (m_sessions[u] == NULL) return; - m_sessions[u]->sendCommand(IrcCommand::createPart(QString::fromStdString(r))); + m_sessions[u]->sendCommand(IrcCommand::createPart(FROM_UTF8(r))); m_sessions[u]->removeAutoJoinChannel(r); m_sessions[u]->rooms -= 1; diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index ac972b5f..08bdd726 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -15,6 +15,9 @@ #include #include +#define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size()) +#define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size()) + #include "transport/logging.h" DEFINE_LOGGER(logger, "IRCSession"); @@ -38,13 +41,13 @@ void MyIrcSession::on_connected() { } for(std::list::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { - sendCommand(IrcCommand::createJoin(QString::fromStdString(*it))); + sendCommand(IrcCommand::createJoin(FROM_UTF8(*it))); } if (getIdentify().find(" ") != std::string::npos) { std::string to = getIdentify().substr(0, getIdentify().find(" ")); std::string what = getIdentify().substr(getIdentify().find(" ") + 1); - sendCommand(IrcCommand::createMessage(QString::fromStdString(to), QString::fromStdString(what))); + sendCommand(IrcCommand::createMessage(FROM_UTF8(to), FROM_UTF8(what))); } } @@ -67,30 +70,30 @@ bool MyIrcSession::correctNickname(std::string &nickname) { void MyIrcSession::on_joined(IrcMessage *message) { IrcJoinMessage *m = (IrcJoinMessage *) message; bool flags = 0; - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - np->handleParticipantChanged(user, nickname, m->channel().toStdString() + suffix, (int) flags, pbnetwork::STATUS_ONLINE); - LOG4CXX_INFO(logger, user << ": Joined " << m->parameters()[0].toStdString()); + np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()), (int) flags, pbnetwork::STATUS_ONLINE); + LOG4CXX_INFO(logger, user << ": Joined " << TO_UTF8(m->parameters()[0])); } void MyIrcSession::on_parted(IrcMessage *message) { IrcPartMessage *m = (IrcPartMessage *) message; bool flags = 0; - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << m->channel().toStdString() + suffix); - np->handleParticipantChanged(user, nickname, m->channel().toStdString() + suffix,(int) flags, pbnetwork::STATUS_NONE, m->reason().toStdString()); + LOG4CXX_INFO(logger, user << ": " << nickname << " parted " << TO_UTF8(m->channel()) + suffix); + np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix,(int) flags, pbnetwork::STATUS_NONE, TO_UTF8(m->reason())); } void MyIrcSession::on_quit(IrcMessage *message) { IrcQuitMessage *m = (IrcQuitMessage *) message; for(std::list::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { bool flags = 0; - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); LOG4CXX_INFO(logger, user << ": " << nickname << " quit " << (*it) + suffix); - np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_NONE, m->reason().toStdString()); + np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_NONE, TO_UTF8(m->reason())); } } @@ -98,10 +101,10 @@ void MyIrcSession::on_nickChanged(IrcMessage *message) { IrcNickMessage *m = (IrcNickMessage *) message; for(std::list::const_iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); bool flags = m_modes[(*it) + nickname]; - LOG4CXX_INFO(logger, user << ": " << nickname << " changed nickname to " << m->nick().toStdString()); - np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", m->nick().toStdString()); + LOG4CXX_INFO(logger, user << ": " << nickname << " changed nickname to " << TO_UTF8(m->nick())); + np->handleParticipantChanged(user, nickname, (*it) + suffix,(int) flags, pbnetwork::STATUS_ONLINE, "", TO_UTF8(m->nick())); } } @@ -109,8 +112,8 @@ void MyIrcSession::on_modeChanged(IrcMessage *message) { IrcModeMessage *m = (IrcModeMessage *) message; // mode changed: "#testik" "HanzZ" "+o" "hanzz_k" - std::string nickname = m->argument().toStdString(); - std::string mode = m->mode().toStdString(); + std::string nickname = TO_UTF8(m->argument()); + std::string mode = TO_UTF8(m->mode()); if (nickname.empty()) return; LOG4CXX_INFO(logger, user << ": " << nickname << " changed mode to " << mode); @@ -130,29 +133,29 @@ void MyIrcSession::on_topicChanged(IrcMessage *message) { IrcTopicMessage *m = (IrcTopicMessage *) message; bool flags = 0; - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - LOG4CXX_INFO(logger, user << ": " << nickname << " topic changed to " << m->topic().toStdString()); - np->handleSubject(user, m->channel().toStdString() + suffix, m->topic().toStdString(), nickname); + LOG4CXX_INFO(logger, user << ": " << nickname << " topic changed to " << TO_UTF8(m->topic())); + np->handleSubject(user, TO_UTF8(m->channel()) + suffix, TO_UTF8(m->topic()), nickname); } void MyIrcSession::on_messageReceived(IrcMessage *message) { IrcPrivateMessage *m = (IrcPrivateMessage *) message; - std::string target = m->target().toStdString(); + std::string target = TO_UTF8(m->target()); LOG4CXX_INFO(logger, user << ": Message from " << target); if (target.find("#") == 0) { bool flags = 0; - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - np->handleMessage(user, target + suffix, m->message().toStdString(), nickname); + np->handleMessage(user, target + suffix, TO_UTF8(m->message()), nickname); } else { bool flags = 0; - std::string nickname = m->sender().name().toStdString(); + std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - np->handleMessage(user, nickname, m->message().toStdString()); + np->handleMessage(user, nickname, TO_UTF8(m->message())); } } @@ -163,10 +166,10 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { IrcNumericMessage *m = (IrcNumericMessage *) message; switch (m->code()) { case 332: - m_topicData = m->parameters().value(2).toStdString(); + m_topicData = TO_UTF8(m->parameters().value(2)); break; case 333: - np->handleSubject(user, m->parameters().value(1).toStdString() + suffix, m_topicData, m->parameters().value(2).toStdString()); + np->handleSubject(user, TO_UTF8(m->parameters().value(1)) + suffix, m_topicData, TO_UTF8(m->parameters().value(2))); break; case 353: channel = m->parameters().value(2); @@ -174,10 +177,10 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { for (int i = 0; i < members.size(); i++) { bool flags = 0; - std::string nickname = members.at(i).toStdString(); + std::string nickname = TO_UTF8(members.at(i)); flags = correctNickname(nickname); - m_modes[channel.toStdString() + nickname] = flags; - np->handleParticipantChanged(user, nickname, channel.toStdString() + suffix,(int) flags, pbnetwork::STATUS_ONLINE); + m_modes[TO_UTF8(channel) + nickname] = flags; + np->handleParticipantChanged(user, nickname, TO_UTF8(channel) + suffix,(int) flags, pbnetwork::STATUS_ONLINE); } break; case 432: @@ -193,7 +196,7 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { } void MyIrcSession::onMessageReceived(IrcMessage *message) { - LOG4CXX_INFO(logger, user << ": " << message->toString().toStdString()); + LOG4CXX_INFO(logger, user << ": " << TO_UTF8(message->toString())); switch (message->type()) { case IrcMessage::Join: on_joined(message); diff --git a/backends/libcommuni/singleircnetworkplugin.cpp b/backends/libcommuni/singleircnetworkplugin.cpp index f668e543..cce79c7b 100644 --- a/backends/libcommuni/singleircnetworkplugin.cpp +++ b/backends/libcommuni/singleircnetworkplugin.cpp @@ -3,13 +3,16 @@ #include #include +#define FROM_UTF8(WHAT) QString::fromUtf8((WHAT).c_str(), (WHAT).size()) +#define TO_UTF8(WHAT) std::string((WHAT).toUtf8().data(), (WHAT).toUtf8().size()) + DEFINE_LOGGER(logger, "SingleIRCNetworkPlugin"); SingleIRCNetworkPlugin::SingleIRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) { this->config = config; m_server = config->getUnregistered().find("service.irc_server")->second; m_socket = new QTcpSocket(); - m_socket->connectToHost(QString::fromStdString(host), port); + m_socket->connectToHost(FROM_UTF8(host), port); connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData())); if (config->getUnregistered().find("service.irc_identify") != config->getUnregistered().end()) { @@ -44,16 +47,18 @@ void SingleIRCNetworkPlugin::handleLoginRequest(const std::string &user, const s LOG4CXX_INFO(logger, user << ": Connecting " << m_server << " as " << legacyName); MyIrcSession *session = new MyIrcSession(user, this); - session->setUserName(QString::fromStdString(legacyName)); - session->setNickName(QString::fromStdString(legacyName)); - session->setRealName(QString::fromStdString(legacyName)); - session->setHost(QString::fromStdString(m_server)); + session->setUserName(FROM_UTF8(legacyName)); + session->setNickName(FROM_UTF8(legacyName)); + session->setRealName(FROM_UTF8(legacyName)); + session->setHost(FROM_UTF8(m_server)); session->setPort(6667); - std::string identify = m_identify; - boost::replace_all(identify, "$password", password); - boost::replace_all(identify, "$name", legacyName); - session->setIdentify(identify); + if (!password.empty()) { + std::string identify = m_identify; + boost::replace_all(identify, "$password", password); + boost::replace_all(identify, "$name", legacyName); + session->setIdentify(identify); + } session->open(); @@ -88,10 +93,10 @@ void SingleIRCNetworkPlugin::handleMessageSendRequest(const std::string &user, c } LOG4CXX_INFO(logger, user << ": Forwarding message to " << r); - m_sessions[user]->sendCommand(IrcCommand::createMessage(QString::fromStdString(r), QString::fromStdString(message))); + m_sessions[user]->sendCommand(IrcCommand::createMessage(FROM_UTF8(r), FROM_UTF8(message))); if (r.find("#") == 0) { - handleMessage(user, legacyName, message, m_sessions[user]->nickName().toStdString()); + handleMessage(user, legacyName, message, TO_UTF8(m_sessions[user]->nickName())); } } @@ -103,11 +108,11 @@ void SingleIRCNetworkPlugin::handleJoinRoomRequest(const std::string &user, cons LOG4CXX_INFO(logger, user << ": Joining " << room); m_sessions[user]->addAutoJoinChannel(room); - m_sessions[user]->sendCommand(IrcCommand::createJoin(QString::fromStdString(room), QString::fromStdString(password))); + m_sessions[user]->sendCommand(IrcCommand::createJoin(FROM_UTF8(room), FROM_UTF8(password))); m_sessions[user]->rooms += 1; // update nickname, because we have nickname per session, no nickname per room. - handleRoomNicknameChanged(user, room, m_sessions[user]->userName().toStdString()); + handleRoomNicknameChanged(user, room, TO_UTF8(m_sessions[user]->userName())); } void SingleIRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, const std::string &room) { @@ -120,7 +125,7 @@ void SingleIRCNetworkPlugin::handleLeaveRoomRequest(const std::string &user, con } LOG4CXX_INFO(logger, user << ": Leaving " << room); - m_sessions[u]->sendCommand(IrcCommand::createPart(QString::fromStdString(r))); + m_sessions[u]->sendCommand(IrcCommand::createPart(FROM_UTF8(r))); m_sessions[u]->removeAutoJoinChannel(r); m_sessions[u]->rooms -= 1; } diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 7a081114..1ccd81e4 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -366,7 +366,7 @@ bool Skype::createDBusProxy() { LOG4CXX_INFO(logger, m_username << ":" << error->message); if (m_counter == 15) { - LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created"); + LOG4CXX_ERROR(logger, "Logging out, proxy couldn't be created: " << error->message); np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, error->message); logout(); g_error_free(error); @@ -444,7 +444,8 @@ void Skype::login() { gchar* argv[6] = {"skype", "--disable-cleanlooks", "--pipelogin", "--dbpath", db, 0}; int fd; - g_spawn_async_with_pipes(NULL, + GError *error = NULL; + bool spawned = g_spawn_async_with_pipes(NULL, argv, NULL /*envp*/, G_SPAWN_SEARCH_PATH, @@ -454,9 +455,16 @@ void Skype::login() { &fd, NULL, &fd_output, - NULL /*error*/); + &error); + + if (!spawned) { + LOG4CXX_ERROR(logger, "Error spawning the Skype instance: " << error->message) + np->handleDisconnected(m_user, pbnetwork::CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE, "Error spawning the Skype instance."); + return; + } + std::string login_data = std::string(m_username + " " + m_password + "\n"); - LOG4CXX_INFO(logger, m_username << ": Login data=" << login_data); + LOG4CXX_INFO(logger, m_username << ": Login data=" << m_username); write(fd, login_data.c_str(), login_data.size()); close(fd); @@ -469,12 +477,12 @@ void Skype::login() { if (m_connection == NULL) { - LOG4CXX_INFO(logger, "Creating DBus connection."); + LOG4CXX_INFO(logger, "Creating DBUS connection."); GError *error = NULL; m_connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error); if (m_connection == NULL && error != NULL) { - LOG4CXX_INFO(logger, m_username << ": DBUS Error: " << error->message); + LOG4CXX_INFO(logger, m_username << ": Creating DBUS Connection error: " << error->message); g_error_free(error); return; } @@ -616,8 +624,12 @@ void Skype::logout() { send_command("SET USERSTATUS OFFLINE"); sleep(2); g_object_unref(m_proxy); - LOG4CXX_INFO(logger, m_username << ": Killing Skype instance"); + LOG4CXX_INFO(logger, m_username << ": Terminating Skype instance (SIGTERM)"); kill((int) m_pid, SIGTERM); + // Give skype a chance + sleep(2); + LOG4CXX_INFO(logger, m_username << ": Killing Skype instance (SIGKILL)"); + kill((int) m_pid, SIGKILL); m_pid = 0; } } diff --git a/include/Swiften/Parser/PayloadParsers/MUCPayloadParser.cpp b/include/Swiften/Parser/PayloadParsers/MUCPayloadParser.cpp new file mode 100644 index 00000000..257c3da3 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/MUCPayloadParser.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#include + +#include + +#include +#include +#include +#include +#include + +namespace Swift { + +void MUCPayloadParser::handleTree(ParserElement::ref root) { + foreach (ParserElement::ref child, root->getAllChildren()) { + if (child->getName() == "password" && child->getNamespace() == root->getNamespace()) { + getPayloadInternal()->setPassword(child->getText()); + } + } +} + +} diff --git a/include/Swiften/Parser/PayloadParsers/MUCPayloadParser.h b/include/Swiften/Parser/PayloadParsers/MUCPayloadParser.h new file mode 100644 index 00000000..5f6910b0 --- /dev/null +++ b/include/Swiften/Parser/PayloadParsers/MUCPayloadParser.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2010 Kevin Smith + * Licensed under the GNU General Public License v3. + * See Documentation/Licenses/GPLv3.txt for more information. + */ + +#pragma once + +#include + +#include +#include +#include + +namespace Swift { + class PayloadParserFactoryCollection; + class MUCPayloadParser : public GenericPayloadTreeParser { + public: + MUCPayloadParser(){} + virtual void handleTree(ParserElement::ref root); + }; +} diff --git a/include/transport/CMakeLists.txt b/include/transport/CMakeLists.txt index 771e051e..531baa9a 100644 --- a/include/transport/CMakeLists.txt +++ b/include/transport/CMakeLists.txt @@ -3,12 +3,12 @@ if (PROTOBUF_FOUND) set (PROTOBUF_PROTOC_EXECUTABLE protoc) endif() ADD_CUSTOM_COMMAND( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/protocol.pb.cc ${CMAKE_CURRENT_BINARY_DIR}/protocol.pb.h - COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_BINARY_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/protocol.proto + OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/protocol.pb.cc ${CMAKE_CURRENT_SOURCE_DIR}/protocol.pb.h + COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_SOURCE_DIR} --proto_path ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/protocol.proto COMMENT "Running C++ protocol buffer compiler on protocol.proto" - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/protocol.proto + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol.proto ) - ADD_CUSTOM_TARGET(pb DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/protocol.pb.cc) + ADD_CUSTOM_TARGET(pb DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/protocol.pb.cc) endif() FILE(GLOB HEADERS *.h protocol.h) diff --git a/include/transport/localbuddy.h b/include/transport/localbuddy.h index c8f81174..16bf12c1 100644 --- a/include/transport/localbuddy.h +++ b/include/transport/localbuddy.h @@ -51,10 +51,20 @@ class LocalBuddy : public Buddy { } std::string getIconHash() { return m_iconHash; } - void setIconHash(const std::string &iconHash) { m_iconHash = iconHash; } + void setIconHash(const std::string &iconHash) { + bool changed = m_iconHash != iconHash; + m_iconHash = iconHash; + if (changed) + getRosterManager()->storeBuddy(this); + } std::vector getGroups() { return m_groups; } - void setGroups(const std::vector &groups) { m_groups = groups; } + void setGroups(const std::vector &groups) { + bool changed = m_groups.size() != groups.size(); + m_groups = groups; + if (changed) + getRosterManager()->storeBuddy(this); + } private: std::string m_name; diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index 43837765..b8ef46c1 100644 --- a/plugin/cpp/CMakeLists.txt +++ b/plugin/cpp/CMakeLists.txt @@ -2,10 +2,10 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp *.h) FILE(GLOB HEADERS ../include/transport/*.h) -set(EXTRA_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/../../src/memoryusage.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/../../src/logging.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/../../src/config.cpp) -set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc) +set(EXTRA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../../src/memoryusage.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/logging.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../src/config.cpp) +set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) if (NOT WIN32) ADD_LIBRARY(transport-plugin SHARED ${HEADERS} ${SRC} ${PROTOBUF_SRC} ${PROTOBUF_HDRS} ${EXTRA_SOURCES}) @@ -15,7 +15,7 @@ else() ADD_DEPENDENCIES(transport-plugin libprotobuf) endif() ADD_DEPENDENCIES(transport-plugin pb) -SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc PROPERTIES GENERATED 1) if (CMAKE_COMPILER_IS_GNUCXX) ADD_DEFINITIONS(-fPIC) @@ -31,7 +31,7 @@ SET_TARGET_PROPERTIES(transport-plugin PROPERTIES VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} ) -INSTALL(TARGETS transport-plugin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries) +INSTALL(TARGETS transport-plugin LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries) -#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc") -#INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig) +#CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_SOURCE_DIR}/transport.pc") +#INSTALL(FILES "${CMAKE_CURRENT_SOURCE_DIR}/transport.pc" DESTINATION lib/pkgconfig) diff --git a/plugin/python/CMakeLists.txt b/plugin/python/CMakeLists.txt index 5bc15fb8..c851b4fd 100644 --- a/plugin/python/CMakeLists.txt +++ b/plugin/python/CMakeLists.txt @@ -7,7 +7,9 @@ if (PROTOBUF_FOUND) COMMENT "Running Python protocol buffer compiler on protocol.proto" DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../../include/transport/protocol.proto ) - ADD_CUSTOM_TARGET(pb-python DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/protocol_pb2.py) + ADD_CUSTOM_TARGET(pb-python ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/protocol_pb2.py) endif() + + diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index d3b4f317..88ec12c8 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,7 +13,8 @@ admin_password=test #cert=server.pfx #patch to PKCS#12 certificate #cert_password=test #password to that certificate if any users_per_backend=10 -backend=../..//backends/libpurple/spectrum2_libpurple_backend +#backend=../..//backends/libpurple/spectrum2_libpurple_backend +backend=../../backends/template/spectrum2_template_backend protocol=prpl-xmpp #protocol=prpl-msn #protocol=any diff --git a/spectrum/src/server.p12 b/spectrum/src/server.p12 new file mode 100644 index 00000000..c05f6b5d Binary files /dev/null and b/spectrum/src/server.p12 differ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ca1ded70..4e55fce4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,8 +46,8 @@ endif() if (NOT CMAKE_COMPILER_IS_GNUCXX) include_directories("${CMAKE_SOURCE_DIR}/msvc-deps/protobuf/libprotobuf") - TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES}) -else () + TARGET_LINK_LIBRARIES(transport transport-plugin sqlite3 libprotobuf ${PQXX_LIBRARY} ${PQ_LIBRARY} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${LOG4CXX_LIBRARIES}) +else (WIN32) TARGET_LINK_LIBRARIES(transport transport-plugin ${PQXX_LIBRARY} ${PQ_LIBRARY} ${SQLITE3_LIBRARIES} ${MYSQL_LIBRARIES} ${SWIFTEN_LIBRARY} ${PROTOBUF_LIBRARIES} ${LOG4CXX_LIBRARIES} ${POPT_LIBRARY}) endif() @@ -55,7 +55,7 @@ SET_TARGET_PROPERTIES(transport PROPERTIES VERSION ${TRANSPORT_VERSION} SOVERSION ${TRANSPORT_VERSION} ) -INSTALL(TARGETS transport LIBRARY DESTINATION lib ARCHIVE DESTINATION lib COMPONENT libraries) +INSTALL(TARGETS transport LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION ${LIB_INSTALL_DIR} COMPONENT libraries) #CONFIGURE_FILE(transport.pc.in "${CMAKE_CURRENT_BINARY_DIR}/transport.pc") #INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/transport.pc" DESTINATION lib/pkgconfig) diff --git a/src/buddy.cpp b/src/buddy.cpp index 55f35713..5e9b30b6 100644 --- a/src/buddy.cpp +++ b/src/buddy.cpp @@ -148,7 +148,6 @@ void Buddy::handleBuddyChanged() { if (presence) { m_rosterManager->getUser()->getComponent()->getStanzaChannel()->sendPresence(presence); } - m_rosterManager->handleBuddyChanged(this); } void Buddy::handleVCardReceived(const std::string &id, Swift::VCard::ref vcard) { diff --git a/src/config.cpp b/src/config.cpp index 6917d858..fdead320 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -93,6 +93,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("registration.instructions", value()->default_value("Enter your legacy network username and password."), "Instructions showed to user in registration form") ("registration.username_label", value()->default_value("Legacy network username:"), "Label for username field") ("registration.username_mask", value()->default_value(""), "Username mask") + ("registration.auto_register", value()->default_value(false), "Register new user automatically when the presence arrives.") ("registration.encoding", value()->default_value("utf8"), "Default encoding in registration form") ("registration.require_local_account", value()->default_value(false), "True if users have to have a local account to register to this transport from remote servers.") ("registration.local_username_label", value()->default_value("Local username:"), "Label for local usernme field") diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 90d66759..fdd68e68 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -163,9 +163,14 @@ static unsigned long exec_(std::string path, const char *host, const char *port, if ( pid == 0 ) { setsid(); // child process - exit(execv(argv[0], argv)); + errno = 0; + int ret = execv(argv[0], argv); + if (ret == -1) { + exit(errno); + } + exit(0); } else if ( pid < 0 ) { - // fork failed + LOG4CXX_ERROR(logger, "Fork failed"); } free(p); @@ -258,12 +263,29 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U LOG4CXX_INFO(logger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); + 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->getConfigFile().c_str()); + LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); + #ifndef _WIN32 + // wait if the backend process will still be alive after 1 second + sleep(1); + pid_t result; + int status; + result = waitpid(-1, &status, WNOHANG); + if (result != 0) { + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) != 0) { + LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status) << ", possible error: " << strerror(WEXITSTATUS(status))); + } + } + else { + LOG4CXX_ERROR(logger, "Backend can not be started"); + } + } + signal(SIGCHLD, SigCatcher); #endif - exec_(CONFIG_STRING(m_config, "service.backend"), CONFIG_STRING(m_config, "service.backend_host").c_str(), CONFIG_STRING(m_config, "service.backend_port").c_str(), m_config->getConfigFile().c_str()); - LOG4CXX_INFO(logger, "Backend should now connect to Spectrum2 instance. Spectrum2 won't accept any connection before backend connects"); } NetworkPluginServer::~NetworkPluginServer() { diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index ea49430b..81a453de 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -152,9 +152,6 @@ void RosterManager::sendBuddySubscribePresence(Buddy *buddy) { } void RosterManager::handleBuddyChanged(Buddy *buddy) { - if (m_rosterStorage) { - m_rosterStorage->storeBuddy(buddy); - } } void RosterManager::setBuddyCallback(Buddy *buddy) { diff --git a/src/transport.cpp b/src/transport.cpp index b29c2ec2..eba43360 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -47,6 +47,7 @@ #include "Swiften/Parser/PayloadParsers/GatewayPayloadParser.h" #include "Swiften/Serializer/PayloadSerializers/GatewayPayloadSerializer.h" #include "Swiften/Serializer/PayloadSerializers/SpectrumErrorSerializer.h" +#include "Swiften/Parser/PayloadParsers/MUCPayloadParser.h" #include "transport/BlockParser.h" #include "transport/BlockSerializer.h" #include "Swiften/Parser/PayloadParsers/InvisibleParser.h" @@ -107,6 +108,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_server->addPayloadParserFactory(new GenericPayloadParserFactory("invisible", "urn:xmpp:invisible:0")); m_server->addPayloadParserFactory(new GenericPayloadParserFactory("query", "http://jabber.org/protocol/stats")); m_server->addPayloadParserFactory(new GenericPayloadParserFactory("query", "jabber:iq:gateway")); + m_server->addPayloadParserFactory(new GenericPayloadParserFactory("x", "http://jabber.org/protocol/muc")); m_server->addPayloadSerializer(new Swift::AttentionSerializer()); m_server->addPayloadSerializer(new Swift::XHTMLIMSerializer()); @@ -135,6 +137,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_component->addPayloadParserFactory(new GenericPayloadParserFactory("invisible", "urn:xmpp:invisible:0")); m_component->addPayloadParserFactory(new GenericPayloadParserFactory("query", "http://jabber.org/protocol/stats")); m_component->addPayloadParserFactory(new GenericPayloadParserFactory("query", "jabber:iq:gateway")); + m_component->addPayloadParserFactory(new GenericPayloadParserFactory("x", "http://jabber.org/protocol/muc")); m_component->addPayloadSerializer(new Swift::AttentionSerializer()); m_component->addPayloadSerializer(new Swift::XHTMLIMSerializer()); diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 82371146..671509f4 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -214,6 +214,34 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { res.password = m_userRegistry->getUserPassword(userkey); } + // We allow auto_register feature in gateway-mode. This allows IRC user to register + // the transport just by joining the room. + if (!m_component->inServerMode()) { + if (!registered && CONFIG_BOOL(m_component->getConfig(), "registration.auto_register")) { + res.password = ""; + res.jid = userkey; + + bool isMUC = presence->getPayload() != NULL || *presence->getTo().getNode().c_str() == '#'; + if (isMUC) { + res.uin = presence->getTo().getResource(); + } + else { + res.uin = presence->getFrom().toString(); + } + LOG4CXX_INFO(logger, "Auto-registering user " << userkey << " with uin=" << res.uin); + + if (m_storageBackend) { + // store user and getUser again to get user ID. + m_storageBackend->setUser(res); + registered = m_storageBackend->getUser(userkey, res); + } + else { + registered = false; + } + } + } + + // Unregistered users are not able to login if (!registered) { LOG4CXX_WARN(logger, "Unregistered user " << userkey << " tried to login"); @@ -282,7 +310,12 @@ void UserManager::handleMessageReceived(Swift::Message::ref message) { } user->getConversationManager()->handleMessageReceived(message); - messageToBackendSent(); + + // Do not count chatstate notification... + boost::shared_ptr statePayload = message->getPayload(); + if (!statePayload) { + messageToBackendSent(); + } } void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) {