From 4795a0002aad828b30950f132ab0142f3a01bb22 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Sun, 30 Dec 2012 17:18:39 +0000 Subject: [PATCH] calendarimporter 1.2 pre: - New timezone management - more imported fields (Busystatus, importance, label, class, organizer, reminder) - smaller improvements - deploy/build script --- build.xml | 263 +++++++++++++++ changelog.txt | 10 +- config.php | 2 +- js/data/timezones.js | 2 +- js/dialogs/ImportPanel.js | 312 +++++++++++------- manifest.xml | 74 ++--- php/ical/calendar.txt | 6 +- php/ical/class.icalparser.php | 74 ++++- php/plugin.calendarimporter.php | 2 +- ...importer.css => calendarimporter-main.css} | 0 10 files changed, 565 insertions(+), 180 deletions(-) create mode 100644 build.xml rename resources/css/{calendarimporter.css => calendarimporter-main.css} (100%) diff --git a/build.xml b/build.xml new file mode 100644 index 0000000..505c017 --- /dev/null +++ b/build.xml @@ -0,0 +1,263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + var Ext = {}; + var Zarafa = {}; + var container = {}; + var _ = function(key, domain) {}; + var dgettext = function(domain, msgid) {}; + var dngettext = function(domain, msgid, msgid_plural, count) {}; + var dnpgettext = function(domain, msgctxt, msgid, msgid_plural, count) {}; + var dpgettext = function(domain, msgctxt, msgid) {}; + var ngettext = function(msgid, msgid_plural, count) {}; + var npgettext = function(msgctxt, msgid, msgid_plural, count) {}; + var pgettext = function(msgctxt, msgid) {}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Processing manifest.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/changelog.txt b/changelog.txt index 8a9b996..bb7cf86 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,10 +1,14 @@ +calendarimporter 1.2: + - New timezone management + - more imported fields (Busystatus, importance, label, class, organizer, reminder) + - smaller improvements + - deploy/build script + calendarimporter 1.1 final: - ics exporter - improved ics fileparser - fixed ExtJS Problem in chrome -KNOWN PROBLEMS: - - importer ignores some fields (priority, status...) +KNOWN PROBLEMS: - attechments are ignored - - timezone handling is not perfect - recurrent events are not handled properly (im/export) \ No newline at end of file diff --git a/config.php b/config.php index de30025..c03312e 100644 --- a/config.php +++ b/config.php @@ -5,5 +5,5 @@ define('PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT', false); /** The default calendar to import to*/ - define('PLUGIN_CALENDARIMPORTER_DEFAULT', "Default"); + define('PLUGIN_CALENDARIMPORTER_DEFAULT', "calendar"); ?> diff --git a/js/data/timezones.js b/js/data/timezones.js index 49fa342..ea2bbb9 100644 --- a/js/data/timezones.js +++ b/js/data/timezones.js @@ -736,7 +736,7 @@ Zarafa.plugins.calendarimporter.data.Timezones = Ext.extend(Object, { getOffset: function(timezone) { /* find timezone, this needs to be optimized ;) */ timezone = this.unMap(timezone); - + var i = 0; for(i = 0; i < this.store.length; i++) { if(this.store[i][0] == timezone) { return (this.store[i][2] * 60000); diff --git a/js/dialogs/ImportPanel.js b/js/dialogs/ImportPanel.js index 5371669..a0917b8 100644 --- a/js/dialogs/ImportPanel.js +++ b/js/dialogs/ImportPanel.js @@ -101,10 +101,16 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { } if(eventdata !== null) { - var parsedData = new Array(eventdata.events.length); - - for(var i=0; i < eventdata.events.length; i++) { - parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset + tz_offset), new Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset + tz_offset), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"]); + parsedData = new Array(eventdata.events.length); + var i = 0; + for(i = 0; i < eventdata.events.length; i++) { + var trigger = null; + + if(eventdata.events[i]["VALARM"]) { + trigger = eventdata.events[i]["VALARM"]["TRIGGER"]; + trigger = new Date(parseInt(trigger) + local_tz_offset + tz_offset); + } + parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], new Date(parseInt(eventdata.events[i]["DTSTART"]) + local_tz_offset + tz_offset), new Date(parseInt(eventdata.events[i]["DTEND"]) + local_tz_offset + tz_offset), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"],eventdata.events[i]["PRIORITY"],eventdata.events[i]["X-ZARAFA-LABEL"],eventdata.events[i]["X-MICROSOFT-CDO-BUSYSTATUS"],eventdata.events[i]["CLASS"],eventdata.events[i]["ORGANIZER"],trigger); } } else { return null; @@ -113,11 +119,17 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { // create the data store var store = new Ext.data.ArrayStore({ fields: [ - {name: 'title'}, - {name: 'start'}, - {name: 'end'}, - {name: 'location'}, - {name: 'description'} + {name: 'title'}, + {name: 'start'}, + {name: 'end'}, + {name: 'location'}, + {name: 'description'}, + {name: 'priority'}, + {name: 'label'}, + {name: 'busy'}, + {name: 'privatestate'}, + {name: 'organizer'}, + {name: 'trigger'} ], data: parsedData }); @@ -142,7 +154,13 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { {header: 'Start', width: 150, sortable: true, dataIndex: 'start', renderer : Zarafa.common.ui.grid.Renderers.datetime}, {header: 'End', width: 150, sortable: true, dataIndex: 'end', renderer : Zarafa.common.ui.grid.Renderers.datetime}, {header: 'Location', width: 150, sortable: true, dataIndex: 'location'}, - {header: 'Description', width: 150, sortable: true, dataIndex: 'description'} + {header: 'Description', width: 150, sortable: true, dataIndex: 'description'}, + {header: "Priority", dataIndex: 'priority', hidden: true}, + {header: "Label", dataIndex: 'label', hidden: true}, + {header: "Busystatus", dataIndex: 'busy', hidden: true}, + {header: "Privacystatus", dataIndex: 'privatestate', hidden: true}, + {header: "Organizer", dataIndex: 'organizer', hidden: true}, + {header: "Alarm", dataIndex: 'trigger', hidden: true, renderer : Zarafa.common.ui.grid.Renderers.datetime} ] }), sm: new Ext.grid.RowSelectionModel({multiSelect:true}) @@ -150,10 +168,10 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { }, createSelectBox: function() { - ctx = container.getContextByName('calendar'); - model = ctx.getModel(); - defaultFolder = model.getDefaultFolder(); // @type: Zarafa.hierarchy.data.MAPIFolderRecord - subFolders = defaultFolder.getChildren(); + var ctx = container.getContextByName('calendar'); + var model = ctx.getModel(); + var defaultFolder = model.getDefaultFolder(); // @type: Zarafa.hierarchy.data.MAPIFolderRecord + var subFolders = defaultFolder.getChildren(); var myStore = new Ext.data.ArrayStore({ fields: ['calendar_id', 'calendar_displayname'], @@ -172,12 +190,12 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { displayname: defaultFolder.getDisplayName() }); myStore.add(myNewRecord); - - for(i=0;i 0) { // call export function here! var responseHandler = new Zarafa.plugins.calendarimporter.data.ResponseHandler({ @@ -548,8 +617,7 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { * @param {Object} response * @private */ - downLoadICS : function(response) - { + downLoadICS : function(response) { Zarafa.common.dialogs.MessageBox.hide(); if(response.status === true) { // needs to be window.open, document.location.href kills the extjs response handler... @@ -561,48 +629,60 @@ Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.Panel, { importCheckedEvents: function () { //receive existing calendar store - var selIndex = this.calendarselector.selectedIndex; var calValue = this.calendarselector.value; - if(selIndex == -1) { // no calendar choosen - Ext.MessageBox.show({ + if(calValue == undefined) { // no calendar choosen + Zarafa.common.dialogs.MessageBox.show({ title : _('Error'), msg : _('You have to choose a calendar!'), - icon : Ext.MessageBox.ERROR, - buttons : Ext.MessageBox.OK + icon : Zarafa.common.dialogs.MessageBox.ERROR, + buttons : Zarafa.common.dialogs.MessageBox.OK }); } else { + var calexist = true; if(this.eventgrid.selModel.getCount() < 1) { - Ext.MessageBox.show({ + Zarafa.common.dialogs.MessageBox.show({ title : _('Error'), msg : _('You have to choose at least one event to import!'), - icon : Ext.MessageBox.ERROR, - buttons : Ext.MessageBox.OK + icon : Zarafa.common.dialogs.MessageBox.ERROR, + buttons : Zarafa.common.dialogs.MessageBox.OK }); } else { var calendarStore = new Zarafa.calendar.AppointmentStore(); var calendarFolder = container.getHierarchyStore().getDefaultFolder('calendar'); if(calValue != "calendar") { var subFolders = calendarFolder.getChildren(); - + var i = 0; for(i=0;i - - 1.1 - calendarimporter - ICS Calendar Importer/Exporter - Christoph Haas - http://www.sprinternet.at - Import a ICS file to the zarafa calendar - - - config.php - - - - - - php/plugin.calendarimporter.php - php/module.calendarexporter.php - - - js/data/timezones.js - js/plugin.calendarimporter.js - js/data/ResponseHandler.js - js/dialogs/ImportContentPanel.js - js/dialogs/ImportPanel.js - - js/data/timezones.js - js/plugin.calendarimporter.js - js/data/ResponseHandler.js - js/dialogs/ImportContentPanel.js - js/dialogs/ImportPanel.js - - - resources/css/calendarimporter.css - resources/css/calendarimporter.css - - - - + + 1.2 + calendarimporter + ICS Calendar Importer/Exporter + Christoph Haas + http://www.sprinternet.at + Import or Export a ICS file to/from the zarafa calendar + + + config.php + + + + + + php/plugin.calendarimporter.php + php/module.calendarexporter.php + + + js/calendarimporter.js + js/calendarimporter-debug.js + + js/data/timezones.js + js/plugin.calendarimporter.js + js/data/ResponseHandler.js + js/dialogs/ImportContentPanel.js + js/dialogs/ImportPanel.js + + + resources/css/calendarimporter-min.css + resources/css/calendarimporter.css + resources/css/calendarimporter-main.css + + + + diff --git a/php/ical/calendar.txt b/php/ical/calendar.txt index cbe61bc..fe9c004 100644 --- a/php/ical/calendar.txt +++ b/php/ical/calendar.txt @@ -4,11 +4,11 @@ VERSION:2.0 CALSCALE:GREGORIAN METHOD:PUBLISH X-WR-CALNAME:Testkalender -X-WR-TIMEZONE:America/Detroit +X-WR-TIMEZONE:Europe/Berlin X-WR-CALDESC:Nur zum testen vom Google Kalender BEGIN:VEVENT -DTSTART:20121227T150000Z -DTEND:20121227T160000Z +DTSTART;TZID="W. Europe":20121227T100000 +DTEND;TZID="W. Europe":20121227T120000 DTSTAMP:20110121T195741Z UID:1koigufm110c5hnq6ln57murd4@google.com CREATED:20110119T142901Z diff --git a/php/ical/class.icalparser.php b/php/ical/class.icalparser.php index 85fec1b..f1c8cd2 100644 --- a/php/ical/class.icalparser.php +++ b/php/ical/class.icalparser.php @@ -9,7 +9,7 @@ * @author Christoph Haas * @modified 17.11.2012 by Christoph Haas (original at http://code.google.com/p/ics-parser/) * @license http://www.opensource.org/licenses/mit-license.php MIT License - * @version SVN: 16 + * @version SVN: 62 * @example $ical = new ical('calendar.ics'); * print_r( $ical->events() ); */ @@ -26,6 +26,9 @@ class ICal { /* How many events are in this ical? */ public /** @type {int} */ $event_count = 0; + + /* Currently editing an alarm? */ + private /** @type {int} */ $isalarm = false; /* The parsed calendar */ public /** @type {Array} */ $cal; @@ -74,7 +77,12 @@ class ICal { $this->todo_count++; $type = "VTODO"; break; - + + case "BEGIN:VALARM": + //echo "vevent gematcht"; + $this->isalarm=true; + $type = "VEVENT"; + break; // http://www.kanzaki.com/docs/ical/vevent.html case "BEGIN:VEVENT": //echo "vevent gematcht"; @@ -91,13 +99,17 @@ class ICal { $type = $value; break; case "END:VTODO": // end special text - goto VCALENDAR key - case "END:VEVENT": + case "END:VEVENT": case "END:VCALENDAR": case "END:DAYLIGHT": case "END:VTIMEZONE": case "END:STANDARD": $type = "VCALENDAR"; - break; + break; + case "END:VALARM": + $this->isalarm=false; + $type = "VEVENT"; + break; default: $this->addCalendarComponentWithKeyAndValue($type, $keyword, $value, $prop, $propvalue); break; @@ -122,13 +134,16 @@ class ICal { switch ($component) { case 'VEVENT': - if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { + if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) { $ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue); $value = $ts * 1000; } $value = str_replace("\\n", "\n", $value); - $value = $this->cal[$component][$this->event_count - 1] - [$keyword].$value; + if(!$this->isalarm) { + $value = $this->cal[$component][$this->event_count - 1][$keyword].$value; + } else { + $value = $this->cal[$component][$this->event_count - 1]["VALARM"][$keyword].$value; + } break; case 'VTODO' : $value = $this->cal[$component][$this->todo_count - 1] @@ -154,14 +169,19 @@ class ICal { //$this->cal[$component][$this->todo_count]['Unix'] = $unixtime; break; case "VEVENT": - if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { + if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND") or stristr($keyword, "TRIGGER")) { $ts = $this->iCalDateToUnixTimestamp($value, $prop, $propvalue); $value = $ts * 1000; } $value = str_replace("\\n", "\n", $value); - $this->cal[$component][$this->event_count - 1][$keyword] = $value; + + if(!$this->isalarm) { + $this->cal[$component][$this->event_count - 1][$keyword] = $value; + } else { + $this->cal[$component][$this->event_count - 1]["VALARM"][$keyword] = $value; + } break; - default: + default: $this->cal[$component][$keyword] = $value; break; } @@ -176,7 +196,7 @@ class ICal { * @return {array} array("VCALENDAR", "Begin", "Optional Props") */ public function keyValueFromString($text) { - preg_match("/(^[^a-z:;]+)([;a-zA-Z]*)[=]*([a-zA-Z\/\"\'\.\s]*)[:]([\w\W]*)/", $text, $matches); + preg_match("/(^[^a-z:;]+)[;]*([a-zA-Z]*)[=]*(.*)[:]([\w\W]*)/", $text, $matches); if (count($matches) == 0) { return false; @@ -200,7 +220,7 @@ class ICal { if($prop) { $pos = strpos("TZIDtzid", $prop); - if($pos !== false && $propvalue) { + if($pos !== false && $propvalue != false) { $timezone = str_replace('"', '', $propvalue); $timezone = str_replace('\'', '', $timezone); } @@ -239,14 +259,34 @@ class ICal { if(!$utc) { $tz = $this->default_timezone; - if($timezone) { + if($timezone != false) { $tz = $timezone; } - $this_tz = new DateTimeZone($tz); - $tz_now = new DateTime("now", $this_tz); - $tz_offset = $this_tz->getOffset($tz_now); - $timestamp_utc = $timestamp - $tz_offset; + $error = false; + $this_tz = false; + + try { + $this_tz = new DateTimeZone($tz); + } catch(Exception $e) { + error_log($e->getMessage()); + $error = true; + } + + if($error) { + try { // Try using the default calendar timezone + $this_tz = new DateTimeZone($this->default_timezone); + } catch(Exception $e) { + error_log($e->getMessage()); + $timestamp_utc = $timestamp; // if that fails, we cannot do anymore + } + } + + if($this_tz != false) { + $tz_now = new DateTime("now", $this_tz); + $tz_offset = $this_tz->getOffset($tz_now); + $timestamp_utc = $timestamp - $tz_offset; + } } else { $timestamp_utc = $timestamp; } diff --git a/php/plugin.calendarimporter.php b/php/plugin.calendarimporter.php index 6dd4c37..9210eff 100644 --- a/php/plugin.calendarimporter.php +++ b/php/plugin.calendarimporter.php @@ -48,7 +48,7 @@ class Plugincalendarimporter extends Plugin { 'calendarimporter' => Array( 'enable' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE, 'enable_export' => PLUGIN_CALENDARIMPORTER_USER_DEFAULT_ENABLE_EXPORT, - 'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT // currently not used, maybe in next release + 'default_calendar' => PLUGIN_CALENDARIMPORTER_DEFAULT ) ) ) diff --git a/resources/css/calendarimporter.css b/resources/css/calendarimporter-main.css similarity index 100% rename from resources/css/calendarimporter.css rename to resources/css/calendarimporter-main.css