Basically these handlers are virtual interfaces from which you derive a class and implement a few virtual functions. Then you register such an object with the respective protocol implementation. A short example:
class MyClass : public PresenceHandler { public: // reimplemented from PresenceHandler virtual void handlePresence( Stanza *stanza ); [...] }; void MyClass::handlePresence( Stanza *stanza ) { // extract further information from the stanza }
Somewhere else you do something like this:
OtherClass::doSomething() { Client *client = new Client( ... ); [...] MyClass *handler = new MyClass( ... ); client->registerPresenceHandler( handler ); }
Now, everytime a presence stanza (not subscription stanza) is received, handlePresence() is called with the current stanza as argument. You can then use the extensive getters of the Stanza class to extract stanza data.
This works similar for all the other event handlers. Another example, this time using the connection event handler (class ConnectionListener ):
class MyClass : public ConnectionListener { public: virtual void onConnect(); virtual bool onTLSConnect( ... ); }; void MyClass::onConnect() { // do something when the connection is established } bool MyClass::onTLSConnect( const CertInfo& info ) { // decide whether you trust the certificate, examine the CertInfo structure return true; // if you trust it, otherwise return false }
The Component class supports this protocol and can be used to create a new Jabber component. It's as simple as:
Component *comp = new Component( ... );
comp->connect();
class MyClass : public ConnectionListener, PresenceHandler { public: void doSomething(); virtual void handlePresence( ... ); virtual void onConnect(); virtual bool onTLSConnect( const CertInfo& info ); }; void MyClass::doSomething() { JID jid( "jid@server/resource" ); Client *client = new Client( jid, "password" ); client->registerConnectionListener( this ); client->registerPresenceHandler( this ); client->connect(); } void MyClass::onConnect() { // connection established, auth done (see API docs for exceptions) } bool MyClass::onTLSConnect( const CertInfo& info ) { // examine certificate info } void MyClass::handlePresence( Stanza *stanza ) { // presence info }
Client::connect() by default blocks until the connection ends (either Client::disconnect() is called or the server closes the connection).
In these cases non-blocking connections can be used. If ClientBase::connect( false ) is called, the function returnes immediately after the connection has been established. It is then the resposibility of the programmer to initiate receiving of data from the socket.
The easiest way is to call ClientBase::recv() periodically with the desired timeout (in microseconds) as parameter. The default value of -1 means the call blocks until any data was received, which is then parsed automatically.
As an alternative to periodic polling you can get a hold of the raw file descriptor used for the connection. You can then use select() on it and use ClientBase::recv() when select indicates that data is available. You should not recv() any data from the file descriptor directly as there is no way to feed that back into the parser.
To get the file descriptor you'll need to set a connection class (e.g. an instance of ConnectionTCPClient ) manually, like so:
Client* client = new Client( ... ); ConnectionTCPClient* conn = new ConnectionTCPClient( client, client->logInstance(), server, port ); client->setConnectionImpl( conn ); client->connect( false ); int sock = conn->socket(); [...]
It would also be possible to fetch the fd like this:
Client* client = new Client( ... ); client->connect( false ); int sock = dynamic_cast<ConnectionTCPClient*>( client->connectionImpl() )->socket(); [...]
If you create a Client object as shown above, you also get a RosterManager for free. Client::rosterManager() returns a pointer to the object.
PrivacyManager *p = new PrivacyManager( ... ); [...] PrivacyListHandler::PrivacyList list; PrivacyItem item( PrivacyItem::TypeJid, PrivacyItem::ActionDeny, PrivacyItem::PacketMessage, "me@there.com" ); list.push_back( item ); PrivacyItem item2( PrivacyItem::TypeJid, PrivacyItem::ActionAllow, PrivacyItem::PacketIq, "me@example.org" ); list.push_back( item2 ); p->store( "myList", list );
Additionally, there is an implementation of XEP-0047 (In-Band Bytestreams) which is currently not integrated into the signalling of XEPs 0095 and 0096. Therefore, this protocol is probably not suited for offering file transfer to end-users. See InBandBytestreamManager .