diff --git a/plugins/libcalendaring/lib/libcalendaring_itip.php b/plugins/libcalendaring/lib/libcalendaring_itip.php index 4c5ecafd..1b0788c7 100644 --- a/plugins/libcalendaring/lib/libcalendaring_itip.php +++ b/plugins/libcalendaring/lib/libcalendaring_itip.php @@ -374,7 +374,7 @@ class libcalendaring_itip { $action = $event['rsvp'] ? 'rsvp' : ''; $status = $event['fallback']; - $latest = $resheduled = false; + $latest = $rescheduled = false; $html = ''; if (is_numeric($event['changed'])) @@ -404,7 +404,7 @@ class libcalendaring_itip if (!$latest) { // FIXME: This is probably to simplistic, or maybe we should just check // attendee's RSVP flag in the new event? - $resheduled = $existing['start'] != $event['start'] || $existing['end'] > $event['end']; + $rescheduled = $existing['start'] != $event['start'] || $existing['end'] > $event['end']; } } else { @@ -428,10 +428,16 @@ class libcalendaring_itip else if (!$existing && !$rsvp) { $action = 'import'; } - else if ($resheduled) { + else if ($rescheduled) { $action = 'rsvp'; } else if ($status_lc != 'needs-action') { + // check if there are any changes + if ($latest) { + $diff = $this->get_itip_diff($event, $existing); + $latest = empty($diff); + } + $action = !$latest ? 'update' : ''; } @@ -485,11 +491,69 @@ class libcalendaring_itip 'latest' => $latest, 'status' => $status, 'action' => $action, - 'resheduled' => $resheduled, + 'rescheduled' => $rescheduled, 'html' => $html, ); } + protected function get_itip_diff($event, $existing) + { + if (empty($event) || empty($existing) || empty($event['message_uid'])) { + return; + } + + $itip = $this->lib->mail_get_itip_object($event['mbox'], $event['message_uid'], $event['mime_id'], + $event['task'] == 'calendar' ? 'event' : 'task'); + + if ($itip) { + // List of properties that could change without SEQUENCE bump + $attrs = array('description', 'title', 'location', 'url'); + $diff = array(); + + foreach ($attrs as $attr) { + if (isset($itip[$attr]) && $itip[$attr] != $existing[$attr]) { + $diff[$attr] = array( + 'new' => $itip[$attr], + 'old' => $existing[$attr] + ); + } + } + + $status = array(); + $itip_attendees = array(); + $existing_attendees = array(); + $emails = $this->lib->get_user_emails(); + + // Compare list of attendees (ignoring current user status) + foreach ((array) $existing['attendees'] as $idx => $attendee) { + if ($attendee['email'] && in_array(strtolower($attendee['email']), $emails)) { + $status[strtolower($attendee['email'])] = $attendee['status']; + } + if ($attendee['role'] == 'ORGANIZER') { + $attendee['status'] = 'ACCEPTED'; // sometimes is not set for exceptions + $existing['attendees'][$idx] = $attendee; + } + $existing_attendees[] = $attendee['email'].$attendee['name']; + } + foreach ((array) $itip['attendees'] as $idx => $attendee) { + if ($attendee['email'] && ($_status = $status[strtolower($attendee['email'])])) { + $attendee['status'] = $_status; + $itip['attendees'][$idx] = $attendee; + } + $itip_attendees[] = $attendee['email'].$attendee['name']; + } + + if ($itip_attendees != $existing_attendees) { + $diff['attendees'] = array( + 'new' => $itip['attendees'], + 'old' => $existing['attendees'] + ); + } + + return $diff; + } + } + /** * Build inline UI elements for iTip messages */ @@ -508,6 +572,7 @@ class libcalendaring_itip 'sequence' => intval($event['sequence']), 'method' => $method, 'task' => $task, + 'mime_id' => $mime_id, ); // create buttons to be activated from async request checking existence of this event in local calendars diff --git a/plugins/libcalendaring/libcalendaring.js b/plugins/libcalendaring/libcalendaring.js index caae913b..a5f3ef14 100644 --- a/plugins/libcalendaring/libcalendaring.js +++ b/plugins/libcalendaring/libcalendaring.js @@ -1325,6 +1325,8 @@ rcube_libcalendaring.decline_attendee_reply = function(mime_id, task) */ rcube_libcalendaring.fetch_itip_object_status = function(p) { + p.mbox = rcmail.env.mailbox; + p.message_uid = rcmail.env.uid; rcmail.http_post(p.task + '/itip-status', { data: p }); }; @@ -1356,7 +1358,7 @@ rcube_libcalendaring.update_itip_object_status = function(p) $('#'+p.action+'-'+p.id).show().find('input.button').last().after(p.select); // highlight date if date change detected - if (p.resheduled) + if (p.rescheduled) $('.calendar-eventdetails td.date').addClass('modified'); // show itip box appendix after replacing the given placeholders