diff --git a/lib/kolab_sync_data_calendar.php b/lib/kolab_sync_data_calendar.php --- a/lib/kolab_sync_data_calendar.php +++ b/lib/kolab_sync_data_calendar.php @@ -184,6 +184,7 @@ $event = is_array($serverId) ? $serverId : $this->getObject($collection->collectionId, $serverId); $config = $this->getFolderConfig($event['_mailbox']); $result = array(); + $is_outlook = stripos($this->device->devicetype, 'outlook') !== false; // Kolab Format 3.0 and xCal does support timezone per-date, but ActiveSync allows // only one timezone per-event. We'll use timezone of the start date @@ -231,7 +232,7 @@ break; case 'free_busy': - if (!empty($value)) { + if (!$is_outlook && !empty($value)) { $value = $this->busyStatusMap[$value]; } break; @@ -314,6 +315,17 @@ if ($email && in_array_nocase($email, $user_emails)) { $user_rsvp = !empty($attendee['rsvp']); $resp_type = $status ?: self::ATTENDEE_STATUS_UNKNOWN; + + // Synchronize the attendee status to the event status to get the same behaviour as outlook. + if ($is_outlook) { + if ($attendee['status'] == 'ACCEPTED') { + $result['busyStatus'] = self::BUSY_STATUS_BUSY; + } + if ($attendee['status'] == 'TENTATIVE') { + $result['busyStatus'] = self::BUSY_STATUS_TENTATIVE; + } + } + } $result['attendees'][] = new Syncroton_Model_EventAttendee($att); @@ -438,6 +450,11 @@ break; case 'free_busy': + // Outlook sets the busy state to the attendance state, and we don't want to change the event state based on that. + // Outlook doesn't have the concept of an event state, so we just ignore this. + if ($is_outlook) { + continue 2; + } $map = array_flip($this->busyStatusMap); $value = isset($map[$value]) ? $map[$value] : null; break; @@ -545,6 +562,22 @@ } } + // Outlook does not send the correct attendee status when changing between accepted and tentative, but it toggles the busyStatus. + if ($is_outlook) { + $status = null; + if ($data->busyStatus == self::BUSY_STATUS_BUSY) { + $status = "ACCEPTED"; + } else if ($data->busyStatus == self::BUSY_STATUS_TENTATIVE) { + $status = "TENTATIVE"; + } + + if ($status) { + $this->logger->debug("Updating our attendee status based on the busy status to {$status}."); + $emails = $this->user_emails(); + $this->find_and_update_attendee_status($attendees, $status, $emails); + } + } + if (!$is_exception) { // Make sure the event has the organizer set if (!$organizer_email && ($identity = kolab_sync::get_instance()->user->get_identity())) { @@ -560,6 +593,7 @@ } $event['attendees'] = $attendees; + $event['categories'] = $categories; $event['exceptions'] = isset($event['recurrence']['EXCEPTIONS']) ? $event['recurrence']['EXCEPTIONS'] : array(); @@ -809,25 +843,33 @@ } /** - * Update the attendee status of the user + * Update the attendee status of the user matching $emails */ - protected function update_attendee_status(&$event, $status) + protected function find_and_update_attendee_status(&$attendees, $status, $emails) { - $emails = $this->user_emails(); - - foreach ((array) $event['attendees'] as $i => $attendee) { + $found = false; + foreach ((array) $attendees as $i => $attendee) { if (!empty($attendee['email']) && (empty($attendee['role']) || $attendee['role'] != 'ORGANIZER') && in_array_nocase($attendee['email'], $emails) ) { - $event['attendees'][$i]['status'] = $status; - $event['attendees'][$i]['rsvp'] = false; - $event_attendee = $attendee; + $attendees[$i]['status'] = $status; + $attendees[$i]['rsvp'] = false; $this->logger->debug('Updating existing attendee: ' . $attendee['email'] . ' status: ' . $status); + $found = true; } } + return $found; + } + + /** + * Update the attendee status of the user + */ + protected function update_attendee_status(&$event, $status) + { + $emails = $this->user_emails(); - if (empty($event_attendee)) { + if (!$this->find_and_update_attendee_status($event['attendees'], $status, $emails)) { $this->logger->debug('Adding new attendee ' . $emails[0] . ' status: ' . $status); // Add the user to the attendees list $event['attendees'][] = array(