1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 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 657 2006-09-01 21:08:06Z 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   
 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   
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   
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   
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   
156   
 159   
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   
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   
198