summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2016-09-30 20:00:54 +0200
committerJeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com>2016-09-30 20:00:54 +0200
commitf30c587b80fdc2a93f0bac0d77a57624c5b13184 (patch)
tree30b5124c721809a4f23102c7aa4a046ba5e954c1
parent95506011fb94098478122df89e03e83a69d0d010 (diff)
downloadpykolab-f30c587b80fdc2a93f0bac0d77a57624c5b13184.tar.gz
T1461: Convert windows timezones into Olson format in iTip
Summary: iCalendar is used to parse iTip data, but it does not support windows tz. Fixes T1461 Reviewers: #pykolab_developers, vanmeeuwen Reviewed By: #pykolab_developers, vanmeeuwen Subscribers: vanmeeuwen Maniphest Tasks: T1461 Differential Revision: https://git.kolab.org/D219
-rw-r--r--pykolab/itip/__init__.py36
-rw-r--r--tests/unit/test-011-itip.py7
2 files changed, 38 insertions, 5 deletions
diff --git a/pykolab/itip/__init__.py b/pykolab/itip/__init__.py
index eda4f04..4999fad 100644
--- a/pykolab/itip/__init__.py
+++ b/pykolab/itip/__init__.py
@@ -2,12 +2,14 @@ import icalendar
import pykolab
import traceback
import kolabformat
+import re
from pykolab.xml import to_dt
from pykolab.xml import event_from_ical
from pykolab.xml import todo_from_ical
from pykolab.xml import participant_status_label
from pykolab.translate import _
+from tzlocal import windows_tz
log = pykolab.getLogger('pykolab.wallace')
@@ -18,7 +20,6 @@ def events_from_message(message, methods=None):
def todos_from_message(message, methods=None):
return objects_from_message(message, ["VTODO"], methods)
-
def objects_from_message(message, objnames, methods=None):
"""
Obtain the iTip payload from email.message <message>
@@ -51,6 +52,9 @@ def objects_from_message(message, objnames, methods=None):
log.debug(_("Raw iTip payload (%r): %r") % (part.get_param('charset'), itip_payload), level=9)
+ # Convert unsupported timezones, etc.
+ itip_payload = _convert_itip_payload(itip_payload)
+
# Python iCalendar prior to 3.0 uses "from_string".
if hasattr(icalendar.Calendar, 'from_ical'):
cal = icalendar.Calendar.from_ical(itip_payload)
@@ -141,7 +145,6 @@ def objects_from_message(message, objnames, methods=None):
return itip_objects
-
def check_event_conflict(kolab_event, itip_event):
"""
Determine whether the given kolab event conflicts with the given itip event
@@ -210,10 +213,35 @@ def check_event_conflict(kolab_event, itip_event):
return conflict
-
def _is_transparent(event):
return event.get_transparency() or event.get_status() == kolabformat.StatusCancelled
+def _convert_itip_payload(itip):
+ matchlist = re.findall("^((DTSTART|DTEND|DUE|EXDATE|COMPLETED)[:;][^\n]+)$", itip, re.MULTILINE)
+
+ for match in matchlist:
+ match = match[0]
+ search = re.search(";TZID=([^:;]+)", match)
+
+ if search:
+ tzorig = tzdest = search.group(1).replace('"', '')
+
+ # timezone in Olson-database format, nothing to convert
+ if re.match("[a-zA-Z]+/[a-zA-Z0-9_+-]+", tzorig):
+ continue
+
+ # convert timezone from windows format to Olson
+ if tzorig in windows_tz.win_tz:
+ tzdest = windows_tz.win_tz[tzorig]
+
+ # @TODO: Should be prefer server time if it has the same offset?
+
+ # replace old with new timezone name
+ if tzorig != tzdest:
+ replace = match.replace(search.group(0), ";TZID=" + tzdest)
+ itip = itip.replace("\n" + match, "\n" + replace)
+
+ return itip
def check_date_conflict(_es, _ee, _is, _ie):
"""
@@ -238,7 +266,7 @@ def check_date_conflict(_es, _ee, _is, _ie):
conflict = True
else:
conflict = False
-
+
return conflict
diff --git a/tests/unit/test-011-itip.py b/tests/unit/test-011-itip.py
index 38e00b8..173a26e 100644
--- a/tests/unit/test-011-itip.py
+++ b/tests/unit/test-011-itip.py
@@ -286,7 +286,7 @@ METHOD:REQUEST
BEGIN:VEVENT
UID:eea25142-fb1c-4831-a02d-ac9fb4c16b70
DTSTAMP:20140213T125414Z
-DTSTART;TZID=3DEurope/London:20140713T100000
+DTSTART;TZID=3D"W. Europe Standard Time":20140713T100000
DTEND;TZID=3DEurope/London:20140713T140000
SUMMARY:Testing =C3=9Cmlauts
DESCRIPTION:Testing =C3=9Cmlauts
@@ -375,6 +375,11 @@ class TestITip(unittest.TestCase):
self.assertEqual(xml.get_summary(), "Testing Ümlauts")
self.assertEqual(xml.get_location(), "Rue the Genève")
+ # Timezone conversion
+ itips = itip.events_from_message(message_from_string(itip_unicode))
+ xml = itips[0]['xml']
+ self.assertEqual(xml.get_start().tzinfo.__str__(), "Europe/Berlin")
+
def test_002_check_date_conflict(self):
astart = datetime.datetime(2014, 7, 13, 10, 0, 0)
aend = astart + datetime.timedelta(hours=2)