XMPP IM protocol support

Roster Management

A roster holds a collection of contacts for a user. Typically a user has one roster kept by the user’s server, but rosters may also be kept by other entities. Usually, a client requests a user’s roster right after authentication, and is then notified of any changes to the roster. A client may also modify the roster, on behalf of the user, by setting or removing roster items.

Requesting the roster

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import sys
from twisted.python import log
from twisted.internet import reactor
from twisted.words.protocols.jabber.jid import JID
from wokkel.client import XMPPClient
from wokkel.xmppim import RosterClientProtocol

class RosterHandler(RosterClientProtocol):
    def gotRoster(self, roster):
        print 'Got roster:'
        for entity, item in roster.iteritems():
            print '  %r (%r)' % (entity, item.name or '')

    def connectionInitialized(self):
        RosterClientProtocol.connectionInitialized(self)
        d = self.getRoster()
        d.addCallback(self.gotRoster)
        d.addErrback(log.err)

USER_JID, PASSWORD = sys.argv[1:3]
client = XMPPClient(JID(USER_JID), PASSWORD)
roster = RosterHandler()
roster.setHandlerParent(client)

client.startService()
reactor.run()

Receiving roster pushes

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import sys
from twisted.python import log
from twisted.internet import reactor
from twisted.words.protocols.jabber.jid import JID
from wokkel.client import XMPPClient
from wokkel.xmppim import RosterClientProtocol

class RosterHandler(RosterClientProtocol):
    def gotRoster(self, roster):
        print 'Got roster:'
        for entity, item in roster.iteritems():
            print '  %r (%r)' % (entity, item.name or '')

    def connectionInitialized(self):
        RosterClientProtocol.connectionInitialized(self)
        d = self.getRoster()
        d.addCallback(self.gotRoster)
        d.addErrback(log.err)

    def removeReceived(self, request):
        print 'Contact %r was removed.' % (request.item.entity,)

    def setReceived(self, request):
        print 'Contact %r (%r) was updated.' % (request.item.entity,
                                                request.item.name)

USER_JID, PASSWORD = sys.argv[1:3]
client = XMPPClient(JID(USER_JID), PASSWORD)
roster = RosterHandler()
roster.setHandlerParent(client)

client.startService()
reactor.run()

Set the name of a contact

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import sys
from twisted.internet import reactor
from twisted.words.protocols.jabber.jid import JID
from wokkel.client import XMPPClient
from wokkel.xmppim import RosterClientProtocol, RosterItem

USER_JID, PASSWORD, CONTACT_JID, NAME = sys.argv[1:5]
client = XMPPClient(JID(USER_JID), PASSWORD)
roster = RosterClientProtocol()
roster.setHandlerParent(client)

d = roster.setItem(RosterItem(JID(CONTACT_JID), name=NAME))
d.addBoth(lambda _: reactor.stop())

client.startService()
reactor.run()

Remove a contact

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import sys
from twisted.internet import reactor
from twisted.words.protocols.jabber.jid import JID
from wokkel.client import XMPPClient
from wokkel.xmppim import RosterClientProtocol

USER_JID, PASSWORD, CONTACT_JID = sys.argv[1:4]
client = XMPPClient(JID(USER_JID), PASSWORD)
roster = RosterClientProtocol()
roster.setHandlerParent(client)

d = roster.removeItem(JID(CONTACT_JID))
d.addBoth(lambda _: reactor.stop())

client.startService()
reactor.run()

Roster versioning

Some XMPP servers support roster versioning. A client can keep a cache of the roster by requesting it and applying changes as roster pushes come in. Each version of the roster is marked with a version identifier. This can be used to request the roster upon reconnect. The server can then choose to send the difference between the requested and current version as roster pushed, instead of returning the complete roster.

When no roster was cached by the client, yet, a client passes the empty string ('') to getRoster to bootstrap the process.

This example will force a reconnect 15 seconds after authentication.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import sys
from twisted.python import log
from twisted.internet import reactor
from twisted.words.protocols.jabber.jid import JID
from wokkel.client import XMPPClient
from wokkel.xmppim import RosterClientProtocol

class RosterHandler(RosterClientProtocol):
    roster = None

    def gotRoster(self, roster):
        if roster is None:
            print "The cached roster is up-to-date!"
            return

        print 'Got roster (%r):' % (roster.version,)
        self.roster = roster
        for entity, item in roster.iteritems():
            print '  %r (%r)' % (entity, item.name or '')

    def connectionInitialized(self):
        RosterClientProtocol.connectionInitialized(self)
        if self.roster is not None:
            version = self.roster.version
        else:
            version = ""
        d = self.getRoster(version)
        d.addCallback(self.gotRoster)
        d.addErrback(log.err)

        reactor.callLater(15, self.xmlstream.sendFooter)

    def removeReceived(self, request):
        print 'Contact %r was removed.' % (request.item.entity,)
        del self.roster[request.item.entity]
        self.roster.version = request.version

    def setReceived(self, request):
        print 'Contact %r (%r) was updated.' % (request.item.entity,
                                                request.item.name)
        self.roster[request.item.entity] = request.item
        self.roster.version = request.version

USER_JID, PASSWORD = sys.argv[1:3]
client = XMPPClient(JID(USER_JID), PASSWORD)
roster = RosterHandler()
roster.setHandlerParent(client)

client.startService()
reactor.run()

Table Of Contents

Previous topic

XMPP Clients

Next topic

Code Examples

This Page