From 6b81ff06d6c506ffc6a60ccfa9c2ae00a04dddb2 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Wed, 30 Nov 2011 21:43:12 +0100 Subject: [PATCH] Support for buddies on more groups --- backends/frotz/main.cpp | 4 +++- backends/libpurple/main.cpp | 19 +++++++++++++++++-- include/transport/networkplugin.h | 6 +++--- include/transport/protocol.proto | 2 +- include/transport/util.h | 4 ++++ plugin/src/networkplugin.cpp | 19 +++++++++++++++---- spectrum/src/sample.cfg | 4 ++-- src/mysqlbackend.cpp | 15 +++++++++------ src/networkpluginserver.cpp | 20 ++++++++++++++------ src/sqlite3backend.cpp | 8 +++++--- src/util.cpp | 25 +++++++++++++++++++++++++ 11 files changed, 98 insertions(+), 28 deletions(-) diff --git a/backends/frotz/main.cpp b/backends/frotz/main.cpp index b1e433a4..7a13290d 100644 --- a/backends/frotz/main.cpp +++ b/backends/frotz/main.cpp @@ -171,7 +171,9 @@ class FrotzNetworkPlugin : public NetworkPlugin { void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) { np->handleConnected(user); - np->handleBuddyChanged(user, "zcode", "ZCode", "ZCode", pbnetwork::STATUS_ONLINE); + std::vector groups; + groups.push_back("ZCode"); + np->handleBuddyChanged(user, "zcode", "ZCode", groups, pbnetwork::STATUS_ONLINE); // sleep(1); // np->handleMessage(np->m_user, "zork", first_msg); } diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index 65d719e3..a8622562 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -1052,7 +1052,22 @@ static std::string getIconHash(PurpleBuddy *m_buddy) { static std::vector getGroups(PurpleBuddy *m_buddy) { std::vector groups; - groups.push_back((purple_buddy_get_group(m_buddy) && purple_group_get_name(purple_buddy_get_group(m_buddy))) ? std::string(purple_group_get_name(purple_buddy_get_group(m_buddy))) : std::string("Buddies")); + if (purple_buddy_get_name(m_buddy)) { + GSList *buddies = purple_find_buddies(purple_buddy_get_account(m_buddy), purple_buddy_get_name(m_buddy)); + while(buddies) { + PurpleGroup *g = purple_buddy_get_group((PurpleBuddy *) buddies->data); + buddies = g_slist_delete_link(buddies, buddies); + + if(g && purple_group_get_name(g)) { + groups.push_back(purple_group_get_name(g)); + } + } + } + + if (groups.empty()) { + groups.push_back("Buddies"); + } + return groups; } @@ -1105,7 +1120,7 @@ static void buddyListNewNode(PurpleBlistNode *node) { } } - np->handleBuddyChanged(np->m_accounts[account], purple_buddy_get_name(buddy), getAlias(buddy), getGroups(buddy)[0], status, message, getIconHash(buddy), + np->handleBuddyChanged(np->m_accounts[account], purple_buddy_get_name(buddy), getAlias(buddy), getGroups(buddy), status, message, getIconHash(buddy), blocked ); } diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index 8bfbf221..bba9c013 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -53,7 +53,7 @@ class NetworkPlugin { /// \param iconHash MD5 hash of buddy icon. Empty if none buddy icon. /// \param blocked True if this buddy is blocked in privacy lists in legacy network. void handleBuddyChanged(const std::string &user, const std::string &buddyName, const std::string &alias, - const std::string &groups, pbnetwork::StatusType status, const std::string &statusMessage = "", const std::string &iconHash = "", + const std::vector &groups, pbnetwork::StatusType status, const std::string &statusMessage = "", const std::string &iconHash = "", bool blocked = false ); @@ -197,8 +197,8 @@ class NetworkPlugin { virtual void handleJoinRoomRequest(const std::string &/*user*/, const std::string &/*room*/, const std::string &/*nickname*/, const std::string &/*pasword*/) {} virtual void handleLeaveRoomRequest(const std::string &/*user*/, const std::string &/*room*/) {} virtual void handleStatusChangeRequest(const std::string &/*user*/, int status, const std::string &statusMessage) {} - virtual void handleBuddyUpdatedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*alias*/, const std::string &/*groups*/) {} - virtual void handleBuddyRemovedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*groups*/) {} + virtual void handleBuddyUpdatedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::string &/*alias*/, const std::vector &/*groups*/) {} + virtual void handleBuddyRemovedRequest(const std::string &/*user*/, const std::string &/*buddyName*/, const std::vector &/*groups*/) {} virtual void handleBuddyBlockToggled(const std::string &/*user*/, const std::string &/*buddyName*/, bool /*blocked*/) {} virtual void handleTypingRequest(const std::string &/*user*/, const std::string &/*buddyName*/) {} diff --git a/include/transport/protocol.proto b/include/transport/protocol.proto index 336915a0..9a296392 100644 --- a/include/transport/protocol.proto +++ b/include/transport/protocol.proto @@ -55,7 +55,7 @@ message Buddy { required string userName = 1; required string buddyName = 2; optional string alias = 3; - optional string groups = 4; + repeated string group = 4; optional StatusType status = 5; optional string statusMessage = 6; optional string iconHash = 7; diff --git a/include/transport/util.h b/include/transport/util.h index 79d52a47..fe171115 100644 --- a/include/transport/util.h +++ b/include/transport/util.h @@ -36,6 +36,10 @@ 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); + } } diff --git a/plugin/src/networkplugin.cpp b/plugin/src/networkplugin.cpp index fb5d58fb..9348eb11 100644 --- a/plugin/src/networkplugin.cpp +++ b/plugin/src/networkplugin.cpp @@ -115,12 +115,14 @@ void NetworkPlugin::handleSubject(const std::string &user, const std::string &le } void NetworkPlugin::handleBuddyChanged(const std::string &user, const std::string &buddyName, const std::string &alias, - const std::string &groups, pbnetwork::StatusType status, const std::string &statusMessage, const std::string &iconHash, bool blocked) { + const std::vector &groups, pbnetwork::StatusType status, const std::string &statusMessage, const std::string &iconHash, bool blocked) { pbnetwork::Buddy buddy; buddy.set_username(user); buddy.set_buddyname(buddyName); buddy.set_alias(alias); - buddy.set_groups(groups); + for (std::vector::const_iterator it = groups.begin(); it != groups.end(); it++) { + buddy.add_group(*it); + } buddy.set_status((pbnetwork::StatusType) status); buddy.set_statusmessage(statusMessage); buddy.set_iconhash(iconHash); @@ -424,7 +426,11 @@ void NetworkPlugin::handleBuddyChangedPayload(const std::string &data) { handleBuddyBlockToggled(payload.username(), payload.buddyname(), payload.blocked()); } else { - handleBuddyUpdatedRequest(payload.username(), payload.buddyname(), payload.alias(), payload.groups()); + std::vector groups; + for (int i = 0; i < payload.group_size(); i++) { + groups.push_back(payload.group(i)); + } + handleBuddyUpdatedRequest(payload.username(), payload.buddyname(), payload.alias(), groups); } } @@ -435,7 +441,12 @@ void NetworkPlugin::handleBuddyRemovedPayload(const std::string &data) { return; } - handleBuddyRemovedRequest(payload.username(), payload.buddyname(), payload.groups()); + std::vector groups; + for (int i = 0; i < payload.group_size(); i++) { + groups.push_back(payload.group(i)); + } + + handleBuddyRemovedRequest(payload.username(), payload.buddyname(), groups); } void NetworkPlugin::handleChatStatePayload(const std::string &data, int type) { diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 3fdca1d1..fcb060d3 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=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend +backend=/home/hanzz/code/libtransport/backends/libpurple/spectrum2_libpurple_backend #backend=/usr/bin/mono /home/hanzz/code/networkplugin-csharp/msnp-sharp-backend/bin/Debug/msnp-sharp-backend.exe #backend=/home/hanzz/code/libtransport/backends/frotz/spectrum2_frotz_backend -backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend +#backend=/home/hanzz/code/libtransport/backends/libircclient-qt/spectrum2_libircclient-qt_backend #protocol=prpl-msn protocol=any #protocol=prpl-icq diff --git a/src/mysqlbackend.cpp b/src/mysqlbackend.cpp index 70ffca45..62dcde06 100644 --- a/src/mysqlbackend.cpp +++ b/src/mysqlbackend.cpp @@ -320,7 +320,7 @@ bool MySQLBackend::connect() { createDatabase(); - m_setUser = new Statement(&m_conn, "sssssbs", "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, NOW(), ?) ON DUPLICATE KEY UPDATE uin=?, password=?"); + m_setUser = new Statement(&m_conn, "sssssbss", "INSERT INTO " + m_prefix + "users (jid, uin, password, language, encoding, last_login, vip) VALUES (?, ?, ?, ?, ?, NOW(), ?) ON DUPLICATE KEY UPDATE uin=?, password=?"); m_getUser = new Statement(&m_conn, "s|isssssb", "SELECT id, jid, uin, password, encoding, language, vip FROM " + m_prefix + "users WHERE jid=?"); m_removeUser = new Statement(&m_conn, "i", "DELETE FROM " + m_prefix + "users WHERE id=?"); @@ -414,7 +414,7 @@ void MySQLBackend::setUser(const UserInfo &user) { if (!CONFIG_STRING(m_config, "database.encryption_key").empty()) { encrypted = Util::encryptPassword(encrypted, CONFIG_STRING(m_config, "database.encryption_key")); } - *m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << user.password; + *m_setUser << user.jid << user.uin << encrypted << user.language << user.encoding << user.vip << user.uin << encrypted; EXEC(m_setUser, setUser(user)); } @@ -444,8 +444,9 @@ void MySQLBackend::setUserOnline(long id, bool online) { 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); *m_addBuddy << userId << buddyInfo.legacyName << buddyInfo.subscription; - *m_addBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); + *m_addBuddy << groups; *m_addBuddy << buddyInfo.alias << buddyInfo.flags; EXEC(m_addBuddy, addBuddy(userId, buddyInfo)); @@ -463,7 +464,8 @@ long MySQLBackend::addBuddy(long userId, const BuddyInfo &buddyInfo) { void MySQLBackend::updateBuddy(long userId, const BuddyInfo &buddyInfo) { // "UPDATE " + m_prefix + "buddies SET groups=?, nickname=?, flags=?, subscription=? WHERE user_id=? AND uin=?" - *m_updateBuddy << (buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); + std::string groups = Util::serializeGroups(buddyInfo.groups); + *m_updateBuddy << groups; *m_updateBuddy << buddyInfo.alias << buddyInfo.flags << buddyInfo.subscription; *m_updateBuddy << userId << buddyInfo.legacyName; @@ -491,8 +493,9 @@ bool MySQLBackend::getBuddies(long id, std::list &roster) { std::string group; *m_getBuddies >> b.id >> b.legacyName >> b.subscription >> b.alias >> group >> b.flags; - if (!group.empty()) - b.groups.push_back(group); + if (!group.empty()) { + b.groups = Util::deserializeGroups(group); + } roster.push_back(b); } diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index a99c51de..64dc9f54 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -198,9 +198,11 @@ static void handleBuddyPayload(LocalBuddy *buddy, const pbnetwork::Buddy &payloa } // Change groups if it's not empty. The same as above... - if (!payload.groups().empty()) { - std::vector groups; - groups.push_back(payload.groups()); + std::vector groups; + for (int i = 0; i < payload.group_size(); i++) { + groups.push_back(payload.group(i)); + } + if (!groups.empty()) { buddy->setGroups(groups); } @@ -1163,7 +1165,9 @@ void NetworkPluginServer::handleBuddyRemoved(Buddy *b) { buddy.set_username(user->getJID().toBare()); buddy.set_buddyname(b->getName()); buddy.set_alias(b->getAlias()); - buddy.set_groups(b->getGroups().size() == 0 ? "" : b->getGroups()[0]); + BOOST_FOREACH(const std::string &g, b->getGroups()) { + buddy.add_group(g); + } buddy.set_status(pbnetwork::STATUS_NONE); std::string message; @@ -1189,7 +1193,9 @@ void NetworkPluginServer::handleBuddyUpdated(Buddy *b, const Swift::RosterItemPa buddy.set_username(user->getJID().toBare()); buddy.set_buddyname(b->getName()); buddy.set_alias(b->getAlias()); - buddy.set_groups(b->getGroups().size() == 0 ? "" : b->getGroups()[0]); + BOOST_FOREACH(const std::string &g, b->getGroups()) { + buddy.add_group(g); + } buddy.set_status(pbnetwork::STATUS_NONE); std::string message; @@ -1215,7 +1221,9 @@ void NetworkPluginServer::handleBlockToggled(Buddy *b) { buddy.set_username(user->getJID().toBare()); buddy.set_buddyname(b->getName()); buddy.set_alias(b->getAlias()); - buddy.set_groups(b->getGroups().size() == 0 ? "" : b->getGroups()[0]); + BOOST_FOREACH(const std::string &g, b->getGroups()) { + buddy.add_group(g); + } buddy.set_status(pbnetwork::STATUS_NONE); buddy.set_blocked(!b->isBlocked()); diff --git a/src/sqlite3backend.cpp b/src/sqlite3backend.cpp index 7a4f444b..4313fd67 100644 --- a/src/sqlite3backend.cpp +++ b/src/sqlite3backend.cpp @@ -21,6 +21,7 @@ #ifdef WITH_SQLITE #include "transport/sqlite3backend.h" +#include "transport/util.h" #include #include "log4cxx/logger.h" @@ -254,7 +255,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, buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); // TODO: serialize groups + BIND_STR(m_addBuddy, Util::serializeGroups(buddyInfo.groups)); BIND_STR(m_addBuddy, buddyInfo.alias); BIND_INT(m_addBuddy, buddyInfo.flags); @@ -280,7 +281,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, buddyInfo.groups.size() == 0 ? "" : buddyInfo.groups[0]); // TODO: serialize groups + BIND_STR(m_updateBuddy, Util::serializeGroups(buddyInfo.groups)); BIND_STR(m_updateBuddy, buddyInfo.alias); BIND_INT(m_updateBuddy, buddyInfo.flags); BIND_STR(m_updateBuddy, buddyInfo.subscription); @@ -321,7 +322,8 @@ bool SQLite3Backend::getBuddies(long id, std::list &roster) { b.legacyName = GET_STR(m_getBuddies); b.subscription = GET_STR(m_getBuddies); b.alias = GET_STR(m_getBuddies); - b.groups.push_back(GET_STR(m_getBuddies)); + std::string groups = GET_STR(m_getBuddies); + b.groups = Util::deserializeGroups(groups); b.flags = GET_INT(m_getBuddies); if (buddy_id == b.id) { diff --git a/src/util.cpp b/src/util.cpp index 0a5f3a04..7053ea06 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace boost::filesystem; @@ -103,6 +104,30 @@ std::string decryptPassword(std::string &encrypted, const std::string &key) { 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; +} + } }