/** * Checks if there has been any significant changes on appointment/meeting item. * Significant changes be: * 1) startdate has been changed * 2) duedate has been changed OR * 3) recurrence pattern has been created, modified or removed * * @param Array oldProps old props before an update * @param Number basedate basedate * @param Boolean isRecurrenceChanged for change in recurrence pattern. * isRecurrenceChanged true means Recurrence pattern has been changed, so clear all attendees response */ function checkSignificantChanges($oldProps, $basedate, $isRecurrenceChanged = false) { $message = null; $attach = null; // If basedate is specified then we need to open exception message to clear recipient responses if ($basedate) { $recurrence = new Recurrence($this->store, $this->message); if ($recurrence->isException($basedate)) { $attach = $recurrence->getExceptionAttachment($basedate); if ($attach) { $message = mapi_attach_openobj($attach, MAPI_MODIFY); } } } else { // use normal message or recurring series message $message = $this->message; } if (!$message) { return; } $newProps = mapi_getprops($message, array($this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['updatecounter'])); // Check whether message is updated or not. if (isset($newProps[$this->proptags['updatecounter']]) && $newProps[$this->proptags['updatecounter']] == 0) { return; } if ($newProps[$this->proptags['startdate']] != $oldProps[$this->proptags['startdate']] || $newProps[$this->proptags['duedate']] != $oldProps[$this->proptags['duedate']] || $isRecurrenceChanged) { $this->clearRecipientResponse($message); mapi_setprops($message, array($this->proptags['owner_critical_change'] => time())); mapi_savechanges($message); if ($attach) { // Also save attachment Object. mapi_savechanges($attach); } } }
/** * Reads recurrence information from MAPI * * @param mixed $mapimessage * @param array $recurprops * @param SyncObject &$syncMessage the message * @param SyncObject &$syncRecurrence the recurrence message * @param array $tz timezone information * * @access private * @return */ private function getRecurrence($mapimessage, $recurprops, &$syncMessage, &$syncRecurrence, $tz) { if ($syncRecurrence instanceof SyncTaskRecurrence) { $recurrence = new TaskRecurrence($this->store, $mapimessage); } else { $recurrence = new Recurrence($this->store, $mapimessage); } switch ($recurrence->recur["type"]) { case 10: // daily switch ($recurrence->recur["subtype"]) { default: $syncRecurrence->type = 0; break; case 1: $syncRecurrence->type = 0; $syncRecurrence->dayofweek = 62; // mon-fri $syncRecurrence->interval = 1; break; } break; case 11: // weekly $syncRecurrence->type = 1; break; case 12: // monthly switch ($recurrence->recur["subtype"]) { default: $syncRecurrence->type = 2; break; case 3: $syncRecurrence->type = 3; break; } break; case 13: // yearly switch ($recurrence->recur["subtype"]) { default: $syncRecurrence->type = 4; break; case 2: $syncRecurrence->type = 5; break; case 3: $syncRecurrence->type = 6; } } // Termination switch ($recurrence->recur["term"]) { case 0x21: $syncRecurrence->until = $recurrence->recur["end"]; // fixes Mantis #350 : recur-end does not consider timezones - use ClipEnd if available if (isset($recurprops[$recurrence->proptags["enddate_recurring"]])) { $syncRecurrence->until = $recurprops[$recurrence->proptags["enddate_recurring"]]; } // add one day (minus 1 sec) to the end time to make sure the last occurrence is covered $syncRecurrence->until += 86399; break; case 0x22: $syncRecurrence->occurrences = $recurrence->recur["numoccur"]; break; case 0x23: // never ends break; } // Correct 'alldayevent' because outlook fails to set it on recurring items of 24 hours or longer if (isset($recurrence->recur["endocc"], $recurrence->recur["startocc"]) && $recurrence->recur["endocc"] - $recurrence->recur["startocc"] >= 1440) { $syncMessage->alldayevent = true; } // Interval is different according to the type/subtype switch ($recurrence->recur["type"]) { case 10: if ($recurrence->recur["subtype"] == 0) { $syncRecurrence->interval = (int) ($recurrence->recur["everyn"] / 1440); } // minutes break; case 11: case 12: $syncRecurrence->interval = $recurrence->recur["everyn"]; break; // months / weeks // months / weeks case 13: $syncRecurrence->interval = (int) ($recurrence->recur["everyn"] / 12); break; // months } if (isset($recurrence->recur["weekdays"])) { $syncRecurrence->dayofweek = $recurrence->recur["weekdays"]; } // bitmask of days (1 == sunday, 128 == saturday if (isset($recurrence->recur["nday"])) { $syncRecurrence->weekofmonth = $recurrence->recur["nday"]; } // N'th {DAY} of {X} (0-5) if (isset($recurrence->recur["month"])) { $syncRecurrence->monthofyear = (int) ($recurrence->recur["month"] / (60 * 24 * 29)) + 1; } // works ok due to rounding. see also $monthminutes below (1-12) if (isset($recurrence->recur["monthday"])) { $syncRecurrence->dayofmonth = $recurrence->recur["monthday"]; } // day of month (1-31) // All changed exceptions are appointments within the 'exceptions' array. They contain the same items as a normal appointment foreach ($recurrence->recur["changed_occurences"] as $change) { $exception = new SyncAppointmentException(); // start, end, basedate, subject, remind_before, reminderset, location, busystatus, alldayevent, label if (isset($change["start"])) { $exception->starttime = $this->getGMTTimeByTZ($change["start"], $tz); } if (isset($change["end"])) { $exception->endtime = $this->getGMTTimeByTZ($change["end"], $tz); } if (isset($change["basedate"])) { $exception->exceptionstarttime = $this->getGMTTimeByTZ($this->getDayStartOfTimestamp($change["basedate"]) + $recurrence->recur["startocc"] * 60, $tz); //open body because getting only property might not work because of memory limit $exceptionatt = $recurrence->getExceptionAttachment($change["basedate"]); if ($exceptionatt) { $exceptionobj = mapi_attach_openobj($exceptionatt, 0); $this->setMessageBodyForType($exceptionobj, SYNC_BODYPREFERENCE_PLAIN, $exception); } } if (isset($change["subject"])) { $exception->subject = w2u($change["subject"]); } if (isset($change["reminder_before"]) && $change["reminder_before"]) { $exception->reminder = $change["remind_before"]; } if (isset($change["location"])) { $exception->location = w2u($change["location"]); } if (isset($change["busystatus"])) { $exception->busystatus = $change["busystatus"]; } if (isset($change["alldayevent"])) { $exception->alldayevent = $change["alldayevent"]; } // set some data from the original appointment if (isset($syncMessage->uid)) { $exception->uid = $syncMessage->uid; } if (isset($syncMessage->organizername)) { $exception->organizername = $syncMessage->organizername; } if (isset($syncMessage->organizeremail)) { $exception->organizeremail = $syncMessage->organizeremail; } if (!isset($syncMessage->exceptions)) { $syncMessage->exceptions = array(); } array_push($syncMessage->exceptions, $exception); } // Deleted appointments contain only the original date (basedate) and a 'deleted' tag foreach ($recurrence->recur["deleted_occurences"] as $deleted) { $exception = new SyncAppointmentException(); $exception->exceptionstarttime = $this->getGMTTimeByTZ($this->getDayStartOfTimestamp($deleted) + $recurrence->recur["startocc"] * 60, $tz); $exception->deleted = "1"; if (!isset($syncMessage->exceptions)) { $syncMessage->exceptions = array(); } array_push($syncMessage->exceptions, $exception); } if (isset($syncMessage->complete) && $syncMessage->complete) { $syncRecurrence->complete = $syncMessage->complete; } }
/** * Function returns exception item based on the basedate passed. * @param MAPIMessage $recurringMessage Resource of Recurring meeting from calendar * @param Unixtime $basedate basedate of exception that needs to be returned. * @param MAPIStore $store store that contains the recurring calendar item. * @return entryid or MAPIMessage resource of exception item. */ function getExceptionItem($recurringMessage, $basedate, $store = false) { $occurItem = false; $props = mapi_getprops($this->message, array(PR_RCVD_REPRESENTING_NAME, $this->proptags['recurring'])); // check if the passed item is recurring series if ($props[$this->proptags['recurring']] !== false) { return false; } if ($store === false) { // If Delegate is processing Meeting Request/Response for Delegator then retrieve Delegator's store and calendar. if (isset($props[PR_RCVD_REPRESENTING_NAME])) { $delegatorStore = $this->getDelegatorStore($props[PR_RCVD_REPRESENTING_NAME]); $store = $delegatorStore['store']; } else { $store = $this->store; } } $recurr = new Recurrence($store, $recurringMessage); $attach = $recurr->getExceptionAttachment($basedate); if ($attach) { $occurItem = mapi_attach_openobj($attach); } return $occurItem; }