mirror of
https://github.com/correl/SleekXMPP.git
synced 2024-11-27 19:19:54 +00:00
Updated XEP-0202 plugin to new format and use XEP-0082.
This commit is contained in:
parent
c98f5d4450
commit
ec3a14e6d9
4 changed files with 227 additions and 117 deletions
|
@ -1,117 +0,0 @@
|
||||||
"""
|
|
||||||
SleekXMPP: The Sleek XMPP Library
|
|
||||||
Copyright (C) 2010 Nathanael C. Fritz
|
|
||||||
This file is part of SleekXMPP.
|
|
||||||
|
|
||||||
See the file LICENSE for copying permission.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from datetime import datetime, tzinfo
|
|
||||||
import logging
|
|
||||||
import time
|
|
||||||
|
|
||||||
from . import base
|
|
||||||
from .. stanza.iq import Iq
|
|
||||||
from .. xmlstream.handler.callback import Callback
|
|
||||||
from .. xmlstream.matcher.xpath import MatchXPath
|
|
||||||
from .. xmlstream import ElementBase, ET, JID, register_stanza_plugin
|
|
||||||
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
class EntityTime(ElementBase):
|
|
||||||
name = 'time'
|
|
||||||
namespace = 'urn:xmpp:time'
|
|
||||||
plugin_attrib = 'entity_time'
|
|
||||||
interfaces = set(('tzo', 'utc'))
|
|
||||||
sub_interfaces = set(('tzo', 'utc'))
|
|
||||||
|
|
||||||
#def get_tzo(self):
|
|
||||||
# TODO: Right now it returns a string but maybe it should
|
|
||||||
# return a datetime.tzinfo object or maybe a datetime.timedelta?
|
|
||||||
#pass
|
|
||||||
|
|
||||||
def set_tzo(self, tzo):
|
|
||||||
if isinstance(tzo, tzinfo):
|
|
||||||
td = datetime.now(tzo).utcoffset() # What if we are faking the time? datetime.now() shouldn't be used here'
|
|
||||||
seconds = td.seconds + td.days * 24 * 3600
|
|
||||||
sign = ('+' if seconds >= 0 else '-')
|
|
||||||
minutes = abs(seconds // 60)
|
|
||||||
tzo = '{sign}{hours:02d}:{minutes:02d}'.format(sign=sign, hours=minutes//60, minutes=minutes%60)
|
|
||||||
elif not isinstance(tzo, str):
|
|
||||||
raise TypeError('The time should be a string or a datetime.tzinfo object.')
|
|
||||||
self._set_sub_text('tzo', tzo)
|
|
||||||
|
|
||||||
def get_utc(self):
|
|
||||||
# Returns a datetime object instead the string. Is this a good idea?
|
|
||||||
value = self._get_sub_text('utc')
|
|
||||||
if '.' in value:
|
|
||||||
return datetime.strptime(value, '%Y-%m-%dT%H:%M:%S.%fZ')
|
|
||||||
else:
|
|
||||||
return datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
|
|
||||||
def set_utc(self, tim=None):
|
|
||||||
if isinstance(tim, datetime):
|
|
||||||
if tim.utcoffset():
|
|
||||||
tim = tim - tim.utcoffset()
|
|
||||||
tim = tim.strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
||||||
elif isinstance(tim, time.struct_time):
|
|
||||||
tim = time.strftime('%Y-%m-%dT%H:%M:%SZ', tim)
|
|
||||||
elif not isinstance(tim, str):
|
|
||||||
raise TypeError('The time should be a string or a datetime.datetime or time.struct_time object.')
|
|
||||||
|
|
||||||
self._set_sub_text('utc', tim)
|
|
||||||
|
|
||||||
|
|
||||||
class xep_0202(base.base_plugin):
|
|
||||||
"""
|
|
||||||
XEP-0202 Entity Time
|
|
||||||
"""
|
|
||||||
def plugin_init(self):
|
|
||||||
self.description = "Entity Time"
|
|
||||||
self.xep = "0202"
|
|
||||||
|
|
||||||
self.xmpp.registerHandler(
|
|
||||||
Callback('Time Request',
|
|
||||||
MatchXPath('{%s}iq/{%s}time' % (self.xmpp.default_ns,
|
|
||||||
EntityTime.namespace)),
|
|
||||||
self.handle_entity_time_query))
|
|
||||||
register_stanza_plugin(Iq, EntityTime)
|
|
||||||
|
|
||||||
self.xmpp.add_event_handler('entity_time_request', self.handle_entity_time)
|
|
||||||
|
|
||||||
|
|
||||||
def post_init(self):
|
|
||||||
base.base_plugin.post_init(self)
|
|
||||||
|
|
||||||
self.xmpp.plugin['xep_0030'].add_feature('urn:xmpp:time')
|
|
||||||
|
|
||||||
def handle_entity_time_query(self, iq):
|
|
||||||
if iq['type'] == 'get':
|
|
||||||
log.debug("Entity time requested by %s" % iq['from'])
|
|
||||||
self.xmpp.event('entity_time_request', iq)
|
|
||||||
elif iq['type'] == 'result':
|
|
||||||
log.debug("Entity time result from %s" % iq['from'])
|
|
||||||
self.xmpp.event('entity_time', iq)
|
|
||||||
|
|
||||||
def handle_entity_time(self, iq):
|
|
||||||
iq = iq.reply()
|
|
||||||
iq.enable('entity_time')
|
|
||||||
tzo = time.strftime('%z') # %z is not on all ANSI C libraries
|
|
||||||
tzo = tzo[:3] + ':' + tzo[3:]
|
|
||||||
iq['entity_time']['tzo'] = tzo
|
|
||||||
iq['entity_time']['utc'] = datetime.utcnow()
|
|
||||||
iq.send()
|
|
||||||
|
|
||||||
def get_entity_time(self, jid):
|
|
||||||
iq = self.xmpp.makeIqGet()
|
|
||||||
iq.enable('entity_time')
|
|
||||||
iq.attrib['to'] = jid
|
|
||||||
iq.attrib['from'] = self.xmpp.boundjid.full
|
|
||||||
id = iq.get('id')
|
|
||||||
result = iq.send()
|
|
||||||
if result and result is not None and result.get('type', 'error') != 'error':
|
|
||||||
return {'utc': result['entity_time']['utc'], 'tzo': result['entity_time']['tzo']}
|
|
||||||
else:
|
|
||||||
return False
|
|
11
sleekxmpp/plugins/xep_0202/__init__.py
Normal file
11
sleekxmpp/plugins/xep_0202/__init__.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2011 Nathanael C. Fritz, Lance J.T. Stout
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from sleekxmpp.plugins.xep_0202 import stanza
|
||||||
|
from sleekxmpp.plugins.xep_0202.stanza import EntityTime
|
||||||
|
from sleekxmpp.plugins.xep_0202.time import xep_0202
|
126
sleekxmpp/plugins/xep_0202/stanza.py
Normal file
126
sleekxmpp/plugins/xep_0202/stanza.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime as dt
|
||||||
|
from dateutil.tz import tzoffset, tzutc
|
||||||
|
|
||||||
|
from sleekxmpp.xmlstream import ElementBase
|
||||||
|
from sleekxmpp.plugins import xep_0082
|
||||||
|
|
||||||
|
|
||||||
|
class EntityTime(ElementBase):
|
||||||
|
|
||||||
|
"""
|
||||||
|
The <time> element represents the local time for an XMPP agent.
|
||||||
|
The time is expressed in UTC to make synchronization easier
|
||||||
|
between entities, but the offset for the local timezone is also
|
||||||
|
included.
|
||||||
|
|
||||||
|
Example <time> stanzas:
|
||||||
|
<iq type="result">
|
||||||
|
<time xmlns="urn:xmpp:time">
|
||||||
|
<utc>2011-07-03T11:37:12.234569</utc>
|
||||||
|
<tzo>-07:00</tzo>
|
||||||
|
</time>
|
||||||
|
</iq>
|
||||||
|
|
||||||
|
Stanza Interface:
|
||||||
|
time -- The local time for the entity (updates utc and tzo).
|
||||||
|
utc -- The UTC equivalent to local time.
|
||||||
|
tzo -- The local timezone offset from UTC.
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
get_time -- Return local time datetime object.
|
||||||
|
set_time -- Set UTC and TZO fields.
|
||||||
|
del_time -- Remove both UTC and TZO fields.
|
||||||
|
get_utc -- Return datetime object of UTC time.
|
||||||
|
set_utc -- Set the UTC time.
|
||||||
|
get_tzo -- Return tzinfo object.
|
||||||
|
set_tzo -- Set the local timezone offset.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name = 'time'
|
||||||
|
namespace = 'urn:xmpp:time'
|
||||||
|
plugin_attrib = 'entity_time'
|
||||||
|
interfaces = set(('tzo', 'utc', 'time'))
|
||||||
|
sub_interfaces = interfaces
|
||||||
|
|
||||||
|
def set_time(self, value):
|
||||||
|
"""
|
||||||
|
Set both the UTC and TZO fields given a time object.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value -- A datetime object or properly formatted
|
||||||
|
string equivalent.
|
||||||
|
"""
|
||||||
|
date = value
|
||||||
|
if not isinstance(value, dt.datetime):
|
||||||
|
date = xep_0082.parse(value)
|
||||||
|
self['utc'] = date
|
||||||
|
self['tzo'] = date.tzinfo
|
||||||
|
|
||||||
|
def get_time(self):
|
||||||
|
"""
|
||||||
|
Return the entity's local time based on the UTC and TZO data.
|
||||||
|
"""
|
||||||
|
date = self['utc']
|
||||||
|
tz = self['tzo']
|
||||||
|
return date.astimezone(tz)
|
||||||
|
|
||||||
|
def del_time(self):
|
||||||
|
"""Remove both the UTC and TZO fields."""
|
||||||
|
del self['utc']
|
||||||
|
del self['tzo']
|
||||||
|
|
||||||
|
def get_tzo(self):
|
||||||
|
"""
|
||||||
|
Return the timezone offset from UTC as a tzinfo object.
|
||||||
|
"""
|
||||||
|
tzo = self._get_sub_text('tzo')
|
||||||
|
if tzo == '':
|
||||||
|
tzo = 'Z'
|
||||||
|
time = xep_0082.parse('00:00:00%s' % tzo)
|
||||||
|
return time.tzinfo
|
||||||
|
|
||||||
|
def set_tzo(self, value):
|
||||||
|
"""
|
||||||
|
Set the timezone offset from UTC.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value -- Either a tzinfo object or the number of
|
||||||
|
seconds (positive or negative) to offset.
|
||||||
|
"""
|
||||||
|
time = xep_0082.time(offset=value)
|
||||||
|
if xep_0082.parse(time).tzinfo == tzutc():
|
||||||
|
self._set_sub_text('tzo', 'Z')
|
||||||
|
else:
|
||||||
|
self._set_sub_text('tzo', time[-6:])
|
||||||
|
|
||||||
|
def get_utc(self):
|
||||||
|
"""
|
||||||
|
Return the time in UTC as a datetime object.
|
||||||
|
"""
|
||||||
|
value = self._get_sub_text('utc')
|
||||||
|
if value == '':
|
||||||
|
return xep_0082.parse(xep_0082.datetime())
|
||||||
|
return xep_0082.parse('%sZ' % value)
|
||||||
|
|
||||||
|
def set_utc(self, value):
|
||||||
|
"""
|
||||||
|
Set the time in UTC.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
value -- A datetime object or properly formatted
|
||||||
|
string equivalent.
|
||||||
|
"""
|
||||||
|
date = value
|
||||||
|
if not isinstance(value, dt.datetime):
|
||||||
|
date = xep_0082.parse(value)
|
||||||
|
date = date.astimezone(tzutc())
|
||||||
|
value = xep_0082.format_datetime(date)[:-1]
|
||||||
|
self._set_sub_text('utc', value)
|
90
sleekxmpp/plugins/xep_0202/time.py
Normal file
90
sleekxmpp/plugins/xep_0202/time.py
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
"""
|
||||||
|
SleekXMPP: The Sleek XMPP Library
|
||||||
|
Copyright (C) 2010 Nathanael C. Fritz
|
||||||
|
This file is part of SleekXMPP.
|
||||||
|
|
||||||
|
See the file LICENSE for copying permission.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sleekxmpp.stanza.iq import Iq
|
||||||
|
from sleekxmpp.xmlstream import register_stanza_plugin
|
||||||
|
from sleekxmpp.xmlstream.handler import Callback
|
||||||
|
from sleekxmpp.xmlstream.matcher import StanzaPath
|
||||||
|
from sleekxmpp.plugins.base import base_plugin
|
||||||
|
from sleekxmpp.plugins import xep_0082
|
||||||
|
from sleekxmpp.plugins.xep_0202 import stanza
|
||||||
|
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class xep_0202(base_plugin):
|
||||||
|
|
||||||
|
"""
|
||||||
|
XEP-0202: Entity Time
|
||||||
|
"""
|
||||||
|
|
||||||
|
def plugin_init(self):
|
||||||
|
"""Start the XEP-0203 plugin."""
|
||||||
|
self.xep = '0202'
|
||||||
|
self.description = 'Entity Time'
|
||||||
|
self.stanza = stanza
|
||||||
|
|
||||||
|
# As a default, respond to time requests with the
|
||||||
|
# local time returned by XEP-0082. However, a
|
||||||
|
# custom function can be supplied which accepts
|
||||||
|
# the JID of the entity to query for the time.
|
||||||
|
self.local_time = self.config.get('local_time', None)
|
||||||
|
if not self.local_time:
|
||||||
|
self.local_time = lambda x: xep_0082.datetime()
|
||||||
|
|
||||||
|
self.xmpp.registerHandler(
|
||||||
|
Callback('Entity Time',
|
||||||
|
StanzaPath('iq/entity_time'),
|
||||||
|
self._handle_time_request))
|
||||||
|
register_stanza_plugin(Iq, stanza.EntityTime)
|
||||||
|
|
||||||
|
def post_init(self):
|
||||||
|
"""Handle cross-plugin interactions."""
|
||||||
|
base_plugin.post_init(self)
|
||||||
|
self.xmpp['xep_0030'].add_feature('urn:xmpp:time')
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_time_request(self, iq):
|
||||||
|
"""
|
||||||
|
Respond to a request for the local time.
|
||||||
|
|
||||||
|
The time is taken from self.local_time(), which may be replaced
|
||||||
|
during plugin configuration with a function that maps JIDs to
|
||||||
|
times.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
iq -- The Iq time request stanza.
|
||||||
|
"""
|
||||||
|
iq.reply()
|
||||||
|
iq['entity_time']['time'] = self.local_time(iq['to'])
|
||||||
|
iq.send()
|
||||||
|
|
||||||
|
def get_entity_time(self, to, ifrom=None, **iqargs):
|
||||||
|
"""
|
||||||
|
Request the time from another entity.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
to -- JID of the entity to query.
|
||||||
|
ifrom -- Specifiy the sender's JID.
|
||||||
|
block -- If true, block and wait for the stanzas' reply.
|
||||||
|
timeout -- The time in seconds to block while waiting for
|
||||||
|
a reply. If None, then wait indefinitely.
|
||||||
|
callback -- Optional callback to execute when a reply is
|
||||||
|
received instead of blocking and waiting for
|
||||||
|
the reply.
|
||||||
|
"""
|
||||||
|
iq = self.xmpp.Iq()
|
||||||
|
iq['type'] = 'get'
|
||||||
|
iq['to'] = 'to'
|
||||||
|
if ifrom:
|
||||||
|
iq['from'] = 'ifrom'
|
||||||
|
iq.enable('entity_time')
|
||||||
|
return iq.send(**iqargs)
|
Loading…
Reference in a new issue