-
Notifications
You must be signed in to change notification settings - Fork 299
Stanzas: Presence
Creating and sending presence stanzas can be done in four ways:
* xmpp.Presence()
* xmpp.makePresence()
* xmpp.sendPresence()
* xmpp.sendPresenceSubscription()
The first option is simply a plain presence stanza object. Any additional
information such as the from
attribute or status
element will need to be
added using the interfaces described below.
The makePresence
method accepts keyword parameters that match the stanza
object's interface, except that they are prefixed with a p
. For example,
to create a presence stanza from aclice@wonderland.lit
with a status of
"Curiouser and curiouser!"
and a show type of 'xa'
the following would
be used:
# Where xmpp is a SleekXMPP object
xmpp.makePresence(pfrom='alice@wonderland.lit',
pstatus='Curiouser and curiouser!',
pshow='xa')
The sendPresence
method accepts the same keyword arguments as
makePresence
and also queues the stanza to be sent to the XMPP server for
broadcasting.
Unlike sendPresence
, sendPresenceSubscription
does not mirror the
keyword parameters of makePresence
. Instead, only pfrom
, pto
,
ptype
, and pnick
are accepted. The pnick
option allows for adding an
optional nick
element to the presence in accordance with
XEP-0172
Adding or removing a subscription is typically a four-step process:
- Send a presence stanza with type
'subscribe'
or'unsubscribe'
- Receive a presence stanza of type
'subscribed'
or'unsubscribed'
- Receive a presence stanza of type
'subscribe'
or'unsubscribe'
- Send a presence stanza of type
'subscribed'
or'unsubscribed'
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.sendPresence
or xmpp.sendPresenceSubscription
. In both cases, the
ptype
keyword parameter must be set. If adding a nick
element to the
subscription request is desired, xmpp.sendPresenceSubscription
must be used.
# Where xmpp is a SleekXMPP object
xmpp.sendPresence(pto='user@example.com', ptype='subscribe')
# -or-
xmpp.sendPresenceSubscription(pto='user@example.com',
ptype='subscribe',
pnick='Sleek')
SleekXMPP already provides basic subscription management, but the automatic handling is to either accept or reject all subscription requests.
The value xmpp.auto_authorize
controls how the agent responds to a
'subscribe'
request. If True
, then a 'subscribed'
response will be
sent. If False
, then an 'unsubscribed'
response will be sent to decline
the subscription. Setting xmpp.auto_authorize
to None
will disable
automatic management.
The value xmpp.auto_subscribe
is used when xmpp.auto_authorize
is set to
True
. If xmpp.auto_subscribe
is True
then a 'subscribe'
request
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
To create custom subscription management, the events 'presence_subscribe'
,
'presence_subscribed'
, 'presence_unsubscribe'
, and
'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, but ComponentXMPP does not). 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 user1@component.example.com
and
user2@component.example.com
.
# 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 user1@component.example.com and user2@component.example.com.
def subscribe(self, presence):
# If the subscription request is rejected.
if not self.backend.allow_subscription(presence['from']):
self.sendPresence(pto=presence['from'],
ptype='unsubscribed')
return
# If the subscription request is accepted.
self.sendPresence(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.sendPresence(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.sendPresence(pto=presence['from'])
Presence probes (presence stanzas with a type of 'probe'
) are used to
discover the status of other XMPP agents. When a presence probe is received, a
presence stanza should be sent in reply that contains the agent's current state.
Some XMPP servers use presence probes to generate the initial burst of presence
stanzas to populate the roster when an agent connects.
Using presence probes can be done in two ways, either as a recipient or as a
sender of the probes. Receiving and handling a probe is done by listening for
the 'presence_probe'
event, as so:
# Where self is a SleekXMPP object:
# def __init__(self, ...):
# ...
# self.add_event_handler('presence_probe', self.handle_probe)
def handle_probe(self, presence):
sender = presence['from']
# Populate the presence reply with the agent's current status.
self.sendPresence(pto=sender, pstatus="Busy studying XMPP", pshow="dnd")
It is a good idea for server components to respond to presence probes since the main XMPP server will usually not respond on its behalf.
Sending a presence probe can be done at any time. It can be especially useful for XMPP components that require some form of registration before interacting with other agents. If a client already has the component in its roster, then the component can receive a presence stanza before registration takes place, and then not receive a presence stanza after registration. By sending a presence probe after a client registers, the server component can be sure to get a new presence update once registration is completed. Issuing a presence probe is done like so:
# Where xmpp is a SleekXMPP object
xmpp.sendPresence(pto='recipient@example.com', ptype='probe')
-
presence['from']
-
Standard stanza interface. The JID of the presence stanza's sender.
-
presence['id']
-
Standard stanza interface. An
'id'
value may be used to track and associate series of stanzas.
-
presence['priority']
-
A number greater than or equal to zero. Most XMPP servers will route messages to connections with the highest priority. Setting the priority to
'0'
is usually recommended for bots that will not interact directly with humans.
-
presence['status']
-
Free form, human readable text that describes the agent's status. For example,
"Ready for data"
, or"Executing job"
. The status text will usually be displayed in a client's roster.
-
presence['to']
-
Standard stanza interface. The JID of the presence stanza's recipient.
-
presence['type']
-
Be careful, this attribute does not correspond exactly with the XML of a presence stanza since. The values that may be used with
'type'
are:'available'
,'away'
,'chat'
,'dnd'
,'error'
,'probe'
,'subscribe'
,'subscribed'
,'unavailable'
,'unsubscribe'
,'unsubscribed'
, and'xa'
.Note: The
'type'
key maps to both thetype
attribute and theshow
element of a presence stanza.
-
presence.reply()
-
A standard stanza interface method. If the presence has a type of
'subscribe'
or'unsubscribe'
, the reply presence will have a type of'subscribed'
or'unsubscribed'
, respectively.
The XEP-0045 plugin adds
support for the <x xmlns="http://jabber.org/protocol/muc#user" />
element as part of presence stanzas. Not every possible subelement of <x
xmlns="http://jabber.org/protocol/muc#user" />
is supported, but interfaces
for the <item />
element are provided.
-
presence['muc']['affiliation']
-
Provide the agent's affiliation with the chatroom. Possible values are:
'owner'
,'admin'
,'member'
,'outcast'
, or''
for no affiliation. Affiliations are persisted across visits to the chatroom and are useful for controlling who may enter the room.
-
presence['muc']['jid']
-
If the chatroom is not anonymous, or the agent has sufficient privileges, then the JID for other members in the chatroom may be found from their presence updates using
presence['muc']['jid']
.
-
presence['muc']['nick']
-
The nickname used by a participant in the chatroom. It is equivalent to
presence['from'].resource
.Note: It is not possible to change the agent's room nick by modifying
presence['muc']['nick']
. The nick must be set before joining the room.
-
presence['muc']['role']
-
The chatroom participant's role in the room. Possible values are:
'visitor'
,'participant'
,'moderator'
, or''
for no role. Roles are typically more temporary than affiliations and are used to control what room participants may do to manage the room's configuration and the roles of other participants.
-
presence['muc']['room']
-
The name of the chatroom. It is equivalent to
presence['from'].bare
.Note: It is not possible to change the room name by modifying
presence['muc']['room']
.