From b0bcade44c94cc3e83f0a868589bff6e6e9ca663 Mon Sep 17 00:00:00 2001 From: HanzZ Date: Fri, 17 Jun 2011 13:43:31 +0200 Subject: [PATCH] Hopefully working authorizations. Tested it only once :) --- backends/libpurple/main.cpp | 56 +++++++++- include/transport/networkplugin.h | 2 + include/transport/networkpluginserver.h | 1 + include/transport/rostermanager.h | 4 + spectrum/src/CMakeLists.txt | 4 +- spectrum/src/sample.cfg | 4 +- src/buddy.cpp | 4 + src/networkplugin.cpp | 13 +++ src/networkpluginserver.cpp | 30 +++++- src/pbnetwork.proto | 1 + src/rostermanager.cpp | 129 +++++++++++++++++++++++- 11 files changed, 238 insertions(+), 10 deletions(-) diff --git a/backends/libpurple/main.cpp b/backends/libpurple/main.cpp index dbc0ce45..8bade6e1 100644 --- a/backends/libpurple/main.cpp +++ b/backends/libpurple/main.cpp @@ -45,6 +45,15 @@ static GOptionEntry options_entries[] = { { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, "", NULL } }; +struct authRequest { + PurpleAccountRequestAuthorizationCb authorize_cb; + PurpleAccountRequestAuthorizationCb deny_cb; + void *user_data; + std::string who; + PurpleAccount *account; + std::string mainJID; // JID of user connected with this request +}; + static void * requestInput(const char *title, const char *primary,const char *secondary, const char *default_value, gboolean multiline, gboolean masked, gchar *hint,const char *ok_text, GCallback ok_cb,const char *cancel_text, GCallback cancel_cb, PurpleAccount *account, const char *who,PurpleConversation *conv, void *user_data) { std::cout << "REQUEST INPUT\n"; if (primary) { @@ -294,6 +303,10 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void handleBuddyRemovedRequest(const std::string &user, const std::string &buddyName, const std::string &groups) { PurpleAccount *account = m_sessions[user]; if (account) { + if (m_authRequests.find(user + buddyName) != m_authRequests.end()) { + m_authRequests[user + buddyName]->deny_cb(m_authRequests[user + buddyName]->user_data); + m_authRequests.erase(user + buddyName); + } PurpleBuddy *buddy = purple_find_buddy(account, buddyName.c_str()); if (buddy) { purple_account_remove_buddy(account, buddy, purple_buddy_get_group(buddy)); @@ -305,6 +318,12 @@ class SpectrumNetworkPlugin : public NetworkPlugin { void handleBuddyUpdatedRequest(const std::string &user, const std::string &buddyName, const std::string &alias, const std::string &groups) { PurpleAccount *account = m_sessions[user]; if (account) { + + if (m_authRequests.find(user + buddyName) != m_authRequests.end()) { + m_authRequests[user + buddyName]->authorize_cb(m_authRequests[user + buddyName]->user_data); + m_authRequests.erase(user + buddyName); + } + PurpleBuddy *buddy = purple_find_buddy(account, buddyName.c_str()); if (buddy) { purple_blist_alias_buddy(buddy, alias.c_str()); @@ -347,6 +366,7 @@ class SpectrumNetworkPlugin : public NetworkPlugin { std::map m_sessions; std::map m_accounts; std::map m_vcards; + std::map m_authRequests; private: Config *config; }; @@ -693,10 +713,44 @@ static PurpleRequestUiOps requestUiOps = NULL }; +static void * accountRequestAuth(PurpleAccount *account, const char *remote_user, const char *id, const char *alias, const char *message, gboolean on_list, PurpleAccountRequestAuthorizationCb authorize_cb, PurpleAccountRequestAuthorizationCb deny_cb, void *user_data) { + authRequest *req = new authRequest; + req->authorize_cb = authorize_cb; + req->deny_cb = deny_cb; + req->user_data = user_data; + req->account = account; + req->who = remote_user; + req->mainJID = np->m_accounts[account]; + np->m_authRequests[req->mainJID + req->who] = req; + + np->handleAuthorization(req->mainJID, req->who); + + return req; +} + +static void accountRequestClose(void *data){ + authRequest *req = (authRequest *) data; + np->m_authRequests.erase(req->mainJID + req->who); +} + + +static PurpleAccountUiOps accountUiOps = +{ + NULL, + NULL, + NULL, + accountRequestAuth, + accountRequestClose, + NULL, + NULL, + NULL, + NULL +}; + static void transport_core_ui_init(void) { purple_blist_set_ui_ops(&blistUiOps); -// purple_accounts_set_ui_ops(&accountUiOps); + purple_accounts_set_ui_ops(&accountUiOps); purple_notify_set_ui_ops(¬ifyUiOps); purple_request_set_ui_ops(&requestUiOps); // purple_xfers_set_ui_ops(getXferUiOps()); diff --git a/include/transport/networkplugin.h b/include/transport/networkplugin.h index f31a556a..aab71ae9 100644 --- a/include/transport/networkplugin.h +++ b/include/transport/networkplugin.h @@ -64,6 +64,8 @@ class NetworkPlugin { void handleBuddyStoppedTyping(const std::string &user, const std::string &buddyName); + void handleAuthorization(const std::string &user, const std::string &buddyName); + virtual void handleLoginRequest(const std::string &user, const std::string &legacyName, const std::string &password) = 0; virtual void handleLogoutRequest(const std::string &user, const std::string &legacyName) = 0; virtual void handleMessageSendRequest(const std::string &user, const std::string &legacyName, const std::string &message) = 0; diff --git a/include/transport/networkpluginserver.h b/include/transport/networkpluginserver.h index 56000bf1..777e061e 100644 --- a/include/transport/networkpluginserver.h +++ b/include/transport/networkpluginserver.h @@ -68,6 +68,7 @@ class NetworkPluginServer { void handleRoomChangedPayload(const std::string &payload); void handleVCardPayload(const std::string &payload); void handleChatStatePayload(const std::string &payload, Swift::ChatState::ChatStateType type); + void handleAuthorizationPayload(const std::string &payload); void handleUserCreated(User *user); void handleRoomJoined(User *user, const std::string &room, const std::string &nickname, const std::string &password); diff --git a/include/transport/rostermanager.h b/include/transport/rostermanager.h index 4bd8ae4b..574c145e 100644 --- a/include/transport/rostermanager.h +++ b/include/transport/rostermanager.h @@ -76,6 +76,10 @@ class RosterManager { /// \param buddy removed Buddy boost::signal onBuddyUnset; + boost::signal onBuddyAdded; + + boost::signal onBuddyRemoved; + void handleSubscription(Swift::Presence::ref presence); private: diff --git a/spectrum/src/CMakeLists.txt b/spectrum/src/CMakeLists.txt index 4a3e6432..3cf5ba1e 100644 --- a/spectrum/src/CMakeLists.txt +++ b/spectrum/src/CMakeLists.txt @@ -3,8 +3,8 @@ FILE(GLOB SRC *.cpp) ADD_EXECUTABLE(spectrum2 ${SRC}) -ADD_DEPENDENCIES(spectrum2 libpurple_backend) -ADD_DEPENDENCIES(spectrum2 libircclient-qt_backend) +ADD_DEPENDENCIES(spectrum2 spectrum_libpurple_backend) +ADD_DEPENDENCIES(spectrum2 spectrum_libircclient-qt_backend) target_link_libraries(spectrum2 transport) diff --git a/spectrum/src/sample.cfg b/spectrum/src/sample.cfg index 85030ced..586c55eb 100644 --- a/spectrum/src/sample.cfg +++ b/spectrum/src/sample.cfg @@ -9,8 +9,8 @@ backend_port=10001 #cert= #patch to PKCS#12 certificate #cert_password= #password to that certificate if any users_per_backend=2 -backend=../../backends/libpurple/libpurple_backend -#backend=../../backends/libircclient-qt/libircclient-qt_backend +backend=../../backends/libpurple/spectrum_libpurple_backend +#backend=../../backends/libircclient-qt/spectrum_libircclient-qt_backend protocol=prpl-jabber #protocol=prpl-msn #protocol=prpl-icq diff --git a/src/buddy.cpp b/src/buddy.cpp index b9879a04..725b969c 100644 --- a/src/buddy.cpp +++ b/src/buddy.cpp @@ -169,6 +169,10 @@ std::string Buddy::JIDToLegacyName(const Swift::JID &jid) { } else { name = jid.getUnescapedNode(); + // Psi sucks... + if (name.find_last_of("\\40") != std::string::npos) { + name.replace(name.find_last_of("\\40"), 1, "@"); + } } return name; } diff --git a/src/networkplugin.cpp b/src/networkplugin.cpp index a3d9ed16..eec1f08e 100644 --- a/src/networkplugin.cpp +++ b/src/networkplugin.cpp @@ -162,6 +162,19 @@ void NetworkPlugin::handleBuddyStoppedTyping(const std::string &user, const std: send(message); } +void NetworkPlugin::handleAuthorization(const std::string &user, const std::string &buddyName) { + pbnetwork::Buddy buddy; + buddy.set_username(user); + buddy.set_buddyname(buddyName); + + std::string message; + buddy.SerializeToString(&message); + + WRAP(message, pbnetwork::WrapperMessage_Type_TYPE_AUTH_REQUEST); + + send(message); +} + void NetworkPlugin::handleConnected(const std::string &user) { std::cout << "LOGIN SENT\n"; pbnetwork::Connected d; diff --git a/src/networkpluginserver.cpp b/src/networkpluginserver.cpp index 71b8fc90..5c5b012e 100644 --- a/src/networkpluginserver.cpp +++ b/src/networkpluginserver.cpp @@ -224,6 +224,32 @@ void NetworkPluginServer::handleVCardPayload(const std::string &data) { m_vcardResponder->sendVCard(payload.id(), vcard); } +void NetworkPluginServer::handleAuthorizationPayload(const std::string &data) { + pbnetwork::Buddy payload; + if (payload.ParseFromString(data) == false) { + // TODO: ERROR + return; + } + + User *user = m_userManager->getUser(payload.username()); + if (!user) + return; + + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(user->getJID()); + std::string name = payload.buddyname(); + +// name = Swift::JID::getEscapedNode(name) + + 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); + m_component->getStanzaChannel()->sendPresence(response); +} + void NetworkPluginServer::handleChatStatePayload(const std::string &data, Swift::ChatState::ChatStateType type) { pbnetwork::Buddy payload; if (payload.ParseFromString(data) == false) { @@ -245,7 +271,6 @@ void NetworkPluginServer::handleChatStatePayload(const std::string &data, Swift: msg->addPayload(boost::make_shared(type)); conv->handleMessage(msg); - } void NetworkPluginServer::handleBuddyChangedPayload(const std::string &data) { @@ -409,6 +434,9 @@ void NetworkPluginServer::handleDataRead(Client *c, const Swift::SafeByteArray & case pbnetwork::WrapperMessage_Type_TYPE_BUDDY_STOPPED_TYPING: handleChatStatePayload(wrapper.payload(), Swift::ChatState::Active); break; + case pbnetwork::WrapperMessage_Type_TYPE_AUTH_REQUEST: + handleAuthorizationPayload(wrapper.payload()); + break; default: return; } diff --git a/src/pbnetwork.proto b/src/pbnetwork.proto index 1cbf782d..e06beda6 100644 --- a/src/pbnetwork.proto +++ b/src/pbnetwork.proto @@ -92,6 +92,7 @@ message WrapperMessage { TYPE_BUDDY_TYPING = 18; TYPE_BUDDY_STOPPED_TYPING = 19; TYPE_BUDDY_TYPED = 20; + TYPE_AUTH_REQUEST = 21; } required Type type = 1; optional bytes payload = 2; diff --git a/src/rostermanager.cpp b/src/rostermanager.cpp index b2f34b28..3ff7037c 100644 --- a/src/rostermanager.cpp +++ b/src/rostermanager.cpp @@ -39,9 +39,6 @@ RosterManager::RosterManager(User *user, Component *component){ m_setBuddyTimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(1000); m_RIETimer = m_component->getNetworkFactories()->getTimerFactory()->createTimer(5000); m_RIETimer->onTick.connect(boost::bind(&RosterManager::sendRIE, this)); - - - } RosterManager::~RosterManager() { @@ -157,7 +154,131 @@ void RosterManager::sendRIE() { void RosterManager::handleSubscription(Swift::Presence::ref presence) { std::string legacyName = Buddy::JIDToLegacyName(presence->getTo()); - + // For server mode the subscription changes are handler in rosterresponder.cpp + // using roster pushes. + if (m_component->inServerMode()) { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(presence->getFrom()); + response->setFrom(presence->getTo()); + Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo())); + if (buddy) { + switch (presence->getType()) { + case Swift::Presence::Subscribe: + response->setType(Swift::Presence::Subscribed); + break; + case Swift::Presence::Unsubscribe: + response->setType(Swift::Presence::Unsubscribed); + break; + default: + return; + } + m_component->getStanzaChannel()->sendPresence(response); + + } + else { + BuddyInfo buddyInfo; + switch (presence->getType()) { + // buddy is not in roster, so add him + case Swift::Presence::Subscribe: + buddyInfo.id = -1; + buddyInfo.alias = ""; + buddyInfo.legacyName = Buddy::JIDToLegacyName(presence->getTo()); + buddyInfo.subscription = "both"; + buddyInfo.flags = 0; + + buddy = m_component->getFactory()->createBuddy(this, buddyInfo); + setBuddy(buddy); + onBuddyAdded(buddy); + response->setType(Swift::Presence::Subscribed); + break; + // buddy is already there, so nothing to do, just answer + case Swift::Presence::Unsubscribe: + response->setType(Swift::Presence::Unsubscribed); + break; + default: + return; + } + m_component->getStanzaChannel()->sendPresence(response); + } + } + else { + Swift::Presence::ref response = Swift::Presence::create(); + response->setTo(presence->getFrom()); + response->setFrom(presence->getTo()); + + Buddy *buddy = getBuddy(Buddy::JIDToLegacyName(presence->getTo())); + if (buddy) { + switch (presence->getType()) { + // buddy is already there, so nothing to do, just answer + case Swift::Presence::Subscribe: + response->setType(Swift::Presence::Subscribed); + break; + // remove buddy + case Swift::Presence::Unsubscribe: + response->setType(Swift::Presence::Unsubscribed); + onBuddyRemoved(buddy); + break; + // just send response + case Swift::Presence::Unsubscribed: + response->setType(Swift::Presence::Unsubscribe); + break; + // just send response + case Swift::Presence::Subscribed: + response->setType(Swift::Presence::Subscribe); + break; + default: + return; + } + } + else { + BuddyInfo buddyInfo; + switch (presence->getType()) { + // buddy is not in roster, so add him + case Swift::Presence::Subscribe: + buddyInfo.id = -1; + buddyInfo.alias = ""; + buddyInfo.legacyName = Buddy::JIDToLegacyName(presence->getTo()); + buddyInfo.subscription = "both"; + buddyInfo.flags = 0; + + buddy = m_component->getFactory()->createBuddy(this, buddyInfo); + setBuddy(buddy); + onBuddyAdded(buddy); + response->setType(Swift::Presence::Subscribed); + break; + // buddy is already there, so nothing to do, just answer + case Swift::Presence::Unsubscribe: + response->setType(Swift::Presence::Unsubscribed); + break; + // just send response + case Swift::Presence::Unsubscribed: + response->setType(Swift::Presence::Unsubscribe); + break; + // just send response + case Swift::Presence::Subscribed: + response->setType(Swift::Presence::Subscribe); + break; + default: + return; + } + } + + m_component->getStanzaChannel()->sendPresence(response); + + // We have to act as buddy and send its subscribe/unsubscribe just to be sure... + switch (response->getType()) { + case Swift::Presence::Unsubscribed: + response->setType(Swift::Presence::Unsubscribe); + m_component->getStanzaChannel()->sendPresence(response); + break; + case Swift::Presence::Subscribed: + response->setType(Swift::Presence::Subscribe); + m_component->getStanzaChannel()->sendPresence(response); + break; + default: + break; + } + } } void RosterManager::setStorageBackend(StorageBackend *storageBackend) {