summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sleekxmpp/stanza/presence.py183
-rw-r--r--tests/test_presencestanzas.py96
2 files changed, 185 insertions, 94 deletions
diff --git a/sleekxmpp/stanza/presence.py b/sleekxmpp/stanza/presence.py
index ec681763..651bf34d 100644
--- a/sleekxmpp/stanza/presence.py
+++ b/sleekxmpp/stanza/presence.py
@@ -6,54 +6,141 @@
See the file LICENSE for copying permission.
"""
-from . error import Error
-from . rootstanza import RootStanza
-from .. xmlstream.stanzabase import StanzaBase, ET
+from sleekxmpp.stanza import Error
+from sleekxmpp.stanza.rootstanza import RootStanza
+from sleekxmpp.xmlstream.stanzabase import StanzaBase, ET
class Presence(RootStanza):
- interfaces = set(('type', 'to', 'from', 'id', 'show', 'status', 'priority'))
- types = set(('available', 'unavailable', 'error', 'probe', 'subscribe', 'subscribed', 'unsubscribe', 'unsubscribed'))
- showtypes = set(('dnd', 'chat', 'xa', 'away'))
- sub_interfaces = set(('show', 'status', 'priority'))
- name = 'presence'
- plugin_attrib = name
- namespace = 'jabber:client'
-
- def setShow(self, show):
- if show in self.showtypes:
- self._setSubText('show', text=show)
- return self
-
- def setType(self, value):
- if value in self.types:
- self['show'] = None
- if value == 'available':
- value = ''
- self._setAttr('type', value)
- elif value in self.showtypes:
- self['show'] = value
- return self
-
- def setPriority(self, value):
- self._setSubText('priority', text = str(value))
-
- def getPriority(self):
- p = self._getSubText('priority')
- if not p: p = 0
- return int(p)
-
- def getType(self):
- out = self._getAttr('type')
- if not out:
- out = self['show']
- if not out or out is None:
- out = 'available'
- return out
-
- def reply(self):
- if self['type'] == 'unsubscribe':
- self['type'] = 'unsubscribed'
- elif self['type'] == 'subscribe':
- self['type'] = 'subscribed'
- return StanzaBase.reply(self)
+
+ """
+ XMPP's <presence> stanza allows entities to know the status of other
+ clients and components. Since it is currently the only multi-cast
+ stanza in XMPP, many extensions add more information to <presence>
+ stanzas to broadcast to every entry in the roster, such as
+ capabilities, music choices, or locations (XEP-0115: Entity Capabilities
+ and XEP-0163: Personal Eventing Protocol).
+
+ Since <presence> stanzas are broadcast when an XMPP entity changes
+ its status, the bulk of the traffic in an XMPP network will be from
+ <presence> stanzas. Therefore, do not include more information than
+ necessary in a status message or within a <presence> stanza in order
+ to help keep the network running smoothly.
+
+ Example <presence> stanzas:
+ <presence />
+
+ <presence from="user@example.com">
+ <show>away</show>
+ <status>Getting lunch.</status>
+ <priority>5</priority>
+ </presence>
+
+ <presence type="unavailable" />
+
+ <presence to="user@otherhost.com" type="subscribe" />
+
+ Stanza Interface:
+ priority -- A value used by servers to determine message routing.
+ show -- The type of status, such as away or available for chat.
+ status -- Custom, human readable status message.
+
+ Attributes:
+ types -- One of: available, unavailable, error, probe,
+ subscribe, subscribed, unsubscribe,
+ and unsubscribed.
+ showtypes -- One of: away, chat, dnd, and xa.
+
+ Methods:
+ reply -- Overrides StanzaBase.reply
+ setShow -- Set the value of the <show> element.
+ getType -- Get the value of the type attribute or <show> element.
+ setType -- Set the value of the type attribute or <show> element.
+ getPriority -- Get the value of the <priority> element.
+ setPriority -- Set the value of the <priority> element.
+ """
+
+ namespace = 'jabber:client'
+ name = 'presence'
+ interfaces = set(('type', 'to', 'from', 'id', 'show',
+ 'status', 'priority'))
+ sub_interfaces = set(('show', 'status', 'priority'))
+ plugin_attrib = name
+
+ types = set(('available', 'unavailable', 'error', 'probe', 'subscribe',
+ 'subscribed', 'unsubscribe', 'unsubscribed'))
+ showtypes = set(('dnd', 'chat', 'xa', 'away'))
+
+ def setShow(self, show):
+ """
+ Set the value of the <show> element.
+
+ Arguments:
+ show -- Must be one of: away, chat, dnd, or xa.
+ """
+ if show in self.showtypes:
+ self._setSubText('show', text=show)
+ return self
+
+ def setType(self, value):
+ """
+ Set the type attribute's value, and the <show> element
+ if applicable.
+
+ Arguments:
+ value -- Must be in either self.types or self.showtypes.
+ """
+ if value in self.types:
+ self['show'] = None
+ if value == 'available':
+ value = ''
+ self._setAttr('type', value)
+ elif value in self.showtypes:
+ self['show'] = value
+ return self
+
+ def setPriority(self, value):
+ """
+ Set the entity's priority value. Some server use priority to
+ determine message routing behavior.
+
+ Bot clients should typically use a priority of 0 if the same
+ JID is used elsewhere by a human-interacting client.
+
+ Arguments:
+ value -- An integer value greater than or equal to 0.
+ """
+ self._setSubText('priority', text=str(value))
+
+ def getPriority(self):
+ """
+ Return the value of the <presence> element as an integer.
+ """
+ p = self._getSubText('priority')
+ if not p:
+ p = 0
+ return int(p)
+
+ def getType(self):
+ """
+ Return the value of the <presence> stanza's type attribute, or
+ the value of the <show> element.
+ """
+ out = self._getAttr('type')
+ if not out:
+ out = self['show']
+ if not out or out is None:
+ out = 'available'
+ return out
+
+ def reply(self):
+ """
+ Set the appropriate presence reply type.
+
+ Overrides StanzaBase.reply.
+ """
+ if self['type'] == 'unsubscribe':
+ self['type'] = 'unsubscribed'
+ elif self['type'] == 'subscribe':
+ self['type'] = 'subscribed'
+ return StanzaBase.reply(self)
diff --git a/tests/test_presencestanzas.py b/tests/test_presencestanzas.py
index 02799c8f..2cab3af7 100644
--- a/tests/test_presencestanzas.py
+++ b/tests/test_presencestanzas.py
@@ -2,52 +2,56 @@ import sleekxmpp
from sleektest import *
from sleekxmpp.stanza.presence import Presence
+
class TestPresenceStanzas(SleekTest):
-
- def testPresenceShowRegression(self):
- """Regression check presence['type'] = 'dnd' show value working"""
- p = self.Presence()
- p['type'] = 'dnd'
- self.checkPresence(p, """
- <presence><show>dnd</show></presence>
- """)
-
- def testPresenceType(self):
- """Test manipulating presence['type']"""
- p = self.Presence()
- p['type'] = 'available'
- self.checkPresence(p, """
- <presence />
- """)
- self.failUnless(p['type'] == 'available', "Incorrect presence['type'] for type 'available'")
-
- for showtype in ['away', 'chat', 'dnd', 'xa']:
- p['type'] = showtype
- self.checkPresence(p, """
- <presence><show>%s</show></presence>
- """ % showtype)
- self.failUnless(p['type'] == showtype, "Incorrect presence['type'] for type '%s'" % showtype)
-
- p['type'] = None
- self.checkPresence(p, """
- <presence />
- """)
-
- def testPresenceUnsolicitedOffline(self):
- """Unsolicted offline presence does not spawn changed_status or update roster"""
- p = self.Presence()
- p['type'] = 'unavailable'
- p['from'] = 'bill@chadmore.com/gmail15af'
-
- c = sleekxmpp.ClientXMPP('crap@wherever', 'password')
- happened = []
- def handlechangedpresence(event):
- happened.append(True)
- c.add_event_handler("changed_status", handlechangedpresence)
- c._handlePresence(p)
-
- self.failUnless(happened == [], "changed_status event triggered for superfulous unavailable presence")
- self.failUnless(c.roster == {}, "Roster updated for superfulous unavailable presence")
-
+
+ def testPresenceShowRegression(self):
+ """Regression check presence['type'] = 'dnd' show value working"""
+ p = self.Presence()
+ p['type'] = 'dnd'
+ self.checkPresence(p, "<presence><show>dnd</show></presence>")
+
+ def testPresenceType(self):
+ """Test manipulating presence['type']"""
+ p = self.Presence()
+ p['type'] = 'available'
+ self.checkPresence(p, "<presence />")
+ self.failUnless(p['type'] == 'available',
+ "Incorrect presence['type'] for type 'available'")
+
+ for showtype in ['away', 'chat', 'dnd', 'xa']:
+ p['type'] = showtype
+ self.checkPresence(p, """
+ <presence><show>%s</show></presence>
+ """ % showtype)
+ self.failUnless(p['type'] == showtype,
+ "Incorrect presence['type'] for type '%s'" % showtype)
+
+ p['type'] = None
+ self.checkPresence(p, "<presence />")
+
+ def testPresenceUnsolicitedOffline(self):
+ """
+ Unsolicted offline presence does not spawn changed_status
+ or update the roster.
+ """
+ p = self.Presence()
+ p['type'] = 'unavailable'
+ p['from'] = 'bill@chadmore.com/gmail15af'
+
+ c = sleekxmpp.ClientXMPP('crap@wherever', 'password')
+ happened = []
+
+ def handlechangedpresence(event):
+ happened.append(True)
+
+ c.add_event_handler("changed_status", handlechangedpresence)
+ c._handlePresence(p)
+
+ self.failUnless(happened == [],
+ "changed_status event triggered for extra unavailable presence")
+ self.failUnless(c.roster == {},
+ "Roster updated for superfulous unavailable presence")
+
suite = unittest.TestLoader().loadTestsFromTestCase(TestPresenceStanzas)