Package pyxmpp :: Module presence |
[hide private]

# Source Code for Module pyxmpp.presence

      1  #
      2  # (C) Copyright 2003-2010 Jacek Konieczny <jajcus@jajcus.net>
      3  #
      4  # This program is free software; you can redistribute it and/or modify
      5  # it under the terms of the GNU Lesser General Public License Version
      6  # 2.1 as published by the Free Software Foundation.
      7  #
      8  # This program is distributed in the hope that it will be useful,
      9  # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11  # GNU Lesser General Public License for more details.
     12  #
     13  # You should have received a copy of the GNU Lesser General Public
     14  # License along with this program; if not, write to the Free Software
     15  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     16  #
     17
     18  """Presence XMPP stanza handling
     19
     20  Normative reference:
     21    - `RFC 3920 <http://www.ietf.org/rfc/rfc3920.txt>`__
     22  """
     23
     24  __docformat__="restructuredtext en"
     25
     26  import libxml2
     27
     28  from pyxmpp.utils import to_utf8,from_utf8
     29  from pyxmpp.stanza import Stanza
     30  from pyxmpp.xmlextra import common_ns
     31
     32  presence_types=("available","unavailable","probe","subscribe","unsubscribe","subscribed",
     33          "unsubscribed","invisible","error")
     34
     35  accept_responses={
     36          "subscribe": "subscribed",
     37          "subscribed": "subscribe",
     38          "unsubscribe": "unsubscribed",
     39          "unsubscribed": "unsubscribe",
     40          }
     41
     42  deny_responses={
     43          "subscribe": "unsubscribed",
     44          "subscribed": "unsubscribe",
     45          "unsubscribe": "subscribed",
     46          "unsubscribed": "subscribe",
     47          }
     48
     49 -class Presence(Stanza):
     50      """Wraper object for <presence /> stanzas."""
     51      stanza_type="presence"
     52 -    def __init__(self, xmlnode = None, from_jid = None, to_jid = None, stanza_type = None,
     53              stanza_id = None, show = None, status = None, priority = 0,
     54              error = None, error_cond = None, stream = None):
     55          """Initialize a `Presence` object.
     56
     57          :Parameters:
     58              - `xmlnode`: XML node to_jid be wrapped into the `Presence` object
     59                or other Presence object to be copied. If not given then new
     60                presence stanza is created using following parameters.
     61              - `from_jid`: sender JID.
     62              - `to_jid`: recipient JID.
     63              - `stanza_type`: staza type: one of: None, "available", "unavailable",
     64                "subscribe", "subscribed", "unsubscribe", "unsubscribed" or
     65                "error". "available" is automaticaly changed to_jid None.
     66              - `stanza_id`: stanza id -- value of stanza's "id" attribute
     67              - `show`: "show" field of presence stanza. One of: None, "away",
     68                "xa", "dnd", "chat".
     69              - `status`: descriptive text for the presence stanza.
     70              - `priority`: presence priority.
     71              - `error_cond`: error condition name. Ignored if `stanza_type` is not "error"
     72          :Types:
     73              - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
     74              - `from_jid`: `JID`
     75              - `to_jid`: `JID`
     76              - `stanza_type`: `unicode`
     77              - `stanza_id`: `unicode`
     78              - `show`: `unicode`
     79              - `status`: `unicode`
     80              - `priority`: `unicode`
     81              - `error_cond`: `unicode`"""
     82          self.xmlnode=None
     83          if isinstance(xmlnode,Presence):
     84              pass
     85          elif isinstance(xmlnode,Stanza):
     86              raise TypeError,"Couldn't make Presence from other Stanza"
     87          elif isinstance(xmlnode,libxml2.xmlNode):
     88              pass
     89          elif xmlnode is not None:
     90              raise TypeError,"Couldn't make Presence from %r" % (type(xmlnode),)
     91
     92          if stanza_type and stanza_type not in presence_types:
     93              raise ValueError, "Invalid presence type: %r" % (type,)
     94
     95          if stanza_type=="available":
     96              stanza_type=None
     97
     98          if xmlnode is None:
     99              xmlnode="presence"
    100
    101          Stanza.__init__(self, xmlnode, from_jid = from_jid, to_jid = to_jid, stanza_type = stanza_type,
    102                  stanza_id = stanza_id, error = error, error_cond = error_cond, stream = stream)
    103
    104          if show:
    105              self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
    106          if status:
    107              self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
    108          if priority and priority!=0:
    109              self.xmlnode.newTextChild(common_ns,"priority",to_utf8(unicode(priority)))
    110
    111 -    def copy(self):
    112          """Create a deep copy of the presence stanza.
    113
    114          :returntype: `Presence`"""
    115          return Presence(self)
    116
    117 -    def set_status(self,status):
    118          """Change presence status description.
    119
    120          :Parameters:
    121              - `status`: descriptive text for the presence stanza.
    122          :Types:
    123              - `status`: `unicode`"""
    124          n=self.xpath_eval("ns:status")
    125          if not status:
    126              if n:
    127                  n[0].unlinkNode()
    128                  n[0].freeNode()
    129              else:
    130                  return
    131          if n:
    132              n[0].setContent(to_utf8(status))
    133          else:
    134              self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
    135
    136 -    def get_status(self):
    137          """Get presence status description.
    138
    139          :return: value of stanza's <status/> field.
    140          :returntype: `unicode`"""
    141          n=self.xpath_eval("ns:status")
    142          if n:
    143              return from_utf8(n[0].getContent())
    144          else:
    145              return None
    146
    147 -    def get_show(self):
    148          """Get presence "show" field.
    149
    150          :return: value of stanza's <show/> field.
    151          :returntype: `unicode`"""
    152          n=self.xpath_eval("ns:show")
    153          if n:
    154              return from_utf8(n[0].getContent())
    155          else:
    156              return None
    157
    158 -    def set_show(self,show):
    159          """Change presence "show" field.
    160
    161          :Parameters:
    162              - `show`: new value for the "show" field of presence stanza. One
    163                of: None, "away", "xa", "dnd", "chat".
    164          :Types:
    165              - `show`: `unicode`"""
    166          n=self.xpath_eval("ns:show")
    167          if not show:
    168              if n:
    169                  n[0].unlinkNode()
    170                  n[0].freeNode()
    171              else:
    172                  return
    173          if n:
    174              n[0].setContent(to_utf8(show))
    175          else:
    176              self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
    177
    178 -    def get_priority(self):
    179          """Get presence priority.
    180
    181          :return: value of stanza's priority. 0 if the stanza doesn't contain
    182              <priority/> element.
    183          :returntype: `int`"""
    184          n=self.xpath_eval("ns:priority")
    185          if not n:
    186              return 0
    187          try:
    188              prio=int(n[0].getContent())
    189          except ValueError:
    190              return 0
    191          return prio
    192
    193 -    def set_priority(self,priority):
    194          """Change presence priority.
    195
    196          :Parameters:
    197              - `priority`: new presence priority.
    198          :Types:
    199              - `priority`: `int`"""
    200          n=self.xpath_eval("ns:priority")
    201          if not priority:
    202              if n:
    203                  n[0].unlinkNode()
    204                  n[0].freeNode()
    205              else:
    206                  return
    207          priority=int(priority)
    208          if priority<-128 or priority>127:
    209              raise ValueError, "Bad priority value"
    210          priority=str(priority)
    211          if n:
    212              n[0].setContent(priority)
    213          else:
    214              self.xmlnode.newTextChild(common_ns,"priority",priority)
    215
    216 -    def make_accept_response(self):
    217          """Create "accept" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
    218          presence stanza.
    219
    220          :return: new stanza.
    221          :returntype: `Presence`"""
    222
    223          if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
    224              raise ValueError, ("Results may only be generated for 'subscribe',"
    225                  "'subscribed','unsubscribe' or 'unsubscribed' presence")
    226
    227          pr=Presence(stanza_type=accept_responses[self.get_type()],
    228              from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
    229          return pr
    230
    231 -    def make_deny_response(self):
    232          """Create "deny" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
    233          presence stanza.
    234
    235          :return: new presence stanza.
    236          :returntype: `Presence`"""
    237          if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
    238              raise ValueError, ("Results may only be generated for 'subscribe',"
    239                  "'subscribed','unsubscribe' or 'unsubscribed' presence")
    240
    241          pr=Presence(stanza_type=deny_responses[self.get_type()],
    242              from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
    243          return pr
    244
    245 -    def make_error_response(self,cond):
    246          """Create error response for the any non-error presence stanza.
    247
    248          :Parameters:
    249              - `cond`: error condition name, as defined in XMPP specification.
    250          :Types:
    251              - `cond`: `unicode`
    252
    253          :return: new presence stanza.
    254          :returntype: `Presence`"""
    255
    256          if self.get_type() == "error":
    257              raise ValueError, "Errors may not be generated in response to errors"
    258
    259          p=Presence(stanza_type="error",from_jid=self.get_to(),to_jid=self.get_from(),
    260              stanza_id=self.get_id(),error_cond=cond)
    261
    262          if self.xmlnode.children:
    263              n=self.xmlnode.children
    264              while n:
    265                  p.xmlnode.children.addPrevSibling(n.copyNode(1))
    266                  n=n.next
    267          return p
    268
    269  # vi: sts=4 et sw=4
    270