pyxmpp.jabber.delay

Package pyxmpp :: Package jabber :: Module delay |
[hide private]

# Source Code for Module pyxmpp.jabber.delay

      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  """Delayed delivery mark (jabber:x:delay) handling.
     19
     20  Normative reference:
     21    - `JEP 91 <http://www.jabber.org/jeps/jep-0091.html>`__
     22  """
     23
     24  __revision__="$Id: delay.py 714 2010-04-05 10:20:10Z jajcus $"
     25  __docformat__="restructuredtext en"
     26
     27  import libxml2
     28  import time
     29  import datetime
     30
     31  from pyxmpp.jid import JID
     32
     33  from pyxmpp.utils import to_utf8,from_utf8
     34  from pyxmpp.xmlextra import get_node_ns_uri
     35  from pyxmpp.utils import datetime_utc_to_local,datetime_local_to_utc
     36  from pyxmpp.objects import StanzaPayloadObject
     37  from pyxmpp.exceptions import BadRequestProtocolError, JIDMalformedProtocolError, JIDError
     38
     39  DELAY_NS="jabber:x:delay"
     40
     41 -class Delay(StanzaPayloadObject):
     42      """
     43      Delayed delivery tag.
     44
     45      Represents 'jabber:x:delay' (JEP-0091) element of a Jabber stanza.
     46
     47      :Ivariables:
     48          - `delay_from`: the "from" value of the delay element
     49          - `reason`: the "reason" (content) of the delay element
     50          - `timestamp`: the UTC timestamp as naive datetime object
     51      """
     52
     53      xml_element_name = "x"
     54      xml_element_namespace = DELAY_NS
     55
     56 -    def __init__(self,node_or_datetime,delay_from=None,reason=None,utc=True):
     57          """
     58          Initialize the Delay object.
     59
     60          :Parameters:
     61              - `node_or_datetime`: an XML node to parse or the timestamp.
     62              - `delay_from`: JID of the entity which adds the delay mark
     63                (when `node_or_datetime` is a timestamp).
     64              - `reason`: reason of the delay (when `node_or_datetime` is a
     65                timestamp).
     66              - `utc`: if `True` then the timestamp is assumed to be UTC,
     67                otherwise it is assumed to be local time.
     68          :Types:
     69              - `node_or_datetime`: `libxml2.xmlNode` or `datetime.datetime`
     70              - `delay_from`: `pyxmpp.JID`
     71              - `reason`: `unicode`
     72              - `utc`: `bool`"""
     73          if isinstance(node_or_datetime,libxml2.xmlNode):
     74              self.from_xml(node_or_datetime)
     75          else:
     76              if utc:
     77                  self.timestamp=node_or_datetime
     78              else:
     79                  self.timestamp=datetime_local_to_utc(node_or_datetime)
     80              self.delay_from=JID(delay_from)
     81              self.reason=unicode(reason)
     82
     83 -    def from_xml(self,xmlnode):
     84          """Initialize Delay object from an XML node.
     85
     86          :Parameters:
     87              - `xmlnode`: the jabber:x:delay XML element.
     88          :Types:
     89              - `xmlnode`: `libxml2.xmlNode`"""
     90          if xmlnode.type!="element":
     91              raise ValueError,"XML node is not a jabber:x:delay element (not an element)"
     92          ns=get_node_ns_uri(xmlnode)
     93          if ns and ns!=DELAY_NS or xmlnode.name!="x":
     94              raise ValueError,"XML node is not a jabber:x:delay element"
     95          stamp=xmlnode.prop("stamp")
     96          if stamp.endswith("Z"):
     97              stamp=stamp[:-1]
     98          if "-" in stamp:
     99              stamp=stamp.split("-",1)[0]
    100          try:
    101              tm = time.strptime(stamp, "%Y%m%dT%H:%M:%S")
    102          except ValueError:
    103              raise BadRequestProtocolError, "Bad timestamp"
    104          tm=tm[0:8]+(0,)
    105          self.timestamp=datetime.datetime.fromtimestamp(time.mktime(tm))
    106          delay_from=from_utf8(xmlnode.prop("from"))
    107          if delay_from:
    108              try:
    109                  self.delay_from = JID(delay_from)
    110              except JIDError:
    111                  raise JIDMalformedProtocolError, "Bad JID in the jabber:x:delay 'from' attribute"
    112          else:
    113              self.delay_from = None
    114          self.reason = from_utf8(xmlnode.getContent())
    115
    116 -    def complete_xml_element(self, xmlnode, _unused):
    117          """Complete the XML node with `self` content.
    118
    119          Should be overriden in classes derived from `StanzaPayloadObject`.
    120
    121          :Parameters:
    122              - `xmlnode`: XML node with the element being built. It has already
    123                right name and namespace, but no attributes or content.
    124              - `_unused`: document to which the element belongs.
    125          :Types:
    126              - `xmlnode`: `libxml2.xmlNode`
    127              - `_unused`: `libxml2.xmlDoc`"""
    128          tm=self.timestamp.strftime("%Y%m%dT%H:%M:%S")
    129          xmlnode.setProp("stamp",tm)
    130          if self.delay_from:
    131              xmlnode.setProp("from",self.delay_from.as_utf8())
    132          if self.reason:
    133              xmlnode.setContent(to_utf8(self.reason))
    134
    135 -    def get_datetime_local(self):
    136          """Get the timestamp as a local time.
    137
    138          :return: the timestamp of the delay element represented in the local
    139            timezone.
    140          :returntype: `datetime.datetime`"""
    141          r=datetime_utc_to_local(self.timestamp)
    142          return r
    143
    144 -    def get_datetime_utc(self):
    145          """Get the timestamp as a UTC.
    146
    147          :return: the timestamp of the delay element represented in UTC.
    148          :returntype: `datetime.datetime`"""
    149          return self.timestamp
    150
    151 -    def __str__(self):
    152          n=self.as_xml()
    153          r=n.serialize()
    154          n.freeNode()
    155          return r
    156
    157 -    def __cmp__(self,other):
    158          return cmp(timestamp, other.timestamp)
    159
    160 -def get_delays(stanza):
    161      """Get jabber:x:delay elements from the stanza.
    162
    163      :Parameters:
    164          - `stanza`: a, probably delayed, stanza.
    165      :Types:
    166          - `stanza`: `pyxmpp.stanza.Stanza`
    167
    168      :return: list of delay tags sorted by the timestamp.
    169      :returntype: `list` of `Delay`"""
    170      delays=[]
    171      n=stanza.xmlnode.children
    172      while n:
    173          if n.type=="element" and get_node_ns_uri(n)==DELAY_NS and n.name=="x":
    174              delays.append(Delay(n))
    175          n=n.next
    176      delays.sort()
    177      return delays
    178
    179 -def get_delay(stanza):
    180      """Get the oldest jabber:x:delay elements from the stanza.
    181
    182      :Parameters:
    183          - `stanza`: a, probably delayed, stanza.
    184      :Types:
    185          - `stanza`: `pyxmpp.stanza.Stanza`
    186
    187      The return value, if not `None`, contains a quite reliable
    188      timestamp of a delayed (e.g. from offline storage) message.
    189
    190      :return: the oldest delay tag of the stanza or `None`.
    191      :returntype: `Delay`"""
    192      delays=get_delays(stanza)
    193      if not delays:
    194          return None
    195      return get_delays(stanza)[0]
    196
    197  # vi: sts=4 et sw=4
    198