From 6a0a3cb849dfaee4df15f0ef7a33739704974c2f Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 26 Mar 2014 10:41:13 +0100 Subject: [PATCH] Add option to save .ics attachments to calendar (without iTip processing) --- plugins/calendar/calendar.php | 84 ++++++++++++++++++++- plugins/calendar/calendar_base.js | 27 ++++++- plugins/calendar/localization/en_US.inc | 2 + plugins/calendar/skins/classic/calendar.css | 3 +- plugins/calendar/skins/larry/calendar.css | 3 +- 5 files changed, 112 insertions(+), 7 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index a742efa2..98c7b584 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -112,7 +112,7 @@ class calendar extends rcube_plugin return; // load Calendar user interface - if (!$this->rc->output->ajax_call && !$this->rc->output->env['framed']) { + if (!$this->rc->output->ajax_call && (!$this->rc->output->env['framed'] || $args['action'] == 'preview')) { $this->ui->init(); // settings are required in (almost) every GUI step @@ -138,7 +138,8 @@ class calendar extends rcube_plugin $this->register_action('freebusy-times', array($this, 'freebusy_times')); $this->register_action('randomdata', array($this, 'generate_randomdata')); $this->register_action('print', array($this,'print_view')); - $this->register_action('mailimportitip', array($this, 'mail_import_event')); + $this->register_action('mailimportitip', array($this, 'mail_import_itip')); + $this->register_action('mailimportattach', array($this, 'mail_import_attachment')); $this->register_action('mailtoevent', array($this, 'mail_message2event')); $this->register_action('inlineui', array($this, 'get_inline_ui')); $this->register_action('check-recent', array($this, 'check_recent')); @@ -2190,9 +2191,9 @@ class calendar extends rcube_plugin // load iCalendar functions (if necessary) if (!empty($this->ics_parts)) { $this->get_ical(); + $this->load_itip(); } - $this->load_itip(); $html = ''; foreach ($this->ics_parts as $mime_id) { $part = $this->message->mime_parts[$mime_id]; @@ -2233,6 +2234,21 @@ class calendar extends rcube_plugin $this->rc->output->add_label('calendar.savingdata','calendar.deleteventconfirm','calendar.declinedeleteconfirm'); } + // add "Save to calendar" button into attachment menu + if (!empty($this->ics_parts)) { + $this->add_button(array( + 'id' => 'attachmentsavecal', + 'name' => 'attachmentsavecal', + 'type' => 'link', + 'wrapper' => 'li', + 'command' => 'attachment-save-calendar', + 'class' => 'icon calendarlink', + 'classact' => 'icon calendarlink active', + 'innerclass' => 'icon calendar', + 'label' => 'calendar.savetocalendar', + ), 'attachmentmenu'); + } + return $p; } @@ -2274,7 +2290,7 @@ class calendar extends rcube_plugin /** * Handler for POST request to import an event attached to a mail message */ - public function mail_import_event() + public function mail_import_itip() { $uid = get_input_value('_uid', RCUBE_INPUT_POST); $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); @@ -2465,6 +2481,66 @@ class calendar extends rcube_plugin } } + /** + * Import the full payload from a mail message attachment + */ + public function mail_import_attachment() + { + $uid = get_input_value('_uid', RCUBE_INPUT_POST); + $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); + $mime_id = get_input_value('_part', RCUBE_INPUT_POST); + $charset = RCMAIL_CHARSET; + + // establish imap connection + $imap = $this->rc->get_storage(); + $imap->set_mailbox($mbox); + + if ($uid && $mime_id) { + $part = $imap->get_message_part($uid, $mime_id); + if ($part->ctype_parameters['charset']) + $charset = $part->ctype_parameters['charset']; + $headers = $imap->get_message_headers($uid); + + if ($part) { + $events = $this->get_ical()->import($part, $charset); + } + } + + $success = $existing = 0; + if (!empty($events)) { + // find writeable calendar to store event + $cal_id = !empty($_REQUEST['_calendar']) ? get_input_value('_calendar', RCUBE_INPUT_POST) : null; + $calendars = $this->driver->list_calendars(false, true); + $calendar = $calendars[$cal_id] ?: $this->get_default_calendar(true); + + foreach ($events as $event) { + // save to calendar + if ($calendar && !$calendar['readonly'] && $event['_type'] == 'event') { + $event['calendar'] = $calendar['id']; + + if (!$this->driver->get_event($event['uid'], true, false)) { + $success += (bool)$this->driver->new_event($event); + } + else { + $existing++; + } + } + } + } + + if ($success) { + $this->rc->output->command('display_message', $this->gettext(array( + 'name' => 'importsuccess', + 'vars' => array('nr' => $success), + )), 'confirmation'); + } + else if ($existing) { + $this->rc->output->command('display_message', $this->gettext('importwarningexists'), 'warning'); + } + else { + $this->rc->output->command('display_message', $this->gettext('errorimportingevent'), 'error'); + } + } /** * Read email message and return contents for a new event based on that message diff --git a/plugins/calendar/calendar_base.js b/plugins/calendar/calendar_base.js index 37552ce6..cc7c65af 100644 --- a/plugins/calendar/calendar_base.js +++ b/plugins/calendar/calendar_base.js @@ -31,6 +31,7 @@ function rcube_calendar(settings) // member vars this.ui; this.ui_loaded = false; + this.selected_attachment = null; // private vars var me = this; @@ -75,6 +76,20 @@ function rcube_calendar(settings) rcmail.message_list.blur(); } }; + + // handler for attachment-save-calendar commands + this.save_to_calendar = function(p) + { + // TODO: show dialog to select the calendar for importing + if (this.selected_attachment && window.rcube_libcalendaring) { + rcmail.http_post('calendar/mailimportattach', { + _uid: rcmail.env.uid, + _mbox: rcmail.env.mailbox, + _part: this.selected_attachment, + // _calendar: $('#calendar-attachment-saveto').val(), + }, rcmail.set_busy(true, 'itip.savingdata')); + } + } } @@ -86,6 +101,7 @@ window.rcmail && rcmail.addEventListener('init', function(evt) { // register create-from-mail command to message_commands array if (rcmail.env.task == 'mail') { rcmail.register_command('calendar-create-from-mail', function() { cal.create_from_mail() }); + rcmail.register_command('attachment-save-calendar', function() { cal.save_to_calendar() }); rcmail.addEventListener('plugin.mail2event_dialog', function(p){ cal.mail2event_dialog(p) }); rcmail.addEventListener('plugin.unlock_saving', function(p){ cal.ui && cal.ui.unlock_saving(); }); @@ -93,8 +109,17 @@ window.rcmail && rcmail.addEventListener('init', function(evt) { rcmail.env.message_commands.push('calendar-create-from-mail'); rcmail.add_element($('')); } - else + else { rcmail.enable_command('calendar-create-from-mail', true); + } + + rcmail.addEventListener('beforemenu-open', function(p) { + if (p.menu == 'attachmentmenu') { + cal.selected_attachment = p.id; + var mimetype = rcmail.env.attachments[p.id]; + rcmail.enable_command('attachment-save-calendar', mimetype == 'text/calendar' || mimetype == 'text/x-vcalendar' || mimetype == 'application/ics'); + } + }); // add contextmenu item if (window.rcm_contextmenu_register_command) { diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index cc8b3974..b243c24b 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -158,6 +158,7 @@ $labels['notanattendee'] = 'You\'re not listed as an attendee of this event'; $labels['eventcancelled'] = 'The event has been cancelled'; $labels['saveincalendar'] = 'save in'; $labels['updatemycopy'] = 'Update in my calendar'; +$labels['savetocalendar'] = 'Save to calendar'; // resources $labels['resource'] = 'Resource'; @@ -191,6 +192,7 @@ $labels['successremoval'] = 'The event has been deleted successfully.'; $labels['successrestore'] = 'The event has been restored successfully.'; $labels['errornotifying'] = 'Failed to send notifications to event participants'; $labels['errorimportingevent'] = 'Failed to import the event'; +$labels['importwarningexists'] = 'A copy of this event already exists in your calendar.'; $labels['newerversionexists'] = 'A newer version of this event already exists! Aborted.'; $labels['nowritecalendarfound'] = 'No calendar found to save the event'; $labels['importedsuccessfully'] = 'The event was successfully added to \'$calendar\''; diff --git a/plugins/calendar/skins/classic/calendar.css b/plugins/calendar/skins/classic/calendar.css index 346d61f4..87ef2da0 100644 --- a/plugins/calendar/skins/classic/calendar.css +++ b/plugins/calendar/skins/classic/calendar.css @@ -1379,7 +1379,8 @@ fieldset #calendarcategories div { /* Invitation UI in mail */ -#messagemenu li a.calendarlink { +#messagemenu li a.calendarlink, +#attachmentmenu li a.calendarlink { background-image: url(images/calendars.png); background-position: 7px -109px; background-repeat: no-repeat; diff --git a/plugins/calendar/skins/larry/calendar.css b/plugins/calendar/skins/larry/calendar.css index d2ade1a1..803ceb6f 100644 --- a/plugins/calendar/skins/larry/calendar.css +++ b/plugins/calendar/skins/larry/calendar.css @@ -1535,7 +1535,8 @@ fieldset #calendarcategories div { /* Invitation UI in mail */ -#messagemenu li a.calendarlink span.calendar { +#messagemenu li a.calendarlink span.calendar, +#attachmentmenu li a.calendarlink span.calendar { background-position: 0px -2197px; }