void RosterManager::handleSubscription( const Subscription& s10n ) { if( !m_rosterListener ) return; switch( s10n.subtype() ) { case Subscription::Subscribe: { bool answer = m_rosterListener->handleSubscriptionRequest( s10n.from(), s10n.status() ); if( m_syncSubscribeReq ) { ackSubscriptionRequest( s10n.from(), answer ); } break; } case Subscription::Subscribed: { // Subscription p( Subscription::Subscribe, s10n.from().bareJID() ); // m_parent->send( p ); m_rosterListener->handleItemSubscribed( s10n.from() ); break; } case Subscription::Unsubscribe: { Subscription p( Subscription::Unsubscribed, s10n.from().bareJID() ); m_parent->send( p ); bool answer = m_rosterListener->handleUnsubscriptionRequest( s10n.from(), s10n.status() ); if( m_syncSubscribeReq && answer ) remove( s10n.from().bare() ); break; } case Subscription::Unsubscribed: { // Subscription p( Subscription::Unsubscribe, s10n.from().bareJID() ); // m_parent->send( p ); m_rosterListener->handleItemUnsubscribed( s10n.from() ); break; } default: break; } }
int main( int /*argc*/, char** /*argv*/ ) { int fail = 0; std::string name; Tag *s10n = new Tag( "presence" ); s10n->addAttribute( "from", "[email protected]/gloox" ); s10n->addAttribute( "to", "[email protected]/gloox" ); new Tag( s10n, "status", "the status" ); Subscription* i = 0; // ------- name = "parse Subscription subscribe"; s10n->addAttribute( "type", "subscribe" ); i = new Subscription( s10n ); if( i->subtype() != Subscription::Subscribe || i->from().full() != "[email protected]/gloox" || i->to().full() != "[email protected]/gloox" || i->status() != "the status" ) { ++fail; fprintf( stderr, "test '%s' failed\n", name.c_str() ); } delete i; i = 0; // ------- name = "parse Subscription subscribed"; s10n->addAttribute( "type", "subscribed" ); i = new Subscription( s10n ); if( i->subtype() != Subscription::Subscribed || i->from().full() != "[email protected]/gloox" || i->to().full() != "[email protected]/gloox" || i->status() != "the status" ) { ++fail; fprintf( stderr, "test '%s' failed\n", name.c_str() ); } delete i; i = 0; // ------- name = "parse Subscription unsubscribe"; s10n->addAttribute( "type", "unsubscribe" ); i = new Subscription( s10n ); if( i->subtype() != Subscription::Unsubscribe || i->from().full() != "[email protected]/gloox" || i->to().full() != "[email protected]/gloox" || i->status() != "the status" ) { ++fail; fprintf( stderr, "test '%s' failed\n", name.c_str() ); } delete i; i = 0; // ------- name = "parse Subscription unsubscribed"; s10n->addAttribute( "type", "unsubscribed" ); i = new Subscription( s10n ); if( i->subtype() != Subscription::Unsubscribed || i->from().full() != "[email protected]/gloox" || i->to().full() != "[email protected]/gloox" || i->status() != "the status" ) { ++fail; fprintf( stderr, "test '%s' failed\n", name.c_str() ); } delete i; i = 0; // ------- { name = "new simple Subscription subscribe"; Subscription s( Subscription::Subscribe, JID( "[email protected]/blah" ), "the status", "the xmllang" ); s.setFrom( JID( "*****@*****.**" ) ); Tag* i = s.tag(); if( i->name() != "presence" || !i->hasAttribute( "type", "subscribe" ) || !i->hasAttribute( "to", "[email protected]/blah" ) || !i->hasAttribute( "from", "*****@*****.**" ) || !i->hasChildWithCData( "status", "the status" ) || !i->hasChild( "status", "xml:lang", "the xmllang" ) ) { ++fail; fprintf( stderr, "test '%s' failed: %s\n", name.c_str(), i->xml().c_str() ); } delete i; } // ------- { name = "new simple Subscription subscribed"; Subscription s( Subscription::Subscribed, JID( "[email protected]/blah" ), "the status", "the xmllang" ); s.setFrom( JID( "*****@*****.**" ) ); Tag* i = s.tag(); if( i->name() != "presence" || !i->hasAttribute( "type", "subscribed" ) || !i->hasAttribute( "to", "[email protected]/blah" ) || !i->hasAttribute( "from", "*****@*****.**" ) || !i->hasChildWithCData( "status", "the status" ) || !i->hasChild( "status", "xml:lang", "the xmllang" ) ) { ++fail; fprintf( stderr, "test '%s' failed: %s\n", name.c_str(), i->xml().c_str() ); } delete i; } // ------- { name = "new simple Subscription unsubscribe"; Subscription s( Subscription::Unsubscribe, JID( "[email protected]/blah" ), "the status", "the xmllang" ); s.setFrom( JID( "*****@*****.**" ) ); Tag* i = s.tag(); if( i->name() != "presence" || !i->hasAttribute( "type", "unsubscribe" ) || !i->hasAttribute( "to", "[email protected]/blah" ) || !i->hasAttribute( "from", "*****@*****.**" ) || !i->hasChildWithCData( "status", "the status" ) || !i->hasChild( "status", "xml:lang", "the xmllang" ) ) { ++fail; fprintf( stderr, "test '%s' failed: %s\n", name.c_str(), i->xml().c_str() ); } delete i; } // ------- { name = "new simple Subscription unsubscribed"; Subscription s( Subscription::Unsubscribed, JID( "[email protected]/blah" ), "the status", "the xmllang" ); s.setFrom( JID( "*****@*****.**" ) ); Tag* i = s.tag(); if( i->name() != "presence" || !i->hasAttribute( "type", "unsubscribed" ) || !i->hasAttribute( "to", "[email protected]/blah" ) || !i->hasAttribute( "from", "*****@*****.**" ) || !i->hasChildWithCData( "status", "the status" ) || !i->hasChild( "status", "xml:lang", "the xmllang" ) ) { ++fail; fprintf( stderr, "test '%s' failed: %s\n", name.c_str(), i->xml().c_str() ); } delete i; } delete s10n; s10n = 0; if( fail == 0 ) { printf( "Subscription: OK\n" ); return 0; } else { fprintf( stderr, "Subscription: %d test(s) failed\n", fail ); return 1; } }
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."); } }