From 65cd18c1b7ef63514a05887750d2420a01b2907c Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Wed, 19 Mar 2014 21:13:06 +0100 Subject: [PATCH] Send CANCEL iTip message to declined attendees (with optional comment) --- plugins/calendar/calendar.php | 64 ++++++++++++++++--- plugins/calendar/localization/en_US.inc | 2 + .../lib/libcalendaring_itip.php | 7 +- plugins/libcalendaring/libcalendaring.js | 60 +++++++++++++---- plugins/libcalendaring/localization/en_US.inc | 7 +- plugins/libcalendaring/skins/larry/libcal.css | 8 +++ 6 files changed, 119 insertions(+), 29 deletions(-) diff --git a/plugins/calendar/calendar.php b/plugins/calendar/calendar.php index cd8567df..aa5e141e 100644 --- a/plugins/calendar/calendar.php +++ b/plugins/calendar/calendar.php @@ -144,6 +144,7 @@ class calendar extends rcube_plugin $this->register_action('check-recent', array($this, 'check_recent')); $this->register_action('itip-status', array($this, 'event_itip_status')); $this->register_action('itip-remove', array($this, 'event_itip_remove')); + $this->register_action('itip-decline-reply', array($this, 'mail_itip_decline_reply')); $this->register_action('resources-list', array($this, 'resources_list')); $this->register_action('resources-owner', array($this, 'resources_owner')); $this->register_action('resources-calendar', array($this, 'resources_calendar')); @@ -2222,18 +2223,10 @@ class calendar extends rcube_plugin } - /** - * Handler for POST request to import an event attached to a mail message - */ - public function mail_import_event() + private function mail_get_itip_event($mbox, $uid, $mime_id) { - $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); - $status = get_input_value('_status', RCUBE_INPUT_POST); - $delete = intval(get_input_value('_del', RCUBE_INPUT_POST)); $charset = RCMAIL_CHARSET; - + // establish imap connection $imap = $this->rc->get_storage(); $imap->set_mailbox($mbox); @@ -2253,6 +2246,26 @@ class calendar extends rcube_plugin // successfully parsed events? if (!empty($events) && ($event = $events[$index])) { + return $event; + } + } + + /** + * Handler for POST request to import an event attached to a mail message + */ + public function mail_import_event() + { + $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); + $status = get_input_value('_status', RCUBE_INPUT_POST); + $delete = intval(get_input_value('_del', RCUBE_INPUT_POST)); + + $error_msg = $this->gettext('errorimportingevent'); + $success = false; + + // successfully parsed events? + if ($event = $this->mail_get_itip_event($mbox, $uid, $mime_id)) { // find writeable calendar to store event $cal_id = !empty($_REQUEST['_folder']) ? get_input_value('_folder', RCUBE_INPUT_POST) : null; $calendars = $this->driver->list_calendars(false, true); @@ -2402,6 +2415,37 @@ class calendar extends rcube_plugin } + /** + * Handler for calendar/itip-remove requests + */ + function mail_itip_decline_reply() + { + $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); + + if (($event = $this->mail_get_itip_event($mbox, $uid, $mime_id)) && $this->ical->method == 'REPLY') { + $event['comment'] = get_input_value('_comment', RCUBE_INPUT_POST); + + foreach ($event['attendees'] as $_attendee) { + if ($_attendee['role'] != 'ORGANIZER') { + $attendee = $_attendee; + break; + } + } + + $itip = $this->load_itip(); + if ($itip->send_itip_message($event, 'CANCEL', $attendee, 'itipsubjectcancel', 'itipmailbodycancel')) + $this->rc->output->command('display_message', $this->gettext(array('name' => 'sentresponseto', 'vars' => array('mailto' => $attendee['name'] ? $attendee['name'] : $attendee['email']))), 'confirmation'); + else + $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); + } + else { + $this->rc->output->command('display_message', $this->gettext('itipresponseerror'), 'error'); + } + } + + /** * Read email message and return contents for a new event based on that message */ diff --git a/plugins/calendar/localization/en_US.inc b/plugins/calendar/localization/en_US.inc index de8e7dd6..04847ed2 100644 --- a/plugins/calendar/localization/en_US.inc +++ b/plugins/calendar/localization/en_US.inc @@ -149,6 +149,8 @@ $labels['itipobjectnotfound'] = 'The event referred by this message was not foun $labels['itipmailbodyaccepted'] = "\$sender has accepted the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees"; $labels['itipmailbodytentative'] = "\$sender has tentatively accepted the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees"; $labels['itipmailbodydeclined'] = "\$sender has declined the invitation to the following event:\n\n*\$title*\n\nWhen: \$date\n\nInvitees: \$attendees"; +$labels['itipmailbodycancel'] = "\$sender has rejected your participation in the following event:\n\n*\$title*\n\nWhen: \$date\n\n\$comment"; + $labels['itipdeclineevent'] = 'Do you want to decline your invitation to this event?'; $labels['declinedeleteconfirm'] = 'Do you also want to delete this declined event from your calendar?'; diff --git a/plugins/libcalendaring/lib/libcalendaring_itip.php b/plugins/libcalendaring/lib/libcalendaring_itip.php index 2fed51f9..c5a4afa6 100644 --- a/plugins/libcalendaring/lib/libcalendaring_itip.php +++ b/plugins/libcalendaring/lib/libcalendaring_itip.php @@ -115,6 +115,7 @@ class libcalendaring_itip 'attendees' => join(', ', $attendees_list), 'sender' => $this->sender['name'], 'organizer' => $this->sender['name'], + 'comment' => $event['comment'], ) )); @@ -465,9 +466,9 @@ class libcalendaring_itip $this->rc->output->add_script("rcube_libcalendaring.fetch_itip_object_status(" . json_serialize($metadata) . ")", 'docready'); // get localized texts from the right domain - $this->rc->output->command('add_label', 'itip.savingdata', $this->gettext('savingdata')); - $this->rc->output->command('add_label', 'itip.declinedeleteconfirm', $this->gettext('declinedeleteconfirm')); - $this->rc->output->command('add_label', 'itip.declinedeleteconfirm', $this->gettext('declinedeleteconfirm')); + foreach (array('savingdata','deleteobjectconfirm','declinedeleteconfirm','declineattendee','declineattendeeconfirm','cancel') as $label) { + $this->rc->output->command('add_label', "itip.$label", $this->gettext($label)); + } // show event details with buttons return $this->itip_object_details_table($event, $title) . diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js index 4acb9425..931a464d 100644 --- a/plugins/libcalendaring/libcalendaring.js +++ b/plugins/libcalendaring/libcalendaring.js @@ -449,12 +449,12 @@ rcube_libcalendaring.add_from_itip_mail = function(mime_id, task, status) } rcmail.http_post(task + '/mailimportitip', { - '_uid': rcmail.env.uid, - '_mbox': rcmail.env.mailbox, - '_part': mime_id, - '_folder': $('#itip-saveto').val(), - '_status': status, - '_del': del?1:0 + _uid: rcmail.env.uid, + _mbox: rcmail.env.mailbox, + _part: mime_id, + _folder: $('#itip-saveto').val(), + _status: status, + _del: del?1:0 }, rcmail.set_busy(true, 'itip.savingdata')); return false; @@ -465,21 +465,53 @@ rcube_libcalendaring.add_from_itip_mail = function(mime_id, task, status) */ rcube_libcalendaring.remove_from_itip = function(uid, task, title) { - if (confirm(rcmail.gettext('itip.deleteobjectconfirm').replace('$title', title))) { - rcmail.http_post(task + '/itip-remove', - { uid: uid }, - rcmail.set_busy(true, 'itip.savingdata')); - } + if (confirm(rcmail.gettext('itip.deleteobjectconfirm').replace('$title', title))) { + rcmail.http_post(task + '/itip-remove', + { uid: uid }, + rcmail.set_busy(true, 'itip.savingdata') + ); + } }; /** * */ -rcube_libcalendaring.decline_attendee_reply = function(mime_id) +rcube_libcalendaring.decline_attendee_reply = function(mime_id, task) { - // TODO: show dialog for entering a comment and send to server + // show dialog for entering a comment and send to server + var html = '
' + rcmail.gettext('itip.declineattendeeconfirm') + '
' + + ''; - return false; + var dialog, buttons = []; + buttons.push({ + text: rcmail.gettext('declineattendee', 'itip'), + click: function() { + rcmail.http_post(task + '/itip-decline-reply', { + _uid: rcmail.env.uid, + _mbox: rcmail.env.mailbox, + _part: mime_id, + _comment: $('#itip-decline-comment', window.parent.document).val() + }, rcmail.set_busy(true, 'itip.savingdata')); + dialog.dialog("close"); + } + }); + + buttons.push({ + text: rcmail.gettext('cancel', 'itip'), + click: function() { + dialog.dialog('close'); + } + }); + + dialog = rcmail.show_popup_dialog(html, rcmail.gettext('declineattendee', 'itip'), buttons, { + width: 460, + open: function() { + $(this).parent().find('.ui-button').first().addClass('mainaction'); + $('#itip-decline-comment').focus(); + } + }); + + return false; }; /** diff --git a/plugins/libcalendaring/localization/en_US.inc b/plugins/libcalendaring/localization/en_US.inc index ea0ad10e..7392e8f2 100644 --- a/plugins/libcalendaring/localization/en_US.inc +++ b/plugins/libcalendaring/localization/en_US.inc @@ -41,12 +41,15 @@ $labels['itipobjectnotfound'] = 'The object referred by this message was not fou $labels['itipsubjectaccepted'] = '"$title" has been accepted by $name'; $labels['itipsubjecttentative'] = '"$title" has been tentatively accepted by $name'; $labels['itipsubjectdeclined'] = '"$title" has been declined by $name'; +$labels['itipsubjectcancel'] = 'Your participation in "$title" has been cancelled'; $labels['itipnewattendee'] = 'This is a reply from a new participant'; $labels['updateattendeestatus'] = 'Update the participant\'s status'; $labels['acceptinvitation'] = 'Do you accept this invitation?'; -$labels['acceptattendee'] = 'Accept attendee'; -$labels['declineattendee'] = 'Decline attendee'; +$labels['acceptattendee'] = 'Accept participant'; +$labels['declineattendee'] = 'Decline participant'; +$labels['declineattendeeconfirm'] = 'Enter a message to the declined participant (optional):'; + $labels['youhaveaccepted'] = 'You have accepted this invitation'; $labels['youhavetentative'] = 'You have tentatively accepted this invitation'; $labels['youhavedeclined'] = 'You have declined this invitation'; diff --git a/plugins/libcalendaring/skins/larry/libcal.css b/plugins/libcalendaring/skins/larry/libcal.css index 1e3a4c88..47323a60 100644 --- a/plugins/libcalendaring/skins/larry/libcal.css +++ b/plugins/libcalendaring/skins/larry/libcal.css @@ -52,3 +52,11 @@ span.edit-alarm-set { width: 20px; height: 16px; } + +.itip-dialog-confirm-text { + margin-bottom: 1em; +} + +.popup textarea.itip-comment { + width: 98%; +} \ No newline at end of file