void RosterManager::handleSubscription(Swift::Presence::ref presence) { std::string legacyName = Buddy::JIDToLegacyName(presence->getTo(), m_user); if (legacyName.empty()) { return; } // 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().toBare()); response->setFrom(presence->getTo().toBare()); Buddy *buddy = getBuddy(legacyName); if (buddy) { LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received and buddy " << legacyName << " is already there => answering"); switch (presence->getType()) { case Swift::Presence::Subscribe: onBuddyAdded(buddy); response->setType(Swift::Presence::Subscribed); break; case Swift::Presence::Unsubscribe: onBuddyRemoved(buddy); removeBuddy(buddy->getName()); buddy = NULL; response->setType(Swift::Presence::Unsubscribed); break; case Swift::Presence::Subscribed: onBuddyAdded(buddy); break; default: return; } m_component->getFrontend()->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 = legacyName; buddyInfo.subscription = "both"; buddyInfo.flags = Buddy::buddyFlagsFromJID(presence->getTo()); LOG4CXX_INFO(logger, m_user->getJID().toString() << ": Subscription received for new buddy " << buddyInfo.legacyName << " => adding to legacy network"); buddy = m_component->getFactory()->createBuddy(this, buddyInfo); setBuddy(buddy); onBuddyAdded(buddy); response->setType(Swift::Presence::Subscribed); break; case Swift::Presence::Subscribed: // onBuddyAdded(buddy); return; // buddy is not there, so nothing to do, just answer case Swift::Presence::Unsubscribe: buddyInfo.id = -1; buddyInfo.alias = ""; buddyInfo.legacyName = legacyName; buddyInfo.subscription = "both"; buddyInfo.flags = Buddy::buddyFlagsFromJID(presence->getTo()); buddy = m_component->getFactory()->createBuddy(this, buddyInfo); onBuddyRemoved(buddy); delete buddy; response->setType(Swift::Presence::Unsubscribed); break; default: return; } m_component->getFrontend()->sendPresence(response); } } else { Swift::Presence::ref response = Swift::Presence::create(); Swift::Presence::ref currentPresence; response->setTo(presence->getFrom().toBare()); response->setFrom(presence->getTo().toBare()); Buddy *buddy = getBuddy(legacyName); if (buddy) { std::vector<Swift::Presence::ref> &presences = buddy->generatePresenceStanzas(255); switch (presence->getType()) { // buddy is already there, so nothing to do, just answer case Swift::Presence::Subscribe: onBuddyAdded(buddy); response->setType(Swift::Presence::Subscribed); BOOST_FOREACH(Swift::Presence::ref ¤tPresence, presences) { currentPresence->setTo(presence->getFrom()); m_component->getFrontend()->sendPresence(currentPresence); } if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); 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: response->setType(Swift::Presence::Unsubscribe); // We set both here, because this Unsubscribed can be response to // subscribe presence and we don't want that unsubscribe presence // to be send later again if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); storeBuddy(buddy); } break; case Swift::Presence::Subscribed: if (buddy->getSubscription() != Buddy::Both) { buddy->setSubscription(Buddy::Both); storeBuddy(buddy); } return; default: return; } } else {
void SpectrumRosterManager::handleSubscription(const Subscription &subscription) { std::string remote_user = purpleUsername(subscription.to().username()); if (remote_user.empty()) { Log(m_user->jid(), "handleSubscription: Remote user is EMPTY!"); return; } if (m_user->isConnected()) { PurpleBuddy *buddy = NULL; // Try to get PurpleBuddy from SpectrumBuddy at first, because SpectrumBuddy // uses normalized username (buddy->name could be "User", but remote_user is normalized // so it's "user" for example). AbstractSpectrumBuddy *s_buddy = getRosterItem(remote_user); if (s_buddy) buddy = s_buddy->getBuddy(); else buddy = purple_find_buddy(m_user->account(), remote_user.c_str()); if (subscription.subtype() == Subscription::Subscribed) { // Accept authorize request. if (hasAuthRequest(remote_user)) { Log(m_user->jid(), "subscribed presence for authRequest arrived => accepting the request"); m_authRequests[remote_user]->authorize_cb(m_authRequests[remote_user]->user_data); removeAuthRequest(remote_user); } if (!isInRoster(remote_user, "both")) { if (buddy) { Log(m_user->jid(), "adding this user to local roster and sending presence"); if (s_buddy == NULL) { // There is PurpleBuddy, but not SpectrumBuddy (that should not happen, but this // code doesn't break anything). addRosterItem(buddy); Transport::instance()->sql()->addBuddy(m_user->storageId(), remote_user, "both"); storeBuddy(buddy); } else { // Update subscription. s_buddy->setSubscription("both"); Transport::instance()->sql()->updateBuddySubscription(m_user->storageId(), remote_user, "both"); storeBuddy(buddy); } } else { Log(m_user->jid(), "user is not in legacy network contact lists => nothing to be subscribed"); } } // XMPP user is able to get the first status presence just after "subscribed" presence. if (s_buddy) { sendPresence(s_buddy); } return; } else if (subscription.subtype() == Subscription::Subscribe) { // User is in roster, so that's probably response for RIE. if (s_buddy) { Log(m_user->jid(), "subscribe presence; user is already in roster => sending subscribed"); s_buddy->setSubscription("to"); Tag *reply = new Tag("presence"); reply->addAttribute( "to", subscription.from().bare() ); reply->addAttribute( "from", subscription.to().bare() ); reply->addAttribute( "type", "subscribe" ); Transport::instance()->send( reply ); reply = new Tag("presence"); reply->addAttribute( "to", subscription.from().bare() ); reply->addAttribute( "from", subscription.to().bare() ); reply->addAttribute( "type", "subscribed" ); Transport::instance()->send( reply ); // Sometimes there is "subscribed" request for new user received before "subscribe", // so s_buddy could be already there, but purple_account_add_buddy has not been called. if (buddy) { Log(m_user->jid(), "Trying to purple_account_add_buddy just to be sure."); purple_account_add_buddy(m_user->account(), buddy); } } // User is not in roster, so that's probably new subscribe request. else { Log(m_user->jid(), "subscribe presence; user is not in roster => adding to legacy network"); // Disable handling new-buddy event, because we're going to create new buddy by Spectrum, not // by libpurple (so we don't want to add it to RIE queue and send back to XMPP user). m_loadingFromDB = true; PurpleBuddy *buddy = purple_buddy_new(m_user->account(), remote_user.c_str(), remote_user.c_str()); #ifndef TESTS SpectrumBuddy *s_buddy = new SpectrumBuddy(-1, buddy); buddy->node.ui_data = (void *) s_buddy; s_buddy->setSubscription("to"); if (usesJidEscaping(subscription.to().username())) s_buddy->setFlags(s_buddy->getFlags() | SPECTRUM_BUDDY_JID_ESCAPING); addRosterItem(s_buddy); #endif // Add newly created buddy to legacy network roster. purple_blist_add_buddy(buddy, NULL, NULL ,NULL); purple_account_add_buddy(m_user->account(), buddy); m_loadingFromDB = false; } return; } else if (subscription.subtype() == Subscription::Unsubscribe || subscription.subtype() == Subscription::Unsubscribed) { if (subscription.subtype() == Subscription::Unsubscribed) { // Reject authorize request. if (hasAuthRequest(remote_user)) { Log(m_user->jid(), "unsubscribed presence for authRequest arrived => rejecting the request"); m_authRequests[remote_user]->deny_cb(m_authRequests[remote_user]->user_data); removeAuthRequest(remote_user); return; } } // Buddy is in legacy network roster, so we can remove it. if (buddy) { Log(m_user->jid(), "unsubscribed presence => removing this contact from legacy network"); // Remove buddy from database, if he's already there. if (s_buddy) { long id = s_buddy->getId(); Transport::instance()->sql()->removeBuddy(m_user->storageId(), remote_user, id); } // Remove buddy from legacy network roster. purple_account_remove_buddy(m_user->account(), buddy, purple_buddy_get_group(buddy)); purple_blist_remove_buddy(buddy); } else { // this buddy is not in legacy network roster, so there is nothing to remove... } removeFromLocalRoster(remote_user); // inform user about removing this buddy Tag *tag = new Tag("presence"); tag->addAttribute("to", subscription.from().bare()); tag->addAttribute("from", subscription.to().username() + "@" + Transport::instance()->jid() + "/bot"); if(subscription.subtype() == Subscription::Unsubscribe) { tag->addAttribute( "type", "unsubscribe" ); } else { tag->addAttribute( "type", "unsubscribed" ); } Transport::instance()->send( tag ); return; } } else { Log(subscription.from().full(), "Subscribe presence received, but is not connected to legacy network yet."); } }