From 9bf88c1f65235ea53583b617a865f1d0fb4b7125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Fri, 16 Nov 2018 23:11:05 +0100 Subject: [PATCH] Improve Entity Time parsing - Use parse_datetime() - Improve tzo node validation --- gajim/common/modules/date_and_time.py | 27 ++++++++++++- gajim/common/modules/entity_time.py | 57 +++++++++------------------ 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/gajim/common/modules/date_and_time.py b/gajim/common/modules/date_and_time.py index 1c680c66b..28030ba15 100644 --- a/gajim/common/modules/date_and_time.py +++ b/gajim/common/modules/date_and_time.py @@ -16,11 +16,13 @@ import re import time +import logging from datetime import datetime from datetime import timedelta from datetime import timezone from datetime import tzinfo +log = logging.getLogger('gajim.c.m.date_and_time') PATTERN_DATETIME = re.compile( r'([0-9]{4}-[0-9]{2}-[0-9]{2})' @@ -94,7 +96,30 @@ class LocalTimezone(tzinfo): return tt.tm_isdst > 0 -def create_tzinfo(hours=0, minutes=0): +def create_tzinfo(hours=0, minutes=0, tz_string=None): + if tz_string is None: + return timezone(timedelta(hours=hours, minutes=minutes)) + + if tz_string.lower() == 'z': + return timezone.utc + + try: + hours, minutes = map(int, tz_string.split(':')) + except Exception: + log.warning('Wrong tz string: %s', tz_string) + return + + if hours not in range(-24, 24): + log.warning('Wrong tz string: %s', tz_string) + return + + if minutes not in range(0, 59): + log.warning('Wrong tz string: %s', tz_string) + return + + if hours in (24, -24) and minutes != 0: + log.warning('Wrong tz string: %s', tz_string) + return return timezone(timedelta(hours=hours, minutes=minutes)) diff --git a/gajim/common/modules/entity_time.py b/gajim/common/modules/entity_time.py index 1088f8dc2..6676fbaef 100644 --- a/gajim/common/modules/entity_time.py +++ b/gajim/common/modules/entity_time.py @@ -15,13 +15,14 @@ # XEP-0202: Entity Time import logging -import datetime import time import nbxmpp from gajim.common import app -from gajim.common.nec import NetworkIncomingEvent +from gajim.common.nec import NetworkEvent +from gajim.common.modules.date_and_time import parse_datetime +from gajim.common.modules.date_and_time import create_tzinfo log = logging.getLogger('gajim.c.m.entity_time') @@ -61,10 +62,10 @@ class EntityTime: log.info('Received: %s %s', stanza.getFrom(), time_info) - app.nec.push_incoming_event( - TimeResultReceivedEvent(None, conn=self._con, - jid=stanza.getFrom(), - time_info=time_info)) + app.nec.push_incoming_event(NetworkEvent('time-result-received', + conn=self._con, + jid=stanza.getFrom(), + time_info=time_info)) @staticmethod def _extract_info(stanza): @@ -74,42 +75,24 @@ class EntityTime: return tzo = time_.getTag('tzo').getData() - if tzo.lower() == 'z': - tzo = '0:0' - try: - tzoh, tzom = tzo.split(':') - except Exception: + if not tzo: log.warning('Wrong tzo node: %s', stanza) return - utc_time = time_.getTag('utc').getData() - if utc_time[-1:] == 'Z': - # Remove the trailing 'Z' - utc_time = utc_time[:-1] - elif utc_time[-6:] == "+00:00": - # Remove the trailing "+00:00" - utc_time = utc_time[:-6] - else: + remote_tz = create_tzinfo(tz_string=tzo) + if remote_tz is None: + log.warning('Wrong tzo node: %s', stanza) + return + + utc_time = time_.getTag('utc').getData() + date_time = parse_datetime(utc_time, check_utc=True) + if date_time is None: log.warning('Wrong timezone defintion: %s %s', utc_time, stanza.getFrom()) return - try: - dtime = datetime.datetime.strptime(utc_time, '%Y-%m-%dT%H:%M:%S') - except ValueError: - try: - dtime = datetime.datetime.strptime(utc_time, - '%Y-%m-%dT%H:%M:%S.%f') - except ValueError as error: - log.warning('Wrong time format: %s %s', - error, stanza.getFrom()) - return - - utc = datetime.timezone(datetime.timedelta(0)) - dtime = dtime.replace(tzinfo=utc) - utc_offset = datetime.timedelta(hours=int(tzoh), minutes=int(tzom)) - contact_tz = datetime.timezone(utc_offset, "remote timezone") - return dtime.astimezone(contact_tz).strftime('%c') + date_time = date_time.astimezone(remote_tz) + return date_time.strftime('%c %Z') def _answer_request(self, _con, stanza): log.info('%s asked for the time', stanza.getFrom()) @@ -132,9 +115,5 @@ class EntityTime: raise nbxmpp.NodeProcessed -class TimeResultReceivedEvent(NetworkIncomingEvent): - name = 'time-result-received' - - def get_instance(*args, **kwargs): return EntityTime(*args, **kwargs), 'EntityTime'