From 084501f53a98abf62b34a7d0505ed3a3ac588331 Mon Sep 17 00:00:00 2001 From: "Aleksander Machniak (Kolab Systems)" Date: Tue, 19 Jul 2011 12:48:31 +0200 Subject: [PATCH 1/4] Fixed datepicker width issue --- plugins/calendar/skins/default/calendar.css | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/calendar/skins/default/calendar.css b/plugins/calendar/skins/default/calendar.css index 42c22a19..f187c921 100644 --- a/plugins/calendar/skins/default/calendar.css +++ b/plugins/calendar/skins/default/calendar.css @@ -160,7 +160,8 @@ pre { width: 100%; } -#agendalist td, th { +#agendalist td, +#agendalist th { border-right: 1px solid #C1DAD7; border-bottom: 1px solid #C1DAD7; background: #fff; @@ -672,6 +673,11 @@ a.alarm-action-snooze:after { padding-right: 0.5em; } +.ui-datepicker th { + padding: 0.3em 0; + font-size: 10px; +} + .ui-datepicker td span, .ui-datepicker td a { padding-left: 0.1em; From dda99db3f05d0c328323adbe23092d842c1fbf03 Mon Sep 17 00:00:00 2001 From: "Bogomil Shopov (Kolab Systems)" Date: Tue, 19 Jul 2011 14:54:13 +0300 Subject: [PATCH 2/4] Adding "Virtual event" filter for exporting to Icalendar format. --- plugins/calendar/calendar.php | 6 +++--- plugins/calendar/drivers/kolab/kolab_calendar.php | 5 +++-- plugins/calendar/drivers/kolab/kolab_driver.php | 5 +++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 76cb88d6..585c11d3 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -580,7 +580,7 @@ class calendar extends rcube_plugin } /** - * + * Construct the ics file for exporting events to iCalendar format; */ function export_events() { @@ -588,8 +588,8 @@ class calendar extends rcube_plugin $end = get_input_value('end', RCUBE_INPUT_GET); if (!$start) $start = mktime(0, 0, 0, 1, date('n'), date('Y')-1); if (!$end) $end = mktime(0, 0, 0, 31, 12, date('Y')+10); - $events = $this->driver->load_events($start, $end, get_input_value('source', RCUBE_INPUT_GET)); - + $events = $this->driver->load_events($start, $end, null, get_input_value('source', RCUBE_INPUT_GET), 0); + header("Content-Type: text/calendar"); header("Content-Disposition: inline; filename=calendar.ics"); diff --git a/plugins/calendar/drivers/kolab/kolab_calendar.php b/plugins/calendar/drivers/kolab/kolab_calendar.php index d7e22c80..d6b89f97 100644 --- a/plugins/calendar/drivers/kolab/kolab_calendar.php +++ b/plugins/calendar/drivers/kolab/kolab_calendar.php @@ -191,9 +191,10 @@ class kolab_calendar * @param integer Event's new start (unix timestamp) * @param integer Event's new end (unix timestamp) * @param string Search query (optional) + * @param boolean Strip virtual events (optional) * @return array A list of event records */ - public function list_events($start, $end, $search = null) + public function list_events($start, $end, $search = null, $virtual = 1) { $this->_fetch_events(); @@ -224,7 +225,7 @@ class kolab_calendar } // resolve recurring events - if ($event['recurrence']) { + if ($event['recurrence'] && $virtual == 1) { $events = array_merge($events, $this->_get_recurring_events($event, $start, $end)); } } diff --git a/plugins/calendar/drivers/kolab/kolab_driver.php b/plugins/calendar/drivers/kolab/kolab_driver.php index 43db91ae..2b22320e 100644 --- a/plugins/calendar/drivers/kolab/kolab_driver.php +++ b/plugins/calendar/drivers/kolab/kolab_driver.php @@ -505,9 +505,10 @@ class kolab_driver extends calendar_driver * @param integer Event's new end (unix timestamp) * @param string Search query (optional) * @param mixed List of calendar IDs to load events from (either as array or comma-separated string) + * @param boolean Strip virtual events (optional) * @return array A list of event records */ - public function load_events($start, $end, $search = null, $calendars = null) + public function load_events($start, $end, $search = null, $calendars = null, $virtual = 1) { if ($calendars && is_string($calendars)) $calendars = explode(',', $calendars); @@ -517,7 +518,7 @@ class kolab_driver extends calendar_driver if ($calendars && !in_array($cid, $calendars)) continue; - $events = array_merge($events, $this->calendars[$cid]->list_events($start, $end, $search)); + $events = array_merge($events, $this->calendars[$cid]->list_events($start, $end, $search, $virtual)); } return $events; From 6b5c895ffc68ab0c0edd54fe4916e4557b988e30 Mon Sep 17 00:00:00 2001 From: "Aleksander Machniak (Kolab Systems)" Date: Tue, 19 Jul 2011 15:18:05 +0200 Subject: [PATCH 3/4] Attachments upload handling: - Fixed regexp for attachment names which can be more complicated when using database_attachments plugin - Don't load driver in 'upload' action to prevent from possible session race-conditions when calling upload progress action and for better performance. --- plugins/calendar/calendar.php | 10 ++++++---- plugins/calendar/calendar_ui.js | 15 +++++++-------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index 76cb88d6..a8c3e8f4 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -91,11 +91,13 @@ class calendar extends rcube_plugin } if ($this->rc->task == 'calendar' && $this->rc->action != 'save-pref') { - $this->load_driver(); + if ($this->rc->action != 'upload') { + $this->load_driver(); - // load iCalendar functions - require($this->home . '/lib/calendar_ical.php'); - $this->ical = new calendar_ical($this->rc, $this->driver); + // load iCalendar functions + require($this->home . '/lib/calendar_ical.php'); + $this->ical = new calendar_ical($this->rc, $this->driver); + } // register calendar actions $this->register_action('index', array($this, 'calendar_view')); diff --git a/plugins/calendar/calendar_ui.js b/plugins/calendar/calendar_ui.js index b5425777..14146322 100644 --- a/plugins/calendar/calendar_ui.js +++ b/plugins/calendar/calendar_ui.js @@ -256,7 +256,7 @@ function rcube_calendar_ui(settings) } } else if (calendar.attachments) { - // fetch attachments, some drivers doesn't set 'attachments' popr of the event + // fetch attachments, some drivers doesn't set 'attachments' prop of the event? } // list event attendees @@ -474,7 +474,7 @@ function rcube_calendar_ui(settings) } else { $('#edit-attachments > ul').empty(); - // fetch attachments, some drivers doesn't set 'attachments' array for event + // fetch attachments, some drivers doesn't set 'attachments' array for event? } } @@ -507,7 +507,8 @@ function rcube_calendar_ui(settings) recurrence: '', alarms: '', attendees: event_attendees, - deleted_attachments: rcmail.env.deleted_attachments + deleted_attachments: rcmail.env.deleted_attachments, + attachments: [] }; // serialize alarm settings @@ -522,12 +523,10 @@ function rcube_calendar_ui(settings) } // uploaded attachments list - var attachments = []; for (var i in rcmail.env.attachments) - if (i.match(/^rcmfile([0-9a-z]+)/)) - attachments.push(RegExp.$1); - data.attachments = attachments; - + if (i.match(/^rcmfile(.+)/)) + data.attachments.push(RegExp.$1); + // read attendee roles $('select.edit-attendee-role').each(function(i, elem){ if (data.attendees[i]) From f610167cc1970f94441784f143ad1e094fd7ac0e Mon Sep 17 00:00:00 2001 From: "Bogomil Shopov (Kolab Systems)" Date: Tue, 19 Jul 2011 17:11:33 +0300 Subject: [PATCH 4/4] Adding rules according to rfc2445#section-4.1 and adding Organizer and Attendees information in VEVENT block. --- plugins/calendar/lib/calendar_ical.php | 84 ++++++++++++++++++++------ 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/plugins/calendar/lib/calendar_ical.php b/plugins/calendar/lib/calendar_ical.php index 798e11a5..66cd9ee9 100644 --- a/plugins/calendar/lib/calendar_ical.php +++ b/plugins/calendar/lib/calendar_ical.php @@ -19,6 +19,7 @@ | | +-------------------------------------------------------------------------+ | Author: Lazlo Westerhof | + | Bogomil "Bogo" Shopov | +-------------------------------------------------------------------------+ */ @@ -55,26 +56,32 @@ class calendar_ical public function export($events) { if (!empty($this->rc->user->ID)) { - $ical = "BEGIN:VCALENDAR\n"; - $ical .= "VERSION:2.0\n"; - $ical .= "PRODID:-//Roundcube Webmail " . RCMAIL_VERSION . "//NONSGML Calendar//EN\n"; - $ical .= "CALSCALE:GREGORIAN\n"; + $ical = "BEGIN:VCALENDAR\r\n"; + $ical .= "VERSION:2.0\r\n"; + $ical .= "PRODID:-//Roundcube Webmail " . RCMAIL_VERSION . "//NONSGML Calendar//EN\r\n"; + $ical .= "CALSCALE:GREGORIAN\r\n"; foreach ($events as $event) { - $ical .= "BEGIN:VEVENT\n"; - $ical .= "UID:" . self::escpape($event['uid']) . "\n"; - $ical .= "DTSTART:" . gmdate('Ymd\THis\Z', $event['start']) . "\n"; - $ical .= "DTEND:" . gmdate('Ymd\THis\Z', $event['end']) . "\n"; - $ical .= "SUMMARY:" . self::escpape($event['title']) . "\n"; - $ical .= "DESCRIPTION:" . self::escpape($event['description']) . "\n"; + $ical .= "BEGIN:VEVENT\r\n"; + $ical .= "UID:" . self::escpape($event['uid']) . "\r\n"; + $ical .= "DTSTART:" . gmdate('Ymd\THis\Z', $event['start']) . "\r\n"; + $ical .= "DTEND:" . gmdate('Ymd\THis\Z', $event['end']) . "\r\n"; + $ical .= "SUMMARY:" . self::escpape($event['title']) . "\r\n"; + $ical .= "DESCRIPTION:" . wordwrap(self::escpape($event['description']),75,'\r\n ') . "\r\n"; + + if (!empty($event['attendees'])){ + + $ical .= $this->_get_attendees($event['attendees']); + } + if (!empty($event['location'])) { - $ical .= "LOCATION:" . self::escpape($event['location']) . "\n"; + $ical .= "LOCATION:" . self::escpape($event['location']) . "\r\n"; } if ($event['recurrence']) { - $ical .= "RRULE:" . calendar::to_rrule($event['recurrence']) . "\n"; + $ical .= "RRULE:" . calendar::to_rrule($event['recurrence']) . "\r\n"; } if(!empty($event['categories'])) { - $ical .= "CATEGORIES:" . self::escpape(strtoupper($event['categories'])) . "\n"; + $ical .= "CATEGORIES:" . self::escpape(strtoupper($event['categories'])) . "\r\n"; } if ($event['sensitivity'] > 0) { $ical .= "X-CALENDARSERVER-ACCESS:CONFIDENTIAL"; @@ -84,16 +91,16 @@ class calendar_ical $val = calendar::parse_alaram_value($trigger); $ical .= "BEGIN:VALARM\n"; - if ($val[1]) $ical .= "TRIGGER:" . preg_replace('/^([-+])(.+)/', '\\1PT\\2', $trigger) . "\n"; - else $ical .= "TRIGGER;VALUE=DATE-TIME:" . gmdate('Ymd\THis\Z', $val[0]) . "\n"; - if ($action) $ical .= "ACTION:" . self::escpape(strtoupper($action)) . "\n"; + if ($val[1]) $ical .= "TRIGGER:" . preg_replace('/^([-+])(.+)/', '\\1PT\\2', $trigger) . "\r\n"; + else $ical .= "TRIGGER;VALUE=DATE-TIME:" . gmdate('Ymd\THis\Z', $val[0]) . "\r\n"; + if ($action) $ical .= "ACTION:" . self::escpape(strtoupper($action)) . "\r\n"; $ical .= "END:VALARM\n"; } - $ical .= "TRANSP:" . ($event['free_busy'] == 'free' ? 'TRANSPARENT' : 'OPAQUE') . "\n"; + $ical .= "TRANSP:" . ($event['free_busy'] == 'free' ? 'TRANSPARENT' : 'OPAQUE') . "\r\n"; // TODO: export attachments - $ical .= "END:VEVENT\n"; + $ical .= "END:VEVENT\r\n"; } $ical .= "END:VCALENDAR"; @@ -106,4 +113,45 @@ class calendar_ical { return preg_replace('/(?