Clone this wiki locally
In XMPP, the presence portion of the protocol is expressed through presence subscriptions between entities. The list of all of these subscriptions is called the roster, and you may think of it as a buddy list or contact list. Manually managing the roster is usually unnecessary since it is done by the server automatically when presence subscribe or unsubscribe requests are received and accepted. However, roster entries may be placed into groups or even removed. In those cases, manual management is needed.
Note: See Stanzas: Presence for more information on adding and removing subscriptions.
If you are using SleekXMPP Beta6.1 or below, see Roster Management Pre RC1.
SleekXMPP builds and maintains a local roster based on roster items pushed
by the XMPP server. For clients, getting an initial copy of the roster is done using
self is a ClientXMPP object),
and can then later be accessed with
Components may also have a roster, but it is up to the component to manage it, not the server. A component's
roster can be accessed with
self.roster. The difference for components is that the component may be
using multiple JIDs, each of which may have its own set of subscriptions. Thus
self.roster is a collection
of rosters for individual JIDs. For example,
self.roster[self.boundjid.bare] is the roster for the JID
that was used to connect to the server. Clients use the same implementation, and
just a shortcut to
The structure for an individual roster item (for
OWNER_JID's roster) is:
The alias assigned to the roster entry to make it easier to identify the owner of the JID. For example, the name of the person using the subscribed JID.
The subscription type defines the directions in which presence updates are broadcast. If the subscription type is
'to', then the SleekXMPP agent will receive presence updates from
user@serverwill not receive presence updates from the JID used by the SleekXMPP agent. The direction is reversed if the subscription type is
'from'. Only if the type is
'both'will presence updates be mutually exchanged. No presence updates are broadcast when the type is
'none'. An additional type,
'remove', is used for deleting a subscription and is described below.
Note: If you are using the roster for deciding on message broadcasting recipients, be sure to ignore entries with a subscription type of
A list of groups that
user@serverhas been placed into for ease of use and organization.
A dictionary of all of the connected resources associated with the given bare JID, keyed by the resource identifier. Each of these dictionaries will contain the keys
prioritywhich will contain the associated information from the last presence stanza received from the particular connection.
See the inline documentation for
sleekxmpp.roster for more information. You can also persist the
roster using an external database; see
sleekxmpp.roster.item for details. As an example, here
is a plugin for hooking the roster to Redis: [Redis Roster](https://github.com/legastero/SleekRedis/blob/master/redis_roster.py).
Updating an Entry
Updating a roster item can be done at any time, but is usually done after a subscription has been established.
# Where self is a ClientXMPP object self.update_roster('email@example.com', name='Romeo', groups=['Montagues'])
The subscription type can be set as well using the
parameter. Some servers will issue the appropriate presence stanzas needed
to obtain the requested subscription state, but that behavior should not be
Deleting an Entry
Even after modifying a subscription to have a type of
'none', the XMPP
server may still keep a record of it and include it in requests for the roster.
For clients that will be adding and removing subscriptions regularly and in
large numbers (such as a public bot), then removing obsolete entries is needed.
Updating a roster item to have a subscription type of
'remove' will instruct
the server to delete the entry from its data store and not include it in future
# Where self is a ClientXMPP object self.del_roster_item('firstname.lastname@example.org') # -or- self.update_roster('email@example.com', subscription='remove')
Adding or removing a subscription is typically a four-step process:
- Send a presence stanza with type
- Receive a presence stanza of type
- Receive a presence stanza of type
- Send a presence stanza of type
If your program will be accepting subscriptions instead of initiating them, reverse the send and receive steps above.
Sending and replying to a presence subscription can be done using
xmpp.send_presence_subscription. In both cases, the
ptype keyword parameter must be set. If adding a
nick element to the
subscription request is desired,
xmpp.send_presence_subscription must be used.
# Where xmpp is a SleekXMPP object xmpp.send_presence(firstname.lastname@example.org', ptype='subscribe') # -or- xmpp.send_presence_subscription(email@example.com', ptype='subscribe', pnick='Sleek')
Automatic Subscription Management
SleekXMPP already provides basic subscription management, but the automatic handling is to either accept or reject all subscription requests.
xmpp.auto_authorize controls how the agent responds to a
'subscribe' request. If
True, then a
'subscribed' response will be
False, then an
'unsubscribed' response will be sent to decline
the subscription. Setting
None will disable
NOTE: By default,
xmpp.auto_authorize is set to
xmpp.auto_subscribe is used when
xmpp.auto_authorize is set to
True then a
will be sent after accepting a subscription request.
- Accept and create bidirectional subscription requests:
xmpp.auto_authorize = True xmpp.auto_subscribe = True
- Accept only one-directional subscription requests:
xmpp.auto_authorize = True xmpp.auto_subscribe = False
- Decline all subscription requests:
xmpp.auto_authorize = False
- Use a custom subscription policy:
xmpp.auto_authorize = None
Custom Subscription Management
To create custom subscription management, the events
'presence_unsubscribed' must be listened for by event handlers.
Note: If your application will both send and receive subscription requests, you will need to keep a roster data structure that knows the status of all pending requests (the ClientXMPP implementation has such a roster object; the ComponentXMPP implementation does not unless you use the experimental roster branch). Otherwise, you can create an infinite loop of two bots subscribing to the other's presence. If you only test with a human-facing client, most client programs will detect that situation and stop the cycle without reporting an error to you.
As an example, here is a sample snippet for custom subscription handling.
However, note that if you are using a server component, it is a good idea
to also set the
pfrom parameter when sending presence subscriptions.
Doing so allows you to support different subscription states for different
JIDs for the component, such as
# Where self is a SleekXMPP object, and self.backend is some arbitrary # object that you create depending on the needs of your application. # self.add_event_handler('presence_subscribe', self.subscribe) # self.add_event_handler('presence_subscribed', self.subscribed) # The unsubscribe and unsubscribed handlers will be similar. # If a component is being used, be sure to set the pfrom parameter # when sending presences if you are using multiple JIDs for the component, # such as firstname.lastname@example.org and email@example.com. def subscribe(self, presence): # If the subscription request is rejected. if not self.backend.allow_subscription(presence['from']): self.send_presence(pto=presence['from'], ptype='unsubscribed') return # If the subscription request is accepted. self.send_presence(pto=presence['from'], ptype='subscribed') # Save the fact that a subscription has been accepted, somehow. Here # we use a backend object that has a roster. self.backend.roster.subscribe(presence['from']) # If a bi-directional subscription does not exist, create one. if not self.backend.roster.sub_from(presence['from']): self.send_presence(pto=presence['from'], ptype='subscribe') def subscribed(self, presence): # Store the new subscription state, somehow. Here we use a backend object. self.backend.roster.subscribed(presence['from']) # Send a new presence update to the subscriber. self.send_presence(pto=presence['from'])