Package pyxmpp :: Module presence |
[hide private]

# Source Code for Module pyxmpp.presence

      1  #
      2  # (C) Copyright 2003-2004 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  __revision__="$Id: presence.py 671 2007-05-09 12:05:52Z jajcus $"
     25  __docformat__="restructuredtext en"
     26
     27  import libxml2
     28
     29  from pyxmpp.utils import to_utf8,from_utf8
     30  from pyxmpp.stanza import Stanza
     31  from pyxmpp.xmlextra import common_ns
     32
     33  presence_types=("available","unavailable","probe","subscribe","unsubscribe","subscribed",
     34          "unsubscribed","invisible","error")
     35
     36  accept_responses={
     37          "subscribe": "subscribed",
     38          "subscribed": "subscribe",
     39          "unsubscribe": "unsubscribed",
     40          "unsubscribed": "unsubscribe",
     41          }
     42
     43  deny_responses={
     44          "subscribe": "unsubscribed",
     45          "subscribed": "unsubscribe",
     46          "unsubscribe": "subscribed",
     47          "unsubscribed": "subscribe",
     48          }
     49
     50 -class Presence(Stanza):
     51      """Wraper object for <presence /> stanzas."""
     52      stanza_type="presence"
     53 -    def __init__(self, xmlnode = None, from_jid = None, to_jid = None, stanza_type = None,
     54              stanza_id = None, show = None, status = None, priority = 0,
     55              error = None, error_cond = None, stream = None):
     56          """Initialize a `Presence` object.
     57
     58          :Parameters:
     59              - `xmlnode`: XML node to_jid be wrapped into the `Presence` object
     60                or other Presence object to be copied. If not given then new
     61                presence stanza is created using following parameters.
     62              - `from_jid`: sender JID.
     63              - `to_jid`: recipient JID.
     64              - `stanza_type`: staza type: one of: None, "available", "unavailable",
     65                "subscribe", "subscribed", "unsubscribe", "unsubscribed" or
     66                "error". "available" is automaticaly changed to_jid None.
     67              - `stanza_id`: stanza id -- value of stanza's "id" attribute
     68              - `show`: "show" field of presence stanza. One of: None, "away",
     69                "xa", "dnd", "chat".
     70              - `status`: descriptive text for the presence stanza.
     71              - `priority`: presence priority.
     72              - `error_cond`: error condition name. Ignored if `stanza_type` is not "error"
     73          :Types:
     74              - `xmlnode`: `unicode` or `libxml2.xmlNode` or `Stanza`
     75              - `from_jid`: `JID`
     76              - `to_jid`: `JID`
     77              - `stanza_type`: `unicode`
     78              - `stanza_id`: `unicode`
     79              - `show`: `unicode`
     80              - `status`: `unicode`
     81              - `priority`: `unicode`
     82              - `error_cond`: `unicode`"""
     83          self.xmlnode=None
     84          if isinstance(xmlnode,Presence):
     85              pass
     86          elif isinstance(xmlnode,Stanza):
     87              raise TypeError,"Couldn't make Presence from other Stanza"
     88          elif isinstance(xmlnode,libxml2.xmlNode):
     89              pass
     90          elif xmlnode is not None:
     91              raise TypeError,"Couldn't make Presence from %r" % (type(xmlnode),)
     92
     93          if stanza_type and stanza_type not in presence_types:
     94              raise ValueError, "Invalid presence type: %r" % (type,)
     95
     96          if stanza_type=="available":
     97              stanza_type=None
     98
     99          if xmlnode is None:
    100              xmlnode="presence"
    101
    102          Stanza.__init__(self, xmlnode, from_jid = from_jid, to_jid = to_jid, stanza_type = stanza_type,
    103                  stanza_id = stanza_id, error = error, error_cond = error_cond, stream = stream)
    104
    105          if show:
    106              self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
    107          if status:
    108              self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
    109          if priority and priority!=0:
    110              self.xmlnode.newTextChild(common_ns,"priority",to_utf8(unicode(priority)))
    111
    112 -    def copy(self):
    113          """Create a deep copy of the presence stanza.
    114
    115          :returntype: `Presence`"""
    116          return Presence(self)
    117
    118 -    def set_status(self,status):
    119          """Change presence status description.
    120
    121          :Parameters:
    122              - `status`: descriptive text for the presence stanza.
    123          :Types:
    124              - `status`: `unicode`"""
    125          n=self.xpath_eval("ns:status")
    126          if not status:
    127              if n:
    128                  n[0].unlinkNode()
    129                  n[0].freeNode()
    130              else:
    131                  return
    132          if n:
    133              n[0].setContent(to_utf8(status))
    134          else:
    135              self.xmlnode.newTextChild(common_ns,"status",to_utf8(status))
    136
    137 -    def get_status(self):
    138          """Get presence status description.
    139
    140          :return: value of stanza's <status/> field.
    141          :returntype: `unicode`"""
    142          n=self.xpath_eval("ns:status")
    143          if n:
    144              return from_utf8(n[0].getContent())
    145          else:
    146              return None
    147
    148 -    def get_show(self):
    149          """Get presence "show" field.
    150
    151          :return: value of stanza's <show/> field.
    152          :returntype: `unicode`"""
    153          n=self.xpath_eval("ns:show")
    154          if n:
    155              return from_utf8(n[0].getContent())
    156          else:
    157              return None
    158
    159 -    def set_show(self,show):
    160          """Change presence "show" field.
    161
    162          :Parameters:
    163              - `show`: new value for the "show" field of presence stanza. One
    164                of: None, "away", "xa", "dnd", "chat".
    165          :Types:
    166              - `show`: `unicode`"""
    167          n=self.xpath_eval("ns:show")
    168          if not show:
    169              if n:
    170                  n[0].unlinkNode()
    171                  n[0].freeNode()
    172              else:
    173                  return
    174          if n:
    175              n[0].setContent(to_utf8(show))
    176          else:
    177              self.xmlnode.newTextChild(common_ns,"show",to_utf8(show))
    178
    179 -    def get_priority(self):
    180          """Get presence priority.
    181
    182          :return: value of stanza's priority. 0 if the stanza doesn't contain
    183              <priority/> element.
    184          :returntype: `int`"""
    185          n=self.xpath_eval("ns:priority")
    186          if not n:
    187              return 0
    188          try:
    189              prio=int(n[0].getContent())
    190          except ValueError:
    191              return 0
    192          return prio
    193
    194 -    def set_priority(self,priority):
    195          """Change presence priority.
    196
    197          :Parameters:
    198              - `priority`: new presence priority.
    199          :Types:
    200              - `priority`: `int`"""
    201          n=self.xpath_eval("ns:priority")
    202          if not priority:
    203              if n:
    204                  n[0].unlinkNode()
    205                  n[0].freeNode()
    206              else:
    207                  return
    208          priority=int(priority)
    209          if priority<-128 or priority>127:
    210              raise ValueError, "Bad priority value"
    211          priority=str(priority)
    212          if n:
    213              n[0].setContent(priority)
    214          else:
    215              self.xmlnode.newTextChild(common_ns,"priority",priority)
    216
    217 -    def make_accept_response(self):
    218          """Create "accept" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
    219          presence stanza.
    220
    221          :return: new stanza.
    222          :returntype: `Presence`"""
    223
    224          if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
    225              raise ValueError, ("Results may only be generated for 'subscribe',"
    226                  "'subscribed','unsubscribe' or 'unsubscribed' presence")
    227
    228          pr=Presence(stanza_type=accept_responses[self.get_type()],
    229              from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
    230          return pr
    231
    232 -    def make_deny_response(self):
    233          """Create "deny" response for the "subscribe"/"subscribed"/"unsubscribe"/"unsubscribed"
    234          presence stanza.
    235
    236          :return: new presence stanza.
    237          :returntype: `Presence`"""
    238          if self.get_type() not in ("subscribe","subscribed","unsubscribe","unsubscribed"):
    239              raise ValueError, ("Results may only be generated for 'subscribe',"
    240                  "'subscribed','unsubscribe' or 'unsubscribed' presence")
    241
    242          pr=Presence(stanza_type=deny_responses[self.get_type()],
    243              from_jid=self.get_to(),to_jid=self.get_from(),stanza_id=self.get_id())
    244          return pr
    245
    246 -    def make_error_response(self,cond):
    247          """Create error response for the any non-error presence stanza.
    248
    249          :Parameters:
    250              - `cond`: error condition name, as defined in XMPP specification.
    251          :Types:
    252              - `cond`: `unicode`
    253
    254          :return: new presence stanza.
    255          :returntype: `Presence`"""
    256
    257          if self.get_type() == "error":
    258              raise ValueError, "Errors may not be generated in response to errors"
    259
    260          p=Presence(stanza_type="error",from_jid=self.get_to(),to_jid=self.get_from(),
    261              stanza_id=self.get_id(),error_cond=cond)
    262
    263          if self.xmlnode.children:
    264              n=self.xmlnode.children
    265              while n:
    266                  p.xmlnode.children.addPrevSibling(n.copyNode(1))
    267                  n=n.next
    268          return p
    269
    270  # vi: sts=4 et sw=4
    271