rostermanager.cpp
/*
Copyright (c) 2004-2023 by Jakob Schröter <js@camaya.net>
This file is part of the gloox library. http://camaya.net/gloox
This software is distributed under a license. The full license
agreement can be found in the file LICENSE in this distribution.
This software may not be copied, modified, sold or distributed
other than expressed in the named license agreement.
This software is distributed without any warranty.
*/
#include "clientbase.h"
#include "rostermanager.h"
#include "disco.h"
#include "rosteritem.h"
#include "rosteritemdata.h"
#include "rosterlistener.h"
#include "privatexml.h"
#include "util.h"
#include "stanzaextension.h"
#include "capabilities.h"
namespace gloox
{
// ---- RosterManager::Query ----
RosterManager::Query::Query( const JID& jid, const std::string& name, const StringList& groups )
: StanzaExtension( ExtRoster )
{
m_roster.push_back( new RosterItemData( jid, name, groups ) );
}
RosterManager::Query::Query( const JID& jid )
: StanzaExtension( ExtRoster )
{
m_roster.push_back( new RosterItemData( jid ) );
}
RosterManager::Query::Query( const Tag* tag )
: StanzaExtension( ExtRoster )
{
if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_ROSTER )
return;
const ConstTagList& l = tag->findTagList( "query/item" );
ConstTagList::const_iterator it = l.begin();
for( ; it != l.end(); ++it )
{
StringList groups;
const ConstTagList& g = (*it)->findTagList( "item/group" );
ConstTagList::const_iterator it_g = g.begin();
for( ; it_g != g.end(); ++it_g )
groups.push_back( (*it_g)->cdata() );
const std::string sub = (*it)->findAttribute( "subscription" );
if( sub == "remove" )
m_roster.push_back( new RosterItemData( JID( (*it)->findAttribute( "jid" ) ) ) );
else
{
RosterItemData* rid = new RosterItemData( JID( (*it)->findAttribute( "jid" ) ),
(*it)->findAttribute( "name" ),
groups );
rid->setSubscription( sub, (*it)->findAttribute( "ask" ) );
m_roster.push_back( rid );
}
}
}
RosterManager::Query::~Query()
{
util::clearList( m_roster );
}
const std::string& RosterManager::Query::filterString() const
{
static const std::string filter = "/iq/query[@xmlns='" + XMLNS_ROSTER + "']";
return filter;
}
Tag* RosterManager::Query::tag() const
{
Tag* t = new Tag( "query" );
t->setXmlns( XMLNS_ROSTER );
RosterData::const_iterator it = m_roster.begin();
for( ; it != m_roster.end(); ++it )
t->addChild( (*it)->tag() );
return t;
}
StanzaExtension* RosterManager::Query::clone() const
{
Query* q = new Query();
RosterData::const_iterator it = m_roster.begin();
for( ; it != m_roster.end(); ++it )
{
q->m_roster.push_back( new RosterItemData( *(*it) ) );
}
return q;
}
// ---- ~RosterManager::Query ----
// ---- RosterManager ----
RosterManager::RosterManager( ClientBase* parent )
: m_rosterListener( 0 ), m_parent( parent ), m_privateXML( 0 ),
m_syncSubscribeReq( false )
{
if( m_parent )
{
m_parent->registerIqHandler( this, ExtRoster );
m_parent->registerPresenceHandler( this );
m_parent->registerSubscriptionHandler( this );
m_parent->registerStanzaExtension( new Query() );
m_self = new RosterItem( m_parent->jid().bare() );
m_privateXML = new PrivateXML( m_parent );
}
}
RosterManager::~RosterManager()
{
if( m_parent )
{
m_parent->removeIqHandler( this, ExtRoster );
m_parent->removeIDHandler( this );
m_parent->removePresenceHandler( this );
m_parent->removeSubscriptionHandler( this );
m_parent->removeStanzaExtension( ExtRoster );
delete m_self;
delete m_privateXML;
}
util::clearMap( m_roster );
}
Roster* RosterManager::roster()
{
return &m_roster;
}
void RosterManager::fill()
{
if( !m_parent )
return;
util::clearMap( m_roster );
m_privateXML->requestXML( "roster", XMLNS_ROSTER_DELIMITER, this );
IQ iq( IQ::Get, JID(), m_parent->getID() );
iq.addExtension( new Query() );
m_parent->send( iq, this, RequestRoster );
}
bool RosterManager::handleIq( const IQ& iq )
{
if( iq.subtype() != IQ::Set ) // FIXME add checks for 'from' attribute (empty or bare self jid?)
return false;
// single roster item push
const Query* q = iq.findExtension<Query>( ExtRoster );
if( q && q->roster().size() )
mergePush( q->roster() );
IQ re( IQ::Result, JID(), iq.id() );
m_parent->send( re );
return true;
}
void RosterManager::handleIqID( const IQ& iq, int context )
{
if( iq.subtype() == IQ::Result ) // initial roster
{
const Query* q = iq.findExtension<Query>( ExtRoster );
if( q )
mergeRoster( q->roster() );
if( context == RequestRoster )
{
if( m_parent )
m_parent->rosterFilled();
if( m_rosterListener )
m_rosterListener->handleRoster( m_roster );
}
}
else if( iq.subtype() == IQ::Error )
{
if( context == RequestRoster && m_parent )
m_parent->rosterFilled();
if( m_rosterListener )
m_rosterListener->handleRosterError( iq );
}
}
void RosterManager::handlePresence( const Presence& presence )
{
if( presence.subtype() == Presence::Error )
return;
bool self = false;
Roster::iterator it = m_roster.find( presence.from().bare() );
if( it != m_roster.end() || ( self = ( presence.from().bareJID() == m_self->jidJID() ) ) )
{
RosterItem* ri = self ? m_self : (*it).second;
const std::string& resource = presence.from().resource();
if( presence.presence() == Presence::Unavailable )
ri->removeResource( resource );
else
{
ri->setPresence( resource, presence.presence() );
ri->setStatus( resource, presence.status() );
ri->setPriority( resource, presence.priority() );
ri->setExtensions( resource, presence.extensions() );
}
if( m_rosterListener && !self )
m_rosterListener->handleRosterPresence( *ri, resource,
presence.presence(), presence.status() );
else if( m_rosterListener && self )
m_rosterListener->handleSelfPresence( *ri, resource,
presence.presence(), presence.status() );
}
else
{
if( m_rosterListener )
m_rosterListener->handleNonrosterPresence( presence );
}
}
void RosterManager::subscribe( const JID& jid, const std::string& name,
const StringList& groups, const std::string& msg )
{
if( !jid )
return;
add( jid, name, groups );
Subscription s( Subscription::Subscribe, jid.bareJID(), msg );
m_parent->send( s );
}
void RosterManager::add( const JID& jid, const std::string& name, const StringList& groups )
{
if( !jid )
return;
IQ iq( IQ::Set, JID(), m_parent->getID() );
iq.addExtension( new Query( jid, name, groups) );
m_parent->send( iq, this, AddRosterItem );
}
void RosterManager::unsubscribe( const JID& jid, const std::string& msg )
{
Subscription p( Subscription::Unsubscribe, jid.bareJID(), msg );
m_parent->send( p );
}
void RosterManager::cancel( const JID& jid, const std::string& msg )
{
Subscription p( Subscription::Unsubscribed, jid.bareJID(), msg );
m_parent->send( p );
}
void RosterManager::remove( const JID& jid )
{
if( !jid )
return;
IQ iq( IQ::Set, JID(), m_parent->getID() );
iq.addExtension( new Query( jid ) );
m_parent->send( iq, this, RemoveRosterItem );
}
void RosterManager::synchronize()
{
Roster::const_iterator it = m_roster.begin();
for( ; it != m_roster.end(); ++it )
{
if( !(*it).second->changed() )
continue;
IQ iq( IQ::Set, JID(), m_parent->getID() );
iq.addExtension( new Query( (*it).second->jidJID(), (*it).second->name(), (*it).second->groups() ) );
m_parent->send( iq, this, SynchronizeRoster );
}
}
void RosterManager::ackSubscriptionRequest( const JID& to, bool ack )
{
Subscription p( ack ? Subscription::Subscribed
: Subscription::Unsubscribed, to.bareJID() );
m_parent->send( p );
}
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:
{
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:
{
m_rosterListener->handleItemUnsubscribed( s10n.from() );
break;
}
default:
break;
}
}
void RosterManager::registerRosterListener( RosterListener* rl, bool syncSubscribeReq )
{
m_syncSubscribeReq = syncSubscribeReq;
m_rosterListener = rl;
}
void RosterManager::removeRosterListener()
{
m_syncSubscribeReq = false;
m_rosterListener = 0;
}
void RosterManager::setDelimiter( const std::string& delimiter )
{
m_delimiter = delimiter;
Tag* t = new Tag( "roster", m_delimiter );
t->addAttribute( XMLNS, XMLNS_ROSTER_DELIMITER );
m_privateXML->storeXML( t, this );
}
void RosterManager::handlePrivateXML( const Tag* xml )
{
if( xml )
m_delimiter = xml->cdata();
}
void RosterManager::handlePrivateXMLResult( const std::string& /*uid*/, PrivateXMLResult /*result*/ )
{
}
RosterItem* RosterManager::getRosterItem( const JID& jid )
{
Roster::const_iterator it = m_roster.find( jid.bare() );
return it != m_roster.end() ? (*it).second : 0;
}
void RosterManager::mergePush( const RosterData& data )
{
RosterData::const_iterator it = data.begin();
for( ; it != data.end(); ++it )
{
Roster::iterator itr = m_roster.find( (*it)->jidJID().full() );
if( itr != m_roster.end() )
{
if( (*it)->remove() )
{
if( m_rosterListener )
m_rosterListener->handleItemRemoved( (*it)->jidJID().full() );
delete (*itr).second;
m_roster.erase( itr );
}
else
{
(*itr).second->setData( *(*it) );
if( m_rosterListener )
m_rosterListener->handleItemUpdated( (*it)->jidJID().full() );
}
}
else if( !(*it)->remove() )
{
m_roster.insert( std::make_pair( (*it)->jidJID().full(), new RosterItem( *(*it) ) ) );
if( m_rosterListener )
m_rosterListener->handleItemAdded( (*it)->jidJID().full() );
}
}
}
void RosterManager::mergeRoster( const RosterData& data )
{
RosterData::const_iterator it = data.begin();
for( ; it != data.end(); ++it )
m_roster.insert( std::make_pair( (*it)->jidJID().full(), new RosterItem( *(*it) ) ) );
}
}
gloox::ClientBase
This is the common base class for a Jabber/XMPP Client and a Jabber Component.
Definition clientbase.h:79
gloox::IQ
An abstraction of an IQ stanza.
Definition iq.h:34
gloox::IQ::subtype
IqType subtype() const
Definition iq.h:74
gloox::IQ::Set
@ Set
Definition iq.h:46
gloox::IQ::Error
@ Error
Definition iq.h:49
gloox::IQ::Result
@ Result
Definition iq.h:48
gloox::IQ::Get
@ Get
Definition iq.h:45
gloox::JID
An abstraction of a JID.
Definition jid.h:31
gloox::JID::resource
const std::string & resource() const
Definition jid.h:116
gloox::JID::bareJID
JID bareJID() const
Definition jid.h:74
gloox::JID::bare
const std::string & bare() const
Definition jid.h:67
gloox::Presence
An abstraction of a presence stanza.
Definition presence.h:33
gloox::Presence::priority
int priority() const
Definition presence.h:131
gloox::Presence::presence
PresenceType presence() const
Definition presence.h:89
gloox::Presence::subtype
PresenceType subtype() const
Definition presence.h:76
gloox::Presence::status
const std::string status(const std::string &lang="default") const
Definition presence.h:106
gloox::Presence::Error
@ Error
Definition presence.h:51
gloox::Presence::Unavailable
@ Unavailable
Definition presence.h:49
gloox::PrivateXMLHandler::PrivateXMLResult
PrivateXMLResult
Definition privatexmlhandler.h:42
gloox::PrivateXML
This class implements XEP-0049 (Private XML Storage).
Definition privatexml.h:38
gloox::RosterItem
An abstraction of a roster item.
Definition rosteritem.h:41
gloox::RosterItem::setPriority
void setPriority(const std::string &resource, int priority)
Definition rosteritem.cpp:128
gloox::RosterItem::removeResource
void removeResource(const std::string &resource)
Definition rosteritem.cpp:160
gloox::RosterItem::setStatus
void setStatus(const std::string &resource, const std::string &msg)
Definition rosteritem.cpp:120
gloox::RosterItem::setExtensions
void setExtensions(const std::string &resource, const StanzaExtensionList &exts)
Definition rosteritem.cpp:152
gloox::RosterItem::setPresence
void setPresence(const std::string &resource, Presence::PresenceType presence)
Definition rosteritem.cpp:112
gloox::RosterListener
A virtual interface which can be reimplemented to receive roster updates.
Definition rosterlistener.h:44
gloox::RosterListener::handleItemRemoved
virtual void handleItemRemoved(const JID &jid)=0
gloox::RosterListener::handleItemUpdated
virtual void handleItemUpdated(const JID &jid)=0
gloox::RosterManager::RosterManager
RosterManager(ClientBase *parent)
Definition rostermanager.cpp:108
gloox::RosterManager::add
void add(const JID &jid, const std::string &name, const StringList &groups)
Definition rostermanager.cpp:248
gloox::RosterManager::subscribe
void subscribe(const JID &jid, const std::string &name=EmptyString, const StringList &groups=StringList(), const std::string &msg=EmptyString)
Definition rostermanager.cpp:235
gloox::RosterManager::unsubscribe
void unsubscribe(const JID &jid, const std::string &msg=EmptyString)
Definition rostermanager.cpp:259
gloox::RosterManager::handleSubscription
virtual void handleSubscription(const Subscription &subscription)
Definition rostermanager.cpp:303
gloox::RosterManager::synchronize
void synchronize()
Definition rostermanager.cpp:282
gloox::RosterManager::handleIqID
virtual void handleIqID(const IQ &iq, int context)
Definition rostermanager.cpp:172
gloox::RosterManager::delimiter
const std::string & delimiter() const
Definition rostermanager.h:141
gloox::RosterManager::handleIq
virtual bool handleIq(const IQ &iq)
Definition rostermanager.cpp:157
gloox::RosterManager::roster
Roster * roster()
Definition rostermanager.cpp:140
gloox::RosterManager::setDelimiter
void setDelimiter(const std::string &delimiter)
Definition rostermanager.cpp:359
gloox::RosterManager::handlePrivateXML
virtual void handlePrivateXML(const Tag *xml)
Definition rostermanager.cpp:367
gloox::RosterManager::handlePresence
virtual void handlePresence(const Presence &presence)
Definition rostermanager.cpp:199
gloox::RosterManager::~RosterManager
virtual ~RosterManager()
Definition rostermanager.cpp:124
gloox::RosterManager::cancel
void cancel(const JID &jid, const std::string &msg=EmptyString)
Definition rostermanager.cpp:265
gloox::RosterManager::getRosterItem
RosterItem * getRosterItem(const JID &jid)
Definition rostermanager.cpp:377
gloox::RosterManager::handlePrivateXMLResult
virtual void handlePrivateXMLResult(const std::string &uid, PrivateXMLResult pxResult)
Definition rostermanager.cpp:373
gloox::RosterManager::ackSubscriptionRequest
void ackSubscriptionRequest(const JID &to, bool ack)
Definition rostermanager.cpp:296
gloox::RosterManager::remove
void remove(const JID &jid)
Definition rostermanager.cpp:271
gloox::RosterManager::fill
void fill()
Definition rostermanager.cpp:145
gloox::RosterManager::registerRosterListener
void registerRosterListener(RosterListener *rl, bool syncSubscribeReq=true)
Definition rostermanager.cpp:347
gloox::RosterManager::removeRosterListener
void removeRosterListener()
Definition rostermanager.cpp:353
gloox::StanzaExtension
This class abstracts a stanza extension, which is usually an XML child element in a specific namespac...
Definition stanzaextension.h:204
gloox::Stanza::addExtension
void addExtension(const StanzaExtension *se)
Definition stanza.cpp:52
gloox::Stanza::id
const std::string & id() const
Definition stanza.h:63
gloox::Stanza::extensions
const StanzaExtensionList & extensions() const
Definition stanza.h:113
gloox::Stanza::from
const JID & from() const
Definition stanza.h:51
gloox::Stanza::findExtension
const StanzaExtension * findExtension(int type) const
Definition stanza.cpp:57
gloox::Subscription
An abstraction of a subscription stanza.
Definition subscription.h:32
gloox::Subscription::Subscribed
@ Subscribed
Definition subscription.h:44
gloox::Subscription::Unsubscribed
@ Unsubscribed
Definition subscription.h:46
gloox::Subscription::Unsubscribe
@ Unsubscribe
Definition subscription.h:45
gloox::Subscription::Subscribe
@ Subscribe
Definition subscription.h:43
gloox::Subscription::subtype
S10nType subtype() const
Definition subscription.h:69
gloox::Subscription::status
const std::string status(const std::string &lang="default") const
Definition subscription.h:80
gloox::Tag
This is an abstraction of an XML element.
Definition tag.h:47
gloox::Tag::addAttribute
bool addAttribute(Attribute *attr)
Definition tag.cpp:354
gloox::Tag::cdata
const std::string cdata() const
Definition tag.cpp:497
gloox::util::clearMap
void clearMap(std::map< Key, T * > &M)
Definition util.h:169
gloox
The namespace for the gloox library.
Definition adhoc.cpp:28
gloox::StringList
std::list< std::string > StringList
Definition gloox.h:1251
gloox::XMLNS
const std::string XMLNS
Definition gloox.cpp:122
gloox::XMLNS_ROSTER
const std::string XMLNS_ROSTER
Definition gloox.cpp:38
gloox::ExtRoster
@ ExtRoster
Definition stanzaextension.h:64
gloox::Roster
std::map< const std::string, RosterItem * > Roster
Definition rosterlistener.h:31
gloox::XMLNS_ROSTER_DELIMITER
const std::string XMLNS_ROSTER_DELIMITER
Definition gloox.cpp:61