From e321feda1537cf77636071391803635be6f031f8 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 5 Oct 2012 19:24:18 +0200 Subject: [PATCH 01/61] Don't handle roster stanzas with empty node --- src/rosterresponder.cpp | 4 ++ src/tests/rosterresponder.cpp | 86 +++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/tests/rosterresponder.cpp diff --git a/src/rosterresponder.cpp b/src/rosterresponder.cpp index 9c0be47d..6bc496c1 100644 --- a/src/rosterresponder.cpp +++ b/src/rosterresponder.cpp @@ -74,6 +74,10 @@ bool RosterResponder::handleSetRequest(const Swift::JID& from, const Swift::JID& Swift::RosterItemPayload item = payload->getItems()[0]; + if (item.getJID().getNode().empty()) { + return true; + } + Buddy *buddy = user->getRosterManager()->getBuddy(Buddy::JIDToLegacyName(item.getJID())); if (buddy) { if (item.getSubscription() == Swift::RosterItemPayload::Remove) { diff --git a/src/tests/rosterresponder.cpp b/src/tests/rosterresponder.cpp new file mode 100644 index 00000000..2c6cf86a --- /dev/null +++ b/src/tests/rosterresponder.cpp @@ -0,0 +1,86 @@ +#include "transport/userregistry.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/rosterresponder.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + +using namespace Transport; + +class RosterResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTest { + CPPUNIT_TEST_SUITE(RosterResponderTest); + CPPUNIT_TEST(addEmptyBuddy); + CPPUNIT_TEST_SUITE_END(); + + public: + RosterResponder *m_rosterResponder; + std::string m_buddy; + + void setUp (void) { + m_buddy = "none"; + setMeUp(); + connectUser(); + + m_rosterResponder = new RosterResponder(component->getIQRouter(), userManager); + m_rosterResponder->onBuddyAdded.connect(boost::bind(&RosterResponderTest::handleBuddyAdded, this, _1, _2)); + m_rosterResponder->onBuddyRemoved.connect(boost::bind(&RosterResponderTest::handleBuddyRemoved, this, _1)); + m_rosterResponder->onBuddyUpdated.connect(boost::bind(&RosterResponderTest::handleBuddyUpdated, this, _1, _2)); + m_rosterResponder->start(); + + received.clear(); + } + + void tearDown (void) { + received.clear(); + disconnectUser(); + tearMeDown(); + } + + void handleBuddyAdded(Buddy *buddy, const Swift::RosterItemPayload &item) { + m_buddy = buddy->getName(); + } + + void handleBuddyRemoved(Buddy *buddy) { + m_buddy = buddy->getName(); + } + + void handleBuddyUpdated(Buddy *buddy, const Swift::RosterItemPayload &item) { + m_buddy = buddy->getName(); + } + + void addEmptyBuddy() { + Swift::RosterPayload::ref p = Swift::RosterPayload::ref(new Swift::RosterPayload()); + Swift::RosterItemPayload item; + item.setJID("icq.localhost"); + item.setSubscription(Swift::RosterItemPayload::Both); + + p->addItem(item); + Swift::SetRosterRequest::ref request = Swift::SetRosterRequest::create(p, "user@localhost", component->getIQRouter()); + + boost::shared_ptr iq(new Swift::IQ(Swift::IQ::Set)); + iq->setTo("icq.localhost"); + iq->setFrom("user@localhost"); + iq->addPayload(p); + iq->setID("123"); + injectIQ(iq); + + CPPUNIT_ASSERT_EQUAL(std::string("none"), m_buddy); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (RosterResponderTest); From 379074e87b8a38df984ff54ef68bb8915f9fd2d0 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 6 Oct 2012 09:14:46 +0200 Subject: [PATCH 02/61] replace invalid characters with _ also in groups --- src/networkpluginserver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index a7efd8fb..6855c36d 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -231,7 +231,9 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa // Change groups if it's not empty. The same as above... std::vector groups; for (int i = 0; i < payload.group_size(); i++) { - groups.push_back(payload.group(i)); + std::string group = payload.group(i); + utf8::replace_invalid(payload.group(i).begin(), payload.group(i).end(), group.begin(), '_'); + groups.push_back(group); } if (!groups.empty()) { buddy->setGroups(groups); From e33358e61f4286a7195e0057f74e783d5d47b1a6 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 8 Oct 2012 10:51:27 +0200 Subject: [PATCH 03/61] Do not join rooms before we're connected to legacy network. Otherwise join requests are lost --- include/transport/factory.h | 2 +- include/transport/user.h | 1 + src/networkpluginserver.cpp | 10 ++-------- src/tests/basictest.h | 4 ++-- src/tests/user.cpp | 38 +++++++++++++++++++++++++++++++++++++ src/user.cpp | 22 +++++++++++++++++++++ 6 files changed, 66 insertions(+), 11 deletions(-) diff --git a/include/transport/factory.h b/include/transport/factory.h index 85b7f37a..0c4595d7 100644 --- a/include/transport/factory.h +++ b/include/transport/factory.h @@ -40,7 +40,7 @@ class RosterManager; class Factory { public: - virtual Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) = 0; + virtual Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMuc = false) = 0; virtual Buddy *createBuddy(RosterManager *rosterManager, const BuddyInfo &buddyInfo) = 0; }; diff --git a/include/transport/user.h b/include/transport/user.h index 11c253b0..e89ba70b 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -142,6 +142,7 @@ class User : public Swift::EntityCapsProvider { std::vector > m_filetransfers; int m_resources; int m_reconnectCounter; + std::vector m_joinedRooms; }; } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 6855c36d..8b8f8cbc 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -92,8 +92,8 @@ class NetworkFactory : public Factory { virtual ~NetworkFactory() {} // Creates new conversation (NetworkConversation in this case) - Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) { - NetworkConversation *nc = new NetworkConversation(conversationManager, legacyName); + Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMuc) { + NetworkConversation *nc = new NetworkConversation(conversationManager, legacyName, isMuc); nc->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, m_nps, _1, _2)); return nc; } @@ -1191,12 +1191,6 @@ void NetworkPluginServer::handleRoomJoined(User *user, const Swift::JID &who, co return; } send(c->connection, message); - - NetworkConversation *conv = new NetworkConversation(user->getConversationManager(), r, true); - user->getConversationManager()->addConversation(conv); - conv->onMessageToSend.connect(boost::bind(&NetworkPluginServer::handleMessageReceived, this, _1, _2)); - conv->setNickname(nickname); - conv->addJID(who); } void NetworkPluginServer::handleRoomLeft(User *user, const std::string &r) { diff --git a/src/tests/basictest.h b/src/tests/basictest.h index 554ab5b6..1d270b20 100644 --- a/src/tests/basictest.h +++ b/src/tests/basictest.h @@ -67,8 +67,8 @@ class TestingFactory : public Factory { } // Creates new conversation (NetworkConversation in this case) - Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName) { - TestingConversation *nc = new TestingConversation(conversationManager, legacyName); + Conversation *createConversation(ConversationManager *conversationManager, const std::string &legacyName, bool isMuc = false) { + TestingConversation *nc = new TestingConversation(conversationManager, legacyName, isMuc); nc->onMessageToSend.connect(boost::bind(&TestingFactory::handleMessageToSend, this, _1, _2)); return nc; } diff --git a/src/tests/user.cpp b/src/tests/user.cpp index bbafedbb..84914b6e 100644 --- a/src/tests/user.cpp +++ b/src/tests/user.cpp @@ -30,6 +30,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(handlePresenceLeaveRoomTwoResources); CPPUNIT_TEST(handlePresenceLeaveRoomTwoResourcesOneDisconnects); CPPUNIT_TEST(leaveJoinedRoom); + CPPUNIT_TEST(joinRoomBeforeConnected); CPPUNIT_TEST(handleDisconnected); CPPUNIT_TEST(handleDisconnectedReconnect); CPPUNIT_TEST_SUITE_END(); @@ -320,6 +321,43 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT(readyToConnect); } + void joinRoomBeforeConnected() { + User *user = userManager->getUser("user@localhost"); + user->setConnected(false); + + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("#room@localhost/hanzz"); + response->setFrom("user@localhost/resource"); + + Swift::MUCPayload *payload = new Swift::MUCPayload(); + payload->setPassword("password"); + response->addPayload(boost::shared_ptr(payload)); + injectPresence(response); + loop->processEvents(); + + // no presence received in server mode, just disco#info + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + + CPPUNIT_ASSERT_EQUAL(std::string(""), room); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + + user->setConnected(true); + CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); + + room = ""; + roomNickname = ""; + roomPassword = ""; + + user->setConnected(true); + CPPUNIT_ASSERT_EQUAL(std::string(""), room); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + } + }; CPPUNIT_TEST_SUITE_REGISTRATION (UserTest); diff --git a/src/user.cpp b/src/user.cpp index f791b992..cf0b2f1c 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -176,6 +176,13 @@ void User::setConnected(bool connected) { updateLastActivity(); sendCurrentPresence(); + + if (m_connected) { + BOOST_FOREACH(Swift::Presence::ref &presence, m_joinedRooms) { + handlePresence(presence); + } + m_joinedRooms.clear(); + } } void User::handlePresence(Swift::Presence::ref presence) { @@ -241,7 +248,16 @@ void User::handlePresence(Swift::Presence::ref presence) { m_readyForConnect = true; onReadyToConnect(); } + std::string room = Buddy::JIDToLegacyName(presence->getTo()); + + if (!m_connected) { + LOG4CXX_INFO(logger, m_jid.toString() << ": Joining room " << room << " postponed, because use is not connected to legacy network yet."); + m_joinedRooms.push_back(presence); + return; + } + + Conversation *conv = m_conversationManager->getConversation(room); if (conv != NULL) { if (std::find(conv->getJIDs().begin(), conv->getJIDs().end(), presence->getFrom()) != conv->getJIDs().end()) { @@ -259,6 +275,12 @@ void User::handlePresence(Swift::Presence::ref presence) { if (presence->getPayload() != NULL) { password = presence->getPayload()->getPassword() ? *presence->getPayload()->getPassword() : ""; } + + conv = m_component->getFactory()->createConversation(m_conversationManager, room, true); + m_conversationManager->addConversation(conv); + conv->setNickname(presence->getTo().getResource()); + conv->addJID(presence->getFrom()); + onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password); } return; From e4cf53f96f29dcc601b3fd2c0b09be30e37487b8 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 9 Oct 2012 09:35:41 +0200 Subject: [PATCH 04/61] Rewrite create_socket so it's portable --- backends/libpurple/utils.cpp | 52 +++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/backends/libpurple/utils.cpp b/backends/libpurple/utils.cpp index 9ae0d37a..4857f37c 100644 --- a/backends/libpurple/utils.cpp +++ b/backends/libpurple/utils.cpp @@ -36,14 +36,14 @@ #ifndef WIN32 #include "sys/wait.h" #include "sys/signal.h" -#include -#include -#include -#include -#include -#include -#include "sys/socket.h" +#include +#include +#include #include +#include +#include +#include +#include #include #include #else @@ -137,30 +137,32 @@ void spectrum_sigchld_handler(int sig) #endif int create_socket(const char *host, int portno) { - struct sockaddr_in serv_addr; - - int main_socket = socket(AF_INET, SOCK_STREAM, 0); - memset((char *) &serv_addr, 0, sizeof(serv_addr)); - serv_addr.sin_family = AF_INET; - serv_addr.sin_port = htons(portno); + struct sockaddr_in stSockAddr; + int SocketFD = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); - hostent *hos; // Resolve name + if (-1 == SocketFD) { + return 0; + } + + hostent *hos; if ((hos = gethostbyname(host)) == NULL) { // strerror() will not work for gethostbyname() and hstrerror() // is supposedly obsolete - exit(1); - } - serv_addr.sin_addr.s_addr = *((unsigned long *) hos->h_addr_list[0]); - - if (connect(main_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { - close(main_socket); - main_socket = 0; + return 0; } -// int flags = fcntl(main_socket, F_GETFL); -// flags |= O_NONBLOCK; -// fcntl(main_socket, F_SETFL, flags); - return main_socket; + memset(&stSockAddr, 0, sizeof(stSockAddr)); + + stSockAddr.sin_family = AF_INET; + stSockAddr.sin_port = htons(portno); + bcopy(hos->h_addr, &(stSockAddr.sin_addr.s_addr), hos->h_length); + + if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { + close(SocketFD); + return 0; + } + + return SocketFD; } #ifdef _WIN32 From ede2ffb4f86b296f6b48154d911bc4cbf201369b Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 9 Oct 2012 09:49:03 +0200 Subject: [PATCH 05/61] Do not call mallopt on BSd --- spectrum/src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 75169b1a..82352ad4 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -130,9 +130,11 @@ int main(int argc, char **argv) setlocale(LC_ALL, ""); #ifndef WIN32 +#ifndef __FreeBSD__ mallopt(M_CHECK_ACTION, 2); mallopt(M_PERTURB, 0xb); #endif +#endif #ifndef WIN32 if (signal(SIGINT, spectrum_sigint_handler) == SIG_ERR) { From c63df9499f11e85e6ae3258ee45e0a5613183a83 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 9 Oct 2012 10:01:51 +0200 Subject: [PATCH 06/61] Do not include malloc.h on BSD --- backends/skype/main.cpp | 2 ++ backends/swiften/main.cpp | 4 ++++ spectrum/src/main.cpp | 2 ++ 3 files changed, 8 insertions(+) diff --git a/backends/skype/main.cpp b/backends/skype/main.cpp index 99d77bc2..7cb7c59f 100644 --- a/backends/skype/main.cpp +++ b/backends/skype/main.cpp @@ -19,7 +19,9 @@ #include "sys/wait.h" #include "sys/signal.h" // #include "valgrind/memcheck.h" +#ifndef __FreeBSD__ #include "malloc.h" +#endif #include diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index d9199aeb..6d7340d3 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -14,8 +14,10 @@ #include "sys/signal.h" #endif +#ifndef __FreeBSD__ // malloc_trim #include "malloc.h" +#endif // Boost #include @@ -106,8 +108,10 @@ class SwiftenPlugin : public NetworkPlugin { } #ifndef WIN32 +#ifndef __FreeBSD__ // force returning of memory chunks allocated by libxml2 to kernel malloc_trim(0); +#endif #endif } diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 82352ad4..4df436d4 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -26,7 +26,9 @@ #include #include #include "libgen.h" +#ifndef __FreeBSD__ #include +#endif #else #include #define getpid _getpid From 0ac67f912d46f30dc3ebdea9f83cc3bbe7e42272 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 9 Oct 2012 16:58:11 +0200 Subject: [PATCH 07/61] include in.h in mongoose --- spectrum_manager/src/mongoose.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spectrum_manager/src/mongoose.c b/spectrum_manager/src/mongoose.c index 976870d3..8d52417b 100644 --- a/spectrum_manager/src/mongoose.c +++ b/spectrum_manager/src/mongoose.c @@ -18,6 +18,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. +#include + #if defined(_WIN32) #define _CRT_SECURE_NO_WARNINGS // Disable deprecation warning in VS2005 #else From 84a6e647e6fb54b3f2038817748a9337f0e11e25 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 10 Oct 2012 13:09:39 +0200 Subject: [PATCH 08/61] Send ctcp action when /me is received from XMPP --- backends/libcommuni/ircnetworkplugin.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index 90e4d663..581ca1b7 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -142,7 +142,13 @@ void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const s std::string target = getTargetName(legacyName); LOG4CXX_INFO(logger, user << ": Session name: " << session << ", message to " << target); - m_sessions[session]->sendCommand(IrcCommand::createMessage(FROM_UTF8(target), FROM_UTF8(message))); + + if (message.find("/me") == 0) { + m_sessions[session]->sendCommand(IrcCommand::createCtcpAction(FROM_UTF8(target), FROM_UTF8(message))); + } + else { + m_sessions[session]->sendCommand(IrcCommand::createMessage(FROM_UTF8(target), FROM_UTF8(message))); + } if (target.find("#") == 0) { handleMessage(user, legacyName, message, TO_UTF8(m_sessions[session]->nickName())); From da1044e0dcabc7bc99285e62f8362ed5237bdd45 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 10 Oct 2012 13:26:27 +0200 Subject: [PATCH 09/61] Remove /me from incoming messages, add /me to outgoing messagse --- backends/libcommuni/ircnetworkplugin.cpp | 2 +- backends/libcommuni/session.cpp | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index 581ca1b7..f2fc4574 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -144,7 +144,7 @@ void IRCNetworkPlugin::handleMessageSendRequest(const std::string &user, const s LOG4CXX_INFO(logger, user << ": Session name: " << session << ", message to " << target); if (message.find("/me") == 0) { - m_sessions[session]->sendCommand(IrcCommand::createCtcpAction(FROM_UTF8(target), FROM_UTF8(message))); + m_sessions[session]->sendCommand(IrcCommand::createCtcpAction(FROM_UTF8(target), FROM_UTF8(message.substr(4)))); } else { m_sessions[session]->sendCommand(IrcCommand::createMessage(FROM_UTF8(target), FROM_UTF8(message))); diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 2eabfe96..6abdb4db 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -158,20 +158,25 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) { } } + QString msg = m->message(); + if (m->isAction()) { + msg = QString("/me ") + msg; + } + std::string target = TO_UTF8(m->target()); LOG4CXX_INFO(logger, user << ": Message from " << target); if (target.find("#") == 0) { bool flags = 0; std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - np->handleMessage(user, target + suffix, TO_UTF8(m->message()), nickname); + np->handleMessage(user, target + suffix, TO_UTF8(msg), nickname); } else { bool flags = 0; std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); LOG4CXX_INFO(logger, nickname + suffix); - np->handleMessage(user, nickname + suffix, TO_UTF8(m->message())); + np->handleMessage(user, nickname + suffix, TO_UTF8(msg)); } } From 2b5b1ca86034eda5fa4f0386779afefe4d13dda8 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 11 Oct 2012 08:46:29 +0200 Subject: [PATCH 10/61] update sample.cfg --- spectrum/src/sample2.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spectrum/src/sample2.cfg b/spectrum/src/sample2.cfg index 3181a6a1..0da3b1ec 100644 --- a/spectrum/src/sample2.cfg +++ b/spectrum/src/sample2.cfg @@ -39,7 +39,7 @@ users_per_backend=10 # Full path to backend binary. backend=/usr/bin/spectrum2_libpurple_backend -#backend=/usr/bin/spectrum2_libircclient-qt_backend +#backend=/usr/bin/spectrum2_libcommuni_backend # For skype: #backend=/usr/bin/xvfb-run -n BACKEND_ID -s "-screen 0 10x10x8" -f /tmp/x-skype-gw /usr/bin/spectrum2_skype_backend From da196682876c8e44adecb5fadab113067861bac0 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 11 Oct 2012 10:45:32 +0200 Subject: [PATCH 11/61] Do not force sqlite3 storage backend --- src/storagebackend.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/storagebackend.cpp b/src/storagebackend.cpp index 2247dee9..ec87e33b 100644 --- a/src/storagebackend.cpp +++ b/src/storagebackend.cpp @@ -10,8 +10,7 @@ namespace Transport { StorageBackend *StorageBackend::createBackend(Config *config, std::string &error) { StorageBackend *storageBackend = NULL; #ifdef WITH_SQLITE - if (CONFIG_STRING(config, "database.type") == "sqlite3" || - (CONFIG_STRING(config, "database.type") == "none" && !CONFIG_BOOL(config, "service.server_mode"))) { + if (CONFIG_STRING(config, "database.type") == "sqlite3") { storageBackend = new SQLite3Backend(config); } #else From 8cc37e1025855e9e56af19a81fbbb2f469fd0a1c Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 14 Oct 2012 12:04:31 +0200 Subject: [PATCH 12/61] Docs update --- docs/guide/libcommuni.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/libcommuni.textile b/docs/guide/libcommuni.textile index 4a0b6b12..395aca5f 100644 --- a/docs/guide/libcommuni.textile +++ b/docs/guide/libcommuni.textile @@ -32,7 +32,7 @@ irc_server=irc.freenode.org h3. 2.2 One transport for more IRC networks -In this mode users can connect more IRC networks, but they can't connect the network without being in the room. Currently this mode is not finished yet in Spectrum 2. +In this mode users can connect more IRC networks, but they can't connect the network without being in the room. To connect the network, user has to join the room in following format: #room%irc.freenode.org@irc.domain.tld. The nickname used in the first join request is used as a nickname for the IRC connection. h2. 3. All configuration variables From 22679e921b90bc41f94dae345cf702e0fe2e462b Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 15 Oct 2012 16:25:36 +0200 Subject: [PATCH 13/61] add RoomList support to libtransport, so backends can send list of available rooms --- include/transport/discoitemsresponder.h | 5 +++++ include/transport/networkplugin.h | 3 +++ include/transport/networkpluginserver.h | 5 ++++- include/transport/protocol.proto | 6 ++++++ plugin/cpp/networkplugin.cpp | 18 ++++++++++++++++++ spectrum/src/main.cpp | 8 ++++---- src/discoitemsresponder.cpp | 12 +++++++++++- src/networkpluginserver.cpp | 20 +++++++++++++++++++- 8 files changed, 70 insertions(+), 7 deletions(-) diff --git a/include/transport/discoitemsresponder.h b/include/transport/discoitemsresponder.h index 44bdc364..2558b8b6 100644 --- a/include/transport/discoitemsresponder.h +++ b/include/transport/discoitemsresponder.h @@ -37,12 +37,17 @@ class DiscoItemsResponder : public Swift::GetResponder { void addAdHocCommand(const std::string &node, const std::string &name); // void removeAdHocCommand(const std::string &node); + void addRoom(const std::string &node, const std::string &name); + void clearRooms(); + private: virtual bool handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr payload); + private: Component *m_component; boost::shared_ptr m_commands; + boost::shared_ptr m_rooms; }; } \ No newline at end of file diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index ea594225..3d5c87da 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -24,6 +24,7 @@ #include "transport/protocol.pb.h" // #include "conversation.h" #include +#include namespace Transport { @@ -164,6 +165,8 @@ class NetworkPlugin { void handleFTData(unsigned long ftID, const std::string &data); + void handleRoomList(const std::string &user, const std::list &rooms, const std::list &names); + /// Called when XMPP user wants to connect legacy network. /// You should connect him to legacy network and call handleConnected or handleDisconnected function later. /// \param user XMPP JID of user for which this event occurs. diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 62fc5b08..3aef279d 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -43,6 +43,7 @@ class RosterResponder; class BlockResponder; class DummyReadBytestream; class AdminInterface; +class DiscoItemsResponder; class NetworkPluginServer { public: @@ -60,7 +61,7 @@ class NetworkPluginServer { std::string id; }; - NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager); + NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager, DiscoItemsResponder *discoItemsResponder); virtual ~NetworkPluginServer(); @@ -109,6 +110,7 @@ class NetworkPluginServer { void handleFTDataPayload(Backend *b, const std::string &payload); void handleQueryPayload(Backend *b, const std::string &payload); void handleBackendConfigPayload(const std::string &payload); + void handleRoomListPayload(const std::string &payload); void handleUserCreated(User *user); void handleRoomJoined(User *user, const Swift::JID &who, const std::string &room, const std::string &nickname, const std::string &password); @@ -154,6 +156,7 @@ class NetworkPluginServer { std::vector m_crashedBackends; AdminInterface *m_adminInterface; bool m_startingBackend; + DiscoItemsResponder *m_discoItemsResponder; }; } diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 929c02b7..de423598 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -78,6 +78,11 @@ message Room { optional string password = 4; } +message RoomList { + repeated string room = 1; + repeated string name = 2; +} + message Participant { required string userName = 1; required string room = 2; @@ -159,6 +164,7 @@ message WrapperMessage { TYPE_EXIT = 29; TYPE_BACKEND_CONFIG = 30; TYPE_QUERY = 31; + TYPE_ROOM_LIST = 32; } required Type type = 1; optional bytes payload = 2; diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index eba6dcff..fccd33f3 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -336,6 +336,24 @@ void NetworkPlugin::handleFTData(unsigned long ftID, const std::string &data) { send(message); } +void NetworkPlugin::handleRoomList(const std::string &user, const std::list &rooms, const std::list &names) { + pbnetwork::RoomList d; + for (std::list::const_iterator it = rooms.begin(); it != rooms.end(); it++) { + d.add_room(*it); + } + + for (std::list::const_iterator it = names.begin(); it != names.end(); it++) { + d.add_name(*it); + } + + std::string message; + d.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_ROOM_LIST); + + send(message); +} + void NetworkPlugin::handleLoginPayload(const std::string &data) { pbnetwork::Login payload; if (payload.ParseFromString(data) == false) { diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 4df436d4..b966014e 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -398,7 +398,10 @@ int main(int argc, char **argv) FileTransferManager ftManager(&transport, &userManager); - NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager); + DiscoItemsResponder discoItemsResponder(&transport); + discoItemsResponder.start(); + + NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder); AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); plugin.setAdminInterface(&adminInterface); @@ -409,9 +412,6 @@ int main(int argc, char **argv) GatewayResponder gatewayResponder(transport.getIQRouter(), &userManager); gatewayResponder.start(); - DiscoItemsResponder discoItemsResponder(&transport); - discoItemsResponder.start(); - AdHocManager adhocmanager(&transport, &discoItemsResponder, &userManager, storageBackend); adhocmanager.start(); diff --git a/src/discoitemsresponder.cpp b/src/discoitemsresponder.cpp index 2365b27e..ec5417f3 100644 --- a/src/discoitemsresponder.cpp +++ b/src/discoitemsresponder.cpp @@ -38,6 +38,8 @@ DiscoItemsResponder::DiscoItemsResponder(Component *component) : Swift::GetRespo m_component = component; m_commands = boost::shared_ptr(new DiscoItems()); m_commands->setNode("http://jabber.org/protocol/commands"); + + m_rooms = boost::shared_ptr(new DiscoItems()); } DiscoItemsResponder::~DiscoItemsResponder() { @@ -48,6 +50,14 @@ void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::st m_commands->addItem(DiscoItems::Item(name, m_component->getJID(), node)); } +void DiscoItemsResponder::addRoom(const std::string &node, const std::string &name) { + m_rooms->addItem(DiscoItems::Item(name, m_component->getJID(), node)); +} + +void DiscoItemsResponder::clearRooms() { + m_rooms = boost::shared_ptr(new DiscoItems()); +} + bool DiscoItemsResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr info) { LOG4CXX_INFO(logger, "get request received with node " << info->getNode()); @@ -55,7 +65,7 @@ bool DiscoItemsResponder::handleGetRequest(const Swift::JID& from, const Swift:: sendResponse(from, id, m_commands); } else if (to.getNode().empty()) { - sendResponse(from, id, boost::shared_ptr(new DiscoItems())); + sendResponse(from, id, m_rooms); } else { sendResponse(from, id, boost::shared_ptr(new DiscoItems())); diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 8b8f8cbc..13138055 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -44,6 +44,7 @@ #include "Swiften/Elements/SpectrumErrorPayload.h" #include "transport/protocol.pb.h" #include "transport/util.h" +#include "transport/discoitemsresponder.h" #include "utf8.h" @@ -244,7 +245,7 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa buddy->setBlocked(payload.blocked()); } -NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager) { +NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, UserManager *userManager, FileTransferManager *ftManager, DiscoItemsResponder *discoItemsResponder) { m_ftManager = ftManager; m_userManager = userManager; m_config = config; @@ -252,6 +253,7 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U m_isNextLongRun = false; m_adminInterface = NULL; m_startingBackend = false; + m_discoItemsResponder = discoItemsResponder; m_component->m_factory = new NetworkFactory(this); m_userManager->onUserCreated.connect(boost::bind(&NetworkPluginServer::handleUserCreated, this, _1)); m_userManager->onUserDestroyed.connect(boost::bind(&NetworkPluginServer::handleUserDestroyed, this, _1)); @@ -850,6 +852,19 @@ void NetworkPluginServer::handleBackendConfigPayload(const std::string &data) { m_config->updateBackendConfig(payload.config()); } +void NetworkPluginServer::handleRoomListPayload(const std::string &data) { + pbnetwork::RoomList payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + m_discoItemsResponder->clearRooms(); + for (int i = 0; i < payload.room_size() && i < payload.name_size(); i++) { + m_discoItemsResponder->addRoom(payload.room(i), payload.name(i)); + } +} + void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptr data) { // Append data to buffer c->data.insert(c->data.end(), data->begin(), data->end()); @@ -947,6 +962,9 @@ void NetworkPluginServer::handleDataRead(Backend *c, boost::shared_ptr Date: Thu, 18 Oct 2012 09:04:20 +0200 Subject: [PATCH 14/61] Get room list on IRC and show rooms in service discovery --- backends/libcommuni/session.cpp | 17 ++++ backends/libcommuni/session.h | 2 + include/transport/discoitemsresponder.h | 4 + include/transport/transport.h | 16 ---- include/transport/user.h | 2 + include/transport/usermanager.h | 6 +- spectrum/src/main.cpp | 8 +- spectrum/src/sample.cfg | 5 +- src/buddy.cpp | 4 +- src/config.cpp | 1 + src/discoinforesponder.cpp | 26 +++++- src/discoinforesponder.h | 4 + src/discoitemsresponder.cpp | 16 +++- src/networkpluginserver.cpp | 2 +- src/tests/basictest.cpp | 8 +- src/tests/discoitemsresponder.cpp | 100 ++++++++++++++++++++++++ src/transport.cpp | 18 +---- src/usermanager.cpp | 4 +- 18 files changed, 192 insertions(+), 51 deletions(-) create mode 100644 src/tests/discoitemsresponder.cpp diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 6abdb4db..7b86f99f 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -23,6 +23,8 @@ DEFINE_LOGGER(logger, "IRCSession"); +static bool sentList; + MyIrcSession::MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix, QObject* parent) : IrcSession(parent) { this->np = np; @@ -40,6 +42,10 @@ void MyIrcSession::on_connected() { m_connected = true; if (suffix.empty()) { np->handleConnected(user); + if (!sentList) { + sendCommand(IrcCommand::createList("")); + sentList = true; + } } for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { @@ -208,6 +214,17 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { case 432: np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname"); break; + case 321: + m_rooms.clear(); + m_names.clear(); + break; + case 322: + m_rooms.push_back(TO_UTF8(m->parameters().value(1))); + m_names.push_back(TO_UTF8(m->parameters().value(1))); + break; + case 323: + np->handleRoomList("", m_rooms, m_names); + break; default: break; } diff --git a/backends/libcommuni/session.h b/backends/libcommuni/session.h index 507feb93..e8a262ac 100644 --- a/backends/libcommuni/session.h +++ b/backends/libcommuni/session.h @@ -85,6 +85,8 @@ protected: AutoJoinMap m_autoJoin; std::string m_topicData; bool m_connected; + std::list m_rooms; + std::list m_names; }; //class MyIrcBuffer : public Irc::Buffer diff --git a/include/transport/discoitemsresponder.h b/include/transport/discoitemsresponder.h index 2558b8b6..9b17e832 100644 --- a/include/transport/discoitemsresponder.h +++ b/include/transport/discoitemsresponder.h @@ -28,12 +28,15 @@ namespace Transport { class Component; +class DiscoInfoResponder; class DiscoItemsResponder : public Swift::GetResponder { public: DiscoItemsResponder(Component *component); ~DiscoItemsResponder(); + Swift::CapsInfo &getBuddyCapsInfo(); + void addAdHocCommand(const std::string &node, const std::string &name); // void removeAdHocCommand(const std::string &node); @@ -48,6 +51,7 @@ class DiscoItemsResponder : public Swift::GetResponder { Component *m_component; boost::shared_ptr m_commands; boost::shared_ptr m_rooms; + DiscoInfoResponder *m_discoInfoResponder; }; } \ No newline at end of file diff --git a/include/transport/transport.h b/include/transport/transport.h index e6f0610d..c69ca396 100644 --- a/include/transport/transport.h +++ b/include/transport/transport.h @@ -47,7 +47,6 @@ namespace Transport { // } SpectrumImportantFeatures; // class StorageBackend; - class DiscoInfoResponder; class Factory; class UserRegistry; @@ -81,8 +80,6 @@ namespace Transport { /// \return Swift::StanzaChannel associated with this Transport::Component. Swift::StanzaChannel *getStanzaChannel(); - Swift::CapsInfo &getBuddyCapsInfo(); - /// Returns Swift::IQRouter associated with this Component. /// \return Swift::IQRouter associated with this Component. @@ -104,18 +101,6 @@ namespace Transport { void start(); void stop(); - /// Sets disco#info features which are sent as answer to disco#info IQ-get. - - /// This sets features of transport contact (For example "j2j.domain.tld"). - /// \param features list of features as sent in disco#info response - void setTransportFeatures(std::list &features); - - /// Sets disco#info features which are sent as answer to disco#info IQ-get. - - /// This sets features of legacy network buddies (For example "me\40gmail.com@j2j.domain.tld"). - /// \param features list of features as sent in disco#info response - void setBuddyFeatures(std::list &features); - /// Returns Jabber ID of this transport. /// \return Jabber ID of this transport @@ -186,7 +171,6 @@ namespace Transport { Transport::UserRegistry *m_userRegistry; StorageBackend *m_storageBackend; - DiscoInfoResponder *m_discoInfoResponder; int m_reconnectCount; Config* m_config; std::string m_protocol; diff --git a/include/transport/user.h b/include/transport/user.h index e89ba70b..47a1206c 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -71,6 +71,8 @@ class User : public Swift::EntityCapsProvider { Component *getComponent() { return m_component; } + UserManager *getUserManager() { return m_userManager; } + void setData(void *data) { m_data = data; } void *getData() { return m_data; } diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 2601be21..683d2f05 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -32,6 +32,7 @@ class Component; class StorageBackend; class StorageResponder; class RosterResponder; +class DiscoItemsResponder; /// Manages online XMPP Users. @@ -55,7 +56,7 @@ class UserManager : public Swift::EntityCapsProvider { /// Creates new UserManager. /// \param component Component which's presence will be handled /// \param storageBackend Storage backend used to fetch UserInfos - UserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend = NULL); + UserManager(Component *component, UserRegistry *userRegistry, DiscoItemsResponder *discoItemsResponder, StorageBackend *storageBackend = NULL); /// Destroys UserManager. ~UserManager(); @@ -84,6 +85,8 @@ class UserManager : public Swift::EntityCapsProvider { Swift::DiscoInfo::ref getCaps(const Swift::JID&) const; + DiscoItemsResponder *getDiscoResponder() { return m_discoItemsResponder; } + /// Called when new User class is created. /// \param user newly created User class boost::signal onUserCreated; @@ -143,6 +146,7 @@ class UserManager : public Swift::EntityCapsProvider { Swift::Timer::ref m_removeTimer; unsigned long m_sentToXMPP; unsigned long m_sentToBackend; + DiscoItemsResponder *m_discoItemsResponder; friend class RosterResponder; }; diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index b966014e..587df261 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -384,7 +384,10 @@ int main(int argc, char **argv) Logging::redirect_stderr(); - UserManager userManager(&transport, &userRegistry, storageBackend); + DiscoItemsResponder discoItemsResponder(&transport); + discoItemsResponder.start(); + + UserManager userManager(&transport, &userRegistry, &discoItemsResponder, storageBackend); userManager_ = &userManager; UserRegistration *userRegistration = NULL; @@ -398,9 +401,6 @@ int main(int argc, char **argv) FileTransferManager ftManager(&transport, &userManager); - DiscoItemsResponder discoItemsResponder(&transport); - discoItemsResponder.start(); - NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder); AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 389c4872..361ee530 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,15 +13,16 @@ 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/twitter/spectrum2_twitter_backend -#backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_communi_backend +backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend protocol=prpl-icq #protocol=prpl-msn #protocol=any #protocol=prpl-icq working_dir=./ portfile=$jid.port +irc_server=irc.freenode.org [backend] #default_avatar=catmelonhead.jpg diff --git a/src/buddy.cpp b/src/buddy.cpp index 3a32c558..07d1a76c 100644 --- a/src/buddy.cpp +++ b/src/buddy.cpp @@ -23,6 +23,8 @@ #include "transport/user.h" #include "transport/transport.h" #include "transport/BlockPayload.h" +#include "transport/usermanager.h" +#include "transport/discoitemsresponder.h" namespace Transport { @@ -106,7 +108,7 @@ Swift::Presence::ref Buddy::generatePresenceStanza(int features, bool only_new) if (presence->getType() != Swift::Presence::Unavailable) { // caps - presence->addPayload(boost::shared_ptr(new Swift::CapsInfo(m_rosterManager->getUser()->getComponent()->getBuddyCapsInfo()))); + presence->addPayload(boost::shared_ptr(new Swift::CapsInfo(m_rosterManager->getUser()->getUserManager()->getDiscoResponder()->getBuddyCapsInfo()))); // if (features & 0/*TRANSPORT_FEATURE_AVATARS*/) { presence->addPayload(boost::shared_ptr(new Swift::VCardUpdate (getIconHash()))); diff --git a/src/config.cpp b/src/config.cpp index ce49f6d6..cda6af24 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -97,6 +97,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("service.more_resources", value()->default_value(false), "Allow more resources to be connected in server mode at the same time.") ("service.enable_privacy_lists", value()->default_value(true), "") ("service.enable_xhtml", value()->default_value(true), "") + ("service.max_room_list_size", value()->default_value(100), "") ("vhosts.vhost", value >()->multitoken(), "") ("identity.name", value()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.") ("identity.category", value()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.") diff --git a/src/discoinforesponder.cpp b/src/discoinforesponder.cpp index 6d701088..0620b8c5 100644 --- a/src/discoinforesponder.cpp +++ b/src/discoinforesponder.cpp @@ -22,15 +22,19 @@ #include #include +#include #include "Swiften/Disco/DiscoInfoResponder.h" #include "Swiften/Queries/IQRouter.h" #include "Swiften/Elements/DiscoInfo.h" #include "Swiften/Swiften.h" #include "transport/config.h" +#include "transport/logging.h" using namespace Swift; using namespace boost; +DEFINE_LOGGER(logger, "DiscoInfoResponder"); + namespace Transport { DiscoInfoResponder::DiscoInfoResponder(Swift::IQRouter *router, Config *config) : Swift::GetResponder(router) { @@ -80,19 +84,37 @@ void DiscoInfoResponder::setBuddyFeatures(std::list &f) { onBuddyCapsInfoChanged(m_capsInfo); } +void DiscoInfoResponder::addRoom(const std::string &jid, const std::string &name) { + std::string j = jid; + boost::algorithm::to_lower(j); + m_rooms[j] = name; +} + +void DiscoInfoResponder::clearRooms() { + m_rooms.clear(); +} + bool DiscoInfoResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr info) { if (!info->getNode().empty()) { sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel); return true; } - // presence for transport + + // disco#info for transport if (to.getNode().empty()) { boost::shared_ptr res(new DiscoInfo(m_transportInfo)); res->setNode(info->getNode()); sendResponse(from, id, res); } - // presence for buddy + // disco#info for room + else if (m_rooms.find(to.toBare().toString()) != m_rooms.end()) { + boost::shared_ptr res(new DiscoInfo()); + res->addIdentity(DiscoInfo::Identity(m_rooms[to.toBare().toString()], "conference", "text")); + res->setNode(info->getNode()); + sendResponse(from, to, id, res); + } + // disco#info for buddy else { boost::shared_ptr res(new DiscoInfo(m_buddyInfo)); res->setNode(info->getNode()); diff --git a/src/discoinforesponder.h b/src/discoinforesponder.h index 7e374702..fadf0586 100644 --- a/src/discoinforesponder.h +++ b/src/discoinforesponder.h @@ -38,6 +38,9 @@ class DiscoInfoResponder : public Swift::GetResponder { void setTransportFeatures(std::list &features); void setBuddyFeatures(std::list &features); + void addRoom(const std::string &jid, const std::string &name); + void clearRooms(); + boost::signal onBuddyCapsInfoChanged; Swift::CapsInfo &getBuddyCapsInfo() { @@ -51,6 +54,7 @@ class DiscoInfoResponder : public Swift::GetResponder { Swift::DiscoInfo m_buddyInfo; Config *m_config; Swift::CapsInfo m_capsInfo; + std::map m_rooms; }; } \ No newline at end of file diff --git a/src/discoitemsresponder.cpp b/src/discoitemsresponder.cpp index ec5417f3..acec5822 100644 --- a/src/discoitemsresponder.cpp +++ b/src/discoitemsresponder.cpp @@ -26,6 +26,7 @@ #include "Swiften/Swiften.h" #include "transport/transport.h" #include "transport/logging.h" +#include "discoinforesponder.h" using namespace Swift; using namespace boost; @@ -40,10 +41,12 @@ DiscoItemsResponder::DiscoItemsResponder(Component *component) : Swift::GetRespo m_commands->setNode("http://jabber.org/protocol/commands"); m_rooms = boost::shared_ptr(new DiscoItems()); + m_discoInfoResponder = new DiscoInfoResponder(component->getIQRouter(), component->getConfig()); + m_discoInfoResponder->start(); } DiscoItemsResponder::~DiscoItemsResponder() { - + delete m_discoInfoResponder; } void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::string &name) { @@ -51,11 +54,20 @@ void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::st } void DiscoItemsResponder::addRoom(const std::string &node, const std::string &name) { - m_rooms->addItem(DiscoItems::Item(name, m_component->getJID(), node)); + if (m_rooms->getItems().size() > CONFIG_INT(m_component->getConfig(), "service.max_room_list_size")) { + return; + } + m_rooms->addItem(DiscoItems::Item(name, node)); + m_discoInfoResponder->addRoom(node, name); } void DiscoItemsResponder::clearRooms() { m_rooms = boost::shared_ptr(new DiscoItems()); + m_discoInfoResponder->clearRooms(); +} + +Swift::CapsInfo &DiscoItemsResponder::getBuddyCapsInfo() { + return m_discoInfoResponder->getBuddyCapsInfo(); } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 13138055..177469f8 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -861,7 +861,7 @@ void NetworkPluginServer::handleRoomListPayload(const std::string &data) { m_discoItemsResponder->clearRooms(); for (int i = 0; i < payload.room_size() && i < payload.name_size(); i++) { - m_discoItemsResponder->addRoom(payload.room(i), payload.name(i)); + m_discoItemsResponder->addRoom(Swift::JID::getEscapedNode(payload.room(i)) + "@" + m_component->getJID().toString(), payload.name(i)); } } diff --git a/src/tests/basictest.cpp b/src/tests/basictest.cpp index 9a893e7d..7c3ef14c 100644 --- a/src/tests/basictest.cpp +++ b/src/tests/basictest.cpp @@ -57,14 +57,14 @@ void BasicTest::setMeUp (void) { component = new Component(loop, factories, cfg, factory, userRegistry); component->start(); - userManager = new UserManager(component, userRegistry, storage); + itemsResponder = new DiscoItemsResponder(component); + itemsResponder->start(); + + userManager = new UserManager(component, userRegistry, itemsResponder, storage); userRegistration = new UserRegistration(component, userManager, storage); userRegistration->start(); - itemsResponder = new DiscoItemsResponder(component); - itemsResponder->start(); - payloadSerializers = new Swift::FullPayloadSerializerCollection(); payloadParserFactories = new Swift::FullPayloadParserFactoryCollection(); diff --git a/src/tests/discoitemsresponder.cpp b/src/tests/discoitemsresponder.cpp new file mode 100644 index 00000000..6032cacb --- /dev/null +++ b/src/tests/discoitemsresponder.cpp @@ -0,0 +1,100 @@ +#include "transport/userregistry.h" +#include "transport/userregistration.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include "transport/settingsadhoccommand.h" +#include "transport/adhocmanager.h" +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + +using namespace Transport; + +class DiscoItemsResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTest { + CPPUNIT_TEST_SUITE(DiscoItemsResponderTest); + CPPUNIT_TEST(roomList); + CPPUNIT_TEST(roomInfo); + CPPUNIT_TEST(clearRooms); + CPPUNIT_TEST_SUITE_END(); + + public: + + void setUp (void) { + setMeUp(); + } + + void tearDown (void) { + received.clear(); + tearMeDown(); + } + + void roomList() { + itemsResponder->addRoom("#room@localhost", "#room"); + + boost::shared_ptr payload(new Swift::DiscoItems()); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload); + iq->setFrom("user@localhost"); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("#room@localhost"), getStanza(received[0])->getPayload()->getItems()[0].getJID().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("#room"), getStanza(received[0])->getPayload()->getItems()[0].getName()); + } + + void roomInfo() { + itemsResponder->addRoom("#room@localhost", "#room"); + + boost::shared_ptr payload(new Swift::DiscoInfo()); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload); + iq->setFrom("user@localhost"); + iq->setTo("#room@localhost"); + injectIQ(iq); + loop->processEvents(); + + dumpReceived(); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("#room"), getStanza(received[0])->getPayload()->getIdentities()[0].getName()); + CPPUNIT_ASSERT_EQUAL(std::string("conference"), getStanza(received[0])->getPayload()->getIdentities()[0].getCategory()); + CPPUNIT_ASSERT_EQUAL(std::string("text"), getStanza(received[0])->getPayload()->getIdentities()[0].getType()); + } + + void clearRooms() { + itemsResponder->addRoom("#room@localhost", "#room"); + itemsResponder->clearRooms(); + + boost::shared_ptr payload(new Swift::DiscoItems()); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload); + iq->setFrom("user@localhost"); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()->getItems().empty()); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (DiscoItemsResponderTest); diff --git a/src/transport.cpp b/src/transport.cpp index 99ef21d9..95ca0319 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -26,7 +26,6 @@ #include "transport/factory.h" #include "transport/userregistry.h" #include "transport/logging.h" -#include "discoinforesponder.h" #include "storageparser.h" #ifdef _WIN32 #include @@ -158,8 +157,7 @@ Component::Component(Swift::EventLoop *loop, Swift::NetworkFactories *factories, m_presenceOracle = new Transport::PresenceOracle(m_stanzaChannel); m_presenceOracle->onPresenceChange.connect(bind(&Component::handlePresence, this, _1)); - m_discoInfoResponder = new DiscoInfoResponder(m_iqRouter, m_config); - m_discoInfoResponder->start(); + // // m_registerHandler = new SpectrumRegisterHandler(m_component); @@ -171,7 +169,6 @@ Component::~Component() { delete m_entityCapsManager; delete m_capsManager; delete m_capsMemoryStorage; - delete m_discoInfoResponder; if (m_component) delete m_component; if (m_server) { @@ -188,19 +185,6 @@ Transport::PresenceOracle *Component::getPresenceOracle() { return m_presenceOracle; } -void Component::setTransportFeatures(std::list &features) { - m_discoInfoResponder->setTransportFeatures(features); -} - -Swift::CapsInfo &Component::getBuddyCapsInfo() { - return m_discoInfoResponder->getBuddyCapsInfo(); -} - -void Component::setBuddyFeatures(std::list &features) { - // TODO: handle caps change - m_discoInfoResponder->setBuddyFeatures(features); -} - void Component::start() { if (m_component && !m_component->isAvailable()) { LOG4CXX_INFO(logger, "Connecting XMPP server " << CONFIG_STRING(m_config, "service.server") << " port " << CONFIG_INT(m_config, "service.port")); diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 98c75dcf..a24161f2 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -26,6 +26,7 @@ #include "transport/rostermanager.h" #include "transport/userregistry.h" #include "transport/logging.h" +#include "transport/discoitemsresponder.h" #include "storageresponder.h" #include "Swiften/Swiften.h" @@ -40,7 +41,7 @@ namespace Transport { DEFINE_LOGGER(logger, "UserManager"); -UserManager::UserManager(Component *component, UserRegistry *userRegistry, StorageBackend *storageBackend) { +UserManager::UserManager(Component *component, UserRegistry *userRegistry, DiscoItemsResponder *discoItemsResponder, StorageBackend *storageBackend) { m_cachedUser = NULL; m_onlineBuddies = 0; m_sentToXMPP = 0; @@ -49,6 +50,7 @@ UserManager::UserManager(Component *component, UserRegistry *userRegistry, Stora m_storageBackend = storageBackend; m_storageResponder = NULL; m_userRegistry = userRegistry; + m_discoItemsResponder = discoItemsResponder; if (m_storageBackend) { m_storageResponder = new StorageResponder(component->getIQRouter(), m_storageBackend, this); From b18424c5b128e9cf3cb8c99705c7cc3302e8d4cb Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 18 Oct 2012 09:33:44 +0200 Subject: [PATCH 15/61] Forward message timestamps --- backends/libpurple/main.cpp | 11 +++++++++-- include/transport/networkplugin.h | 2 +- include/transport/protocol.proto | 1 + plugin/cpp/networkplugin.cpp | 3 ++- spectrum/src/sample.cfg | 6 +++--- src/networkpluginserver.cpp | 5 +++++ 6 files changed, 21 insertions(+), 7 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 1c3f8c48..06df61ee 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -933,14 +933,21 @@ static void conv_write_im(PurpleConversation *conv, const char *who, const char xhtml_ = ""; } + std::string timestamp; + if (mtime && (unsigned long) time(NULL)-10 > (unsigned long) mtime/* && (unsigned long) time(NULL) - 31536000 < (unsigned long) mtime*/) { + char buf[80]; + strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", gmtime(&mtime)); + timestamp = buf; + } + // LOG4CXX_INFO(logger, "Received message body='" << message_ << "' xhtml='" << xhtml_ << "'"); if (purple_conversation_get_type_wrapped(conv) == PURPLE_CONV_TYPE_IM) { - np->handleMessage(np->m_accounts[account], w, message_, "", xhtml_); + np->handleMessage(np->m_accounts[account], w, message_, "", xhtml_, timestamp); } else { LOG4CXX_INFO(logger, "Received message body='" << message_ << "' name='" << purple_conversation_get_name_wrapped(conv) << "' " << w); - np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, w, xhtml_); + np->handleMessage(np->m_accounts[account], purple_conversation_get_name_wrapped(conv), message_, w, xhtml_, timestamp); } } diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 3d5c87da..6c4ababd 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -110,7 +110,7 @@ class NetworkPlugin { /// \param message Plain text message. /// \param nickname Nickname of buddy in room. Empty if it's normal chat message. /// \param xhtml XHTML message. - void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = ""); + void handleMessage(const std::string &user, const std::string &legacyName, const std::string &message, const std::string &nickname = "", const std::string &xhtml = "", const std::string ×tamp = ""); /// Call this function when subject in room changed. /// \param user XMPP JID of user for which this event occurs. You can get it from NetworkPlugin::handleLoginRequest(). (eg. "user%gmail.com@xmpp.domain.tld") diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index de423598..4475b707 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -69,6 +69,7 @@ message ConversationMessage { required string message = 3; optional string nickname = 4; optional string xhtml = 5; + optional string timestamp = 6; } message Room { diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index fccd33f3..b5622326 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -82,13 +82,14 @@ void NetworkPlugin::sendConfig(const PluginConfig &cfg) { send(message); } -void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml) { +void NetworkPlugin::handleMessage(const std::string &user, const std::string &legacyName, const std::string &msg, const std::string &nickname, const std::string &xhtml, const std::string ×tamp) { pbnetwork::ConversationMessage m; m.set_username(user); m.set_buddyname(legacyName); m.set_message(msg); m.set_nickname(nickname); m.set_xhtml(xhtml); + m.set_timestamp(timestamp); std::string message; m.SerializeToString(&message); diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 361ee530..2e412b69 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,10 +13,10 @@ 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/twitter/spectrum2_twitter_backend -backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend -protocol=prpl-icq +#backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend +protocol=prpl-jabber #protocol=prpl-msn #protocol=any #protocol=prpl-icq diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 177469f8..6849a023 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -628,6 +628,11 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool msg->addPayload(boost::make_shared(payload.xhtml())); } + if (!payload.timestamp().empty()) { + boost::posix_time::ptime timestamp = boost::posix_time::from_iso_string(payload.timestamp()); + msg->addPayload(boost::make_shared(timestamp)); + } + // Create new Conversation if it does not exist NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname()); if (!conv) { From abc5b11ca563b762f62a34258bdf7f075c785e02 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Thu, 18 Oct 2012 10:40:47 +0200 Subject: [PATCH 16/61] Do not dumpReceived() --- src/tests/discoitemsresponder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/discoitemsresponder.cpp b/src/tests/discoitemsresponder.cpp index 6032cacb..dfdf3619 100644 --- a/src/tests/discoitemsresponder.cpp +++ b/src/tests/discoitemsresponder.cpp @@ -68,7 +68,6 @@ class DiscoItemsResponderTest : public CPPUNIT_NS :: TestFixture, public BasicTe injectIQ(iq); loop->processEvents(); - dumpReceived(); CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); From 9a15e789edecd393b917f7ffce6549e2eb1c285a Mon Sep 17 00:00:00 2001 From: HanzZ Date: Mon, 22 Oct 2012 11:52:53 +0200 Subject: [PATCH 17/61] check if server started in spectrum2_manager --- spectrum_manager/src/main.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spectrum_manager/src/main.cpp b/spectrum_manager/src/main.cpp index 636172a6..94d29345 100644 --- a/spectrum_manager/src/main.cpp +++ b/spectrum_manager/src/main.cpp @@ -139,7 +139,10 @@ int main(int argc, char **argv) } else if (command[0] == "server") { Server server(&config); - server.start(); + if (server.start() == false) { + std::cerr << "Can't set up server handler.\n"; + return 1; + } while (1) { sleep(10); } } else { From 3720df9cbef999373e1388c7d7e92f396dbabaaf Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 22 Oct 2012 12:26:44 +0200 Subject: [PATCH 18/61] Fixed Twitter backend --- backends/twitter/main.cpp | 61 +++++++-------------------------------- 1 file changed, 10 insertions(+), 51 deletions(-) diff --git a/backends/twitter/main.cpp b/backends/twitter/main.cpp index b3404d82..5cbf2def 100644 --- a/backends/twitter/main.cpp +++ b/backends/twitter/main.cpp @@ -27,58 +27,17 @@ int main (int argc, char* argv[]) { return -1; } - std::string configFile; - boost::program_options::variables_map vm; - boost::program_options::options_description desc("Usage: spectrum \nAllowed options"); - desc.add_options() - ("help", "help") - ("host,h", boost::program_options::value(&host)->default_value(""), "Host to connect to") - ("port,p", boost::program_options::value(&port)->default_value(10000), "Port to connect to") - ("config", boost::program_options::value(&configFile)->default_value(""), "Config file") - ; - - try - { - boost::program_options::positional_options_description p; - p.add("config", -1); - boost::program_options::store(boost::program_options::command_line_parser(argc, argv). - options(desc).positional(p).allow_unregistered().run(), vm); - boost::program_options::notify(vm); - - if(vm.count("help")) - { - std::cout << desc << "\n"; - return 1; - } - - if(vm.count("config") == 0) { - std::cout << desc << "\n"; - return 1; - } - } - catch (std::runtime_error& e) - { - std::cout << desc << "\n"; - return 1; - } - catch (...) - { - std::cout << desc << "\n"; - return 1; - } - - Config config(argc, argv); - if (!config.load(configFile)) { - std::cerr << "Can't open " << argv[1] << " configuration file.\n"; - return 1; - } - - Logging::initBackendLogging(&config); - std::string error; + Config *cfg = Config::createFromArgs(argc, argv, error, host, port); + if (cfg == NULL) { + std::cerr << error; + return 1; + } + + Logging::initBackendLogging(cfg); + StorageBackend *storagebackend; - - storagebackend = StorageBackend::createBackend(&config, error); + storagebackend = StorageBackend::createBackend(cfg, error); if (storagebackend == NULL) { LOG4CXX_ERROR(logger, "Error creating StorageBackend! " << error) return -2; @@ -91,7 +50,7 @@ int main (int argc, char* argv[]) { Swift::SimpleEventLoop eventLoop; loop_ = &eventLoop; - np = new TwitterPlugin(&config, &eventLoop, storagebackend, host, port); + np = new TwitterPlugin(cfg, &eventLoop, storagebackend, host, port); loop_->run(); return 0; From 38f907aa6e085e8b467a069d13e79b20597abca9 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 22 Oct 2012 15:05:17 +0200 Subject: [PATCH 19/61] Log mongoose error --- spectrum_manager/src/server.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spectrum_manager/src/server.cpp b/spectrum_manager/src/server.cpp index cc86e927..510fb3a4 100644 --- a/spectrum_manager/src/server.cpp +++ b/spectrum_manager/src/server.cpp @@ -149,7 +149,9 @@ Server::Server(ManagerConfig *config) { } Server::~Server() { - mg_stop(ctx); + if (ctx) { + mg_stop(ctx); + } } @@ -446,7 +448,12 @@ void *Server::event_handler(enum mg_event event, struct mg_connection *conn) { // try to serve the request. processed = NULL; } - } else { + } + else if (event == MG_EVENT_LOG) { + // Called by Mongoose's cry() + std::cerr << "Mongoose error: " << request_info->log_message << "\n"; + } + else { processed = NULL; } From 581217137292397d39d81ab074c8895887e4ccf5 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 22 Oct 2012 17:20:47 +0200 Subject: [PATCH 20/61] Do not create conversation when the message contain nickname, because that means the conversation should be MUC, but user didn't connect to that room yet --- src/networkpluginserver.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 6849a023..ea809858 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -633,8 +633,16 @@ void NetworkPluginServer::handleConvMessagePayload(const std::string &data, bool msg->addPayload(boost::make_shared(timestamp)); } - // Create new Conversation if it does not exist + NetworkConversation *conv = (NetworkConversation *) user->getConversationManager()->getConversation(payload.buddyname()); + + // We can't create Conversation for payload with nickname, because this means the message is from room, + // but this user is not in any room, so it's OK to just reject this message + if (!conv && !payload.nickname().empty()) { + return; + } + + // Create new Conversation if it does not exist if (!conv) { conv = new NetworkConversation(user->getConversationManager(), payload.buddyname()); user->getConversationManager()->addConversation(conv); From 8f7a62c72706c4931545ecb5355367220dbbd8a3 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 23 Oct 2012 11:28:54 +0200 Subject: [PATCH 21/61] Fix crash when data for unknown filetransfer has been received --- src/networkpluginserver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index ea809858..58789709 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -763,6 +763,11 @@ void NetworkPluginServer::handleFTDataPayload(Backend *b, const std::string &dat // if (!user) // return; + if (m_filetransfers.find(payload.ftid()) == m_filetransfers.end()) { + LOG4CXX_ERROR(logger, "Uknown filetransfer with id " << payload.ftid()); + return; + } + FileTransferManager::Transfer &transfer = m_filetransfers[payload.ftid()]; MemoryReadBytestream *bytestream = (MemoryReadBytestream *) transfer.readByteStream.get(); From 4055180802abda864fc07ab593fe524ea66fbfd5 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 23 Oct 2012 18:27:04 +0200 Subject: [PATCH 22/61] Send subscribe/subscribed presence from transport contact when connecting --- backends/libpurple/utils.cpp | 2 +- src/tests/basictest.cpp | 2 ++ src/tests/usermanager.cpp | 10 +++++++++- src/usermanager.cpp | 29 +++++++++++++++++++++++++---- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/backends/libpurple/utils.cpp b/backends/libpurple/utils.cpp index 4857f37c..c375421e 100644 --- a/backends/libpurple/utils.cpp +++ b/backends/libpurple/utils.cpp @@ -155,7 +155,7 @@ int create_socket(const char *host, int portno) { stSockAddr.sin_family = AF_INET; stSockAddr.sin_port = htons(portno); - bcopy(hos->h_addr, &(stSockAddr.sin_addr.s_addr), hos->h_length); + memcpy(&(stSockAddr.sin_addr.s_addr), hos->h_addr, hos->h_length); if (-1 == connect(SocketFD, (struct sockaddr *)&stSockAddr, sizeof(stSockAddr))) { close(SocketFD); diff --git a/src/tests/basictest.cpp b/src/tests/basictest.cpp index 7c3ef14c..1c0b2eed 100644 --- a/src/tests/basictest.cpp +++ b/src/tests/basictest.cpp @@ -202,6 +202,7 @@ void BasicTest::connectUser() { CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + received.clear(); receivedData.clear(); } @@ -236,6 +237,7 @@ void BasicTest::connectSecondResource() { } void BasicTest::disconnectUser() { + received.clear(); userManager->disconnectUser("user@localhost"); dynamic_cast(factories->getTimerFactory())->setTime(10); loop->processEvents(); diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index 1f03575d..a0adceff 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -79,12 +79,20 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); loop->processEvents(); - CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); Swift::Presence *presence = dynamic_cast(getStanza(received[1])); CPPUNIT_ASSERT(presence); CPPUNIT_ASSERT_EQUAL(Swift::Presence::Unavailable, presence->getType()); + + presence = dynamic_cast(getStanza(received[2])); + CPPUNIT_ASSERT(presence); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, presence->getType()); + + presence = dynamic_cast(getStanza(received[3])); + CPPUNIT_ASSERT(presence); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribed, presence->getType()); } void connectTwoResources() { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index a24161f2..20247ba8 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -184,14 +184,33 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { } } + UserInfo res; + bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false; + // No user and unavailable presence -> answer with unavailable - if (presence->getType() == Swift::Presence::Unavailable) { + if (presence->getType() == Swift::Presence::Unavailable || presence->getType() == Swift::Presence::Probe) { Swift::Presence::ref response = Swift::Presence::create(); response->setTo(presence->getFrom()); response->setFrom(presence->getTo()); response->setType(Swift::Presence::Unavailable); m_component->getStanzaChannel()->sendPresence(response); + // bother him with subscribe presence, just to be + // sure he is subscribed to us. + if (/*registered && */presence->getType() == Swift::Presence::Probe) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(presence->getFrom()); + response->setFrom(presence->getTo()); + response->setType(Swift::Presence::Subscribe); + m_component->getStanzaChannel()->sendPresence(response); + + response = Swift::Presence::create(); + response->setTo(presence->getFrom()); + response->setFrom(presence->getTo()); + response->setType(Swift::Presence::Subscribed); + m_component->getStanzaChannel()->sendPresence(response); + } + // Set user offline in database if (m_storageBackend) { UserInfo res; @@ -203,9 +222,6 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { return; } - UserInfo res; - bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false; - // In server mode, we don't need registration normally, but for networks like IRC // or Twitter where there's no real authorization using password, we have to force // registration otherwise some data (like bookmarked rooms) could leak. @@ -378,6 +394,11 @@ void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) { } void UserManager::handleProbePresence(Swift::Presence::ref presence) { + // Don't let RosterManager to handle presences for us + if (presence->getTo().getNode().empty()) { + return; + } + User *user = getUser(presence->getFrom().toBare().toString()); if (user) { From 353588c406a6cdfd8b0966236e4a6c53526af7fe Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 24 Oct 2012 10:53:26 +0200 Subject: [PATCH 23/61] Try to join the rooms after every reconnect, not only after first one --- include/transport/conversationmanager.h | 2 ++ include/transport/user.h | 4 +-- src/conversationmanager.cpp | 9 +++++ src/tests/user.cpp | 22 +++++++++--- src/user.cpp | 45 ++++++++++++++++++------- 5 files changed, 63 insertions(+), 19 deletions(-) diff --git a/include/transport/conversationmanager.h b/include/transport/conversationmanager.h index 016914c8..865736b2 100644 --- a/include/transport/conversationmanager.h +++ b/include/transport/conversationmanager.h @@ -69,6 +69,8 @@ class ConversationManager { /// \param conv Conversation. void removeConversation(Conversation *conv); + void deleteAllConversations(); + void resetResources(); void removeJID(const Swift::JID &jid); diff --git a/include/transport/user.h b/include/transport/user.h index 47a1206c..1719b13d 100644 --- a/include/transport/user.h +++ b/include/transport/user.h @@ -78,7 +78,7 @@ class User : public Swift::EntityCapsProvider { /// Handles presence from XMPP JID associated with this user. /// \param presence Swift::Presence. - void handlePresence(Swift::Presence::ref presence); + void handlePresence(Swift::Presence::ref presence, bool forceJoin = false); void handleSubscription(Swift::Presence::ref presence); @@ -144,7 +144,7 @@ class User : public Swift::EntityCapsProvider { std::vector > m_filetransfers; int m_resources; int m_reconnectCounter; - std::vector m_joinedRooms; + std::list m_joinedRooms; }; } diff --git a/src/conversationmanager.cpp b/src/conversationmanager.cpp index 4fc23afc..066a4603 100644 --- a/src/conversationmanager.cpp +++ b/src/conversationmanager.cpp @@ -47,6 +47,15 @@ ConversationManager::~ConversationManager() { } } +void ConversationManager::deleteAllConversations() { + while(!m_convs.empty()) { + LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Removing conversation " << (*m_convs.begin()).first); + (*m_convs.begin()).second->destroyRoom(); + delete (*m_convs.begin()).second; + m_convs.erase(m_convs.begin()); + } +} + Conversation *ConversationManager::getConversation(const std::string &name) { if (m_convs.find(name) != m_convs.end()) return m_convs[name]; diff --git a/src/tests/user.cpp b/src/tests/user.cpp index 84914b6e..054cc100 100644 --- a/src/tests/user.cpp +++ b/src/tests/user.cpp @@ -33,6 +33,7 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(joinRoomBeforeConnected); CPPUNIT_TEST(handleDisconnected); CPPUNIT_TEST(handleDisconnectedReconnect); + CPPUNIT_TEST(joinRoomHandleDisconnectedRejoin); CPPUNIT_TEST_SUITE_END(); public: @@ -319,6 +320,12 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { user = userManager->getUser("user@localhost"); CPPUNIT_ASSERT(user); CPPUNIT_ASSERT(readyToConnect); + + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost/resource"); + injectPresence(response); + loop->processEvents(); } void joinRoomBeforeConnected() { @@ -347,15 +354,22 @@ class UserTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); + } + void joinRoomHandleDisconnectedRejoin() { + User *user = userManager->getUser("user@localhost"); + handlePresenceJoinRoom(); + handleDisconnectedReconnect(); room = ""; roomNickname = ""; roomPassword = ""; - + received.clear(); user->setConnected(true); - CPPUNIT_ASSERT_EQUAL(std::string(""), room); - CPPUNIT_ASSERT_EQUAL(std::string(""), roomNickname); - CPPUNIT_ASSERT_EQUAL(std::string(""), roomPassword); + + CPPUNIT_ASSERT_EQUAL(std::string("#room"), room); + CPPUNIT_ASSERT_EQUAL(std::string("hanzz"), roomNickname); + CPPUNIT_ASSERT_EQUAL(std::string("password"), roomPassword); + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); } }; diff --git a/src/user.cpp b/src/user.cpp index cf0b2f1c..558138a2 100644 --- a/src/user.cpp +++ b/src/user.cpp @@ -179,18 +179,18 @@ void User::setConnected(bool connected) { if (m_connected) { BOOST_FOREACH(Swift::Presence::ref &presence, m_joinedRooms) { - handlePresence(presence); + handlePresence(presence, true); } - m_joinedRooms.clear(); } } -void User::handlePresence(Swift::Presence::ref presence) { +void User::handlePresence(Swift::Presence::ref presence, bool forceJoin) { int currentResourcesCount = m_presenceOracle->getAllPresence(m_jid).size(); m_conversationManager->resetResources(); + LOG4CXX_INFO(logger, "PRESENCE " << presence->getFrom().toString() << " " << presence->getTo().toString()); if (!m_connected) { // we are not connected to legacy network, so we should do it when disco#info arrive :) if (m_readyForConnect == false) { @@ -236,6 +236,13 @@ void User::handlePresence(Swift::Presence::ref presence) { LOG4CXX_INFO(logger, m_jid.toString() << ": Going to left room " << room); onRoomLeft(room); + BOOST_FOREACH(Swift::Presence::ref &p, m_joinedRooms) { + if (p->getTo() == presence->getTo()) { + m_joinedRooms.remove(p); + break; + } + } + if (conv) { m_conversationManager->removeConversation(conv); delete conv; @@ -250,14 +257,11 @@ void User::handlePresence(Swift::Presence::ref presence) { } std::string room = Buddy::JIDToLegacyName(presence->getTo()); - - if (!m_connected) { - LOG4CXX_INFO(logger, m_jid.toString() << ": Joining room " << room << " postponed, because use is not connected to legacy network yet."); - m_joinedRooms.push_back(presence); - return; + std::string password = ""; + if (presence->getPayload() != NULL) { + password = presence->getPayload()->getPassword() ? *presence->getPayload()->getPassword() : ""; } - Conversation *conv = m_conversationManager->getConversation(room); if (conv != NULL) { if (std::find(conv->getJIDs().begin(), conv->getJIDs().end(), presence->getFrom()) != conv->getJIDs().end()) { @@ -267,14 +271,29 @@ void User::handlePresence(Swift::Presence::ref presence) { conv->addJID(presence->getFrom()); conv->sendParticipants(presence->getFrom()); } + + if (forceJoin) { + onRoomJoined(presence->getFrom(), room, presence->getTo().getResource(), password); + } + return; + } + + bool isInJoined = false; + BOOST_FOREACH(Swift::Presence::ref &p, m_joinedRooms) { + if (p->getTo() == presence->getTo()) { + isInJoined = true; + } + } + if (!isInJoined) { + m_joinedRooms.push_back(presence); + } + + if (!m_connected) { + LOG4CXX_INFO(logger, m_jid.toString() << ": Joining room " << room << " postponed, because use is not connected to legacy network yet."); return; } LOG4CXX_INFO(logger, m_jid.toString() << ": Going to join room " << room << " as " << presence->getTo().getResource()); - std::string password = ""; - if (presence->getPayload() != NULL) { - password = presence->getPayload()->getPassword() ? *presence->getPayload()->getPassword() : ""; - } conv = m_component->getFactory()->createConversation(m_conversationManager, room, true); m_conversationManager->addConversation(conv); From 3ec3ef32b3366c18005277c216d175a144edc477 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 24 Oct 2012 12:33:15 +0200 Subject: [PATCH 24/61] Way to run particular unit tests instead of all tests --- src/tests/main.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/tests/main.cpp b/src/tests/main.cpp index aea740f0..218d66fb 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -22,6 +22,16 @@ int main (int argc, char* argv[]) root->addAppender(new FileAppender(new PatternLayout("%d %-5p %c: %m%n"), "libtransport_test.log", false)); #endif + std::vector testsToRun; + for (int i = 1; i < argc; ++i) { + std::string param(argv[i]); + testsToRun.push_back(param); + } + + if (testsToRun.empty()) { + testsToRun.push_back(""); + } + // informs test-listener about testresults CPPUNIT_NS :: TestResult testresult; @@ -36,7 +46,15 @@ int main (int argc, char* argv[]) // insert test-suite at test-runner by registry CPPUNIT_NS :: TestRunner testrunner; testrunner.addTest (CPPUNIT_NS :: TestFactoryRegistry :: getRegistry ().makeTest ()); - testrunner.run (testresult); + for (std::vector::const_iterator i = testsToRun.begin(); i != testsToRun.end(); ++i) { + try { + testrunner.run(testresult, *i); + } + catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return -1; + } + } // output results in compiler-format CPPUNIT_NS :: CompilerOutputter compileroutputter (&collectedresults, std::cerr); From b816395870e130ffed25a90d641966a1f1da89d1 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 26 Oct 2012 11:59:28 +0200 Subject: [PATCH 25/61] Reconnect automatically in case of swiften backend errors --- backends/swiften/main.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/backends/swiften/main.cpp b/backends/swiften/main.cpp index 6d7340d3..6db0d86c 100644 --- a/backends/swiften/main.cpp +++ b/backends/swiften/main.cpp @@ -63,14 +63,15 @@ class SwiftenPlugin : public NetworkPlugin { void handleSwiftDisconnected(const std::string &user, const boost::optional &error) { std::string message = ""; + bool reconnect = false; if (error) { switch(error->getType()) { - case Swift::ClientError::UnknownError: message = ("Unknown Error"); break; + case Swift::ClientError::UnknownError: message = ("Unknown Error"); reconnect = true; break; case Swift::ClientError::DomainNameResolveError: message = ("Unable to find server"); break; case Swift::ClientError::ConnectionError: message = ("Error connecting to server"); break; - case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); break; - case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); break; - case Swift::ClientError::XMLError: message = ("Error parsing server data"); break; + case Swift::ClientError::ConnectionReadError: message = ("Error while receiving server data"); reconnect = true; break; + case Swift::ClientError::ConnectionWriteError: message = ("Error while sending data to the server"); reconnect = true; break; + case Swift::ClientError::XMLError: message = ("Error parsing server data"); reconnect = true; break; case Swift::ClientError::AuthenticationFailedError: message = ("Login/password invalid"); break; case Swift::ClientError::CompressionFailedError: message = ("Error while compressing stream"); break; case Swift::ClientError::ServerVerificationFailedError: message = ("Server verification failed"); break; @@ -97,7 +98,7 @@ class SwiftenPlugin : public NetworkPlugin { } } LOG4CXX_INFO(logger, user << ": Disconnected " << message); - handleDisconnected(user, 3, message); + handleDisconnected(user, reconnect ? 0 : 3, message); boost::shared_ptr client = m_users[user]; if (client) { From bff95a3f7a98cc14768b911699e42314fb0b7c46 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 27 Oct 2012 16:21:25 +0200 Subject: [PATCH 26/61] Call IrcCommand::createList with two arguments --- backends/libcommuni/session.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 7b86f99f..91a7fee8 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -43,7 +43,7 @@ void MyIrcSession::on_connected() { if (suffix.empty()) { np->handleConnected(user); if (!sentList) { - sendCommand(IrcCommand::createList("")); + sendCommand(IrcCommand::createList("", "")); sentList = true; } } From 5257bb4304f98e788d39f87ad4f7e2b3768459ca Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sun, 28 Oct 2012 10:04:39 +0100 Subject: [PATCH 27/61] Fixed debian docs --- docs/guide/debian_ubuntu.textile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/debian_ubuntu.textile b/docs/guide/debian_ubuntu.textile index eff14e2c..d034dec0 100644 --- a/docs/guide/debian_ubuntu.textile +++ b/docs/guide/debian_ubuntu.textile @@ -33,7 +33,7 @@ h2. Install spectrum2 - development version After you have done that, simply do:
-apt-get install spectrum2-git spectrum2-backend-libpurple-git
+apt-get install spectrum2 spectrum2-backend-libpurple
 
Note that these repositories pull in quite a few dependencies, depending on the distribution you use. From df32761194980e555aec7d58ca3f5049dc6e3d39 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Mon, 29 Oct 2012 14:08:54 +0100 Subject: [PATCH 28/61] Added support for service.jid_escaping config --- include/transport/networkpluginserver.h | 5 +- spectrum/src/main.cpp | 1 + src/CMakeLists.txt | 1 + src/config.cpp | 1 + src/conversation.cpp | 12 +++- src/networkpluginserver.cpp | 66 +++++++++-------- src/tests/conversationmanager.cpp | 18 +++-- src/tests/localbuddy.cpp | 15 ++++ src/tests/networkpluginserver.cpp | 95 +++++++++++++++++++++++++ src/userregistration.cpp | 10 ++- 10 files changed, 188 insertions(+), 36 deletions(-) create mode 100644 src/tests/networkpluginserver.cpp diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 3aef279d..b0d742b8 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -65,6 +65,8 @@ class NetworkPluginServer { virtual ~NetworkPluginServer(); + void start(); + void setAdminInterface(AdminInterface *adminInterface) { m_adminInterface = adminInterface; } @@ -87,7 +89,7 @@ class NetworkPluginServer { void handleMessageReceived(NetworkConversation *conv, boost::shared_ptr &message); - private: + public: void handleNewClientConnection(boost::shared_ptr c); void handleSessionFinished(Backend *c); void handlePongReceived(Backend *c); @@ -133,6 +135,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); + private: void send(boost::shared_ptr &, const std::string &data); void pingTimeout(); diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 587df261..962b9d60 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -402,6 +402,7 @@ int main(int argc, char **argv) FileTransferManager ftManager(&transport, &userManager); NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder); + plugin.start(); AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); plugin.setAdminInterface(&adminInterface); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6c815564..27fbfae7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,6 +15,7 @@ if (CPPUNIT_FOUND) FILE(GLOB SRC_TEST tests/*.cpp) ADD_EXECUTABLE(libtransport_test ${SRC_TEST}) + set_target_properties(libtransport_test PROPERTIES COMPILE_DEFINITIONS LIBTRANSPORT_TEST=1) target_link_libraries(libtransport_test transport ${CPPUNIT_LIBRARY} ${Boost_LIBRARIES}) endif() diff --git a/src/config.cpp b/src/config.cpp index cda6af24..5e134db0 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -98,6 +98,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("service.enable_privacy_lists", value()->default_value(true), "") ("service.enable_xhtml", value()->default_value(true), "") ("service.max_room_list_size", value()->default_value(100), "") + ("service.jid_escaping", value()->default_value(true), "") ("vhosts.vhost", value >()->multitoken(), "") ("identity.name", value()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.") ("identity.category", value()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.") diff --git a/src/conversation.cpp b/src/conversation.cpp index f6105461..67a5c386 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -91,7 +91,17 @@ void Conversation::handleMessage(boost::shared_ptr &message, con message->setFrom(buddy->getJID()); } else { - message->setFrom(Swift::JID(Swift::JID::getEscapedNode(m_legacyName), m_conversationManager->getComponent()->getJID().toBare())); + std::string name = m_legacyName; + if (CONFIG_BOOL_DEFAULTED(m_conversationManager->getComponent()->getConfig(), "service.jid_escaping", true)) { + name = Swift::JID::getEscapedNode(m_legacyName); + } + else { + if (name.find_last_of("@") != std::string::npos) { + name.replace(name.find_last_of("@"), 1, "%"); + } + } + + message->setFrom(Swift::JID(name, m_conversationManager->getComponent()->getJID().toBare(), "bot")); } } // PM message diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 58789709..51c4aded 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -285,6 +285,30 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U m_server = component->getNetworkFactories()->getConnectionServerFactory()->createConnectionServer(Swift::HostAddress(CONFIG_STRING(m_config, "service.backend_host")), boost::lexical_cast(CONFIG_STRING(m_config, "service.backend_port"))); m_server->onNewConnection.connect(boost::bind(&NetworkPluginServer::handleNewClientConnection, this, _1)); +} + +NetworkPluginServer::~NetworkPluginServer() { + for (std::list::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) { + LOG4CXX_INFO(logger, "Stopping backend " << *it); + std::string message; + pbnetwork::WrapperMessage wrap; + wrap.set_type(pbnetwork::WrapperMessage_Type_TYPE_EXIT); + wrap.SerializeToString(&message); + + Backend *c = (Backend *) *it; + send(c->connection, message); + } + + m_pingTimer->stop(); + m_server->stop(); + m_server.reset(); + delete m_component->m_factory; + delete m_vcardResponder; + delete m_rosterResponder; + delete m_blockResponder; +} + +void NetworkPluginServer::start() { m_server->start(); LOG4CXX_INFO(logger, "Listening on host " << CONFIG_STRING(m_config, "service.backend_host") << " port " << CONFIG_STRING(m_config, "service.backend_port")); @@ -318,28 +342,6 @@ NetworkPluginServer::NetworkPluginServer(Component *component, Config *config, U // quit the while loop break; } - -} - -NetworkPluginServer::~NetworkPluginServer() { - for (std::list::const_iterator it = m_clients.begin(); it != m_clients.end(); it++) { - LOG4CXX_INFO(logger, "Stopping backend " << *it); - std::string message; - pbnetwork::WrapperMessage wrap; - wrap.set_type(pbnetwork::WrapperMessage_Type_TYPE_EXIT); - wrap.SerializeToString(&message); - - Backend *c = (Backend *) *it; - send(c->connection, message); - } - - m_pingTimer->stop(); - m_server->stop(); - m_server.reset(); - delete m_component->m_factory; - delete m_vcardResponder; - delete m_rosterResponder; - delete m_blockResponder; } void NetworkPluginServer::handleNewClientConnection(boost::shared_ptr c) { @@ -479,11 +481,14 @@ void NetworkPluginServer::handleAuthorizationPayload(const std::string &data) { response->setTo(user->getJID()); std::string name = payload.buddyname(); - name = Swift::JID::getEscapedNode(name); - -// if (name.find_last_of("@") != std::string::npos) { // OK when commented -// name.replace(name.find_last_of("@"), 1, "%"); // OK when commented -// } + if (CONFIG_BOOL_DEFAULTED(m_config, "service.jid_escaping", true)) { + name = Swift::JID::getEscapedNode(name); + } + else { + if (name.find_last_of("@") != std::string::npos) { + name.replace(name.find_last_of("@"), 1, "%"); + } + } response->setFrom(Swift::JID(name, m_component->getJID().toString())); response->setType(Swift::Presence::Subscribe); @@ -536,7 +541,12 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { for (int i = 0; i < payload.group_size(); i++) { groups.push_back(payload.group(i)); } - buddy = new LocalBuddy(user->getRosterManager(), -1, payload.buddyname(), payload.alias(), groups, BUDDY_JID_ESCAPING); + if (CONFIG_BOOL_DEFAULTED(m_config, "service.jid_escaping", true)) { + buddy = new LocalBuddy(user->getRosterManager(), -1, payload.buddyname(), payload.alias(), groups, BUDDY_JID_ESCAPING); + } + else { + buddy = new LocalBuddy(user->getRosterManager(), -1, payload.buddyname(), payload.alias(), groups, BUDDY_NO_FLAG); + } if (!buddy->isValid()) { delete buddy; return; diff --git a/src/tests/conversationmanager.cpp b/src/tests/conversationmanager.cpp index 9aa739fa..ef31975d 100644 --- a/src/tests/conversationmanager.cpp +++ b/src/tests/conversationmanager.cpp @@ -127,7 +127,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe void handleNormalMessages() { User *user = userManager->getUser("user@localhost"); - TestingConversation *conv = new TestingConversation(user->getConversationManager(), "buddy1"); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "buddy1@test"); user->getConversationManager()->addConversation(conv); conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); @@ -142,13 +142,13 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[0]))->getBody()); CPPUNIT_ASSERT_EQUAL(std::string("user@localhost"), dynamic_cast(getStanza(received[0]))->getTo().toString()); - CPPUNIT_ASSERT_EQUAL(std::string("buddy1@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40test@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); received.clear(); // send response msg->setFrom("user@localhost/resource"); - msg->setTo("buddy1@localhost/bot"); + msg->setTo("buddy1\\40test@localhost/bot"); msg->setBody("response!"); injectMessage(msg); loop->processEvents(); @@ -169,20 +169,28 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[0]))->getBody()); CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[0]))->getTo().toString()); - CPPUNIT_ASSERT_EQUAL(std::string("buddy1@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40test@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); received.clear(); + // disable jid_escaping + std::istringstream ifs("service.server_mode = 1\nservice.jid_escaping=0\nservice.jid=localhost\nservice.more_resources=1\n"); + cfg->load(ifs); + // and now to bare JID again... user->getConversationManager()->resetResources(); conv->handleMessage(msg2); loop->processEvents(); + + // enable jid_escaping again + std::istringstream ifs2("service.server_mode = 1\nservice.jid_escaping=1\nservice.jid=localhost\nservice.more_resources=1\n"); + cfg->load(ifs2); CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[0]))->getBody()); CPPUNIT_ASSERT_EQUAL(std::string("user@localhost"), dynamic_cast(getStanza(received[0]))->getTo().toString()); - CPPUNIT_ASSERT_EQUAL(std::string("buddy1@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("buddy1%test@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); received.clear(); } diff --git a/src/tests/localbuddy.cpp b/src/tests/localbuddy.cpp index fdc6fb87..3a0ee795 100644 --- a/src/tests/localbuddy.cpp +++ b/src/tests/localbuddy.cpp @@ -25,6 +25,7 @@ class LocalBuddyTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(createWithInvalidName); CPPUNIT_TEST(buddyFlagsFromJID); CPPUNIT_TEST(JIDToLegacyName); + CPPUNIT_TEST(getSafeName); CPPUNIT_TEST(handleBuddyChanged); CPPUNIT_TEST(setAlias); CPPUNIT_TEST_SUITE_END(); @@ -70,6 +71,20 @@ class LocalBuddyTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT_EQUAL(std::string("hanzz@test"), Buddy::JIDToLegacyName("hanzz%test@localhost/bot")); } + void getSafeName() { + User *user = userManager->getUser("user@localhost"); + CPPUNIT_ASSERT(user); + + std::vector grp; + grp.push_back("group1"); + LocalBuddy *buddy = new LocalBuddy(user->getRosterManager(), -1, "buddy1@test", "Buddy 1", grp, BUDDY_JID_ESCAPING); + + CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40test"), buddy->getSafeName()); + + buddy->setFlags(BUDDY_NO_FLAG); + CPPUNIT_ASSERT_EQUAL(std::string("buddy1%test"), buddy->getSafeName()); + } + void buddyFlagsFromJID() { CPPUNIT_ASSERT_EQUAL(BUDDY_JID_ESCAPING, Buddy::buddyFlagsFromJID("hanzz\\40test@localhost/bot")); CPPUNIT_ASSERT_EQUAL(BUDDY_NO_FLAG, Buddy::buddyFlagsFromJID("hanzz%test@localhost/bot")); diff --git a/src/tests/networkpluginserver.cpp b/src/tests/networkpluginserver.cpp new file mode 100644 index 00000000..9a9d921c --- /dev/null +++ b/src/tests/networkpluginserver.cpp @@ -0,0 +1,95 @@ +#include "transport/userregistry.h" +#include "transport/userregistration.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include "transport/settingsadhoccommand.h" +#include "transport/adhocmanager.h" +#include "transport/protocol.pb.h" +#include "transport/networkpluginserver.h" +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + +using namespace Transport; + +class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { + CPPUNIT_TEST_SUITE(NetworkPluginServerTest); + CPPUNIT_TEST(handleBuddyChangedPayload); + CPPUNIT_TEST(handleBuddyChangedPayloadNoEscaping); + CPPUNIT_TEST_SUITE_END(); + + public: + NetworkPluginServer *serv; + + void setUp (void) { + setMeUp(); + + serv = new NetworkPluginServer(component, cfg, userManager, NULL, NULL); + connectUser(); + received.clear(); + } + + void tearDown (void) { + received.clear(); + disconnectUser(); + delete serv; + tearMeDown(); + } + + void handleBuddyChangedPayload() { + User *user = userManager->getUser("user@localhost"); + + pbnetwork::Buddy buddy; + buddy.set_username("user@localhost"); + buddy.set_buddyname("buddy1@test"); + + std::string message; + buddy.SerializeToString(&message); + + serv->handleBuddyChangedPayload(message); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload(); + CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size()); + Swift::RosterItemPayload item = payload1->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40test@localhost"), item.getJID().toString()); + } + + void handleBuddyChangedPayloadNoEscaping() { + std::istringstream ifs("service.server_mode = 1\nservice.jid_escaping=0\nservice.jid=localhost\nservice.more_resources=1\n"); + cfg->load(ifs); + User *user = userManager->getUser("user@localhost"); + + pbnetwork::Buddy buddy; + buddy.set_username("user@localhost"); + buddy.set_buddyname("buddy1@test"); + + std::string message; + buddy.SerializeToString(&message); + + serv->handleBuddyChangedPayload(message); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + Swift::RosterPayload::ref payload1 = getStanza(received[0])->getPayload(); + CPPUNIT_ASSERT_EQUAL(1, (int) payload1->getItems().size()); + Swift::RosterItemPayload item = payload1->getItems()[0]; + CPPUNIT_ASSERT_EQUAL(std::string("buddy1%test@localhost"), item.getJID().toString()); + + std::istringstream ifs2("service.server_mode = 1\nservice.jid_escaping=1\nservice.jid=localhost\nservice.more_resources=1\n"); + cfg->load(ifs2); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (NetworkPluginServerTest); diff --git a/src/userregistration.cpp b/src/userregistration.cpp index a13006ca..4160f9e0 100644 --- a/src/userregistration.cpp +++ b/src/userregistration.cpp @@ -94,7 +94,15 @@ void UserRegistration::handleUnregisterRemoteRosterResponse(boost::shared_ptr roster; m_storageBackend->getBuddies(userInfo.id, roster); for(std::list::iterator u = roster.begin(); u != roster.end() ; u++){ - std::string name = Swift::JID::getEscapedNode((*u).legacyName); + std::string name = (*u).legacyName; + if ((*u).flags & BUDDY_JID_ESCAPING) { + name = Swift::JID::getEscapedNode((*u).legacyName); + } + else { + if (name.find_last_of("@") != std::string::npos) { + name.replace(name.find_last_of("@"), 1, "%"); + } + } Swift::Presence::ref response; response = Swift::Presence::create(); From 700ce9918794b4e8d5546b0b503693c5f2d31e83 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 30 Oct 2012 12:09:23 +0100 Subject: [PATCH 29/61] Close all sockets before fork() --- src/networkpluginserver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 51c4aded..28275c63 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -185,6 +185,11 @@ static unsigned long exec_(const std::string& exePath, const char *host, const c pid_t pid = fork(); if ( pid == 0 ) { setsid(); + // close all files + int maxfd=sysconf(_SC_OPEN_MAX); + for(int fd=3; fd Date: Tue, 30 Oct 2012 18:06:29 +0100 Subject: [PATCH 30/61] Do not send subscribed on probe presence. Just subscribe should be enough --- spectrum/src/sample.cfg | 2 +- src/usermanager.cpp | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 2e412b69..d795b60e 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -13,7 +13,7 @@ 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/swiften/spectrum2_swiften_backend #backend=../../backends/twitter/spectrum2_twitter_backend #backend=/home/hanzz/code/libtransport/backends/libcommuni/spectrum2_libcommuni_backend protocol=prpl-jabber diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 20247ba8..64e1d1c3 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -203,12 +203,6 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { response->setFrom(presence->getTo()); response->setType(Swift::Presence::Subscribe); m_component->getStanzaChannel()->sendPresence(response); - - response = Swift::Presence::create(); - response->setTo(presence->getFrom()); - response->setFrom(presence->getTo()); - response->setType(Swift::Presence::Subscribed); - m_component->getStanzaChannel()->sendPresence(response); } // Set user offline in database From 3dc0598886da122488a123e81630960d580bbfb3 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 30 Oct 2012 19:33:13 +0100 Subject: [PATCH 31/61] Logging docs update --- docs/guide/logging.textile | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/guide/logging.textile b/docs/guide/logging.textile index fa1c9640..49052811 100644 --- a/docs/guide/logging.textile +++ b/docs/guide/logging.textile @@ -95,7 +95,7 @@ log4j.additivity.Component.XML=false # Create new RollingFileAppender logger and set the file name log4j.appender.XML=org.apache.log4j.RollingFileAppender -log4j.appender.XML.File=/var/log/spectrum2/${jid}/spectrum2.log +log4j.appender.XML.File=/var/log/spectrum2/${jid}/spectrum2_xml.log # Set MaxFileSize. Log will be rotated automatically when this limit is reached log4j.appender.XML.MaxFileSize=100000KB @@ -107,6 +107,25 @@ log4j.appender.XML.layout=org.apache.log4j.PatternLayout log4j.appender.XML.layout.ConversionPattern=%d %-5p %c: %m%n +h3. Disable XML logging + +
+# We create two rootLoggers:
+#   - "debug" is internal logger used by log4cxx
+#   - "stdout" is name of our ConsoleAppender logger
+log4j.rootLogger=debug, stdout
+
+# Create new ConsoleAppender logger with custom PatternLayout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+
+# Define the output pattern. Characters are mentioned here: http://logging.apache.org/log4cxx/apidocs/classlog4cxx_1_1_pattern_layout.html
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %-5p %c: %m%n
+
+# Disable XML category
+log4j.category.Component.XML = OFF
+
+ h3. Disable logging To disable logging, you still *must have* one logger created (probably the ConsoleAppender), but you can set log4j.threshold = OFF to not log everything later: From 372ee69043f19b4fdddc94d4f1d2ab224c14fbef Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 31 Oct 2012 09:12:33 +0100 Subject: [PATCH 32/61] Create directories with proper owner/group/permissions. Moved StorageBackend related methods from Util into StorageBackend --- include/transport/storagebackend.h | 8 +++ include/transport/util.h | 13 ++--- plugin/cpp/CMakeLists.txt | 1 + spectrum/src/main.cpp | 26 ++++----- src/logging.cpp | 53 ++++++++++------- src/mysqlbackend.cpp | 10 ++-- src/pqxxbackend.cpp | 8 +-- src/sqlite3backend.cpp | 6 +- src/storagebackend.cpp | 54 +++++++++++++++++ src/tests/util.cpp | 5 +- src/util.cpp | 94 +++++++++++++----------------- 11 files changed, 166 insertions(+), 112 deletions(-) diff --git a/include/transport/storagebackend.h b/include/transport/storagebackend.h index 52890104..a5d101be 100644 --- a/include/transport/storagebackend.h +++ b/include/transport/storagebackend.h @@ -86,6 +86,14 @@ class Config; class StorageBackend { public: + static std::string encryptPassword(const std::string &password, const std::string &key); + + static std::string decryptPassword(std::string &encrypted, const std::string &key); + + static std::string serializeGroups(const std::vector &groups); + + static std::vector deserializeGroups(std::string &groups); + /// Virtual desctructor. virtual ~StorageBackend() {} diff --git a/include/transport/util.h b/include/transport/util.h index 3301ad90..490724bf 100644 --- a/include/transport/util.h +++ b/include/transport/util.h @@ -26,20 +26,17 @@ #include #include "Swiften/StringCodecs/Base64.h" +#include +#include "transport/config.h" + namespace Transport { namespace Util { +void createDirectories(Transport::Config *config, const boost::filesystem::path& ph); + void removeEverythingOlderThan(const std::vector &dirs, time_t t); -std::string encryptPassword(const std::string &password, const std::string &key); - -std::string decryptPassword(std::string &encrypted, const std::string &key); - -std::string serializeGroups(const std::vector &groups); - -std::vector deserializeGroups(std::string &groups); - int getRandomPort(const std::string &s); #ifdef _WIN32 diff --git a/plugin/cpp/CMakeLists.txt b/plugin/cpp/CMakeLists.txt index d80b8f59..75ea2aa1 100644 --- a/plugin/cpp/CMakeLists.txt +++ b/plugin/cpp/CMakeLists.txt @@ -5,6 +5,7 @@ FILE(GLOB HEADERS ../include/transport/*.h) 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}/../../src/util.cpp) set(EXTRA_SOURCES ${EXTRA_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/../../include/transport/protocol.pb.cc) if (NOT WIN32) diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 962b9d60..2ae15fdc 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -22,6 +22,7 @@ #include #ifndef WIN32 #include "sys/signal.h" +#include "sys/stat.h" #include #include #include @@ -248,9 +249,14 @@ int main(int argc, char **argv) return 1; } +#ifndef WIN32 + mode_t old_cmask = umask(0007); +#endif + // create directories try { - boost::filesystem::create_directories(CONFIG_STRING(&config, "service.working_dir")); + + Transport::Util::createDirectories(&config, CONFIG_STRING(&config, "service.working_dir")); } catch (...) { std::cerr << "Can't create service.working_dir directory " << CONFIG_STRING(&config, "service.working_dir") << ".\n"; @@ -284,20 +290,6 @@ int main(int argc, char **argv) #endif #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"; - return 1; - } - 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"; - return 1; - } - chown(CONFIG_STRING(&config, "service.working_dir").c_str(), pw->pw_uid, gr->gr_gid); - } - char backendport[20]; FILE* port_file_f; port_file_f = fopen(CONFIG_STRING(&config, "service.portfile").c_str(), "w+"); @@ -423,6 +415,10 @@ int main(int argc, char **argv) eventLoop.run(); +#ifndef WIN32 + umask(old_cmask); +#endif + if (userRegistration) { userRegistration->stop(); delete userRegistration; diff --git a/src/logging.cpp b/src/logging.cpp index f724993e..a7f8478b 100644 --- a/src/logging.cpp +++ b/src/logging.cpp @@ -20,6 +20,7 @@ #include "transport/logging.h" #include "transport/config.h" +#include "transport/util.h" #include #include #include @@ -31,6 +32,7 @@ #ifndef WIN32 #include "sys/signal.h" +#include #include #include #include @@ -136,35 +138,42 @@ static void initLogging(Config *config, std::string key) { break; } } - + mode_t old_cmask; if (!dir.empty()) { // create directories - try { - boost::filesystem::create_directories( - boost::filesystem::path(dir).parent_path().string() - ); - } - catch (...) { - std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ".\n"; - } - #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(dir.c_str(), pw->pw_uid, gr->gr_gid); - } - + old_cmask = umask(0007); #endif + try { + Transport::Util::createDirectories(config, boost::filesystem::path(dir).parent_path()); + } + catch (const boost::filesystem::filesystem_error &e) { + std::cerr << "Can't create logging directory directory " << boost::filesystem::path(dir).parent_path().string() << ": " << e.what() << ".\n"; + } } log4cxx::PropertyConfigurator::configure(p); + + // Change owner of main log file +#ifndef WIN32 + if (!CONFIG_STRING(config, "service.group").empty() && !CONFIG_STRING(config, "service.user").empty()) { + struct group *gr; + if ((gr = getgrnam(CONFIG_STRING(config, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config, "service.group") << "\n"; + } + struct passwd *pw; + if ((pw = getpwnam(CONFIG_STRING(config, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config, "service.user") << "\n"; + } + chown(dir.c_str(), pw->pw_uid, gr->gr_gid); + } +#endif + +#ifndef WIN32 + if (!dir.empty()) { + umask(old_cmask); + } +#endif } } diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 67aa6508..f0769368 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -421,7 +421,7 @@ bool MySQLBackend::exec(const std::string &query) { void MySQLBackend::setUser(const UserInfo &user) { std::string encrypted = user.password; if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { - encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); + encrypted = StorageBackend::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } *m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted; EXEC(m_setUser, setUser(user)); @@ -439,7 +439,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { *m_getUser >> user.id >> user.jid >> user.uin >> user.password >> user.encoding >> user.language >> user.vip; if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { - user.password = Util::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key")); + user.password = StorageBackend::decryptPassword(user.password, CONFIG_STRING(m_config, "database.encryption_key")); } } @@ -467,7 +467,7 @@ bool MySQLBackend::getOnlineUsers(std::vector &users) { long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { // "INSERT INTO " + m_prefix + "buddies (user_id, uin, subscription, groups, nickname, flags) VALUES (?, ?, ?, ?, ?, ?)" - std::string groups = Util::serializeGroups(buddyInfo.groups); + std::string groups = StorageBackend::serializeGroups(buddyInfo.groups); *m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription; *m_addBuddy << groups; *m_addBuddy << buddyInfo.alias << buddyInfo.flags; @@ -517,7 +517,7 @@ void MySQLBackend::removeBuddy(long id) { void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { // "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?" - std::string groups = Util::serializeGroups(buddyInfo.groups); + std::string groups = StorageBackend::serializeGroups(buddyInfo.groups); *m_updateBuddy << groups; *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; *m_updateBuddy << userId << buddyInfo.legacyName; @@ -547,7 +547,7 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { *m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags; if (!group.empty()) { - b.groups = Util::deserializeGroups(group); + b.groups = StorageBackend::deserializeGroups(group); } roster.push_back(b); diff --git a/src/pqxxbackend.cpp b/src/pqxxbackend.cpp index c2ae4580..90fffb87 100644 --- a/src/pqxxbackend.cpp +++ b/src/pqxxbackend.cpp @@ -157,7 +157,7 @@ bool PQXXBackend::exec(pqxx::nontransaction &txn, const std::string &query, bool void PQXXBackend::setUser(const UserInfo &user) { std::string encrypted = user.password; if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { - encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); + encrypted = StorageBackend::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } try { pqxx::nontransaction txn(*m_conn); @@ -236,7 +236,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { + "(" + pqxx::to_string(userId) + "," + quote(txn, buddyInfo.legacyName) + "," + quote(txn, buddyInfo.subscription) + "," - + quote(txn, Util::serializeGroups(buddyInfo.groups)) + "," + + quote(txn, StorageBackend::serializeGroups(buddyInfo.groups)) + "," + quote(txn, buddyInfo.alias) + "," + pqxx::to_string(buddyInfo.flags) + ") RETURNING id"); @@ -263,7 +263,7 @@ long PQXXBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void PQXXBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { try { pqxx::nontransaction txn(*m_conn); - txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, Util::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); + txn.exec("UPDATE " + m_prefix + "buddies SET groups=" + quote(txn, StorageBackend::serializeGroups(buddyInfo.groups)) + ", nickname=" + quote(txn, buddyInfo.alias) + ", flags=" + pqxx::to_string(buddyInfo.flags) + ", subscription=" + quote(txn, buddyInfo.subscription) + " WHERE user_id=" + pqxx::to_string(userId) + " AND uin=" + quote(txn, buddyInfo.legacyName)); } catch (std::exception& e) { LOG4CXX_ERROR(logger, e.what()); @@ -287,7 +287,7 @@ bool PQXXBackend::getBuddies(long id, std::list &roster) { b.flags = r[0][5].as(); if (!group.empty()) { - b.groups = Util::deserializeGroups(group); + b.groups = StorageBackend::deserializeGroups(group); } roster.push_back(b); diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index 3de7371b..b95deb3f 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -287,7 +287,7 @@ long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) { BIND_INT(m_addBuddy, userId); BIND_STR(m_addBuddy, buddyInfo.legacyName); BIND_STR(m_addBuddy, buddyInfo.subscription); - BIND_STR(m_addBuddy, Util::serializeGroups(buddyInfo.groups)); + BIND_STR(m_addBuddy, StorageBackend::serializeGroups(buddyInfo.groups)); BIND_STR(m_addBuddy, buddyInfo.alias); BIND_INT(m_addBuddy, buddyInfo.flags); @@ -313,7 +313,7 @@ long SQLite3Backend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void SQLite3Backend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { // UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=? BEGIN(m_updateBuddy); - BIND_STR(m_updateBuddy, Util::serializeGroups(buddyInfo.groups)); + BIND_STR(m_updateBuddy, StorageBackend::serializeGroups(buddyInfo.groups)); BIND_STR(m_updateBuddy, buddyInfo.alias); BIND_INT(m_updateBuddy, buddyInfo.flags); BIND_STR(m_updateBuddy, buddyInfo.subscription); @@ -355,7 +355,7 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { b.subscription = GET_STR(m_getBuddies); b.alias = GET_STR(m_getBuddies); std::string groups = GET_STR(m_getBuddies); - b.groups = Util::deserializeGroups(groups); + b.groups = StorageBackend::deserializeGroups(groups); b.flags = GET_INT(m_getBuddies); if (buddy_id == b.id) { diff --git a/src/storagebackend.cpp b/src/storagebackend.cpp index ec87e33b..ce27dfae 100644 --- a/src/storagebackend.cpp +++ b/src/storagebackend.cpp @@ -5,6 +5,8 @@ #include "transport/mysqlbackend.h" #include "transport/pqxxbackend.h" +#include "Swiften/Swiften.h" + namespace Transport { StorageBackend *StorageBackend::createBackend(Config *config, std::string &error) { @@ -47,4 +49,56 @@ StorageBackend *StorageBackend::createBackend(Config *config, std::string &error return storageBackend; } +std::string StorageBackend::encryptPassword(const std::string &password, const std::string &key) { + std::string encrypted; + encrypted.resize(password.size()); + for (int i = 0; i < password.size(); i++) { + char c = password[i]; + char keychar = key[i % key.size()]; + c += keychar; + encrypted[i] = c; + } + + encrypted = Swift::Base64::encode(Swift::createByteArray(encrypted)); + return encrypted; +} + +std::string StorageBackend::decryptPassword(std::string &encrypted, const std::string &key) { + encrypted = Swift::byteArrayToString(Swift::Base64::decode(encrypted)); + std::string password; + password.resize(encrypted.size()); + for (int i = 0; i < encrypted.size(); i++) { + char c = encrypted[i]; + char keychar = key[i % key.size()]; + c -= keychar; + password[i] = c; + } + + return password; +} + +std::string StorageBackend::serializeGroups(const std::vector &groups) { + std::string ret; + BOOST_FOREACH(const std::string &group, groups) { + ret += group + "\n"; + } + if (!ret.empty()) { + ret.erase(ret.end() - 1); + } + return ret; +} + +std::vector StorageBackend::deserializeGroups(std::string &groups) { + std::vector ret; + if (groups.empty()) { + return ret; + } + + boost::split(ret, groups, boost::is_any_of("\n")); + if (ret.back().empty()) { + ret.erase(ret.end() - 1); + } + return ret; +} + } diff --git a/src/tests/util.cpp b/src/tests/util.cpp index f5c66819..c091f2ec 100644 --- a/src/tests/util.cpp +++ b/src/tests/util.cpp @@ -3,6 +3,7 @@ #include "transport/storagebackend.h" #include "transport/user.h" #include "transport/transport.h" +#include "transport/storagebackend.h" #include "transport/conversation.h" #include "transport/usermanager.h" #include "transport/localbuddy.h" @@ -36,8 +37,8 @@ class UtilTest : public CPPUNIT_NS :: TestFixture{ } void encryptDecryptPassword() { - std::string encrypted = Util::encryptPassword("password", "key"); - CPPUNIT_ASSERT_EQUAL(std::string("password"), Util::decryptPassword(encrypted, "key")); + std::string encrypted = StorageBackend::encryptPassword("password", "key"); + CPPUNIT_ASSERT_EQUAL(std::string("password"), StorageBackend::decryptPassword(encrypted, "key")); } }; diff --git a/src/util.cpp b/src/util.cpp index 7589f213..b8c3adc5 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -19,6 +19,7 @@ */ #include "transport/util.h" +#include "transport/config.h" #include #include #include @@ -27,6 +28,19 @@ #include #include +#ifndef WIN32 +#include "sys/signal.h" +#include +#include +#include +#include +#include "libgen.h" +#else +#include +#include +#define getpid _getpid +#endif + using namespace boost::filesystem; using namespace boost; @@ -35,6 +49,32 @@ namespace Transport { namespace Util { +void createDirectories(Transport::Config *config, const 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 + 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 +} + void removeEverythingOlderThan(const std::vector &dirs, time_t t) { BOOST_FOREACH(const std::string &dir, dirs) { path p(dir); @@ -58,7 +98,7 @@ void removeEverythingOlderThan(const std::vector &dirs, time_t t) { std::vector nextDirs; nextDirs.push_back(itr->path().string()); removeEverythingOlderThan(nextDirs, t); - if (is_empty(itr->path())) { + if (boost::filesystem::is_empty(itr->path())) { remove_all(itr->path()); } } @@ -77,58 +117,6 @@ void removeEverythingOlderThan(const std::vector &dirs, time_t t) { } } -std::string encryptPassword(const std::string &password, const std::string &key) { - std::string encrypted; - encrypted.resize(password.size()); - for (int i = 0; i < password.size(); i++) { - char c = password[i]; - char keychar = key[i % key.size()]; - c += keychar; - encrypted[i] = c; - } - - encrypted = Swift::Base64::encode(Swift::createByteArray(encrypted)); - return encrypted; -} - -std::string decryptPassword(std::string &encrypted, const std::string &key) { - encrypted = Swift::byteArrayToString(Swift::Base64::decode(encrypted)); - std::string password; - password.resize(encrypted.size()); - for (int i = 0; i < encrypted.size(); i++) { - char c = encrypted[i]; - char keychar = key[i % key.size()]; - c -= keychar; - password[i] = c; - } - - return password; -} - -std::string serializeGroups(const std::vector &groups) { - std::string ret; - BOOST_FOREACH(const std::string &group, groups) { - ret += group + "\n"; - } - if (!ret.empty()) { - ret.erase(ret.end() - 1); - } - return ret; -} - -std::vector deserializeGroups(std::string &groups) { - std::vector ret; - if (groups.empty()) { - return ret; - } - - boost::split(ret, groups, boost::is_any_of("\n")); - if (ret.back().empty()) { - ret.erase(ret.end() - 1); - } - return ret; -} - int getRandomPort(const std::string &s) { unsigned long r = 0; BOOST_FOREACH(char c, s) { From dc1cc4170e4a4abd456e27d4e567501ad67928b9 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 31 Oct 2012 09:39:03 +0100 Subject: [PATCH 33/61] Do not forward user's contact (representing himself) from legacy network (situation when user A has himself in his XMPP roster) --- src/networkpluginserver.cpp | 5 +++++ src/tests/networkpluginserver.cpp | 14 ++++++++++++++ src/tests/usermanager.cpp | 5 +---- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 28275c63..bcea34f7 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -542,6 +542,10 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { buddy->handleBuddyChanged(); } else { + if (payload.buddyname() == user->getUserInfo().uin) { + return; + } + std::vector groups; for (int i = 0; i < payload.group_size(); i++) { groups.push_back(payload.group(i)); @@ -556,6 +560,7 @@ void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { delete buddy; return; } + buddy->setStatus(Swift::StatusShow((Swift::StatusShow::Type) payload.status()), payload.statusmessage()); buddy->setIconHash(payload.iconhash()); buddy->setBlocked(payload.blocked()); diff --git a/src/tests/networkpluginserver.cpp b/src/tests/networkpluginserver.cpp index 9a9d921c..d9e1655d 100644 --- a/src/tests/networkpluginserver.cpp +++ b/src/tests/networkpluginserver.cpp @@ -29,6 +29,7 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_TEST_SUITE(NetworkPluginServerTest); CPPUNIT_TEST(handleBuddyChangedPayload); CPPUNIT_TEST(handleBuddyChangedPayloadNoEscaping); + CPPUNIT_TEST(handleBuddyChangedPayloadUserContactInRoster); CPPUNIT_TEST_SUITE_END(); public: @@ -90,6 +91,19 @@ class NetworkPluginServerTest : public CPPUNIT_NS :: TestFixture, public BasicTe cfg->load(ifs2); } + void handleBuddyChangedPayloadUserContactInRoster() { + User *user = userManager->getUser("user@localhost"); + + pbnetwork::Buddy buddy; + buddy.set_username("user@localhost"); + buddy.set_buddyname("user"); + + std::string message; + buddy.SerializeToString(&message); + + serv->handleBuddyChangedPayload(message); + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + } }; CPPUNIT_TEST_SUITE_REGISTRATION (NetworkPluginServerTest); diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index a0adceff..5177d802 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -79,7 +79,7 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); loop->processEvents(); - CPPUNIT_ASSERT_EQUAL(4, (int) received.size()); + CPPUNIT_ASSERT_EQUAL(3, (int) received.size()); CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); Swift::Presence *presence = dynamic_cast(getStanza(received[1])); @@ -90,9 +90,6 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT(presence); CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, presence->getType()); - presence = dynamic_cast(getStanza(received[3])); - CPPUNIT_ASSERT(presence); - CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribed, presence->getType()); } void connectTwoResources() { From 3aff761db6789faeab97d5153650df5698ed9ddf Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Fri, 2 Nov 2012 09:50:03 +0100 Subject: [PATCH 34/61] Do not send subscribe presence just because, but send it as response to probe presence --- include/transport/usermanager.h | 1 + src/tests/usermanager.cpp | 41 +++++++++++++++++++++++++++++++++ src/transport.cpp | 13 ++++++++--- src/usermanager.cpp | 38 ++++++++++++++++++++++++++++-- 4 files changed, 88 insertions(+), 5 deletions(-) diff --git a/include/transport/usermanager.h b/include/transport/usermanager.h index 683d2f05..38a5c7bc 100644 --- a/include/transport/usermanager.h +++ b/include/transport/usermanager.h @@ -131,6 +131,7 @@ class UserManager : public Swift::EntityCapsProvider { void handleMessageReceived(Swift::Message::ref message); void handleGeneralPresenceReceived(Swift::Presence::ref presence); void handleProbePresence(Swift::Presence::ref presence); + void handleErrorPresence(Swift::Presence::ref presence); void handleSubscription(Swift::Presence::ref presence); void handleRemoveTimeout(const std::string jid, User *user, bool reconnect); void handleDiscoInfo(const Swift::JID& jid, boost::shared_ptr info); diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index 5177d802..26ba476a 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -72,6 +72,11 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { } void handleProbePresence() { + UserInfo info; + info.id = 1; + info.jid = "user@localhost"; + storage->setUser(info); + Swift::Presence::ref response = Swift::Presence::create(); response->setTo("localhost"); response->setFrom("user@localhost/resource"); @@ -88,8 +93,44 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { presence = dynamic_cast(getStanza(received[2])); CPPUNIT_ASSERT(presence); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Probe, presence->getType()); + + received.clear(); + response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost"); + response->setType(Swift::Presence::Unsubscribed); + dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + presence = dynamic_cast(getStanza(received[1])); + CPPUNIT_ASSERT(presence); CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, presence->getType()); + received.clear(); + response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost"); + response->setType(Swift::Presence::Error); + dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + presence = dynamic_cast(getStanza(received[0])); + CPPUNIT_ASSERT(presence); + CPPUNIT_ASSERT_EQUAL(Swift::Presence::Subscribe, presence->getType()); + + storage->removeUser(1); + received.clear(); + response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost"); + response->setType(Swift::Presence::Unsubscribed); + dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); } void connectTwoResources() { diff --git a/src/transport.cpp b/src/transport.cpp index 95ca0319..f4e0480b 100644 --- a/src/transport.cpp +++ b/src/transport.cpp @@ -281,9 +281,16 @@ void Component::handlePresence(Swift::Presence::ref presence) { return; } - if (presence->getType() == Presence::Error) { - return; - } + switch (presence->getType()) { + case Presence::Error: + case Presence::Subscribe: + case Presence::Subscribed: + case Presence::Unsubscribe: + case Presence::Unsubscribed: + return; + default: + break; + }; // check if we have this client's capabilities and ask for them if (presence->getType() != Swift::Presence::Unavailable) { diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 64e1d1c3..32795e6c 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -195,13 +195,13 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { response->setType(Swift::Presence::Unavailable); m_component->getStanzaChannel()->sendPresence(response); - // bother him with subscribe presence, just to be + // bother him with probe presence, just to be // sure he is subscribed to us. if (/*registered && */presence->getType() == Swift::Presence::Probe) { Swift::Presence::ref response = Swift::Presence::create(); response->setTo(presence->getFrom()); response->setFrom(presence->getTo()); - response->setType(Swift::Presence::Subscribe); + response->setType(Swift::Presence::Probe); m_component->getStanzaChannel()->sendPresence(response); } @@ -382,6 +382,9 @@ void UserManager::handleGeneralPresenceReceived(Swift::Presence::ref presence) { case Swift::Presence::Probe: handleProbePresence(presence); break; + case Swift::Presence::Error: + handleErrorPresence(presence); + break; default: break; }; @@ -407,7 +410,25 @@ void UserManager::handleProbePresence(Swift::Presence::ref presence) { } } +void UserManager::handleErrorPresence(Swift::Presence::ref presence) { + // Don't let RosterManager to handle presences for us + if (!presence->getTo().getNode().empty()) { + return; + } + std::string userkey = presence->getFrom().toBare().toString(); + UserInfo res; + bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false; + if (registered) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setFrom(presence->getTo().toBare()); + response->setTo(presence->getFrom().toBare()); + response->setType(Swift::Presence::Subscribe); + m_component->getStanzaChannel()->sendPresence(response); + } +} + void UserManager::handleSubscription(Swift::Presence::ref presence) { + // answer to subscibe for transport itself if (presence->getType() == Swift::Presence::Subscribe && presence->getTo().getNode().empty()) { Swift::Presence::ref response = Swift::Presence::create(); @@ -423,6 +444,19 @@ void UserManager::handleSubscription(Swift::Presence::ref presence) { // m_component->getStanzaChannel()->sendPresence(response); return; } + else if (presence->getType() == Swift::Presence::Unsubscribed && presence->getTo().getNode().empty()) { + std::string userkey = presence->getFrom().toBare().toString(); + UserInfo res; + bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false; + if (registered) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setFrom(presence->getTo().toBare()); + response->setTo(presence->getFrom().toBare()); + response->setType(Swift::Presence::Subscribe); + m_component->getStanzaChannel()->sendPresence(response); + } + return; + } // Don't let RosterManager to handle presences for us if (presence->getTo().getNode().empty()) { From 0d8056349af29a08e32cdcf95297e0fe7e0b12e3 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 6 Nov 2012 09:52:56 +0100 Subject: [PATCH 35/61] When auto_registration is enabled, set register=True also when storage backend does not exist --- src/usermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 32795e6c..38f31bd0 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -266,7 +266,7 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { registered = m_storageBackend->getUser(userkey, res); } else { - registered = false; + registered = true; } } } From a78794c2e7e1ddcd72588e47ade52575f088bda7 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Sat, 10 Nov 2012 02:59:46 +0400 Subject: [PATCH 36/61] Windows Service Support --- spectrum/src/CMakeLists.txt | 12 +- spectrum/src/main.cpp | 74 +++++---- spectrum/src/win32/ServiceWrapper.cpp | 120 ++++++++++++++ spectrum/src/win32/ServiceWrapper.h | 19 +++ spectrum/src/win32/SpectrumService.cpp | 19 --- spectrum/src/win32/SpectrumService.h | 14 -- spectrum/src/win32/WindowsService.cpp | 214 ------------------------- spectrum/src/win32/WindowsService.h | 58 ------- 8 files changed, 191 insertions(+), 339 deletions(-) create mode 100644 spectrum/src/win32/ServiceWrapper.cpp create mode 100644 spectrum/src/win32/ServiceWrapper.h delete mode 100644 spectrum/src/win32/SpectrumService.cpp delete mode 100644 spectrum/src/win32/SpectrumService.h delete mode 100644 spectrum/src/win32/WindowsService.cpp delete mode 100644 spectrum/src/win32/WindowsService.h diff --git a/spectrum/src/CMakeLists.txt b/spectrum/src/CMakeLists.txt index 2dd5b0da..fb38f5f0 100644 --- a/spectrum/src/CMakeLists.txt +++ b/spectrum/src/CMakeLists.txt @@ -1,13 +1,13 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp) -# if (WIN32) -# FILE(GLOB WIN_SRC win32/*.cpp) -# include_directories(win32) -# ADD_EXECUTABLE(spectrum2 ${SRC} ${WIN_SRC}) -# else() +if (WIN32) +FILE(GLOB WIN_SRC win32/*.cpp) +include_directories(win32) +ADD_EXECUTABLE(spectrum2 ${SRC} ${WIN_SRC}) +else() ADD_EXECUTABLE(spectrum2 ${SRC}) -# endif() +endif() diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 2ae15fdc..4fada002 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -33,7 +33,7 @@ #else #include #define getpid _getpid -// #include "win32/SpectrumService.h" +#include "win32/ServiceWrapper.h" #endif #include @@ -45,6 +45,13 @@ DEFINE_LOGGER(logger, "Spectrum"); Swift::SimpleEventLoop *eventLoop_ = NULL; Component *component_ = NULL; UserManager *userManager_ = NULL; +Config *config_ = NULL; + +void stop() { + userManager_->removeAllUsers(false); + component_->stop(); + eventLoop_->stop(); +} static void stop_spectrum() { userManager_->removeAllUsers(false); @@ -125,7 +132,7 @@ static void daemonize(const char *cwd, const char *lock_file) { int main(int argc, char **argv) { Config config(argc, argv); - + config_ = &config; boost::program_options::variables_map vm; bool no_daemon = false; std::string config_file; @@ -160,9 +167,9 @@ int main(int argc, char **argv) ("version,v", "Shows Spectrum version") ; #ifdef WIN32 -// desc.add_options() -// ("install-service,i", "Install spectrum as Windows service") -// ("uninstall-service,u", "Uninstall Windows service"); + desc.add_options() + ("install-service,i", "Install spectrum as Windows service") + ("uninstall-service,u", "Uninstall Windows service"); #endif try { @@ -192,18 +199,17 @@ int main(int argc, char **argv) no_daemon = true; } #ifdef WIN32 -#if 0 if (vm.count("install-service")) { - SpectrumService ntservice; + ServiceWrapper ntservice("Spectrum2"); if (!ntservice.IsInstalled()) { // determine the name of the currently executing file char szFilePath[MAX_PATH]; - GetModuleFileName(NULL, szFilePath, sizeof(szFilePath)); + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); std::string exe_file(szFilePath); std::string config_file = exe_file.replace(exe_file.end() - 4, exe_file.end(), ".cfg"); std::string service_path = std::string(szFilePath) + std::string(" --config ") + config_file; - if (ntservice.Install(service_path.c_str())) { + if (ntservice.Install((char *)service_path.c_str())) { std::cout << "Successfully installed" << std::endl; return 0; } else { @@ -216,9 +222,9 @@ int main(int argc, char **argv) } } if (vm.count("uninstall-service")) { - SpectrumService ntservice; + ServiceWrapper ntservice("Spectrum2"); if (ntservice.IsInstalled()) { - if (ntservice.Remove()) { + if (ntservice.UnInstall()) { std::cout << "Successfully removed" << std::endl; return 0; } else { @@ -229,8 +235,7 @@ int main(int argc, char **argv) std::cout << "Service not installed" << std::endl; return 1; } - } -#endif + } #endif } catch (std::runtime_error& e) @@ -310,36 +315,49 @@ int main(int argc, char **argv) // removeOldIcons(CONFIG_STRING(&config, "service.working_dir") + "/icons"); } #endif +#ifdef WIN32 + ServiceWrapper ntservice("Spectrum2"); + if (ntservice.IsInstalled()) { + ntservice.RunService(); + } else { + mainloop(); + } +#else + mainloop(); +#endif +} - Logging::initMainLogging(&config); +int mainloop() { + + Logging::initMainLogging(config_); #ifndef WIN32 - if (!CONFIG_STRING(&config, "service.group").empty() ||!CONFIG_STRING(&config, "service.user").empty() ) { + if (!CONFIG_STRING(config_, "service.group").empty() ||!CONFIG_STRING(config_, "service.user").empty() ) { struct rlimit limit; getrlimit(RLIMIT_CORE, &limit); - if (!CONFIG_STRING(&config, "service.group").empty()) { + if (!CONFIG_STRING(config_, "service.group").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"; + if ((gr = getgrnam(CONFIG_STRING(config_, "service.group").c_str())) == NULL) { + std::cerr << "Invalid service.group name " << CONFIG_STRING(config_, "service.group") << "\n"; return 1; } - if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(&config, "service.user").c_str(), gr->gr_gid) != 0)) { - std::cerr << "Failed to set service.group name " << CONFIG_STRING(&config, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n"; + if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(config_, "service.user").c_str(), gr->gr_gid) != 0)) { + std::cerr << "Failed to set service.group name " << CONFIG_STRING(config_, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n"; return 1; } } - if (!CONFIG_STRING(&config, "service.user").empty()) { + if (!CONFIG_STRING(config_, "service.user").empty()) { 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"; + if ((pw = getpwnam(CONFIG_STRING(config_, "service.user").c_str())) == NULL) { + std::cerr << "Invalid service.user name " << CONFIG_STRING(config_, "service.user") << "\n"; return 1; } if ((setuid(pw->pw_uid)) != 0) { - std::cerr << "Failed to set service.user name " << CONFIG_STRING(&config, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n"; + std::cerr << "Failed to set service.user name " << CONFIG_STRING(config_, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n"; return 1; } } @@ -355,14 +373,14 @@ int main(int argc, char **argv) Swift::SimpleEventLoop eventLoop; Swift::BoostNetworkFactories *factories = new Swift::BoostNetworkFactories(&eventLoop); - UserRegistry userRegistry(&config, factories); + UserRegistry userRegistry(config_, factories); - Component transport(&eventLoop, factories, &config, NULL, &userRegistry); + Component transport(&eventLoop, factories, config_, NULL, &userRegistry); component_ = &transport; // Logger logger(&transport); std::string error; - StorageBackend *storageBackend = StorageBackend::createBackend(&config, error); + StorageBackend *storageBackend = StorageBackend::createBackend(config_, error); if (storageBackend == NULL) { if (!error.empty()) { std::cerr << error << "\n"; @@ -393,7 +411,7 @@ int main(int argc, char **argv) FileTransferManager ftManager(&transport, &userManager); - NetworkPluginServer plugin(&transport, &config, &userManager, &ftManager, &discoItemsResponder); + NetworkPluginServer plugin(&transport, config_, &userManager, &ftManager, &discoItemsResponder); plugin.start(); AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); diff --git a/spectrum/src/win32/ServiceWrapper.cpp b/spectrum/src/win32/ServiceWrapper.cpp new file mode 100644 index 00000000..adb988d2 --- /dev/null +++ b/spectrum/src/win32/ServiceWrapper.cpp @@ -0,0 +1,120 @@ +#include "ServiceWrapper.h" + + +LPSTR ServiceName; +SERVICE_STATUS ServiceStatus; +SERVICE_STATUS_HANDLE ServiceStatusHandle; + +bool doAction (int action, int desiredAccess, LPSTR path = NULL); + +enum actions { + DO_INSTALL, DO_DELETE, DO_CHECK +}; + + +ServiceWrapper::ServiceWrapper(LPSTR serviceName) +{ + ServiceName = serviceName; + ServiceStatusHandle = 0; +} + +ServiceWrapper::~ServiceWrapper(void) +{ +} + +bool ServiceWrapper::Install(LPSTR commandLine) { + return doAction(DO_INSTALL, SC_MANAGER_ALL_ACCESS, commandLine); +} + +bool ServiceWrapper::UnInstall() { + return doAction(DO_DELETE, SC_MANAGER_ALL_ACCESS); +} + +bool ServiceWrapper::IsInstalled() { + return doAction(DO_CHECK, SC_MANAGER_CONNECT); +} + +bool doAction(int action, int desiredAccess, LPSTR path) { + SC_HANDLE scm = OpenSCManager(NULL, NULL, desiredAccess); + SC_HANDLE service = NULL; + if (!scm) return FALSE; + + switch(action) { + case DO_INSTALL: + service = CreateServiceA( + scm, + ServiceName, + ServiceName, + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_DEMAND_START, + SERVICE_ERROR_NORMAL, + path, + NULL, + NULL, + NULL, + NULL, + NULL + ); + return (service != NULL); + break; + case DO_DELETE: + service = OpenServiceA(scm, ServiceName, DELETE); + if (service == NULL) + return FALSE; + if (DeleteService(service)) + return TRUE; + break; + case DO_CHECK: + service = OpenServiceA(scm, ServiceName, SERVICE_QUERY_STATUS); + return (service != NULL); + default: + return FALSE; + } + CloseServiceHandle(service); + CloseServiceHandle(scm); + return FALSE; +} + +void WINAPI ServiceControlHandler(DWORD controlCode) { + switch (controlCode) { + case SERVICE_CONTROL_INTERROGATE: + break; + case SERVICE_CONTROL_STOP: + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + break; + default: + break; + } + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + stop(); +} + +void WINAPI ServiceMain(DWORD argc, LPSTR *argv) { + ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + ServiceStatus.dwServiceSpecificExitCode = NO_ERROR; + + ServiceStatusHandle = RegisterServiceCtrlHandlerA(ServiceName, ServiceControlHandler); + if (ServiceStatusHandle) { + ServiceStatus.dwCurrentState = SERVICE_START_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + ServiceStatus.dwControlsAccepted |= (SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + ServiceStatus.dwCurrentState = SERVICE_RUNNING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + mainloop(); + ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + ServiceStatus.dwControlsAccepted &= ~(SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN); + ServiceStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(ServiceStatusHandle, &ServiceStatus); + } +} + +void ServiceWrapper::RunService() { + SERVICE_TABLE_ENTRYA serviceTable[] = { + { ServiceName, ServiceMain }, + { NULL, NULL} + }; + + StartServiceCtrlDispatcherA(serviceTable); +} \ No newline at end of file diff --git a/spectrum/src/win32/ServiceWrapper.h b/spectrum/src/win32/ServiceWrapper.h new file mode 100644 index 00000000..9ee2fb0d --- /dev/null +++ b/spectrum/src/win32/ServiceWrapper.h @@ -0,0 +1,19 @@ +#pragma once +#include "transport/config.h" +#include +#include + +class ServiceWrapper +{ +public: + ServiceWrapper(LPSTR serviceName); + ~ServiceWrapper(void); + bool Install(LPSTR commandLine); + bool UnInstall(); + bool IsInstalled(); + void RunService(); +}; + +int mainloop(); +void stop(); + diff --git a/spectrum/src/win32/SpectrumService.cpp b/spectrum/src/win32/SpectrumService.cpp deleted file mode 100644 index 1fbcacd3..00000000 --- a/spectrum/src/win32/SpectrumService.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "SpectrumService.h" - -SpectrumService::SpectrumService(void) { - serviceName = "Spectrum2"; - displayName = "Spectrum2 XMPP Transport"; - username = NULL; - password = NULL; -} - -SpectrumService::~SpectrumService(void) {} - -void SpectrumService::Stop() { - ReportStatus((DWORD)SERVICE_STOP_PENDING); -} - -void SpectrumService::Run(DWORD argc, LPTSTR *argv) { - ReportStatus((DWORD)SERVICE_RUNNING); - main(argc, argv); -} \ No newline at end of file diff --git a/spectrum/src/win32/SpectrumService.h b/spectrum/src/win32/SpectrumService.h deleted file mode 100644 index 404b1057..00000000 --- a/spectrum/src/win32/SpectrumService.h +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include "WindowsService.h" - -class SpectrumService : public WindowsService { - -public: - SpectrumService(void); - ~SpectrumService(void); -protected: - void Stop(); - void Run(DWORD argc, LPTSTR *argv); -}; - -int main(int argc, char **argv); \ No newline at end of file diff --git a/spectrum/src/win32/WindowsService.cpp b/spectrum/src/win32/WindowsService.cpp deleted file mode 100644 index 0a749378..00000000 --- a/spectrum/src/win32/WindowsService.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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; version 2 of the License. - - 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#include -#include -#include ".\windowsservice.h" - -static WindowsService *gService; - -WindowsService::WindowsService(void) : - statusCheckpoint(0), - serviceName(NULL), - inited(false), - dwAcceptedControls(SERVICE_ACCEPT_STOP), - debugging(false) -{ - gService= this; - status.dwServiceType= SERVICE_WIN32_OWN_PROCESS; - status.dwServiceSpecificExitCode= 0; -} - -WindowsService::~WindowsService(void) -{ -} - -BOOL WindowsService::Install(const char *szFilePath) -{ - bool ret_val= false; - SC_HANDLE newService; - SC_HANDLE scm; - - if (IsInstalled()) return true; - - // open a connection to the SCM - if (!(scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE))) - return false; - - newService= CreateService(scm, serviceName, displayName, - SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, - SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, - szFilePath, NULL, NULL, NULL, username, - password); - - if (newService) - { - CloseServiceHandle(newService); - ret_val= true; - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::Init() -{ - assert(serviceName != NULL); - - if (inited) return true; - - SERVICE_TABLE_ENTRY stb[] = - { - { (LPSTR)serviceName, (LPSERVICE_MAIN_FUNCTION) ServiceMain}, - { NULL, NULL } - }; - inited= true; - return StartServiceCtrlDispatcher(stb); //register with the Service Manager -} - -BOOL WindowsService::Remove() -{ - bool ret_val= false; - - if (! IsInstalled()) - return true; - - // open a connection to the SCM - SC_HANDLE scm= OpenSCManager(0, 0,SC_MANAGER_CREATE_SERVICE); - if (! scm) - return false; - - SC_HANDLE service= OpenService(scm, serviceName, DELETE); - if (service) - { - if (DeleteService(service)) - ret_val= true; - DWORD dw= ::GetLastError(); - CloseServiceHandle(service); - } - - CloseServiceHandle(scm); - return ret_val; -} - -BOOL WindowsService::IsInstalled() -{ - BOOL ret_val= FALSE; - - SC_HANDLE scm= ::OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); - SC_HANDLE serv_handle= ::OpenService(scm, serviceName, SERVICE_QUERY_STATUS); - - ret_val= serv_handle != NULL; - - ::CloseServiceHandle(serv_handle); - ::CloseServiceHandle(scm); - - return ret_val; -} - -void WindowsService::SetAcceptedControls(DWORD acceptedControls) -{ - dwAcceptedControls= acceptedControls; -} - - -BOOL WindowsService::ReportStatus(DWORD currentState, DWORD waitHint, - DWORD dwError) -{ - if(debugging) return TRUE; - - if(currentState == SERVICE_START_PENDING) - status.dwControlsAccepted= 0; - else - status.dwControlsAccepted= dwAcceptedControls; - - status.dwCurrentState= currentState; - status.dwWin32ExitCode= dwError != 0 ? - ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR; - status.dwWaitHint= waitHint; - status.dwServiceSpecificExitCode= dwError; - - if(currentState == SERVICE_RUNNING || currentState == SERVICE_STOPPED) - { - status.dwCheckPoint= 0; - statusCheckpoint= 0; - } - else - status.dwCheckPoint= ++statusCheckpoint; - - // Report the status of the service to the service control manager. - BOOL result= SetServiceStatus(statusHandle, &status); - if (!result) - Log("ReportStatus failed"); - - return result; -} - -void WindowsService::RegisterAndRun(DWORD argc, LPTSTR *argv) -{ - statusHandle= ::RegisterServiceCtrlHandler(serviceName, ControlHandler); - if (statusHandle && ReportStatus(SERVICE_START_PENDING)) - Run(argc, argv); - ReportStatus(SERVICE_STOPPED); -} - -void WindowsService::HandleControlCode(DWORD opcode) -{ - // Handle the requested control code. - switch(opcode) { - case SERVICE_CONTROL_STOP: - // Stop the service. - status.dwCurrentState= SERVICE_STOP_PENDING; - Stop(); - break; - - case SERVICE_CONTROL_PAUSE: - status.dwCurrentState= SERVICE_PAUSE_PENDING; - Pause(); - break; - - case SERVICE_CONTROL_CONTINUE: - status.dwCurrentState= SERVICE_CONTINUE_PENDING; - Continue(); - break; - - case SERVICE_CONTROL_SHUTDOWN: - Shutdown(); - break; - - case SERVICE_CONTROL_INTERROGATE: - ReportStatus(status.dwCurrentState); - break; - - default: - // invalid control code - break; - } -} - -void WINAPI WindowsService::ServiceMain(DWORD argc, LPTSTR *argv) -{ - assert(gService != NULL); - - // register our service control handler: - gService->RegisterAndRun(argc, argv); -} - -void WINAPI WindowsService::ControlHandler(DWORD opcode) -{ - assert(gService != NULL); - - return gService->HandleControlCode(opcode); -} diff --git a/spectrum/src/win32/WindowsService.h b/spectrum/src/win32/WindowsService.h deleted file mode 100644 index 55e91d8b..00000000 --- a/spectrum/src/win32/WindowsService.h +++ /dev/null @@ -1,58 +0,0 @@ -/* Copyright (C) 2005 MySQL AB - - 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; version 2 of the License. - - 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 St, Fifth Floor, Boston, MA 02110-1301 USA */ - -#pragma once - -class WindowsService -{ -protected: - bool inited; - const char *serviceName; - const char *displayName; - const char *username; - const char *password; - SERVICE_STATUS_HANDLE statusHandle; - DWORD statusCheckpoint; - SERVICE_STATUS status; - DWORD dwAcceptedControls; - bool debugging; - -public: - WindowsService(void); - ~WindowsService(void); - - BOOL Install(const char *szFilePath); - BOOL Remove(); - BOOL Init(); - BOOL IsInstalled(); - void SetAcceptedControls(DWORD acceptedControls); - void Debug(bool debugFlag) { debugging= debugFlag; } - -public: - static void WINAPI ServiceMain(DWORD argc, LPTSTR *argv); - static void WINAPI ControlHandler(DWORD CtrlType); - -protected: - virtual void Run(DWORD argc, LPTSTR *argv)= 0; - virtual void Stop() {} - virtual void Shutdown() {} - virtual void Pause() {} - virtual void Continue() {} - virtual void Log(const char *msg) {} - - BOOL ReportStatus(DWORD currentStatus, DWORD waitHint= 3000, DWORD dwError=0); - void HandleControlCode(DWORD opcode); - void RegisterAndRun(DWORD argc, LPTSTR *argv); -}; From 8bd6de376842aeb305083489632916feda9a9dfe Mon Sep 17 00:00:00 2001 From: HanzZ Date: Sat, 10 Nov 2012 16:01:54 +0100 Subject: [PATCH 37/61] Move mainloop() up to compile it with g++ --- spectrum/src/main.cpp | 257 +++++++++++++++++++++--------------------- 1 file changed, 129 insertions(+), 128 deletions(-) diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 4fada002..0b312bf2 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -129,6 +129,135 @@ static void daemonize(const char *cwd, const char *lock_file) { #endif +int mainloop() { + +#ifndef WIN32 + mode_t old_cmask = umask(0007); +#endif + + Logging::initMainLogging(config_); + +#ifndef WIN32 + if (!CONFIG_STRING(config_, "service.group").empty() ||!CONFIG_STRING(config_, "service.user").empty() ) { + struct rlimit limit; + getrlimit(RLIMIT_CORE, &limit); + + if (!CONFIG_STRING(config_, "service.group").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"; + return 1; + } + + if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(config_, "service.user").c_str(), gr->gr_gid) != 0)) { + std::cerr << "Failed to set service.group name " << CONFIG_STRING(config_, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n"; + return 1; + } + } + + if (!CONFIG_STRING(config_, "service.user").empty()) { + 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"; + return 1; + } + + if ((setuid(pw->pw_uid)) != 0) { + std::cerr << "Failed to set service.user name " << CONFIG_STRING(config_, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n"; + return 1; + } + } + setrlimit(RLIMIT_CORE, &limit); + } + + struct rlimit limit; + limit.rlim_max = RLIM_INFINITY; + limit.rlim_cur = RLIM_INFINITY; + setrlimit(RLIMIT_CORE, &limit); +#endif + + Swift::SimpleEventLoop eventLoop; + + Swift::BoostNetworkFactories *factories = new Swift::BoostNetworkFactories(&eventLoop); + UserRegistry userRegistry(config_, factories); + + Component transport(&eventLoop, factories, config_, NULL, &userRegistry); + component_ = &transport; +// Logger logger(&transport); + + std::string error; + StorageBackend *storageBackend = StorageBackend::createBackend(config_, error); + if (storageBackend == NULL) { + if (!error.empty()) { + std::cerr << error << "\n"; + return -2; + } + } + else if (!storageBackend->connect()) { + std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; + return -1; + } + + Logging::redirect_stderr(); + + DiscoItemsResponder discoItemsResponder(&transport); + discoItemsResponder.start(); + + UserManager userManager(&transport, &userRegistry, &discoItemsResponder, storageBackend); + userManager_ = &userManager; + + UserRegistration *userRegistration = NULL; + UsersReconnecter *usersReconnecter = NULL; + if (storageBackend) { + userRegistration = new UserRegistration(&transport, &userManager, storageBackend); + userRegistration->start(); + + usersReconnecter = new UsersReconnecter(&transport, storageBackend); + } + + FileTransferManager ftManager(&transport, &userManager); + + NetworkPluginServer plugin(&transport, config_, &userManager, &ftManager, &discoItemsResponder); + plugin.start(); + + AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); + plugin.setAdminInterface(&adminInterface); + + StatsResponder statsResponder(&transport, &userManager, &plugin, storageBackend); + statsResponder.start(); + + GatewayResponder gatewayResponder(transport.getIQRouter(), &userManager); + gatewayResponder.start(); + + AdHocManager adhocmanager(&transport, &discoItemsResponder, &userManager, storageBackend); + adhocmanager.start(); + + SettingsAdHocCommandFactory settings; + adhocmanager.addAdHocCommand(&settings); + + eventLoop_ = &eventLoop; + + eventLoop.run(); + +#ifndef WIN32 + umask(old_cmask); +#endif + + if (userRegistration) { + userRegistration->stop(); + delete userRegistration; + } + + if (usersReconnecter) { + delete usersReconnecter; + } + + delete storageBackend; + delete factories; + return 0; +} + + int main(int argc, char **argv) { Config config(argc, argv); @@ -254,10 +383,6 @@ int main(int argc, char **argv) return 1; } -#ifndef WIN32 - mode_t old_cmask = umask(0007); -#endif - // create directories try { @@ -326,127 +451,3 @@ int main(int argc, char **argv) mainloop(); #endif } - -int mainloop() { - - Logging::initMainLogging(config_); - -#ifndef WIN32 - if (!CONFIG_STRING(config_, "service.group").empty() ||!CONFIG_STRING(config_, "service.user").empty() ) { - struct rlimit limit; - getrlimit(RLIMIT_CORE, &limit); - - if (!CONFIG_STRING(config_, "service.group").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"; - return 1; - } - - if (((setgid(gr->gr_gid)) != 0) || (initgroups(CONFIG_STRING(config_, "service.user").c_str(), gr->gr_gid) != 0)) { - std::cerr << "Failed to set service.group name " << CONFIG_STRING(config_, "service.group") << " - " << gr->gr_gid << ":" << strerror(errno) << "\n"; - return 1; - } - } - - if (!CONFIG_STRING(config_, "service.user").empty()) { - 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"; - return 1; - } - - if ((setuid(pw->pw_uid)) != 0) { - std::cerr << "Failed to set service.user name " << CONFIG_STRING(config_, "service.user") << " - " << pw->pw_uid << ":" << strerror(errno) << "\n"; - return 1; - } - } - setrlimit(RLIMIT_CORE, &limit); - } - - struct rlimit limit; - limit.rlim_max = RLIM_INFINITY; - limit.rlim_cur = RLIM_INFINITY; - setrlimit(RLIMIT_CORE, &limit); -#endif - - Swift::SimpleEventLoop eventLoop; - - Swift::BoostNetworkFactories *factories = new Swift::BoostNetworkFactories(&eventLoop); - UserRegistry userRegistry(config_, factories); - - Component transport(&eventLoop, factories, config_, NULL, &userRegistry); - component_ = &transport; -// Logger logger(&transport); - - std::string error; - StorageBackend *storageBackend = StorageBackend::createBackend(config_, error); - if (storageBackend == NULL) { - if (!error.empty()) { - std::cerr << error << "\n"; - return -2; - } - } - else if (!storageBackend->connect()) { - std::cerr << "Can't connect to database. Check the log to find out the reason.\n"; - return -1; - } - - Logging::redirect_stderr(); - - DiscoItemsResponder discoItemsResponder(&transport); - discoItemsResponder.start(); - - UserManager userManager(&transport, &userRegistry, &discoItemsResponder, storageBackend); - userManager_ = &userManager; - - UserRegistration *userRegistration = NULL; - UsersReconnecter *usersReconnecter = NULL; - if (storageBackend) { - userRegistration = new UserRegistration(&transport, &userManager, storageBackend); - userRegistration->start(); - - usersReconnecter = new UsersReconnecter(&transport, storageBackend); - } - - FileTransferManager ftManager(&transport, &userManager); - - NetworkPluginServer plugin(&transport, config_, &userManager, &ftManager, &discoItemsResponder); - plugin.start(); - - AdminInterface adminInterface(&transport, &userManager, &plugin, storageBackend, userRegistration); - plugin.setAdminInterface(&adminInterface); - - StatsResponder statsResponder(&transport, &userManager, &plugin, storageBackend); - statsResponder.start(); - - GatewayResponder gatewayResponder(transport.getIQRouter(), &userManager); - gatewayResponder.start(); - - AdHocManager adhocmanager(&transport, &discoItemsResponder, &userManager, storageBackend); - adhocmanager.start(); - - SettingsAdHocCommandFactory settings; - adhocmanager.addAdHocCommand(&settings); - - eventLoop_ = &eventLoop; - - eventLoop.run(); - -#ifndef WIN32 - umask(old_cmask); -#endif - - if (userRegistration) { - userRegistration->stop(); - delete userRegistration; - } - - if (usersReconnecter) { - delete usersReconnecter; - } - - delete storageBackend; - delete factories; - return 0; -} From ba5f26a7cebaac0ecae6d070b6097bd5788216aa Mon Sep 17 00:00:00 2001 From: Richard H Date: Sat, 10 Nov 2012 17:02:29 +0100 Subject: [PATCH 38/61] Re-worked top-level CMakeLists.txt to allow configuring using ENABLE_* style variables. --- CMakeLists.txt | 371 +++++++++++++++++++++++++++++++------------------ 1 file changed, 233 insertions(+), 138 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e1c2792..d162e877 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,21 @@ message(STATUS "|- log4cxx : -DLOG4CXX_INCLUDE_DIR, -DLOG4CXX_LIBRARY") message(STATUS "|- purple : -DPURPLE_INCLUDE_DIR, -DPURPLE_LIBRARY") message(STATUS " : -DPURPLE_NOT_RUNTIME - enables compilation with libpurple.lib") +option(ENABLE_SQLITE3 "Build with SQLite3 support" ON) +option(ENABLE_MYSQL "Build with MySQL support" ON) +option(ENABLE_PQXX "Build with Postgres supoort" ON) + +#option(ENABLE_FROTZ "Build Frotz plugin" ON) +option(ENABLE_IRC "Build IRC plugin" ON) +option(ENABLE_PURPLE "Build Libpurple plugin" ON) +option(ENABLE_SKYPE "Build Skype plugin" ON) +#option(ENABLE_TWITTER "Build Twitter plugin" ON) +#option(ENABLE_YAHOO2 "Build Yahoo plugin" ON) + +option(ENABLE_DOCS "Build Docs" ON) +option(ENABLE_LOG "Build with logging using Log4cxx" ON) +option(ENABLE_TESTS "Build Tests using CppUnit" ON) + MACRO(LIST_CONTAINS var value) SET(${var}) FOREACH (value2 ${ARGN}) @@ -30,69 +45,114 @@ endif() set(CMAKE_MODULE_PATH "cmake_modules") -# FIND CPPUNIT -set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(cppunit) +###### Prerequisites ###### -if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) - set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) - set(CPPUNIT_FOUND 1) - message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}") -else() +# FIND BOOST +set(Boost_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +if (WIN32) + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME OFF) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) +else(WIN32) + LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY}) + if(contains) + message(STATUS "Using non-multithreaded boost") + set(Boost_USE_MULTITHREADED 0) + endif(contains) + set(Boost_FIND_QUIETLY ON) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals) + if (NOT Boost_FOUND) + set(Boost_FIND_QUIETLY OFF) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) + endif() +endif(WIN32) +message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") + +# FIND POPT +if (NOT WIN32) + set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(popt REQUIRED) endif() +###### Database ###### + # FIND SQLITE3 -if (NOT CMAKE_COMPILER_IS_GNUCXX) -ADD_SUBDIRECTORY(msvc-deps) -else() -if (WIN32) -ADD_SUBDIRECTORY(msvc-deps/sqlite3) -else() -set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(sqlite3) -endif() +if (ENABLE_SQLITE3) + if (NOT CMAKE_COMPILER_IS_GNUCXX) + ADD_SUBDIRECTORY(msvc-deps) + else() + if (WIN32) + ADD_SUBDIRECTORY(msvc-deps/sqlite3) + else() + set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(sqlite3) + endif() + endif() endif() # FIND MYSQL -set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(mysql) +if(ENABLE_MYSQL) + set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(mysql) +endif() + +# FIND PQXX +if(ENABLE_PQXX) + set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(pqxx) +endif() + +###### Plugins ###### # FIND LIBPURPLE -set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(purple) +if(ENABLE_PURPLE) + set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(purple) -if (WIN32) - if (PURPLE_NOT_RUNTIME) + if (WIN32) + if (PURPLE_NOT_RUNTIME) + add_definitions(-DPURPLE_RUNTIME=0) + else(PURPLE_NOT_RUNTIME) + add_definitions(-DPURPLE_RUNTIME=1) + endif(PURPLE_NOT_RUNTIME) + else() add_definitions(-DPURPLE_RUNTIME=0) - else(PURPLE_NOT_RUNTIME) - add_definitions(-DPURPLE_RUNTIME=1) - endif(PURPLE_NOT_RUNTIME) -else() - add_definitions(-DPURPLE_RUNTIME=0) + endif() + + # FIND LIBEVENT + set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(event) endif() # FIND GLIB -# if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) -# set(GLIB2_FOUND TRUE) -# else() - set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(glib) -# endif() +if(ENABLE_SKYPE OR ENABLE_PURPLE) +# if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) +# set(GLIB2_FOUND TRUE) +# else() + set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(glib) +# endif() +endif() # FIND LIBXML2 # set(libxml2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") # find_package(libxml2) -# FIND POPT -if (NOT WIN32) - set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(popt) -endif() +# FIND PROTOBUF +set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(Protobuf REQUIRED) -# FIND LIBEVENT -set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(event) +if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY) + set(PROTOBUF_FOUND 1) + set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) + if (PROTOBUF_PROTOC_EXECUTABLE) + else() + set(PROTOBUF_PROTOC_EXECUTABLE protoc) + endif() + message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}") +endif() # FIND SWIFTEN @@ -132,78 +192,58 @@ set(openssl_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(openssl) endif() -# FIND BOOST -set(Boost_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -if (WIN32) - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(Boost_USE_STATIC_RUNTIME OFF) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) -else(WIN32) - LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY}) - if(contains) - message(STATUS "Using non-multithreaded boost") - set(Boost_USE_MULTITHREADED 0) - endif(contains) - set(Boost_FIND_QUIETLY ON) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals) - if (NOT Boost_FOUND) - set(Boost_FIND_QUIETLY OFF) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) - endif() -endif(WIN32) +if(ENABLE_IRC) + set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(Communi) -message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") - -set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(Protobuf) - -# FIND PROTOBUF -if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY) - set(PROTOBUF_FOUND 1) - set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) - if (PROTOBUF_PROTOC_EXECUTABLE) - else() - set(PROTOBUF_PROTOC_EXECUTABLE protoc) - endif() - message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}") -endif() - - -set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(Communi) - -if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) - set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) - set(LOG4CXX_FOUND 1) - message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}") -else() - set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(log4cxx) + INCLUDE(FindQt4) + FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork) + # ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) + ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) + # ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) endif() set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(event) -set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(pqxx) - -if (NOT WIN32) +if (NOT WIN32 AND ENABLE_SKYPE) set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(dbus) endif() -set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(yahoo2) +#if(ENABLE_YAHOO2) +# set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +# find_package(yahoo2) +#endif() -find_package(Doxygen) +####### Miscallanous ###### -INCLUDE(FindQt4) -FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork) +if(ENABLE_DOCS) + find_package(Doxygen) +endif() -# ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) -ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) -# ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) +if(ENABLE_LOG) + if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) + set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) + set(LOG4CXX_FOUND 1) + message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}") + else() + set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(log4cxx) + endif() +endif() + +# FIND CPPUNIT +if(ENABLE_TESTS) + set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(cppunit) + + if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) + set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) + set(CPPUNIT_FOUND 1) + message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}") + endif() +endif() message(" Supported features") message("-----------------------") @@ -234,14 +274,18 @@ if (SQLITE3_FOUND) include_directories(${SQLITE3_INCLUDE_DIR}) message("SQLite3 : yes") else (SQLITE3_FOUND) -if (WIN32) - ADD_DEFINITIONS(-DWITH_SQLITE) - include_directories(msvc-deps/sqlite3) - message("SQLite3 : bundled") -else() - set(SQLITE3_LIBRARIES "") - message("SQLite3 : no") -endif() + if (WIN32) + ADD_DEFINITIONS(-DWITH_SQLITE) + include_directories(msvc-deps/sqlite3) + message("SQLite3 : bundled") + else() + set(SQLITE3_LIBRARIES "") + if(ENABLE_SQLITE3) + message("SQLite3 : no (install sqlite3)") + else(ENABLE_SQLITE3) + message("SQLite3 : no (user disabled)") + endif() + endif() endif (SQLITE3_FOUND) if (MYSQL_FOUND) @@ -250,7 +294,11 @@ if (MYSQL_FOUND) message("MySQL : yes") else (MYSQL_FOUND) set(MYSQL_LIBRARIES "") - message("MySQL : no (install mysql-devel)") + if(ENABLE_MYSQL) + message("MySQL : no (install mysql-devel)") + else(ENABLE_MYSQL) + message("MySQL : no (user disabled)") + endif() endif (MYSQL_FOUND) if (PQXX_FOUND) @@ -260,7 +308,11 @@ if (PQXX_FOUND) else (PQXX_FOUND) set(PQXX_LIBRARY "") set(PQ_LIBRARY "") - message("PostgreSQL : no (install libpqxx-devel)") + if(ENABLE_PQXX) + message("PostgreSQL : no (install libpqxx-devel)") + else(ENABLE_PQXX) + message("PostgreSQL : no (user disabled)") + endif() endif (PQXX_FOUND) if (PROTOBUF_FOUND) @@ -273,7 +325,11 @@ if (PROTOBUF_FOUND) include_directories(${PURPLE_INCLUDE_DIR}) include_directories(${GLIB2_INCLUDE_DIR}) else() - message("Libpurple plugin : no (install libpurple)") + if(ENABLE_PURPLE) + message("Libpurple plugin : no (install libpurple)") + else(ENABLE_PURPLE) + message("Libpurple plugin : no (user disabled)") + endif() endif() if (HAVE_EVENT) @@ -281,7 +337,9 @@ if (PROTOBUF_FOUND) include_directories(${EVENT_INCLUDE_DIRS}) message(" libev eventloop : yes") else() - message(" libev eventloop : no (install libev-devel)") + if(ENABLE_PURPLE) + message(" libev eventloop : no (install libev-devel)") + endif() endif() if(IRC_FOUND) @@ -291,28 +349,44 @@ if (PROTOBUF_FOUND) include_directories(${IRC_INCLUDE_DIR}) include(${QT_USE_FILE}) else() - message("IRC plugin : no (install libCommuni and libprotobuf-dev)") + if(ENABLE_IRC) + message("IRC plugin : no (install libCommuni and libprotobuf-dev)") + else(ENABLE_IRC) + message("IRC plugin : no (user disabled)") + endif() endif() -if (NOT WIN32) - message("Frotz plugin : yes") - message("SMSTools3 plugin : yes") - if(${LIBDBUSGLIB_FOUND}) - message("Skype plugin : yes") - include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + if (NOT WIN32) + message("Frotz plugin : yes") + if(ENABLE_SMSTOOLS3) + message("SMSTools3 plugin : yes") + else() + message("SMSTools3 plugin : no") + endif() + if(${LIBDBUSGLIB_FOUND}) + message("Skype plugin : yes") + include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + else() + if(ENABLE_SKYPE) + message("Skype plugin : no (install dbus-glib-devel)") + else(ENABLE_SKYPE) + message("Skype plugin : no (user disabled)") + endif() + endif() else() - message("Skype plugin : no (install dbus-glib-devel)") + message("Frotz plugin : no") + message("SMSTools3 plugin : no") + message("Skype plugin : no") endif() -else() - message("Frotz plugin : no") - message("SMSTools3 plugin : no") - message("Skype plugin : no") -endif() # We have our own copy now... # if(YAHOO2_FOUND) + if(ENABLE_YAHOO2) message("Libyahoo2 plugin : yes") # include_directories(${YAHOO2_INCLUDE_DIR}) + else() + message("Libyahoo2 plugin : no") + endif() # else() # message("Libyahoo2 plugin : no (install libyahoo2-devel)") # endif() @@ -336,22 +410,26 @@ if (LOG4CXX_FOUND) ADD_DEFINITIONS(-DWITH_LOG4CXX) else() set(LOG4CXX_LIBRARIES "") - message("Log4cxx : no (install log4cxx-devel)") + if(ENABLE_LOG) + message("Log4cxx : no (install log4cxx-devel)") + else(ENABLE_LOG) + message("Log4cxx : no (user disabled)") + endif() endif() if (WIN32) -ADD_DEFINITIONS(-DLOG4CXX_STATIC) -ADD_DEFINITIONS(-D_WIN32_WINNT=0x501) -ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) -ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H) -ADD_DEFINITIONS(-DBOOST_THREAD_USE_LIB) + ADD_DEFINITIONS(-DLOG4CXX_STATIC) + ADD_DEFINITIONS(-D_WIN32_WINNT=0x501) + ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) + ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H) + ADD_DEFINITIONS(-DBOOST_THREAD_USE_LIB) endif() if(CMAKE_BUILD_TYPE MATCHES Debug) -if (CMAKE_COMPILER_IS_GNUCXX) - ADD_DEFINITIONS(-O0) - ADD_DEFINITIONS(-ggdb) -endif() + if (CMAKE_COMPILER_IS_GNUCXX) + ADD_DEFINITIONS(-O0) + ADD_DEFINITIONS(-ggdb) + endif() ADD_DEFINITIONS(-DDEBUG) message("Debug : yes") else(CMAKE_BUILD_TYPE MATCHES Debug) @@ -386,14 +464,31 @@ if (CPPUNIT_FOUND) message("tests : yes") include_directories(${CPPUNIT_INCLUDE_DIR}) else() - message("tests : no (install CPPUnit)") + if(ENABLE_TESTS) + message("tests : no (install CPPUnit)") + else(ENABLE_TESTS) + message("tests : no (user disabled)") + endif() endif() if(DOXYGEN_FOUND) message("Docs : yes") ADD_SUBDIRECTORY(docs) else(DOXYGEN_FOUND) - message("Docs : no (install doxygen)") + if(ENABLE_DOCS) + message("Docs : no (install doxygen)") + else(ENABLE_DOCS) + message("Docs : no (user disabled)") + endif() endif(DOXYGEN_FOUND) message("----------------------") + +if(NOT SQLITE3_FOUND AND NOT MYSQL_FOUND AND NOT PQXX_FOUND) + if(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) + message("Could not find any database - Please install at least one of sqlite3-devel, mysql-devel or pqxx-devel if you want to use transport mode.") + else(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) + message("Please enable at least one of SQLITE3, MYSQL, PQXX databases to use transport mode.") + endif() +endif() + From fb4b587ef8f38e46613acffd45bd26f7ae3472bb Mon Sep 17 00:00:00 2001 From: chain Date: Sat, 10 Nov 2012 17:11:19 +0100 Subject: [PATCH 39/61] Re-worked top-level CMakeLists.txt to allow configuring using ENABLE_* style variables. --- CMakeLists.txt | 371 +++++++++++++++++++++++++++++++------------------ 1 file changed, 233 insertions(+), 138 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e1c2792..d162e877 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,21 @@ message(STATUS "|- log4cxx : -DLOG4CXX_INCLUDE_DIR, -DLOG4CXX_LIBRARY") message(STATUS "|- purple : -DPURPLE_INCLUDE_DIR, -DPURPLE_LIBRARY") message(STATUS " : -DPURPLE_NOT_RUNTIME - enables compilation with libpurple.lib") +option(ENABLE_SQLITE3 "Build with SQLite3 support" ON) +option(ENABLE_MYSQL "Build with MySQL support" ON) +option(ENABLE_PQXX "Build with Postgres supoort" ON) + +#option(ENABLE_FROTZ "Build Frotz plugin" ON) +option(ENABLE_IRC "Build IRC plugin" ON) +option(ENABLE_PURPLE "Build Libpurple plugin" ON) +option(ENABLE_SKYPE "Build Skype plugin" ON) +#option(ENABLE_TWITTER "Build Twitter plugin" ON) +#option(ENABLE_YAHOO2 "Build Yahoo plugin" ON) + +option(ENABLE_DOCS "Build Docs" ON) +option(ENABLE_LOG "Build with logging using Log4cxx" ON) +option(ENABLE_TESTS "Build Tests using CppUnit" ON) + MACRO(LIST_CONTAINS var value) SET(${var}) FOREACH (value2 ${ARGN}) @@ -30,69 +45,114 @@ endif() set(CMAKE_MODULE_PATH "cmake_modules") -# FIND CPPUNIT -set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(cppunit) +###### Prerequisites ###### -if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) - set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) - set(CPPUNIT_FOUND 1) - message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}") -else() +# FIND BOOST +set(Boost_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +if (WIN32) + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME OFF) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) +else(WIN32) + LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY}) + if(contains) + message(STATUS "Using non-multithreaded boost") + set(Boost_USE_MULTITHREADED 0) + endif(contains) + set(Boost_FIND_QUIETLY ON) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals) + if (NOT Boost_FOUND) + set(Boost_FIND_QUIETLY OFF) + find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) + endif() +endif(WIN32) +message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") + +# FIND POPT +if (NOT WIN32) + set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(popt REQUIRED) endif() +###### Database ###### + # FIND SQLITE3 -if (NOT CMAKE_COMPILER_IS_GNUCXX) -ADD_SUBDIRECTORY(msvc-deps) -else() -if (WIN32) -ADD_SUBDIRECTORY(msvc-deps/sqlite3) -else() -set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(sqlite3) -endif() +if (ENABLE_SQLITE3) + if (NOT CMAKE_COMPILER_IS_GNUCXX) + ADD_SUBDIRECTORY(msvc-deps) + else() + if (WIN32) + ADD_SUBDIRECTORY(msvc-deps/sqlite3) + else() + set(sqlite3_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(sqlite3) + endif() + endif() endif() # FIND MYSQL -set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(mysql) +if(ENABLE_MYSQL) + set(mysql_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(mysql) +endif() + +# FIND PQXX +if(ENABLE_PQXX) + set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(pqxx) +endif() + +###### Plugins ###### # FIND LIBPURPLE -set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(purple) +if(ENABLE_PURPLE) + set(purple_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(purple) -if (WIN32) - if (PURPLE_NOT_RUNTIME) + if (WIN32) + if (PURPLE_NOT_RUNTIME) + add_definitions(-DPURPLE_RUNTIME=0) + else(PURPLE_NOT_RUNTIME) + add_definitions(-DPURPLE_RUNTIME=1) + endif(PURPLE_NOT_RUNTIME) + else() add_definitions(-DPURPLE_RUNTIME=0) - else(PURPLE_NOT_RUNTIME) - add_definitions(-DPURPLE_RUNTIME=1) - endif(PURPLE_NOT_RUNTIME) -else() - add_definitions(-DPURPLE_RUNTIME=0) + endif() + + # FIND LIBEVENT + set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(event) endif() # FIND GLIB -# if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) -# set(GLIB2_FOUND TRUE) -# else() - set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(glib) -# endif() +if(ENABLE_SKYPE OR ENABLE_PURPLE) +# if (GLIB2_INCLUDE_DIR AND GLIB2_LIBRARIES) +# set(GLIB2_FOUND TRUE) +# else() + set(glib_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(glib) +# endif() +endif() # FIND LIBXML2 # set(libxml2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") # find_package(libxml2) -# FIND POPT -if (NOT WIN32) - set(popt_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(popt) -endif() +# FIND PROTOBUF +set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +find_package(Protobuf REQUIRED) -# FIND LIBEVENT -set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(event) +if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY) + set(PROTOBUF_FOUND 1) + set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) + if (PROTOBUF_PROTOC_EXECUTABLE) + else() + set(PROTOBUF_PROTOC_EXECUTABLE protoc) + endif() + message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}") +endif() # FIND SWIFTEN @@ -132,78 +192,58 @@ set(openssl_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(openssl) endif() -# FIND BOOST -set(Boost_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -if (WIN32) - set(Boost_USE_STATIC_LIBS ON) - set(Boost_USE_MULTITHREADED ON) - set(Boost_USE_STATIC_RUNTIME OFF) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) -else(WIN32) - LIST_CONTAINS(contains -lboost_program_options ${SWIFTEN_LIBRARY}) - if(contains) - message(STATUS "Using non-multithreaded boost") - set(Boost_USE_MULTITHREADED 0) - endif(contains) - set(Boost_FIND_QUIETLY ON) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread-mt signals) - if (NOT Boost_FOUND) - set(Boost_FIND_QUIETLY OFF) - find_package(Boost COMPONENTS program_options date_time system filesystem regex thread signals REQUIRED) - endif() -endif(WIN32) +if(ENABLE_IRC) + set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(Communi) -message( STATUS "Found Boost: ${Boost_LIBRARIES}, ${Boost_INCLUDE_DIR}") - -set(Protobuf_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(Protobuf) - -# FIND PROTOBUF -if (NOT PROTOBUF_FOUND AND PROTOBUF_INCLUDE_DIR AND PROTOBUF_LIBRARY) - set(PROTOBUF_FOUND 1) - set(PROTOBUF_INCLUDE_DIRS ${PROTOBUF_INCLUDE_DIR}) - if (PROTOBUF_PROTOC_EXECUTABLE) - else() - set(PROTOBUF_PROTOC_EXECUTABLE protoc) - endif() - message(STATUS "Using protobuf: ${PROTOBUF_INCLUDE_DIRS} ${PROTOBUF_LIBRARY}") -endif() - - -set(Communi_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(Communi) - -if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) - set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) - set(LOG4CXX_FOUND 1) - message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}") -else() - set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") - find_package(log4cxx) + INCLUDE(FindQt4) + FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork) + # ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) + ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) + # ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) endif() set(event_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(event) -set(pqxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(pqxx) - -if (NOT WIN32) +if (NOT WIN32 AND ENABLE_SKYPE) set(dbus_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") find_package(dbus) endif() -set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") -find_package(yahoo2) +#if(ENABLE_YAHOO2) +# set(yahoo2_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") +# find_package(yahoo2) +#endif() -find_package(Doxygen) +####### Miscallanous ###### -INCLUDE(FindQt4) -FIND_PACKAGE(Qt4 COMPONENTS QtCore QtNetwork) +if(ENABLE_DOCS) + find_package(Doxygen) +endif() -# ADD_DEFINITIONS(${SWIFTEN_CFLAGS}) -ADD_DEFINITIONS(-DSUPPORT_LEGACY_CAPS) -# ADD_DEFINITIONS(-DBOOST_FILESYSTEM_VERSION=2) +if(ENABLE_LOG) + if(LOG4CXX_INCLUDE_DIR AND LOG4CXX_LIBRARY) + set(LOG4CXX_LIBRARIES ${LOG4CXX_LIBRARY}) + set(LOG4CXX_FOUND 1) + message(STATUS "Using log4cxx: ${CPPUNIT_INCLUDE_DIR} ${LOG4CXX_INCLUDE_DIR}") + else() + set(log4cxx_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(log4cxx) + endif() +endif() + +# FIND CPPUNIT +if(ENABLE_TESTS) + set(cppunit_DIR "${CMAKE_SOURCE_DIR}/cmake_modules") + find_package(cppunit) + + if(NOT CPPUNIT_FOUND AND CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY) + set(CCPUNIT_LIBRARIES ${CPPUNIT_LIBRARY}) + set(CPPUNIT_FOUND 1) + message(STATUS "Using cppunit: ${CPPUNIT_INCLUDE_DIR} ${CPPUNIT_LIBRARIES}") + endif() +endif() message(" Supported features") message("-----------------------") @@ -234,14 +274,18 @@ if (SQLITE3_FOUND) include_directories(${SQLITE3_INCLUDE_DIR}) message("SQLite3 : yes") else (SQLITE3_FOUND) -if (WIN32) - ADD_DEFINITIONS(-DWITH_SQLITE) - include_directories(msvc-deps/sqlite3) - message("SQLite3 : bundled") -else() - set(SQLITE3_LIBRARIES "") - message("SQLite3 : no") -endif() + if (WIN32) + ADD_DEFINITIONS(-DWITH_SQLITE) + include_directories(msvc-deps/sqlite3) + message("SQLite3 : bundled") + else() + set(SQLITE3_LIBRARIES "") + if(ENABLE_SQLITE3) + message("SQLite3 : no (install sqlite3)") + else(ENABLE_SQLITE3) + message("SQLite3 : no (user disabled)") + endif() + endif() endif (SQLITE3_FOUND) if (MYSQL_FOUND) @@ -250,7 +294,11 @@ if (MYSQL_FOUND) message("MySQL : yes") else (MYSQL_FOUND) set(MYSQL_LIBRARIES "") - message("MySQL : no (install mysql-devel)") + if(ENABLE_MYSQL) + message("MySQL : no (install mysql-devel)") + else(ENABLE_MYSQL) + message("MySQL : no (user disabled)") + endif() endif (MYSQL_FOUND) if (PQXX_FOUND) @@ -260,7 +308,11 @@ if (PQXX_FOUND) else (PQXX_FOUND) set(PQXX_LIBRARY "") set(PQ_LIBRARY "") - message("PostgreSQL : no (install libpqxx-devel)") + if(ENABLE_PQXX) + message("PostgreSQL : no (install libpqxx-devel)") + else(ENABLE_PQXX) + message("PostgreSQL : no (user disabled)") + endif() endif (PQXX_FOUND) if (PROTOBUF_FOUND) @@ -273,7 +325,11 @@ if (PROTOBUF_FOUND) include_directories(${PURPLE_INCLUDE_DIR}) include_directories(${GLIB2_INCLUDE_DIR}) else() - message("Libpurple plugin : no (install libpurple)") + if(ENABLE_PURPLE) + message("Libpurple plugin : no (install libpurple)") + else(ENABLE_PURPLE) + message("Libpurple plugin : no (user disabled)") + endif() endif() if (HAVE_EVENT) @@ -281,7 +337,9 @@ if (PROTOBUF_FOUND) include_directories(${EVENT_INCLUDE_DIRS}) message(" libev eventloop : yes") else() - message(" libev eventloop : no (install libev-devel)") + if(ENABLE_PURPLE) + message(" libev eventloop : no (install libev-devel)") + endif() endif() if(IRC_FOUND) @@ -291,28 +349,44 @@ if (PROTOBUF_FOUND) include_directories(${IRC_INCLUDE_DIR}) include(${QT_USE_FILE}) else() - message("IRC plugin : no (install libCommuni and libprotobuf-dev)") + if(ENABLE_IRC) + message("IRC plugin : no (install libCommuni and libprotobuf-dev)") + else(ENABLE_IRC) + message("IRC plugin : no (user disabled)") + endif() endif() -if (NOT WIN32) - message("Frotz plugin : yes") - message("SMSTools3 plugin : yes") - if(${LIBDBUSGLIB_FOUND}) - message("Skype plugin : yes") - include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + if (NOT WIN32) + message("Frotz plugin : yes") + if(ENABLE_SMSTOOLS3) + message("SMSTools3 plugin : yes") + else() + message("SMSTools3 plugin : no") + endif() + if(${LIBDBUSGLIB_FOUND}) + message("Skype plugin : yes") + include_directories(${LIBDBUSGLIB_INCLUDE_DIRS}) + else() + if(ENABLE_SKYPE) + message("Skype plugin : no (install dbus-glib-devel)") + else(ENABLE_SKYPE) + message("Skype plugin : no (user disabled)") + endif() + endif() else() - message("Skype plugin : no (install dbus-glib-devel)") + message("Frotz plugin : no") + message("SMSTools3 plugin : no") + message("Skype plugin : no") endif() -else() - message("Frotz plugin : no") - message("SMSTools3 plugin : no") - message("Skype plugin : no") -endif() # We have our own copy now... # if(YAHOO2_FOUND) + if(ENABLE_YAHOO2) message("Libyahoo2 plugin : yes") # include_directories(${YAHOO2_INCLUDE_DIR}) + else() + message("Libyahoo2 plugin : no") + endif() # else() # message("Libyahoo2 plugin : no (install libyahoo2-devel)") # endif() @@ -336,22 +410,26 @@ if (LOG4CXX_FOUND) ADD_DEFINITIONS(-DWITH_LOG4CXX) else() set(LOG4CXX_LIBRARIES "") - message("Log4cxx : no (install log4cxx-devel)") + if(ENABLE_LOG) + message("Log4cxx : no (install log4cxx-devel)") + else(ENABLE_LOG) + message("Log4cxx : no (user disabled)") + endif() endif() if (WIN32) -ADD_DEFINITIONS(-DLOG4CXX_STATIC) -ADD_DEFINITIONS(-D_WIN32_WINNT=0x501) -ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) -ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H) -ADD_DEFINITIONS(-DBOOST_THREAD_USE_LIB) + ADD_DEFINITIONS(-DLOG4CXX_STATIC) + ADD_DEFINITIONS(-D_WIN32_WINNT=0x501) + ADD_DEFINITIONS(-DWIN32_LEAN_AND_MEAN) + ADD_DEFINITIONS(-DBOOST_USE_WINDOWS_H) + ADD_DEFINITIONS(-DBOOST_THREAD_USE_LIB) endif() if(CMAKE_BUILD_TYPE MATCHES Debug) -if (CMAKE_COMPILER_IS_GNUCXX) - ADD_DEFINITIONS(-O0) - ADD_DEFINITIONS(-ggdb) -endif() + if (CMAKE_COMPILER_IS_GNUCXX) + ADD_DEFINITIONS(-O0) + ADD_DEFINITIONS(-ggdb) + endif() ADD_DEFINITIONS(-DDEBUG) message("Debug : yes") else(CMAKE_BUILD_TYPE MATCHES Debug) @@ -386,14 +464,31 @@ if (CPPUNIT_FOUND) message("tests : yes") include_directories(${CPPUNIT_INCLUDE_DIR}) else() - message("tests : no (install CPPUnit)") + if(ENABLE_TESTS) + message("tests : no (install CPPUnit)") + else(ENABLE_TESTS) + message("tests : no (user disabled)") + endif() endif() if(DOXYGEN_FOUND) message("Docs : yes") ADD_SUBDIRECTORY(docs) else(DOXYGEN_FOUND) - message("Docs : no (install doxygen)") + if(ENABLE_DOCS) + message("Docs : no (install doxygen)") + else(ENABLE_DOCS) + message("Docs : no (user disabled)") + endif() endif(DOXYGEN_FOUND) message("----------------------") + +if(NOT SQLITE3_FOUND AND NOT MYSQL_FOUND AND NOT PQXX_FOUND) + if(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) + message("Could not find any database - Please install at least one of sqlite3-devel, mysql-devel or pqxx-devel if you want to use transport mode.") + else(ENABLE_SQLITE3 OR ENABLE_MYSQL OR ENABLE_PQXX) + message("Please enable at least one of SQLITE3, MYSQL, PQXX databases to use transport mode.") + endif() +endif() + From 1548f91d4022e70a51e43b75ce2b7b7ea631f6e1 Mon Sep 17 00:00:00 2001 From: chain Date: Mon, 12 Nov 2012 02:41:17 +0100 Subject: [PATCH 40/61] Make Libyahoo2 backend optional (by using ENABLE_YAHOO2) --- CMakeLists.txt | 27 +++++++++++++-------------- backends/CMakeLists.txt | 4 ++-- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d162e877..213fc1e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ option(ENABLE_IRC "Build IRC plugin" ON) option(ENABLE_PURPLE "Build Libpurple plugin" ON) option(ENABLE_SKYPE "Build Skype plugin" ON) #option(ENABLE_TWITTER "Build Twitter plugin" ON) -#option(ENABLE_YAHOO2 "Build Yahoo plugin" ON) +option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) option(ENABLE_DOCS "Build Docs" ON) option(ENABLE_LOG "Build with logging using Log4cxx" ON) @@ -211,10 +211,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 ###### @@ -379,17 +379,16 @@ if (PROTOBUF_FOUND) message("Skype plugin : no") endif() -# We have our own copy now... -# if(YAHOO2_FOUND) - if(ENABLE_YAHOO2) + if(YAHOO2_FOUND) message("Libyahoo2 plugin : yes") -# include_directories(${YAHOO2_INCLUDE_DIR}) + include_directories(${YAHOO2_INCLUDE_DIR}) else() - message("Libyahoo2 plugin : no") - endif() -# else() -# message("Libyahoo2 plugin : no (install libyahoo2-devel)") -# endif() + if(ENABLE_YAHOO2) + message("Libyahoo2 plugin : no (install libyahoo2-devel)") + else(ENABLE_YAHOO2) + message("Libyahoo2 plugin : no (user disabled)") + endif() + endif() message("Swiften plugin : yes") message("Twitter plugin : yes") diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index ac9b6f0b..3b843b1c 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -15,9 +15,9 @@ if (PROTOBUF_FOUND) if (NOT WIN32) ADD_SUBDIRECTORY(smstools3) ADD_SUBDIRECTORY(frotz) -# if(YAHOO2_FOUND) + if(YAHOO2_FOUND) ADD_SUBDIRECTORY(libyahoo2) -# endif() + endif() ADD_SUBDIRECTORY(twitter) if (${LIBDBUSGLIB_FOUND}) ADD_SUBDIRECTORY(skype) From 487ad85fad8f59555a44a877d5b68b3ada4ef0ad Mon Sep 17 00:00:00 2001 From: chain Date: Mon, 12 Nov 2012 21:18:15 +0100 Subject: [PATCH 41/61] make Twitter optional (by using ENABLE_TWITTER) --- CMakeLists.txt | 16 ++++++++++------ backends/CMakeLists.txt | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 213fc1e0..0147cf25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ option(ENABLE_PQXX "Build with Postgres supoort" ON) option(ENABLE_IRC "Build IRC plugin" ON) option(ENABLE_PURPLE "Build Libpurple plugin" ON) option(ENABLE_SKYPE "Build Skype plugin" ON) -#option(ENABLE_TWITTER "Build Twitter plugin" ON) +option(ENABLE_TWITTER "Build Twitter plugin" ON) option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) option(ENABLE_DOCS "Build Docs" ON) @@ -373,10 +373,16 @@ if (PROTOBUF_FOUND) message("Skype plugin : no (user disabled)") endif() endif() + if(ENABLE_TWITTER) + message("Twitter plugin : yes") + else(ENABLE_TWITTER) + message("Twitter plugin : no (user disabled)") + endif() else() - message("Frotz plugin : no") - message("SMSTools3 plugin : no") - message("Skype plugin : no") + message("Frotz plugin : no (does not run on Win32)") + message("SMSTools3 plugin : no (does not run on Win32)") + message("Skype plugin : no (does not run on Win32)") + message("Twitter plugin : no (does not run on Win32)") endif() if(YAHOO2_FOUND) @@ -391,8 +397,6 @@ if (PROTOBUF_FOUND) endif() message("Swiften plugin : yes") - message("Twitter plugin : yes") - else() message("Network plugins : no (install libprotobuf-dev)") message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 3b843b1c..1306f711 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -18,7 +18,9 @@ if (NOT WIN32) if(YAHOO2_FOUND) ADD_SUBDIRECTORY(libyahoo2) endif() - ADD_SUBDIRECTORY(twitter) + if(ENABLE_TWITTER) + ADD_SUBDIRECTORY(twitter) + endif() if (${LIBDBUSGLIB_FOUND}) ADD_SUBDIRECTORY(skype) endif() From edfa4ec644896ca2980c85cd11e35af1cd036ead Mon Sep 17 00:00:00 2001 From: chain Date: Mon, 12 Nov 2012 21:18:15 +0100 Subject: [PATCH 42/61] make Twitter optional (by using ENABLE_TWITTER) --- CMakeLists.txt | 16 ++++++++++------ backends/CMakeLists.txt | 4 +++- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 213fc1e0..0147cf25 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ option(ENABLE_PQXX "Build with Postgres supoort" ON) option(ENABLE_IRC "Build IRC plugin" ON) option(ENABLE_PURPLE "Build Libpurple plugin" ON) option(ENABLE_SKYPE "Build Skype plugin" ON) -#option(ENABLE_TWITTER "Build Twitter plugin" ON) +option(ENABLE_TWITTER "Build Twitter plugin" ON) option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) option(ENABLE_DOCS "Build Docs" ON) @@ -373,10 +373,16 @@ if (PROTOBUF_FOUND) message("Skype plugin : no (user disabled)") endif() endif() + if(ENABLE_TWITTER) + message("Twitter plugin : yes") + else(ENABLE_TWITTER) + message("Twitter plugin : no (user disabled)") + endif() else() - message("Frotz plugin : no") - message("SMSTools3 plugin : no") - message("Skype plugin : no") + message("Frotz plugin : no (does not run on Win32)") + message("SMSTools3 plugin : no (does not run on Win32)") + message("Skype plugin : no (does not run on Win32)") + message("Twitter plugin : no (does not run on Win32)") endif() if(YAHOO2_FOUND) @@ -391,8 +397,6 @@ if (PROTOBUF_FOUND) endif() message("Swiften plugin : yes") - message("Twitter plugin : yes") - else() message("Network plugins : no (install libprotobuf-dev)") message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 3b843b1c..1306f711 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -18,7 +18,9 @@ if (NOT WIN32) if(YAHOO2_FOUND) ADD_SUBDIRECTORY(libyahoo2) endif() - ADD_SUBDIRECTORY(twitter) + if(ENABLE_TWITTER) + ADD_SUBDIRECTORY(twitter) + endif() if (${LIBDBUSGLIB_FOUND}) ADD_SUBDIRECTORY(skype) endif() From e64853b91ea1b292c825e7d85a01306a4cddc3fa Mon Sep 17 00:00:00 2001 From: chain Date: Mon, 12 Nov 2012 22:50:44 +0100 Subject: [PATCH 43/61] Make SMSTools3 plugin optional (by using ENABLE_SMSTOOLS3) --- CMakeLists.txt | 3 ++- backends/CMakeLists.txt | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0147cf25..6ded9c07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ option(ENABLE_PQXX "Build with Postgres supoort" ON) #option(ENABLE_FROTZ "Build Frotz plugin" ON) option(ENABLE_IRC "Build IRC plugin" ON) option(ENABLE_PURPLE "Build Libpurple plugin" ON) +option(ENABLE_SMSTOOLS3 "Build SMSTools3 plugin" ON) option(ENABLE_SKYPE "Build Skype plugin" ON) option(ENABLE_TWITTER "Build Twitter plugin" ON) option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) @@ -361,7 +362,7 @@ if (PROTOBUF_FOUND) if(ENABLE_SMSTOOLS3) message("SMSTools3 plugin : yes") else() - message("SMSTools3 plugin : no") + message("SMSTools3 plugin : no (user disabled)") endif() if(${LIBDBUSGLIB_FOUND}) message("Skype plugin : yes") diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index 1306f711..fb4ca0e2 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -13,7 +13,9 @@ if (PROTOBUF_FOUND) if (NOT WIN32) - ADD_SUBDIRECTORY(smstools3) + if(ENABLE_SMSTOOLS3) + ADD_SUBDIRECTORY(smstools3) + endif() ADD_SUBDIRECTORY(frotz) if(YAHOO2_FOUND) ADD_SUBDIRECTORY(libyahoo2) From 74983ae8c25765c13031835df2e2d7a326dc65b9 Mon Sep 17 00:00:00 2001 From: chain Date: Tue, 13 Nov 2012 01:11:12 +0100 Subject: [PATCH 44/61] Make Frotz and Swiften optional (using ENABLE_FROTZ and ENABLE_SWIFTEN) --- CMakeLists.txt | 15 ++++++++++++--- backends/CMakeLists.txt | 36 +++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6ded9c07..f575e953 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,11 +19,12 @@ option(ENABLE_SQLITE3 "Build with SQLite3 support" ON) option(ENABLE_MYSQL "Build with MySQL support" ON) option(ENABLE_PQXX "Build with Postgres supoort" ON) -#option(ENABLE_FROTZ "Build Frotz plugin" ON) +option(ENABLE_FROTZ "Build Frotz plugin" ON) option(ENABLE_IRC "Build IRC plugin" ON) option(ENABLE_PURPLE "Build Libpurple plugin" ON) option(ENABLE_SMSTOOLS3 "Build SMSTools3 plugin" ON) option(ENABLE_SKYPE "Build Skype plugin" ON) +option(ENABLE_SWIFTEN "Build Swiften plugin" ON) option(ENABLE_TWITTER "Build Twitter plugin" ON) option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) @@ -358,7 +359,11 @@ if (PROTOBUF_FOUND) endif() if (NOT WIN32) - message("Frotz plugin : yes") + if(ENABLE_FROTZ) + message("Frotz plugin : yes") + else() + message("Frotz plugin : no (user disabled)") + endif() if(ENABLE_SMSTOOLS3) message("SMSTools3 plugin : yes") else() @@ -397,7 +402,11 @@ if (PROTOBUF_FOUND) endif() endif() - message("Swiften plugin : yes") + if(ENABLE_SWIFTEN) + message("Swiften plugin : yes") + else() + message("Swiften plugin : no (user disabled)") + endif() else() message("Network plugins : no (install libprotobuf-dev)") message("Libpurple plugin : no (install libpurple and libprotobuf-dev)") diff --git a/backends/CMakeLists.txt b/backends/CMakeLists.txt index fb4ca0e2..70918f94 100644 --- a/backends/CMakeLists.txt +++ b/backends/CMakeLists.txt @@ -7,25 +7,27 @@ if (PROTOBUF_FOUND) ADD_SUBDIRECTORY(libcommuni) endif() - ADD_SUBDIRECTORY(swiften) + if (ENABLE_SWIFTEN) + ADD_SUBDIRECTORY(swiften) + endif() ADD_SUBDIRECTORY(template) - -if (NOT WIN32) - if(ENABLE_SMSTOOLS3) - ADD_SUBDIRECTORY(smstools3) - endif() - ADD_SUBDIRECTORY(frotz) - if(YAHOO2_FOUND) - ADD_SUBDIRECTORY(libyahoo2) - endif() - if(ENABLE_TWITTER) - ADD_SUBDIRECTORY(twitter) - endif() - if (${LIBDBUSGLIB_FOUND}) - ADD_SUBDIRECTORY(skype) + if (NOT WIN32) + if(ENABLE_SMSTOOLS3) + ADD_SUBDIRECTORY(smstools3) + endif() + if(ENABLE_FROTZ) + ADD_SUBDIRECTORY(frotz) + endif() + if(YAHOO2_FOUND) + ADD_SUBDIRECTORY(libyahoo2) + endif() + if(ENABLE_TWITTER) + ADD_SUBDIRECTORY(twitter) + endif() + if (${LIBDBUSGLIB_FOUND}) + ADD_SUBDIRECTORY(skype) + endif() endif() endif() - -endif() From 4691982ffba774c0b1c0013327a34843e35a7eb6 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 13 Nov 2012 10:37:37 +0100 Subject: [PATCH 45/61] Disable tests by default --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f575e953..2f14df81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,7 @@ option(ENABLE_YAHOO2 "Build Libyahoo2 plugin" ON) option(ENABLE_DOCS "Build Docs" ON) option(ENABLE_LOG "Build with logging using Log4cxx" ON) -option(ENABLE_TESTS "Build Tests using CppUnit" ON) +option(ENABLE_TESTS "Build Tests using CppUnit" OFF) MACRO(LIST_CONTAINS var value) SET(${var}) From e0f560a64814be67debae69991598e5b6b8276e6 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 13 Nov 2012 12:37:42 +0100 Subject: [PATCH 46/61] Added database.vip_statement, database.vip_only and database.vip_message variables --- src/config.cpp | 3 +++ src/mysqlbackend.cpp | 17 +++++++++++++++++ src/tests/basictest.h | 1 + src/tests/usermanager.cpp | 21 +++++++++++++++++++++ src/usermanager.cpp | 16 ++++++++++++++++ 5 files changed, 58 insertions(+) diff --git a/src/config.cpp b/src/config.cpp index 5e134db0..6bf3a4b2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -99,6 +99,8 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("service.enable_xhtml", value()->default_value(true), "") ("service.max_room_list_size", value()->default_value(100), "") ("service.jid_escaping", value()->default_value(true), "") + ("service.vip_only", value()->default_value(false), "") + ("service.vip_message", value()->default_value(""), "") ("vhosts.vhost", value >()->multitoken(), "") ("identity.name", value()->default_value("Spectrum 2 Transport"), "Name showed in service discovery.") ("identity.category", value()->default_value("gateway"), "Disco#info identity category. 'gateway' by default.") @@ -125,6 +127,7 @@ bool Config::load(std::istream &ifs, boost::program_options::options_description ("database.port", value()->default_value(0), "Database port.") ("database.prefix", value()->default_value(""), "Prefix of tables in database") ("database.encryption_key", value()->default_value(""), "Encryption key.") + ("database.vip_statement", value()->default_value(""), "Encryption key.") ("logging.config", value()->default_value(""), "Path to log4cxx config file which is used for Spectrum 2 instance") ("logging.backend_config", value()->default_value(""), "Path to log4cxx config file which is used for backends") ("backend.default_avatar", value()->default_value(""), "Full path to default avatar") diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index f0769368..642127ac 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -443,6 +443,23 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { } } + if (!CONFIG_STRING(m_config, "database.vip_statement").empty()) { + std::string query = CONFIG_STRING(m_config, "database.vip_statement"); + boost::replace_all(query, "$jid", barejid); + LOG4CXX_INFO(logger, "Executing '" << query << "' to find out if user " << barejid << " is VIP"); + if (exec(query)) { + MYSQL_RES *result = mysql_store_result(&m_conn); + if (result) { + LOG4CXX_INFO(logger, "User " << barejid << " is VIP"); + user.vip = 1; + } + else { + LOG4CXX_INFO(logger, "User " << barejid << " is not VIP"); + user.vip = 0; + } + } + } + return ret; } diff --git a/src/tests/basictest.h b/src/tests/basictest.h index 1d270b20..a1d9a0f1 100644 --- a/src/tests/basictest.h +++ b/src/tests/basictest.h @@ -225,6 +225,7 @@ class BasicTest : public Swift::XMPPParserClient { user.jid = "user@localhost"; user.uin = "legacyname"; user.password = "password"; + user.vip = 0; storage->setUser(user); } diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index 26ba476a..a95c063f 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -27,6 +27,7 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST(connectUserTransportDisabled); CPPUNIT_TEST(connectUserRegistrationNeeded); CPPUNIT_TEST(connectUserRegistrationNeededRegistered); + CPPUNIT_TEST(connectUserVipOnlyNonVip); CPPUNIT_TEST(handleProbePresence); CPPUNIT_TEST(disconnectUser); CPPUNIT_TEST_SUITE_END(); @@ -71,6 +72,26 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_ASSERT(!streamEnded); } + void connectUserVipOnlyNonVip() { + addUser(); + std::istringstream ifs("service.server_mode = 1\nservice.jid_escaping=0\nservice.jid=localhost\nservice.vip_only=1\nservice.vip_message=Ahoj\n"); + cfg->load(ifs); + CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); + userRegistry->isValidUserPassword(Swift::JID("user@localhost/resource"), serverFromClientSession.get(), Swift::createSafeByteArray("password")); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(3, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + CPPUNIT_ASSERT_EQUAL(std::string("Ahoj"), dynamic_cast(getStanza(received[1]))->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("user@localhost/resource"), dynamic_cast(getStanza(received[1]))->getTo().toString()); + CPPUNIT_ASSERT_EQUAL(std::string("localhost"), dynamic_cast(getStanza(received[1]))->getFrom().toString()); + + CPPUNIT_ASSERT_EQUAL(0, userManager->getUserCount()); + CPPUNIT_ASSERT(streamEnded); + std::istringstream ifs2("service.server_mode = 1\nservice.jid_escaping=1\nservice.jid=localhost\nservice.more_resources=1\n"); + cfg->load(ifs2); + } + void handleProbePresence() { UserInfo info; info.id = 1; diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 38f31bd0..e870f8a4 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -277,6 +277,22 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { return; } + if (CONFIG_BOOL(m_component->getConfig(), "service.vip_only") && res.vip == false) { + if (!CONFIG_STRING(m_component->getConfig(), "service.vip_message").empty()) { + boost::shared_ptr msg(new Swift::Message()); + msg->setBody(CONFIG_STRING(m_component->getConfig(), "service.vip_message")); + msg->setTo(presence->getFrom()); + msg->setFrom(m_component->getJID()); + m_component->getStanzaChannel()->sendMessage(msg); + } + + LOG4CXX_WARN(logger, "Non VIP user " << userkey << " tried to login"); + if (m_component->inServerMode()) { + m_userRegistry->onPasswordInvalid(presence->getFrom()); + } + return; + } + bool transport_enabled = true; if (m_storageBackend) { std::string value = "1"; From dc1228b5bd506f8f7a546c1370e4b68f1ab96295 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 13 Nov 2012 17:31:47 +0100 Subject: [PATCH 47/61] use instead of --- src/mysqlbackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 642127ac..d7c6f7eb 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -445,7 +445,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { if (!CONFIG_STRING(m_config, "database.vip_statement").empty()) { std::string query = CONFIG_STRING(m_config, "database.vip_statement"); - boost::replace_all(query, "$jid", barejid); + boost::replace_all(query, "$barejid", barejid); LOG4CXX_INFO(logger, "Executing '" << query << "' to find out if user " << barejid << " is VIP"); if (exec(query)) { MYSQL_RES *result = mysql_store_result(&m_conn); From db3096599f54ace73ea7cd45a07595a51b5ba565 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 13 Nov 2012 17:38:07 +0100 Subject: [PATCH 48/61] MYSQL_RES can be valid pointer even when empty result set is returned --- src/mysqlbackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index d7c6f7eb..7d28d506 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -449,7 +449,7 @@ bool MySQLBackend::getUser(const std::string &barejid, UserInfo &user) { LOG4CXX_INFO(logger, "Executing '" << query << "' to find out if user " << barejid << " is VIP"); if (exec(query)) { MYSQL_RES *result = mysql_store_result(&m_conn); - if (result) { + if (result && mysql_num_rows(result) > 0) { LOG4CXX_INFO(logger, "User " << barejid << " is VIP"); user.vip = 1; } From 8c7caaf94a3f9eb5cea730a01baecb52146888d9 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 13 Nov 2012 17:52:51 +0100 Subject: [PATCH 49/61] send subscribe presence as response to error presence only when error type is SubscriptionRequested --- src/usermanager.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/usermanager.cpp b/src/usermanager.cpp index e870f8a4..4e6e4b01 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -431,6 +431,15 @@ void UserManager::handleErrorPresence(Swift::Presence::ref presence) { if (!presence->getTo().getNode().empty()) { return; } + + if (!presence->getPayload()) { + return; + } + + if (presence->getPayload()->getCondition() != Swift::ErrorPayload::SubscriptionRequired) { + return; + } + std::string userkey = presence->getFrom().toBare().toString(); UserInfo res; bool registered = m_storageBackend ? m_storageBackend->getUser(userkey, res) : false; From f16af993ce28db4f55c39bf62dc69f1def4434d4 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 14 Nov 2012 13:49:52 +0100 Subject: [PATCH 50/61] Fixed tests --- src/tests/usermanager.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/tests/usermanager.cpp b/src/tests/usermanager.cpp index a95c063f..8f59ab8f 100644 --- a/src/tests/usermanager.cpp +++ b/src/tests/usermanager.cpp @@ -137,6 +137,16 @@ class UserManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTest { dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); loop->processEvents(); + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + + response = Swift::Presence::create(); + response->setTo("localhost"); + response->setFrom("user@localhost"); + response->setType(Swift::Presence::Error); + response->addPayload(boost::shared_ptr(new Swift::ErrorPayload(Swift::ErrorPayload::SubscriptionRequired))); + dynamic_cast(component->getStanzaChannel())->onPresenceReceived(response); + loop->processEvents(); + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); presence = dynamic_cast(getStanza(received[0])); CPPUNIT_ASSERT(presence); From a76d99e4b618f9e24b3c259a889587a9b77eefff Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 14 Nov 2012 14:52:23 +0100 Subject: [PATCH 51/61] Call storeBuddy instead of handleBuddyChanged in handleSusbcription to save proper subscriptions into database. call onBuddyRemoved also in gateway-mode --- src/rostermanager.cpp | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index 77ed09a3..0abec9f6 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -181,7 +181,7 @@ void RosterManager::sendBuddyRosterPush(Buddy *buddy) { if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); - handleBuddyChanged(buddy); + storeBuddy(buddy); } } @@ -446,13 +446,15 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { } if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); - handleBuddyChanged(buddy); + storeBuddy(buddy); } break; // remove buddy case Swift::Presence::Unsubscribe: response->setType(Swift::Presence::Unsubscribed); onBuddyRemoved(buddy); + removeBuddy(buddy->getName()); + buddy = NULL; break; // just send response case Swift::Presence::Unsubscribed: @@ -462,13 +464,13 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { // to be send later again if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); - handleBuddyChanged(buddy); + storeBuddy(buddy); } break; case Swift::Presence::Subscribed: if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); - handleBuddyChanged(buddy); + storeBuddy(buddy); } return; default: @@ -491,10 +493,19 @@ void RosterManager::handleSubscription(Swift::Presence::ref presence) { onBuddyAdded(buddy); response->setType(Swift::Presence::Subscribed); break; - // buddy is already there, so nothing to do, just answer case Swift::Presence::Unsubscribe: + buddyInfo.id = -1; + buddyInfo.alias = ""; + buddyInfo.legacyName = Buddy::JIDToLegacyName(presence->getTo()); + buddyInfo.subscription = "both"; + buddyInfo.flags = Buddy::buddyFlagsFromJID(presence->getTo()); + response->setType(Swift::Presence::Unsubscribed); -// onBuddyRemoved(buddy); + + buddy = m_component->getFactory()->createBuddy(this, buddyInfo); + onBuddyRemoved(buddy); + delete buddy; + buddy = NULL; break; // just send response case Swift::Presence::Unsubscribed: From 158abda4e9486196b9ad3bcf2ec28e2d273b5540 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Tue, 20 Nov 2012 14:29:59 +0400 Subject: [PATCH 52/61] Multiple Windows services support --- spectrum/src/main.cpp | 53 +++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/spectrum/src/main.cpp b/spectrum/src/main.cpp index 0b312bf2..21f6a1c4 100644 --- a/spectrum/src/main.cpp +++ b/spectrum/src/main.cpp @@ -266,7 +266,13 @@ int main(int argc, char **argv) bool no_daemon = false; std::string config_file; std::string jid; - +#ifdef WIN32 + std::string install_service_name, uninstall_service_name, run_service_name; + // determine the name of the currently executing file + char szFilePath[MAX_PATH]; + GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); + std::string exe_file(szFilePath); +#endif setlocale(LC_ALL, ""); #ifndef WIN32 #ifndef __FreeBSD__ @@ -297,8 +303,9 @@ int main(int argc, char **argv) ; #ifdef WIN32 desc.add_options() - ("install-service,i", "Install spectrum as Windows service") - ("uninstall-service,u", "Uninstall Windows service"); + ("install-service,i", boost::program_options::value(&install_service_name)->default_value(""), "Install spectrum as Windows service") + ("uninstall-service,u", boost::program_options::value(&uninstall_service_name)->default_value(""), "Uninstall Windows service") + ("run-as-service,r", boost::program_options::value(&run_service_name)->default_value(""), "stub for Windows Service Manager"); #endif try { @@ -327,41 +334,38 @@ int main(int argc, char **argv) if(vm.count("no-daemonize")) { no_daemon = true; } -#ifdef WIN32 - if (vm.count("install-service")) { - ServiceWrapper ntservice("Spectrum2"); +#ifdef WIN32 + if (!install_service_name.empty()) { + // build command line for Service Manager + std::string service_path = exe_file + std::string(" --config ") + vm["config"].as() + + std::string(" --run-as-service ") + install_service_name; + + ServiceWrapper ntservice((char *)install_service_name.c_str()); if (!ntservice.IsInstalled()) { - // determine the name of the currently executing file - char szFilePath[MAX_PATH]; - GetModuleFileNameA(NULL, szFilePath, sizeof(szFilePath)); - std::string exe_file(szFilePath); - std::string config_file = exe_file.replace(exe_file.end() - 4, exe_file.end(), ".cfg"); - std::string service_path = std::string(szFilePath) + std::string(" --config ") + config_file; - if (ntservice.Install((char *)service_path.c_str())) { - std::cout << "Successfully installed" << std::endl; + std::cout << "Successfully installed " << install_service_name << std::endl; return 0; } else { std::cout << "Error installing service, are you an Administrator?" << std::endl; return 1; } } else { - std::cout << "Already installed" << std::endl; + std::cout << "Already installed " << install_service_name << std::endl; return 1; } } - if (vm.count("uninstall-service")) { - ServiceWrapper ntservice("Spectrum2"); + if (!uninstall_service_name.empty()) { + ServiceWrapper ntservice((char *)uninstall_service_name.c_str()); if (ntservice.IsInstalled()) { if (ntservice.UnInstall()) { - std::cout << "Successfully removed" << std::endl; + std::cout << "Successfully removed " << uninstall_service_name << std::endl; return 0; } else { std::cout << "Error removing service, are you an Administrator?" << std::endl; return 1; } } else { - std::cout << "Service not installed" << std::endl; + std::cout << "Service not installed: " << uninstall_service_name << std::endl; return 1; } } @@ -441,9 +445,14 @@ int main(int argc, char **argv) } #endif #ifdef WIN32 - ServiceWrapper ntservice("Spectrum2"); - if (ntservice.IsInstalled()) { - ntservice.RunService(); + if (!run_service_name.empty()) { + ServiceWrapper ntservice((char *)run_service_name.c_str()); + if (ntservice.IsInstalled()) { + ntservice.RunService(); + } else { + std::cerr << "Service not installed: " << run_service_name << std::endl; + return 1; + } } else { mainloop(); } From 08a5e487db0c2f288eb0a56a11b3917b8fb33922 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 27 Nov 2012 10:33:04 +0100 Subject: [PATCH 53/61] Better error message when backends can't be started --- backends/twitter/main.cpp | 3 ++- src/networkpluginserver.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/backends/twitter/main.cpp b/backends/twitter/main.cpp index 5cbf2def..f68f25ab 100644 --- a/backends/twitter/main.cpp +++ b/backends/twitter/main.cpp @@ -39,7 +39,8 @@ int main (int argc, char* argv[]) { StorageBackend *storagebackend; storagebackend = StorageBackend::createBackend(cfg, error); if (storagebackend == NULL) { - LOG4CXX_ERROR(logger, "Error creating StorageBackend! " << error) + LOG4CXX_ERROR(logger, "Error creating StorageBackend! " << error); + LOG4CXX_ERROR(logger, "Twitter backend needs storage backend configured to work! " << error); return -2; } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index bcea34f7..5061d1ce 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -332,7 +332,13 @@ void NetworkPluginServer::start() { 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))); + if (status == 254) { + LOG4CXX_ERROR(logger, "Backend can not be started, because it needs database to store data, but the database backend is not configured."); + } + else { + LOG4CXX_ERROR(logger, "Backend can not be started, exit_code=" << WEXITSTATUS(status) << ", possible error: " << strerror(WEXITSTATUS(status))); + } + LOG4CXX_ERROR(logger, "Check backend log for more details"); continue; } } From 110a366bfb8667978c79f1cdffd275f93667a40c Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 27 Nov 2012 10:50:49 +0100 Subject: [PATCH 54/61] Added NetworkPlugin::StorageBackendNeeded instead of -2 constant --- backends/twitter/main.cpp | 2 +- include/transport/networkplugin.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/twitter/main.cpp b/backends/twitter/main.cpp index f68f25ab..bb28d601 100644 --- a/backends/twitter/main.cpp +++ b/backends/twitter/main.cpp @@ -41,7 +41,7 @@ int main (int argc, char* argv[]) { if (storagebackend == NULL) { LOG4CXX_ERROR(logger, "Error creating StorageBackend! " << error); LOG4CXX_ERROR(logger, "Twitter backend needs storage backend configured to work! " << error); - return -2; + return NetworkPlugin::StorageBackendNeeded; } else if (!storagebackend->connect()) { diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 6c4ababd..a5e123f7 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -35,6 +35,7 @@ namespace Transport { /// development. class NetworkPlugin { public: + enum ExitCode { StorageBackendNeeded = -2 }; class PluginConfig { public: From 8b6973539f23ea00dfb950f7e109f2d5f2139d51 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 27 Nov 2012 12:51:19 +0100 Subject: [PATCH 55/61] Postpone room subject forwarding if we haven't sent initial presences yet --- backends/libcommuni/ircnetworkplugin.cpp | 12 ++++++++++++ backends/libcommuni/ircnetworkplugin.h | 1 + backends/libcommuni/session.cpp | 10 +++++++++- include/transport/conversation.h | 2 ++ plugin/cpp/networkplugin.cpp | 2 +- src/conversation.cpp | 12 ++++++++++++ src/tests/conversationmanager.cpp | 25 ++++++++++++++++-------- src/usermanager.cpp | 3 ++- 8 files changed, 56 insertions(+), 11 deletions(-) diff --git a/backends/libcommuni/ircnetworkplugin.cpp b/backends/libcommuni/ircnetworkplugin.cpp index f2fc4574..bda4cc4d 100644 --- a/backends/libcommuni/ircnetworkplugin.cpp +++ b/backends/libcommuni/ircnetworkplugin.cpp @@ -11,6 +11,7 @@ DEFINE_LOGGER(logger, "IRCNetworkPlugin"); IRCNetworkPlugin::IRCNetworkPlugin(Config *config, Swift::QtEventLoop *loop, const std::string &host, int port) { this->config = config; m_currentServer = 0; + m_firstPing = true; m_socket = new QTcpSocket(); m_socket->connectToHost(FROM_UTF8(host), port); connect(m_socket, SIGNAL(readyRead()), this, SLOT(readData())); @@ -48,6 +49,17 @@ void IRCNetworkPlugin::readData() { if (availableBytes == 0) return; + if (m_firstPing) { + m_firstPing = false; + // Users can join the network without registering if we allow + // one user to connect multiple IRC networks. + if (m_servers.empty()) { + NetworkPlugin::PluginConfig cfg; + cfg.setNeedRegistration(false); + sendConfig(cfg); + } + } + std::string d = std::string(m_socket->readAll().data(), availableBytes); handleDataRead(d); } diff --git a/backends/libcommuni/ircnetworkplugin.h b/backends/libcommuni/ircnetworkplugin.h index 043089cd..d4a84d73 100644 --- a/backends/libcommuni/ircnetworkplugin.h +++ b/backends/libcommuni/ircnetworkplugin.h @@ -46,4 +46,5 @@ class IRCNetworkPlugin : public QObject, public NetworkPlugin { std::vector m_servers; int m_currentServer; std::string m_identify; + bool m_firstPing; }; \ No newline at end of file diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 91a7fee8..cb0b6c92 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -189,6 +189,7 @@ void MyIrcSession::on_messageReceived(IrcMessage *message) { void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { QString channel; QStringList members; + std::string nick; IrcNumericMessage *m = (IrcNumericMessage *) message; switch (m->code()) { @@ -196,7 +197,14 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { m_topicData = TO_UTF8(m->parameters().value(2)); break; case 333: - np->handleSubject(user, TO_UTF8(m->parameters().value(1)) + suffix, m_topicData, TO_UTF8(m->parameters().value(2))); + nick = TO_UTF8(m->parameters().value(2)); + if (nick.find("!") != std::string::npos) { + nick = nick.substr(0, nick.find("!")); + } + if (nick.find("/") != std::string::npos) { + nick = nick.substr(0, nick.find("/")); + } + np->handleSubject(user, TO_UTF8(m->parameters().value(1)) + suffix, m_topicData, nick); break; case 353: channel = m->parameters().value(2); diff --git a/include/transport/conversation.h b/include/transport/conversation.h index e137b566..ff109aa2 100644 --- a/include/transport/conversation.h +++ b/include/transport/conversation.h @@ -148,6 +148,8 @@ class Conversation { Swift::JID m_jid; std::list m_jids; std::map m_participants; + boost::shared_ptr m_subject; + bool m_sentInitialPresence; }; } diff --git a/plugin/cpp/networkplugin.cpp b/plugin/cpp/networkplugin.cpp index b5622326..3dde9c53 100644 --- a/plugin/cpp/networkplugin.cpp +++ b/plugin/cpp/networkplugin.cpp @@ -63,7 +63,7 @@ NetworkPlugin::~NetworkPlugin() { } void NetworkPlugin::sendConfig(const PluginConfig &cfg) { - std::string data = "[registration]"; + std::string data = "[registration]\n"; data += std::string("needPassword=") + (cfg.m_needPassword ? "1" : "0") + "\n"; data += std::string("needRegistration=") + (cfg.m_needRegistration ? "1" : "0") + "\n"; diff --git a/src/conversation.cpp b/src/conversation.cpp index 67a5c386..9cd8f739 100644 --- a/src/conversation.cpp +++ b/src/conversation.cpp @@ -33,6 +33,7 @@ Conversation::Conversation(ConversationManager *conversationManager, const std:: // m_conversationManager->addConversation(this); m_muc = isMUC; m_jid = m_conversationManager->getUser()->getJID().toBare(); + m_sentInitialPresence = false; } Conversation::~Conversation() { @@ -128,6 +129,11 @@ void Conversation::handleMessage(boost::shared_ptr &message, con BOOST_FOREACH(const Swift::JID &jid, m_jids) { message->setTo(jid); message->setFrom(Swift::JID(legacyName, m_conversationManager->getComponent()->getJID().toBare(), n)); + // Subject has to be sent after our own presence (the one with code 110) + if (!message->getSubject().empty() && m_sentInitialPresence == false) { + m_subject = message; + return; + } m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(message); } } @@ -169,6 +175,7 @@ Swift::Presence::ref Conversation::generatePresence(const std::string &nick, int Swift::MUCUserPayload::StatusCode c; c.code = 110; p->addStatusCode(c); + m_sentInitialPresence = true; } @@ -217,6 +224,11 @@ void Conversation::handleParticipantChanged(const std::string &nick, int flag, i if (!newname.empty()) { handleParticipantChanged(newname, flag, status, statusMessage); } + + if (m_sentInitialPresence && m_subject) { + m_conversationManager->getComponent()->getStanzaChannel()->sendMessage(m_subject); + m_subject.reset(); + } } } diff --git a/src/tests/conversationmanager.cpp b/src/tests/conversationmanager.cpp index ef31975d..c182146c 100644 --- a/src/tests/conversationmanager.cpp +++ b/src/tests/conversationmanager.cpp @@ -94,26 +94,35 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe void handleSubjectMessages() { User *user = userManager->getUser("user@localhost"); - - TestingConversation *conv = new TestingConversation(user->getConversationManager(), "buddy1"); - user->getConversationManager()->addConversation(conv); + TestingConversation *conv = new TestingConversation(user->getConversationManager(), "#room", true); + conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); + conv->setNickname("nickname"); + conv->addJID("user@localhost/resource"); boost::shared_ptr msg(new Swift::Message()); msg->setSubject("subject"); + msg->setType(Swift::Message::Groupchat); - // Forward it conv->handleMessage(msg); loop->processEvents(); + + // No response, because presence with code 110 has not been sent yet and we must not send + // subject before this one. + CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); + + // this user presence - status code 110 + conv->handleParticipantChanged("nickname", 1, Swift::StatusShow::Away, "my status message"); + loop->processEvents(); - CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); - CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); - CPPUNIT_ASSERT_EQUAL(std::string("subject"), dynamic_cast(getStanza(received[0]))->getSubject()); + CPPUNIT_ASSERT_EQUAL(2, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[1]))); + CPPUNIT_ASSERT_EQUAL(std::string("subject"), dynamic_cast(getStanza(received[1]))->getSubject()); received.clear(); // send response msg->setFrom("user@localhost/resource"); - msg->setTo("buddy1@localhost/bot"); + msg->setTo("#room@localhost"); injectMessage(msg); loop->processEvents(); diff --git a/src/usermanager.cpp b/src/usermanager.cpp index 4e6e4b01..fd4305ce 100644 --- a/src/usermanager.cpp +++ b/src/usermanager.cpp @@ -247,7 +247,8 @@ void UserManager::handlePresence(Swift::Presence::ref presence) { // We allow auto_register feature in gateway-mode. This allows IRC user to register // the transport just by joining the room. if (!m_component->inServerMode()) { - if (!registered && CONFIG_BOOL(m_component->getConfig(), "registration.auto_register")) { + if (!registered && (CONFIG_BOOL(m_component->getConfig(), "registration.auto_register") || + !CONFIG_BOOL_DEFAULTED(m_component->getConfig(), "registration.needRegistration", true))) { res.password = ""; res.jid = userkey; From 827bac538d8df2b45250a211e50b8c608e90d134 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Tue, 27 Nov 2012 12:53:46 +0100 Subject: [PATCH 56/61] Fix qt-moc error while parsing boost headers --- backends/libcommuni/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backends/libcommuni/CMakeLists.txt b/backends/libcommuni/CMakeLists.txt index 38e7507b..699b02bd 100644 --- a/backends/libcommuni/CMakeLists.txt +++ b/backends/libcommuni/CMakeLists.txt @@ -1,10 +1,14 @@ cmake_minimum_required(VERSION 2.6) FILE(GLOB SRC *.cpp) FILE(GLOB HEADERS *.h) -QT4_WRAP_CPP(SRC ${HEADERS}) +QT4_WRAP_CPP(SRC ${HEADERS} OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED) ADD_EXECUTABLE(spectrum2_libcommuni_backend ${SRC}) -target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread) +if (NOT WIN32) + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport pthread) +else () + target_link_libraries(spectrum2_libcommuni_backend ${IRC_LIBRARY} ${QT_LIBRARIES} transport) +endif() INSTALL(TARGETS spectrum2_libcommuni_backend RUNTIME DESTINATION bin) From 9388d599156cb6677278cd31471a684671aff6ad Mon Sep 17 00:00:00 2001 From: HanzZ Date: Tue, 27 Nov 2012 22:18:15 +0100 Subject: [PATCH 57/61] Store last tweet ID in database so all tweets are not forwarded on reconnect. Send proper timestamp of tweets --- backends/twitter/TwitterPlugin.cpp | 44 +++++++++++++++++----- backends/twitter/TwitterPlugin.h | 2 + backends/twitter/TwitterResponseParser.cpp | 16 ++++++-- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/backends/twitter/TwitterPlugin.cpp b/backends/twitter/TwitterPlugin.cpp index e6a0d52e..ef84bbf3 100644 --- a/backends/twitter/TwitterPlugin.cpp +++ b/backends/twitter/TwitterPlugin.cpp @@ -322,7 +322,7 @@ void TwitterPlugin::pollForTweets() std::set::iterator it = onlineUsers.begin(); while(it != onlineUsers.end()) { std::string user = *it; - tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, "", userdb[user].mostRecentTweetID, + tp->runAsThread(new TimelineRequest(userdb[user].sessions, user, "", getMostRecentTweetIDUnsafe(user), boost::bind(&TwitterPlugin::displayTweets, this, _1, _2, _3, _4))); it++; } @@ -517,14 +517,39 @@ void TwitterPlugin::updateLastTweetID(const std::string user, const std::string { boost::mutex::scoped_lock lock(userlock); userdb[user].mostRecentTweetID = ID; + + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + return; + } + + storagebackend->updateUserSetting((long)info.id, "twitter_last_tweet", ID); +} + +std::string TwitterPlugin::getMostRecentTweetIDUnsafe(const std::string user) +{ + std::string ID = ""; + if(onlineUsers.count(user)) { + ID = userdb[user].mostRecentTweetID; + if (ID.empty()) { + int type; + UserInfo info; + if(storagebackend->getUser(user, info) == false) { + LOG4CXX_ERROR(logger, "Didn't find entry for " << user << " in the database!") + } + else { + storagebackend->getUserSetting(info.id, "twitter_last_tweet", type, ID); + } + } + } + return ID; } std::string TwitterPlugin::getMostRecentTweetID(const std::string user) -{ - boost::mutex::scoped_lock lock(userlock); - std::string ID = "-1"; - if(onlineUsers.count(user)) ID = userdb[user].mostRecentTweetID; - return ID; +{ + boost::mutex::scoped_lock lock(userlock); + return getMostRecentTweetIDUnsafe(user); } void TwitterPlugin::updateLastDMID(const std::string user, const std::string ID) @@ -622,16 +647,17 @@ void TwitterPlugin::displayTweets(std::string &user, std::string &userRequested, std::map lastTweet; std::map::iterator it; - for(int i=0 ; i= 0 ; i--) { if(userdb[user].twitterMode != CHATROOM) { - timeline += " - " + tweets[i].getUserData().getScreenName() + ": " + tweets[i].getTweet() + " (MsgId: " + tweets[i].getID() + ")\n"; + std::string m = " - " + tweets[i].getUserData().getScreenName() + ": " + tweets[i].getTweet() + " (MsgId: " + tweets[i].getID() + ")\n"; + handleMessage(user, adminLegacyName, m, "", "", tweets[i].getCreationTime()); std::string scrname = tweets[i].getUserData().getScreenName(); if(lastTweet.count(scrname) == 0 || cmp(tweets[lastTweet[scrname]].getID(), tweets[i].getID()) <= 0) lastTweet[scrname] = i; } else { handleMessage(user, userdb[user].twitterMode == CHATROOM ? adminChatRoom : adminLegacyName, - tweets[i].getTweet() + " (MsgId: " + tweets[i].getID() + ")", tweets[i].getUserData().getScreenName()); + tweets[i].getTweet() + " (MsgId: " + tweets[i].getID() + ")", tweets[i].getUserData().getScreenName(), "", tweets[i].getCreationTime()); } } diff --git a/backends/twitter/TwitterPlugin.h b/backends/twitter/TwitterPlugin.h index b49ea866..ab4aca3b 100644 --- a/backends/twitter/TwitterPlugin.h +++ b/backends/twitter/TwitterPlugin.h @@ -134,6 +134,8 @@ class TwitterPlugin : public NetworkPlugin { /***********************************************************************************/ private: + std::string getMostRecentTweetIDUnsafe(const std::string user); + enum status {NEW, WAITING_FOR_PIN, CONNECTED, DISCONNECTED}; enum mode {SINGLECONTACT, MULTIPLECONTACT, CHATROOM}; diff --git a/backends/twitter/TwitterResponseParser.cpp b/backends/twitter/TwitterResponseParser.cpp index 4ccc5e85..4324b310 100644 --- a/backends/twitter/TwitterResponseParser.cpp +++ b/backends/twitter/TwitterResponseParser.cpp @@ -11,6 +11,15 @@ static std::string tolowercase(std::string inp) return out; } +static std::string toIsoTime(std::string in) { + time_t now = time(0); + struct tm *mtime = gmtime(&now); + strptime(in.c_str(), "%a %b %d %H:%M:%S %z %Y", mtime); + char buf[80]; + strftime(buf, sizeof(buf), "%Y%m%dT%H%M%S", mtime); + return buf; +} + EmbeddedStatus getEmbeddedStatus(const Swift::ParserElement::ref &element, const std::string xmlns) { EmbeddedStatus status; @@ -19,7 +28,8 @@ EmbeddedStatus getEmbeddedStatus(const Swift::ParserElement::ref &element, const return status; } - status.setCreationTime( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ); + status.setCreationTime( toIsoTime(std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ) ); + status.setID( std::string( element->getChild(TwitterReponseTypes::id, xmlns)->getText() ) ); status.setTweet( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ); status.setTruncated( std::string( element->getChild(TwitterReponseTypes::truncated, xmlns)->getText() )=="true" ); @@ -60,7 +70,7 @@ Status getStatus(const Swift::ParserElement::ref &element, const std::string xml return status; } - status.setCreationTime( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ); + status.setCreationTime( toIsoTime ( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ) ); status.setID( std::string( element->getChild(TwitterReponseTypes::id, xmlns)->getText() ) ); status.setTweet( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ); status.setTruncated( std::string( element->getChild(TwitterReponseTypes::truncated, xmlns)->getText() )=="true" ); @@ -82,7 +92,7 @@ DirectMessage getDirectMessage(const Swift::ParserElement::ref &element, const s return DM; } - DM.setCreationTime( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ); + DM.setCreationTime( toIsoTime ( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ) ); DM.setID( std::string( element->getChild(TwitterReponseTypes::id, xmlns)->getText() ) ); DM.setMessage( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ); DM.setSenderID( std::string( element->getChild(TwitterReponseTypes::sender_id, xmlns)->getText() ) ); From 4eeeb8465232ee07aea05bae8354cabeeecfec77 Mon Sep 17 00:00:00 2001 From: Jan Kaluza Date: Wed, 28 Nov 2012 11:15:49 +0100 Subject: [PATCH 58/61] Show away users when joining the room. This is not finished yet, polling has to be implemented to refresh the list of away users --- backends/libcommuni/session.cpp | 18 +++++++++++++++-- backends/libcommuni/session.h | 34 +-------------------------------- 2 files changed, 17 insertions(+), 35 deletions(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index cb0b6c92..61200b72 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -48,6 +48,8 @@ void MyIrcSession::on_connected() { } } + sendCommand(IrcCommand::createCapability("REQ", QStringList("away-notify"))); + for(AutoJoinMap::iterator it = m_autoJoin.begin(); it != m_autoJoin.end(); it++) { sendCommand(IrcCommand::createJoin(FROM_UTF8(it->second->getChannel()), FROM_UTF8(it->second->getPassword()))); } @@ -86,8 +88,8 @@ void MyIrcSession::on_joined(IrcMessage *message) { bool flags = 0; std::string nickname = TO_UTF8(m->sender().name()); flags = correctNickname(nickname); - np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()), (int) flags, pbnetwork::STATUS_ONLINE); - LOG4CXX_INFO(logger, user << ": Joined " << TO_UTF8(m->parameters()[0])); + np->handleParticipantChanged(user, nickname, TO_UTF8(m->channel()) + suffix, (int) flags, pbnetwork::STATUS_ONLINE); + LOG4CXX_INFO(logger, user << ": " << nickname << " joined " << TO_UTF8(m->channel()) + suffix); } @@ -193,6 +195,8 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { IrcNumericMessage *m = (IrcNumericMessage *) message; switch (m->code()) { + case 301: + break; case 332: m_topicData = TO_UTF8(m->parameters().value(2)); break; @@ -206,6 +210,13 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { } np->handleSubject(user, TO_UTF8(m->parameters().value(1)) + suffix, m_topicData, nick); break; + case 352: + channel = m->parameters().value(1); + nick = TO_UTF8(m->parameters().value(5)); + if (m->parameters().value(6).toUpper().startsWith("G")) { + np->handleParticipantChanged(user, nick, TO_UTF8(channel) + suffix, m_modes[TO_UTF8(channel) + nick], pbnetwork::STATUS_AWAY); + } + break; case 353: channel = m->parameters().value(2); members = m->parameters().value(3).split(" "); @@ -218,6 +229,9 @@ void MyIrcSession::on_numericMessageReceived(IrcMessage *message) { m_modes[TO_UTF8(channel) + nickname] = flags; np->handleParticipantChanged(user, nickname, TO_UTF8(channel) + suffix,(int) flags, pbnetwork::STATUS_ONLINE); } + + // ask /who to get away states + sendCommand(IrcCommand::createWho(channel)); break; case 432: np->handleDisconnected(user, pbnetwork::CONNECTION_ERROR_INVALID_USERNAME, "Erroneous Nickname"); diff --git a/backends/libcommuni/session.h b/backends/libcommuni/session.h index e8a262ac..d398dd25 100644 --- a/backends/libcommuni/session.h +++ b/backends/libcommuni/session.h @@ -41,6 +41,7 @@ public: MyIrcSession(const std::string &user, IRCNetworkPlugin *np, const std::string &suffix = "", QObject* parent = 0); std::map m_modes; + std::map m_away; std::string suffix; int rooms; @@ -89,37 +90,4 @@ protected: std::list m_names; }; -//class MyIrcBuffer : public Irc::Buffer -//{ -// Q_OBJECT - -//public: -// MyIrcBuffer(const QString& receiver, const std::string &user, NetworkPlugin *np, const std::string &suffix, Irc::Session* parent); -// NetworkPlugin *np; -// std::string user; -// MyIrcSession *p; -// std::string m_topicData; -// std::string suffix; - -//protected Q_SLOTS: -// void on_receiverChanged(const QString& receiver); -// void on_joined(const QString& origin); -// void on_parted(const QString& origin, const QString& message); -// void on_quit(const QString& origin, const QString& message); -// void on_nickChanged(const QString& origin, const QString& nick); -// void on_modeChanged(const QString& origin, const QString& mode, const QString& args); -// void on_topicChanged(const QString& origin, const QString& topic); -// void on_invited(const QString& origin, const QString& receiver, const QString& channel); -// void on_kicked(const QString& origin, const QString& nick, const QString& message); -// void on_messageReceived(const QString& origin, const QString& message, Irc::Buffer::MessageFlags flags); -// void on_noticeReceived(const QString& origin, const QString& notice, Irc::Buffer::MessageFlags flags); -// void on_ctcpRequestReceived(const QString& origin, const QString& request, Irc::Buffer::MessageFlags flags); -// void on_ctcpReplyReceived(const QString& origin, const QString& reply, Irc::Buffer::MessageFlags flags); -// void on_ctcpActionReceived(const QString& origin, const QString& action, Irc::Buffer::MessageFlags flags); -// void on_numericMessageReceived(const QString& origin, uint code, const QStringList& params); -// void on_unknownMessageReceived(const QString& origin, const QStringList& params); - -// bool correctNickname(std::string &nickname); -//}; - #endif // SESSION_H From 9469109d37e40843cd7edd7a672ae210c342237c Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 28 Nov 2012 18:52:58 +0100 Subject: [PATCH 59/61] Unescape double-escaped messages from twitter --- backends/twitter/TwitterResponseParser.cpp | 17 ++++++-- src/tests/conversationmanager.cpp | 8 ++-- src/tests/stringtreeparser.cpp | 47 ++++++++++++++++++++++ 3 files changed, 65 insertions(+), 7 deletions(-) create mode 100644 src/tests/stringtreeparser.cpp diff --git a/backends/twitter/TwitterResponseParser.cpp b/backends/twitter/TwitterResponseParser.cpp index 4324b310..b908b770 100644 --- a/backends/twitter/TwitterResponseParser.cpp +++ b/backends/twitter/TwitterResponseParser.cpp @@ -1,5 +1,6 @@ #include "TwitterResponseParser.h" #include "transport/logging.h" +#include "boost/algorithm/string.hpp" #include DEFINE_LOGGER(logger, "TwitterResponseParser") @@ -11,6 +12,16 @@ static std::string tolowercase(std::string inp) return out; } +static std::string unescape(std::string data) { + using boost::algorithm::replace_all; + replace_all(data, "&", "&"); + replace_all(data, """, "\""); + replace_all(data, "'", "\'"); + replace_all(data, "<", "<"); + replace_all(data, ">", ">"); + return data; +} + static std::string toIsoTime(std::string in) { time_t now = time(0); struct tm *mtime = gmtime(&now); @@ -31,7 +42,7 @@ EmbeddedStatus getEmbeddedStatus(const Swift::ParserElement::ref &element, const status.setCreationTime( toIsoTime(std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ) ); status.setID( std::string( element->getChild(TwitterReponseTypes::id, xmlns)->getText() ) ); - status.setTweet( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ); + status.setTweet( unescape (std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ) ); status.setTruncated( std::string( element->getChild(TwitterReponseTypes::truncated, xmlns)->getText() )=="true" ); status.setReplyToStatusID( std::string( element->getChild(TwitterReponseTypes::in_reply_to_status_id, xmlns)->getText() ) ); status.setReplyToUserID( std::string( element->getChild(TwitterReponseTypes::in_reply_to_user_id, xmlns)->getText() ) ); @@ -72,7 +83,7 @@ Status getStatus(const Swift::ParserElement::ref &element, const std::string xml status.setCreationTime( toIsoTime ( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ) ); status.setID( std::string( element->getChild(TwitterReponseTypes::id, xmlns)->getText() ) ); - status.setTweet( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ); + status.setTweet( unescape ( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ) ); status.setTruncated( std::string( element->getChild(TwitterReponseTypes::truncated, xmlns)->getText() )=="true" ); status.setReplyToStatusID( std::string( element->getChild(TwitterReponseTypes::in_reply_to_status_id, xmlns)->getText() ) ); status.setReplyToUserID( std::string( element->getChild(TwitterReponseTypes::in_reply_to_user_id, xmlns)->getText() ) ); @@ -94,7 +105,7 @@ DirectMessage getDirectMessage(const Swift::ParserElement::ref &element, const s DM.setCreationTime( toIsoTime ( std::string( element->getChild(TwitterReponseTypes::created_at, xmlns)->getText() ) ) ); DM.setID( std::string( element->getChild(TwitterReponseTypes::id, xmlns)->getText() ) ); - DM.setMessage( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ); + DM.setMessage( unescape ( std::string( element->getChild(TwitterReponseTypes::text, xmlns)->getText() ) ) ); DM.setSenderID( std::string( element->getChild(TwitterReponseTypes::sender_id, xmlns)->getText() ) ); DM.setRecipientID( std::string( element->getChild(TwitterReponseTypes::recipient_id, xmlns)->getText() ) ); DM.setSenderScreenName( std::string( element->getChild(TwitterReponseTypes::sender_screen_name, xmlns)->getText() ) ); diff --git a/src/tests/conversationmanager.cpp b/src/tests/conversationmanager.cpp index c182146c..0869ec8a 100644 --- a/src/tests/conversationmanager.cpp +++ b/src/tests/conversationmanager.cpp @@ -141,7 +141,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe conv->onMessageToSend.connect(boost::bind(&ConversationManagerTest::handleMessageReceived, this, _1, _2)); boost::shared_ptr msg(new Swift::Message()); - msg->setBody("hi there!"); + msg->setBody("hi there<>!"); // Forward it conv->handleMessage(msg); @@ -149,7 +149,7 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); - CPPUNIT_ASSERT_EQUAL(std::string("hi there!"), dynamic_cast(getStanza(received[0]))->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("hi there<>!"), dynamic_cast(getStanza(received[0]))->getBody()); CPPUNIT_ASSERT_EQUAL(std::string("user@localhost"), dynamic_cast(getStanza(received[0]))->getTo().toString()); CPPUNIT_ASSERT_EQUAL(std::string("buddy1\\40test@localhost/bot"), dynamic_cast(getStanza(received[0]))->getFrom().toString()); @@ -158,13 +158,13 @@ class ConversationManagerTest : public CPPUNIT_NS :: TestFixture, public BasicTe // send response msg->setFrom("user@localhost/resource"); msg->setTo("buddy1\\40test@localhost/bot"); - msg->setBody("response!"); + msg->setBody("response<>!"); injectMessage(msg); loop->processEvents(); CPPUNIT_ASSERT_EQUAL(0, (int) received.size()); CPPUNIT_ASSERT(m_msg); - CPPUNIT_ASSERT_EQUAL(std::string("response!"), m_msg->getBody()); + CPPUNIT_ASSERT_EQUAL(std::string("response<>!"), m_msg->getBody()); // send another message from legacy network, should be sent to user@localhost/resource now boost::shared_ptr msg2(new Swift::Message()); diff --git a/src/tests/stringtreeparser.cpp b/src/tests/stringtreeparser.cpp new file mode 100644 index 00000000..e25b24d8 --- /dev/null +++ b/src/tests/stringtreeparser.cpp @@ -0,0 +1,47 @@ +#include "transport/userregistry.h" +#include "transport/config.h" +#include "transport/storagebackend.h" +#include "transport/user.h" +#include "transport/transport.h" +#include "transport/storagebackend.h" +#include "transport/conversation.h" +#include "transport/usermanager.h" +#include "transport/localbuddy.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "Swiften/Server/ServerStanzaChannel.h" +#include "Swiften/Server/ServerFromClientSession.h" +#include "Swiften/Parser/PayloadParsers/FullPayloadParserFactoryCollection.h" +#include "basictest.h" + +#include "transport/util.h" + +using namespace Transport; + +class StringTreeParserTest : public CPPUNIT_NS :: TestFixture{ + CPPUNIT_TEST_SUITE(StringTreeParserTest); + CPPUNIT_TEST(parseEscapedCharacters); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp (void) { + } + + void tearDown (void) { + + } + + void parseEscapedCharacters() { + Swift::ParserElement::ref root = Swift::StringTreeParser::parse("<test>"); + CPPUNIT_ASSERT_EQUAL(std::string(""), root->getText()); + } + +}; + +CPPUNIT_TEST_SUITE_REGISTRATION (StringTreeParserTest); From 389f066d9e2d4b5444f53fe418274812d0340c10 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 30 Nov 2012 16:08:38 +0100 Subject: [PATCH 60/61] Send proper identity in disco#info response with adhoc command node --- src/discoinforesponder.cpp | 32 +++++++++++++++++++++--------- src/discoinforesponder.h | 3 +++ src/discoitemsresponder.cpp | 1 + src/tests/settingsadhoccommand.cpp | 17 ++++++++++++++++ 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/discoinforesponder.cpp b/src/discoinforesponder.cpp index 0620b8c5..2ca5746c 100644 --- a/src/discoinforesponder.cpp +++ b/src/discoinforesponder.cpp @@ -94,18 +94,32 @@ void DiscoInfoResponder::clearRooms() { m_rooms.clear(); } +void DiscoInfoResponder::addAdHocCommand(const std::string &node, const std::string &name) { + m_commands[node] = node; +} + bool DiscoInfoResponder::handleGetRequest(const Swift::JID& from, const Swift::JID& to, const std::string& id, boost::shared_ptr info) { - if (!info->getNode().empty()) { - sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel); - return true; - } - - // disco#info for transport if (to.getNode().empty()) { - boost::shared_ptr res(new DiscoInfo(m_transportInfo)); - res->setNode(info->getNode()); - sendResponse(from, id, res); + // Adhoc command + if (m_commands.find(info->getNode()) != m_commands.end()) { + boost::shared_ptr res(new DiscoInfo()); + res->addFeature("http://jabber.org/protocol/commands"); + res->addFeature("jabber:x:data"); + res->addIdentity(DiscoInfo::Identity(m_commands[info->getNode()], "automation", "command-node")); + res->setNode(info->getNode()); + sendResponse(from, to, id, res); + } + else { + if (!info->getNode().empty()) { + sendError(from, id, ErrorPayload::ItemNotFound, ErrorPayload::Cancel); + return true; + } + + boost::shared_ptr res(new DiscoInfo(m_transportInfo)); + res->setNode(info->getNode()); + sendResponse(from, id, res); + } } // disco#info for room else if (m_rooms.find(to.toBare().toString()) != m_rooms.end()) { diff --git a/src/discoinforesponder.h b/src/discoinforesponder.h index fadf0586..a3109222 100644 --- a/src/discoinforesponder.h +++ b/src/discoinforesponder.h @@ -41,6 +41,8 @@ class DiscoInfoResponder : public Swift::GetResponder { void addRoom(const std::string &jid, const std::string &name); void clearRooms(); + void addAdHocCommand(const std::string &node, const std::string &name); + boost::signal onBuddyCapsInfoChanged; Swift::CapsInfo &getBuddyCapsInfo() { @@ -55,6 +57,7 @@ class DiscoInfoResponder : public Swift::GetResponder { Config *m_config; Swift::CapsInfo m_capsInfo; std::map m_rooms; + std::map m_commands; }; } \ No newline at end of file diff --git a/src/discoitemsresponder.cpp b/src/discoitemsresponder.cpp index acec5822..72ac8390 100644 --- a/src/discoitemsresponder.cpp +++ b/src/discoitemsresponder.cpp @@ -51,6 +51,7 @@ DiscoItemsResponder::~DiscoItemsResponder() { void DiscoItemsResponder::addAdHocCommand(const std::string &node, const std::string &name) { m_commands->addItem(DiscoItems::Item(name, m_component->getJID(), node)); + m_discoInfoResponder->addAdHocCommand(node, name); } void DiscoItemsResponder::addRoom(const std::string &node, const std::string &name) { diff --git a/src/tests/settingsadhoccommand.cpp b/src/tests/settingsadhoccommand.cpp index e3e14d9c..3e9602be 100644 --- a/src/tests/settingsadhoccommand.cpp +++ b/src/tests/settingsadhoccommand.cpp @@ -26,6 +26,7 @@ using namespace Transport; class SettingsAdHocCommandTest : public CPPUNIT_NS :: TestFixture, public BasicTest { CPPUNIT_TEST_SUITE(SettingsAdHocCommandTest); CPPUNIT_TEST(getItems); + CPPUNIT_TEST(getInfo); CPPUNIT_TEST(execute); CPPUNIT_TEST(executeBadSessionID); CPPUNIT_TEST(executeNotRegistered); @@ -70,6 +71,22 @@ class SettingsAdHocCommandTest : public CPPUNIT_NS :: TestFixture, public BasicT CPPUNIT_ASSERT_EQUAL(std::string("settings"), getStanza(received[0])->getPayload()->getItems()[0].getNode()); } + void getInfo() { + boost::shared_ptr payload(new Swift::DiscoInfo()); + payload->setNode("settings"); + boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Get, Swift::JID("localhost"), "id", payload); + iq->setFrom("user@localhost"); + injectIQ(iq); + loop->processEvents(); + + CPPUNIT_ASSERT_EQUAL(1, (int) received.size()); + CPPUNIT_ASSERT(dynamic_cast(getStanza(received[0]))); + CPPUNIT_ASSERT_EQUAL(Swift::IQ::Result, dynamic_cast(getStanza(received[0]))->getType()); + CPPUNIT_ASSERT(getStanza(received[0])->getPayload()); + CPPUNIT_ASSERT_EQUAL(std::string("automation"), getStanza(received[0])->getPayload()->getIdentities()[0].getCategory()); + CPPUNIT_ASSERT_EQUAL(std::string("command-node"), getStanza(received[0])->getPayload()->getIdentities()[0].getType()); + } + void executeNotRegistered() { boost::shared_ptr payload(new Swift::Command("settings")); boost::shared_ptr iq = Swift::IQ::createRequest(Swift::IQ::Set, Swift::JID("localhost"), "id", payload); From 636253d514ace7d143edcff3933bf86c909e6886 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 30 Nov 2012 16:57:57 +0100 Subject: [PATCH 61/61] Disable /LIST for IRC --- backends/libcommuni/session.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backends/libcommuni/session.cpp b/backends/libcommuni/session.cpp index 61200b72..025de37a 100644 --- a/backends/libcommuni/session.cpp +++ b/backends/libcommuni/session.cpp @@ -42,10 +42,10 @@ void MyIrcSession::on_connected() { m_connected = true; if (suffix.empty()) { np->handleConnected(user); - if (!sentList) { - sendCommand(IrcCommand::createList("", "")); - sentList = true; - } +// if (!sentList) { +// sendCommand(IrcCommand::createList("", "")); +// sentList = true; +// } } sendCommand(IrcCommand::createCapability("REQ", QStringList("away-notify")));