Merge branch 'master' of https://lab.louiz.org/poezio/slixmpp
This commit is contained in:
commit
afedfa4b06
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# Slixmpp: The Slick XMPP Library
|
# Slixmpp: The Slick XMPP Library
|
||||||
# Copyright (C) 2010 Nathanael C. Fritz
|
# Copyright (C) 2010 Nathanael C. Fritz
|
||||||
# This file is part of Slixmpp.
|
# This file is part of Slixmpp.
|
||||||
@ -93,6 +92,7 @@ __all__ = [
|
|||||||
'xep_0335', # JSON Containers
|
'xep_0335', # JSON Containers
|
||||||
'xep_0352', # Client State Indication
|
'xep_0352', # Client State Indication
|
||||||
'xep_0353', # Jingle Message Initiation
|
'xep_0353', # Jingle Message Initiation
|
||||||
|
'xep_0356', # Privileged entity
|
||||||
'xep_0359', # Unique and Stable Stanza IDs
|
'xep_0359', # Unique and Stable Stanza IDs
|
||||||
'xep_0363', # HTTP File Upload
|
'xep_0363', # HTTP File Upload
|
||||||
'xep_0369', # MIX-CORE
|
'xep_0369', # MIX-CORE
|
||||||
|
@ -493,6 +493,8 @@ class XEP_0045(BasePlugin):
|
|||||||
"""
|
"""
|
||||||
if affiliation not in AFFILIATIONS:
|
if affiliation not in AFFILIATIONS:
|
||||||
raise ValueError('%s is not a valid affiliation' % affiliation)
|
raise ValueError('%s is not a valid affiliation' % affiliation)
|
||||||
|
if affiliation == 'outcast' and not jid:
|
||||||
|
raise ValueError('Outcast affiliation requires a using a jid')
|
||||||
if not any((jid, nick)):
|
if not any((jid, nick)):
|
||||||
raise ValueError('One of jid or nick must be set')
|
raise ValueError('One of jid or nick must be set')
|
||||||
iq = self.xmpp.make_iq_set(ito=room, ifrom=ifrom)
|
iq = self.xmpp.make_iq_set(ito=room, ifrom=ifrom)
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
|
||||||
from slixmpp.plugins import BasePlugin, register_plugin
|
from slixmpp.plugins import BasePlugin, register_plugin
|
||||||
from slixmpp.thirdparty import tzutc, tzoffset, parse_iso
|
|
||||||
|
|
||||||
|
|
||||||
# =====================================================================
|
# =====================================================================
|
||||||
@ -21,7 +20,10 @@ def parse(time_str):
|
|||||||
Arguments:
|
Arguments:
|
||||||
time_str -- A formatted timestamp string.
|
time_str -- A formatted timestamp string.
|
||||||
"""
|
"""
|
||||||
return parse_iso(time_str)
|
try:
|
||||||
|
return dt.datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S.%f%z')
|
||||||
|
except ValueError:
|
||||||
|
return dt.datetime.strptime(time_str, '%Y-%m-%dT%H:%M:%S%z')
|
||||||
|
|
||||||
|
|
||||||
def format_date(time_obj):
|
def format_date(time_obj):
|
||||||
@ -52,7 +54,7 @@ def format_time(time_obj):
|
|||||||
if isinstance(time_obj, dt.datetime):
|
if isinstance(time_obj, dt.datetime):
|
||||||
time_obj = time_obj.timetz()
|
time_obj = time_obj.timetz()
|
||||||
timestamp = time_obj.isoformat()
|
timestamp = time_obj.isoformat()
|
||||||
if time_obj.tzinfo == tzutc():
|
if time_obj.tzinfo == dt.timezone.utc:
|
||||||
timestamp = timestamp[:-6]
|
timestamp = timestamp[:-6]
|
||||||
return '%sZ' % timestamp
|
return '%sZ' % timestamp
|
||||||
return timestamp
|
return timestamp
|
||||||
@ -69,7 +71,7 @@ def format_datetime(time_obj):
|
|||||||
time_obj -- A datetime object.
|
time_obj -- A datetime object.
|
||||||
"""
|
"""
|
||||||
timestamp = time_obj.isoformat('T')
|
timestamp = time_obj.isoformat('T')
|
||||||
if time_obj.tzinfo == tzutc():
|
if time_obj.tzinfo == dt.timezone.utc:
|
||||||
timestamp = timestamp[:-6]
|
timestamp = timestamp[:-6]
|
||||||
return '%sZ' % timestamp
|
return '%sZ' % timestamp
|
||||||
return timestamp
|
return timestamp
|
||||||
@ -128,9 +130,9 @@ def time(hour=None, min=None, sec=None, micro=None, offset=None, obj=False):
|
|||||||
if micro is None:
|
if micro is None:
|
||||||
micro = now.microsecond
|
micro = now.microsecond
|
||||||
if offset in (None, 0):
|
if offset in (None, 0):
|
||||||
offset = tzutc()
|
offset = dt.timezone.utc
|
||||||
elif not isinstance(offset, dt.tzinfo):
|
elif not isinstance(offset, dt.tzinfo):
|
||||||
offset = tzoffset(None, offset)
|
offset = dt.timezone(dt.timedelta(seconds=offset))
|
||||||
value = dt.time(hour, min, sec, micro, offset)
|
value = dt.time(hour, min, sec, micro, offset)
|
||||||
if obj:
|
if obj:
|
||||||
return value
|
return value
|
||||||
@ -175,9 +177,9 @@ def datetime(year=None, month=None, day=None, hour=None,
|
|||||||
if micro is None:
|
if micro is None:
|
||||||
micro = now.microsecond
|
micro = now.microsecond
|
||||||
if offset in (None, 0):
|
if offset in (None, 0):
|
||||||
offset = tzutc()
|
offset = dt.timezone.utc
|
||||||
elif not isinstance(offset, dt.tzinfo):
|
elif not isinstance(offset, dt.tzinfo):
|
||||||
offset = tzoffset(None, offset)
|
offset = dt.timezone(dt.timedelta(seconds=offset))
|
||||||
|
|
||||||
value = dt.datetime(year, month, day, hour,
|
value = dt.datetime(year, month, day, hour,
|
||||||
min, sec, micro, offset)
|
min, sec, micro, offset)
|
||||||
|
@ -8,7 +8,6 @@ import datetime as dt
|
|||||||
|
|
||||||
from slixmpp.xmlstream import ElementBase
|
from slixmpp.xmlstream import ElementBase
|
||||||
from slixmpp.plugins import xep_0082
|
from slixmpp.plugins import xep_0082
|
||||||
from slixmpp.thirdparty import tzutc, tzoffset
|
|
||||||
|
|
||||||
|
|
||||||
class EntityTime(ElementBase):
|
class EntityTime(ElementBase):
|
||||||
@ -87,7 +86,7 @@ class EntityTime(ElementBase):
|
|||||||
seconds (positive or negative) to offset.
|
seconds (positive or negative) to offset.
|
||||||
"""
|
"""
|
||||||
time = xep_0082.time(offset=value)
|
time = xep_0082.time(offset=value)
|
||||||
if xep_0082.parse(time).tzinfo == tzutc():
|
if xep_0082.parse(time).tzinfo == dt.timezone.utc:
|
||||||
self._set_sub_text('tzo', 'Z')
|
self._set_sub_text('tzo', 'Z')
|
||||||
else:
|
else:
|
||||||
self._set_sub_text('tzo', time[-6:])
|
self._set_sub_text('tzo', time[-6:])
|
||||||
@ -111,6 +110,6 @@ class EntityTime(ElementBase):
|
|||||||
date = value
|
date = value
|
||||||
if not isinstance(value, dt.datetime):
|
if not isinstance(value, dt.datetime):
|
||||||
date = xep_0082.parse(value)
|
date = xep_0082.parse(value)
|
||||||
date = date.astimezone(tzutc())
|
date = date.astimezone(dt.timezone.utc)
|
||||||
value = xep_0082.format_datetime(date)
|
value = xep_0082.format_datetime(date)
|
||||||
self._set_sub_text('utc', value)
|
self._set_sub_text('utc', value)
|
||||||
|
@ -30,6 +30,10 @@ class Delay(ElementBase):
|
|||||||
|
|
||||||
def set_stamp(self, value):
|
def set_stamp(self, value):
|
||||||
if isinstance(value, dt.datetime):
|
if isinstance(value, dt.datetime):
|
||||||
|
if value.tzinfo is None:
|
||||||
|
raise ValueError(f'Datetime provided without timezone information: {value}')
|
||||||
|
if value.tzinfo != dt.timezone.utc:
|
||||||
|
value = value.astimezone(dt.timezone.utc)
|
||||||
value = xep_0082.format_datetime(value)
|
value = xep_0082.format_datetime(value)
|
||||||
self._set_attr('stamp', value)
|
self._set_attr('stamp', value)
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ from slixmpp.plugins.xep_0297 import Forwarded
|
|||||||
|
|
||||||
|
|
||||||
class Privilege(ElementBase):
|
class Privilege(ElementBase):
|
||||||
namespace = "urn:xmpp:privilege:1"
|
namespace = "urn:xmpp:privilege:2"
|
||||||
name = "privilege"
|
name = "privilege"
|
||||||
plugin_attrib = "privilege"
|
plugin_attrib = "privilege"
|
||||||
|
|
||||||
@ -25,6 +25,9 @@ class Privilege(ElementBase):
|
|||||||
def presence(self):
|
def presence(self):
|
||||||
return self.permission("presence")
|
return self.permission("presence")
|
||||||
|
|
||||||
|
def iq(self):
|
||||||
|
return self.permission("iq")
|
||||||
|
|
||||||
def add_perm(self, access, type):
|
def add_perm(self, access, type):
|
||||||
# This should only be needed for servers, so maybe out of scope for slixmpp
|
# This should only be needed for servers, so maybe out of scope for slixmpp
|
||||||
perm = Perm()
|
perm = Perm()
|
||||||
@ -34,7 +37,7 @@ class Privilege(ElementBase):
|
|||||||
|
|
||||||
|
|
||||||
class Perm(ElementBase):
|
class Perm(ElementBase):
|
||||||
namespace = "urn:xmpp:privilege:1"
|
namespace = "urn:xmpp:privilege:2"
|
||||||
name = "perm"
|
name = "perm"
|
||||||
plugin_attrib = "perm"
|
plugin_attrib = "perm"
|
||||||
plugin_multi_attrib = "perms"
|
plugin_multi_attrib = "perms"
|
||||||
|
1
slixmpp/thirdparty/__init__.py
vendored
1
slixmpp/thirdparty/__init__.py
vendored
@ -3,5 +3,4 @@ try:
|
|||||||
except:
|
except:
|
||||||
from slixmpp.thirdparty.gnupg import GPG
|
from slixmpp.thirdparty.gnupg import GPG
|
||||||
|
|
||||||
from slixmpp.thirdparty.mini_dateutil import tzutc, tzoffset, parse_iso
|
|
||||||
from slixmpp.thirdparty.orderedset import OrderedSet
|
from slixmpp.thirdparty.orderedset import OrderedSet
|
||||||
|
273
slixmpp/thirdparty/mini_dateutil.py
vendored
273
slixmpp/thirdparty/mini_dateutil.py
vendored
@ -1,273 +0,0 @@
|
|||||||
# This module is a very stripped down version of the dateutil
|
|
||||||
# package for when dateutil has not been installed. As a replacement
|
|
||||||
# for dateutil.parser.parse, the parsing methods from
|
|
||||||
# http://blog.mfabrik.com/2008/06/30/relativity-of-time-shortcomings-in-python-datetime-and-workaround/
|
|
||||||
|
|
||||||
#As such, the following copyrights and licenses applies:
|
|
||||||
|
|
||||||
|
|
||||||
# dateutil - Extensions to the standard python 2.3+ datetime module.
|
|
||||||
#
|
|
||||||
# Copyright (c) 2003-2011 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
|
||||||
#
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
#
|
|
||||||
# * Redistributions of source code must retain the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
# this list of conditions and the following disclaimer in the documentation
|
|
||||||
# and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of the copyright holder nor the names of its
|
|
||||||
# contributors may be used to endorse or promote products derived from
|
|
||||||
# this software without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
||||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
||||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
||||||
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
||||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
||||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
||||||
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
||||||
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
# fixed_dateime
|
|
||||||
#
|
|
||||||
# Copyright (c) 2008, Red Innovation Ltd., Finland
|
|
||||||
# All rights reserved.
|
|
||||||
#
|
|
||||||
# Redistribution and use in source and binary forms, with or without
|
|
||||||
# modification, are permitted provided that the following conditions are met:
|
|
||||||
# * Redistributions of source code must retain the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer.
|
|
||||||
# * Redistributions in binary form must reproduce the above copyright
|
|
||||||
# notice, this list of conditions and the following disclaimer in the
|
|
||||||
# documentation and/or other materials provided with the distribution.
|
|
||||||
# * Neither the name of Red Innovation nor the names of its contributors
|
|
||||||
# may be used to endorse or promote products derived from this software
|
|
||||||
# without specific prior written permission.
|
|
||||||
#
|
|
||||||
# THIS SOFTWARE IS PROVIDED BY RED INNOVATION ``AS IS'' AND ANY
|
|
||||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
# DISCLAIMED. IN NO EVENT SHALL RED INNOVATION BE LIABLE FOR ANY
|
|
||||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
||||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import re
|
|
||||||
import math
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
|
|
||||||
ZERO = datetime.timedelta(0)
|
|
||||||
|
|
||||||
|
|
||||||
try:
|
|
||||||
from dateutil.parser import parse as parse_iso
|
|
||||||
from dateutil.tz import tzoffset, tzutc
|
|
||||||
except:
|
|
||||||
# As a stopgap, define the two timezones here based
|
|
||||||
# on the dateutil code.
|
|
||||||
|
|
||||||
class tzutc(datetime.tzinfo):
|
|
||||||
|
|
||||||
def utcoffset(self, dt):
|
|
||||||
return ZERO
|
|
||||||
|
|
||||||
def dst(self, dt):
|
|
||||||
return ZERO
|
|
||||||
|
|
||||||
def tzname(self, dt):
|
|
||||||
return "UTC"
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return (isinstance(other, tzutc) or
|
|
||||||
(isinstance(other, tzoffset) and other._offset == ZERO))
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "%s()" % self.__class__.__name__
|
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
|
||||||
|
|
||||||
class tzoffset(datetime.tzinfo):
|
|
||||||
|
|
||||||
def __init__(self, name, offset):
|
|
||||||
self._name = name
|
|
||||||
self._offset = datetime.timedelta(minutes=offset)
|
|
||||||
|
|
||||||
def utcoffset(self, dt):
|
|
||||||
return self._offset
|
|
||||||
|
|
||||||
def dst(self, dt):
|
|
||||||
return ZERO
|
|
||||||
|
|
||||||
def tzname(self, dt):
|
|
||||||
return self._name
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
return (isinstance(other, tzoffset) and
|
|
||||||
self._offset == other._offset)
|
|
||||||
|
|
||||||
def __ne__(self, other):
|
|
||||||
return not self.__eq__(other)
|
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
return "%s(%s, %s)" % (self.__class__.__name__,
|
|
||||||
repr(self._name),
|
|
||||||
self._offset.days*86400+self._offset.seconds)
|
|
||||||
|
|
||||||
__reduce__ = object.__reduce__
|
|
||||||
|
|
||||||
|
|
||||||
_fixed_offset_tzs = { }
|
|
||||||
UTC = tzutc()
|
|
||||||
|
|
||||||
def _get_fixed_offset_tz(offsetmins):
|
|
||||||
"""For internal use only: Returns a tzinfo with
|
|
||||||
the given fixed offset. This creates only one instance
|
|
||||||
for each offset; the zones are kept in a dictionary"""
|
|
||||||
|
|
||||||
if offsetmins == 0:
|
|
||||||
return UTC
|
|
||||||
|
|
||||||
if not offsetmins in _fixed_offset_tzs:
|
|
||||||
if offsetmins < 0:
|
|
||||||
sign = '-'
|
|
||||||
absoff = -offsetmins
|
|
||||||
else:
|
|
||||||
sign = '+'
|
|
||||||
absoff = offsetmins
|
|
||||||
|
|
||||||
name = "UTC%s%02d:%02d" % (sign, int(absoff / 60), absoff % 60)
|
|
||||||
inst = tzoffset(name,offsetmins)
|
|
||||||
_fixed_offset_tzs[offsetmins] = inst
|
|
||||||
|
|
||||||
return _fixed_offset_tzs[offsetmins]
|
|
||||||
|
|
||||||
|
|
||||||
_iso8601_parser = re.compile(r"""
|
|
||||||
^
|
|
||||||
(?P<year> [0-9]{4})?(?P<ymdsep>-?)?
|
|
||||||
(?P<month>[0-9]{2})?(?P=ymdsep)?
|
|
||||||
(?P<day> [0-9]{2})?
|
|
||||||
|
|
||||||
(?P<time>
|
|
||||||
(?: # time part... optional... at least hour must be specified
|
|
||||||
(?:T|\s+)?
|
|
||||||
(?P<hour>[0-9]{2})
|
|
||||||
(?:
|
|
||||||
# minutes, separated with :, or none, from hours
|
|
||||||
(?P<hmssep>[:]?)
|
|
||||||
(?P<minute>[0-9]{2})
|
|
||||||
(?:
|
|
||||||
# same for seconds, separated with :, or none, from hours
|
|
||||||
(?P=hmssep)
|
|
||||||
(?P<second>[0-9]{2})
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
|
|
||||||
# fractions
|
|
||||||
(?: [,.] (?P<frac>[0-9]{1,10}))?
|
|
||||||
|
|
||||||
# timezone, Z, +-hh or +-hh:?mm. MUST BE, but complain if not there.
|
|
||||||
(
|
|
||||||
(?P<tzempty>Z)
|
|
||||||
|
|
|
||||||
(?P<tzh>[+-][0-9]{2})
|
|
||||||
(?: :? # optional separator
|
|
||||||
(?P<tzm>[0-9]{2})
|
|
||||||
)?
|
|
||||||
)?
|
|
||||||
)
|
|
||||||
)?
|
|
||||||
$
|
|
||||||
""", re.X) # """
|
|
||||||
|
|
||||||
def parse_iso(timestamp):
|
|
||||||
"""Internal function for parsing a timestamp in
|
|
||||||
ISO 8601 format"""
|
|
||||||
|
|
||||||
timestamp = timestamp.strip()
|
|
||||||
|
|
||||||
m = _iso8601_parser.match(timestamp)
|
|
||||||
if not m:
|
|
||||||
raise ValueError("Not a proper ISO 8601 timestamp!: %s" % timestamp)
|
|
||||||
|
|
||||||
vals = m.groupdict()
|
|
||||||
def_vals = {'year': 1970, 'month': 1, 'day': 1}
|
|
||||||
for key in vals:
|
|
||||||
if vals[key] is None:
|
|
||||||
vals[key] = def_vals.get(key, 0)
|
|
||||||
elif key not in ['time', 'ymdsep', 'hmssep', 'tzempty']:
|
|
||||||
vals[key] = int(vals[key])
|
|
||||||
|
|
||||||
year = vals['year']
|
|
||||||
month = vals['month']
|
|
||||||
day = vals['day']
|
|
||||||
|
|
||||||
if m.group('time') is None:
|
|
||||||
return datetime.date(year, month, day)
|
|
||||||
|
|
||||||
h, min, s, us = None, None, None, 0
|
|
||||||
frac = 0
|
|
||||||
if m.group('tzempty') == None and m.group('tzh') == None:
|
|
||||||
raise ValueError("Not a proper ISO 8601 timestamp: " +
|
|
||||||
"missing timezone (Z or +hh[:mm])!")
|
|
||||||
|
|
||||||
if m.group('frac'):
|
|
||||||
frac = m.group('frac')
|
|
||||||
power = len(frac)
|
|
||||||
frac = int(frac) / 10.0 ** power
|
|
||||||
|
|
||||||
if m.group('hour'):
|
|
||||||
h = vals['hour']
|
|
||||||
|
|
||||||
if m.group('minute'):
|
|
||||||
min = vals['minute']
|
|
||||||
|
|
||||||
if m.group('second'):
|
|
||||||
s = vals['second']
|
|
||||||
|
|
||||||
if frac != None:
|
|
||||||
# ok, fractions of hour?
|
|
||||||
if min == None:
|
|
||||||
frac, min = math.modf(frac * 60.0)
|
|
||||||
min = int(min)
|
|
||||||
|
|
||||||
# fractions of second?
|
|
||||||
if s == None:
|
|
||||||
frac, s = math.modf(frac * 60.0)
|
|
||||||
s = int(s)
|
|
||||||
|
|
||||||
# and extract microseconds...
|
|
||||||
us = int(frac * 1000000)
|
|
||||||
|
|
||||||
if m.group('tzempty') == 'Z':
|
|
||||||
offsetmins = 0
|
|
||||||
else:
|
|
||||||
# timezone: hour diff with sign
|
|
||||||
offsetmins = vals['tzh'] * 60
|
|
||||||
tzm = m.group('tzm')
|
|
||||||
|
|
||||||
# add optional minutes
|
|
||||||
if tzm != None:
|
|
||||||
tzm = int(tzm)
|
|
||||||
offsetmins += tzm if offsetmins > 0 else -tzm
|
|
||||||
|
|
||||||
tz = _get_fixed_offset_tz(offsetmins)
|
|
||||||
return datetime.datetime(year, month, day, h, min, s, us, tz)
|
|
@ -493,16 +493,11 @@ class XMLStream(asyncio.BaseProtocol):
|
|||||||
except Socket.gaierror as e:
|
except Socket.gaierror as e:
|
||||||
self.event('connection_failed',
|
self.event('connection_failed',
|
||||||
'No DNS record available for %s' % self.default_domain)
|
'No DNS record available for %s' % self.default_domain)
|
||||||
|
self.reschedule_connection_attempt()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
log.debug('Connection failed: %s', e)
|
log.debug('Connection failed: %s', e)
|
||||||
self.event("connection_failed", e)
|
self.event("connection_failed", e)
|
||||||
if self._current_connection_attempt is None:
|
self.reschedule_connection_attempt()
|
||||||
return
|
|
||||||
self._connect_loop_wait = self._connect_loop_wait * 2 + 1
|
|
||||||
self._current_connection_attempt = asyncio.ensure_future(
|
|
||||||
self._connect_routine(),
|
|
||||||
loop=self.loop,
|
|
||||||
)
|
|
||||||
|
|
||||||
def process(self, *, forever: bool = True, timeout: Optional[int] = None) -> None:
|
def process(self, *, forever: bool = True, timeout: Optional[int] = None) -> None:
|
||||||
"""Process all the available XMPP events (receiving or sending data on the
|
"""Process all the available XMPP events (receiving or sending data on the
|
||||||
@ -638,6 +633,20 @@ class XMLStream(asyncio.BaseProtocol):
|
|||||||
self._set_disconnected_future()
|
self._set_disconnected_future()
|
||||||
self.event("disconnected", self.disconnect_reason or exception)
|
self.event("disconnected", self.disconnect_reason or exception)
|
||||||
|
|
||||||
|
def reschedule_connection_attempt(self) -> None:
|
||||||
|
"""
|
||||||
|
Increase the exponential back-off and initate another background
|
||||||
|
_connect_routine call to connect to the server.
|
||||||
|
"""
|
||||||
|
# abort if there is no ongoing connection attempt
|
||||||
|
if self._current_connection_attempt is None:
|
||||||
|
return
|
||||||
|
self._connect_loop_wait = min(300, self._connect_loop_wait * 2 + 1)
|
||||||
|
self._current_connection_attempt = asyncio.ensure_future(
|
||||||
|
self._connect_routine(),
|
||||||
|
loop=self.loop,
|
||||||
|
)
|
||||||
|
|
||||||
def cancel_connection_attempt(self) -> None:
|
def cancel_connection_attempt(self) -> None:
|
||||||
"""
|
"""
|
||||||
Immediately cancel the current create_connection() Future.
|
Immediately cancel the current create_connection() Future.
|
||||||
@ -800,6 +809,8 @@ class XMLStream(asyncio.BaseProtocol):
|
|||||||
|
|
||||||
self.ssl_context.verify_mode = ssl.CERT_REQUIRED
|
self.ssl_context.verify_mode = ssl.CERT_REQUIRED
|
||||||
self.ssl_context.load_verify_locations(cafile=ca_cert)
|
self.ssl_context.load_verify_locations(cafile=ca_cert)
|
||||||
|
else:
|
||||||
|
self.ssl_context.set_default_verify_paths()
|
||||||
|
|
||||||
return self.ssl_context
|
return self.ssl_context
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ class TestPermissions(SlixTest):
|
|||||||
def testAdvertisePermission(self):
|
def testAdvertisePermission(self):
|
||||||
xmlstring = """
|
xmlstring = """
|
||||||
<message from='capulet.net' to='pubub.capulet.lit'>
|
<message from='capulet.net' to='pubub.capulet.lit'>
|
||||||
<privilege xmlns='urn:xmpp:privilege:1'>
|
<privilege xmlns='urn:xmpp:privilege:2'>
|
||||||
<perm access='roster' type='both'/>
|
<perm access='roster' type='both'/>
|
||||||
<perm access='message' type='outgoing'/>
|
<perm access='message' type='outgoing'/>
|
||||||
<perm access='presence' type='managed_entity'/>
|
<perm access='presence' type='managed_entity'/>
|
||||||
|
@ -31,7 +31,7 @@ class TestPermissions(SlixTest):
|
|||||||
self.recv(
|
self.recv(
|
||||||
"""
|
"""
|
||||||
<message from='capulet.net' to='pubub.capulet.lit' id='54321'>
|
<message from='capulet.net' to='pubub.capulet.lit' id='54321'>
|
||||||
<privilege xmlns='urn:xmpp:privilege:1'>
|
<privilege xmlns='urn:xmpp:privilege:2'>
|
||||||
<perm access='roster' type='both'/>
|
<perm access='roster' type='both'/>
|
||||||
<perm access='message' type='outgoing'/>
|
<perm access='message' type='outgoing'/>
|
||||||
</privilege>
|
</privilege>
|
||||||
@ -95,7 +95,7 @@ class TestPermissions(SlixTest):
|
|||||||
def testMakeOutgoingMessage(self):
|
def testMakeOutgoingMessage(self):
|
||||||
xmlstring = """
|
xmlstring = """
|
||||||
<message xmlns="jabber:component:accept" from='pubsub.capulet.lit' to='capulet.net'>
|
<message xmlns="jabber:component:accept" from='pubsub.capulet.lit' to='capulet.net'>
|
||||||
<privilege xmlns='urn:xmpp:privilege:1'>
|
<privilege xmlns='urn:xmpp:privilege:2'>
|
||||||
<forwarded xmlns='urn:xmpp:forward:0'>
|
<forwarded xmlns='urn:xmpp:forward:0'>
|
||||||
<message from="juliet@capulet.lit" to="romeo@montague.lit" xmlns="jabber:client">
|
<message from="juliet@capulet.lit" to="romeo@montague.lit" xmlns="jabber:client">
|
||||||
<body>I do not hate you</body>
|
<body>I do not hate you</body>
|
||||||
|
Loading…
Reference in New Issue
Block a user