/** * Function which save an exception into recurring item * * @param resource $recurringItem reference to MAPI_message of recurring item * @param resource $occurrenceItem reference to MAPI_message of occurrence * @param string $basedate basedate of occurrence * @param boolean $move if true then occurrence item is deleted * @param boolean $tentative true if user has tentatively accepted it or false if user has accepted it. * @param boolean $userAction true if user has manually responded to meeting request * @param resource $store user store * @param boolean $isDelegate true if delegate is processing this meeting request */ function acceptException(&$recurringItem, &$occurrenceItem, $basedate, $move = false, $tentative, $userAction = false, $store, $isDelegate = false) { $recurr = new Recurrence($store, $recurringItem); // Copy properties from meeting request $exception_props = mapi_getprops($occurrenceItem); // Copy recipients list $reciptable = mapi_message_getrecipienttable($occurrenceItem); // If delegate, then do not add the delegate in recipients if ($isDelegate) { $delegate = mapi_getprops($this->message, array(PR_RECEIVED_BY_EMAIL_ADDRESS)); $res = array(RES_PROPERTY, array(RELOP => RELOP_NE, ULPROPTAG => PR_EMAIL_ADDRESS, VALUE => $delegate[PR_RECEIVED_BY_EMAIL_ADDRESS])); $recips = mapi_table_queryallrows($reciptable, $this->recipprops, $res); } else { $recips = mapi_table_queryallrows($reciptable, $this->recipprops); } // add owner to recipient table $this->addOrganizer($exception_props, $recips, true); // add delegator to meetings if ($isDelegate) { $this->addDelegator($exception_props, $recips); } $exception_props[$this->proptags['meetingstatus']] = olMeetingReceived; $exception_props[$this->proptags['responsestatus']] = $userAction ? $tentative ? olResponseTentative : olResponseAccepted : olResponseNotResponded; // Set basedate property (ExceptionReplaceTime) if (isset($exception_props[$this->proptags['intendedbusystatus']])) { if ($tentative && $exception_props[$this->proptags['intendedbusystatus']] !== fbFree) { $exception_props[$this->proptags['busystatus']] = $tentative; } else { $exception_props[$this->proptags['busystatus']] = $exception_props[$this->proptags['intendedbusystatus']]; } // we already have intendedbusystatus value in $exception_props so no need to copy it } else { $exception_props[$this->proptags['busystatus']] = $tentative ? fbTentative : fbBusy; } if ($userAction) { // if user has responded then set replytime $exception_props[$this->proptags['replytime']] = time(); } if ($recurr->isException($basedate)) { $recurr->modifyException($exception_props, $basedate, $recips, $occurrenceItem); } else { $recurr->createException($exception_props, $basedate, false, $recips, $occurrenceItem); } // Move the occurrenceItem to the waste basket if ($move) { $wastebasket = $this->openDefaultWastebasket(); $sourcefolder = mapi_msgstore_openentry($this->store, $exception_props[PR_PARENT_ENTRYID]); mapi_folder_copymessages($sourcefolder, array($exception_props[PR_ENTRYID]), $wastebasket, MESSAGE_MOVE); } mapi_savechanges($recurringItem); }
/** * Writes a SyncAppointment to MAPI * * @param mixed $mapimessage * @param SyncAppointment $message * * @access private * @return boolean */ private function setAppointment($mapimessage, $appointment) { // Get timezone info if (isset($appointment->timezone)) { $tz = $this->getTZFromSyncBlob(base64_decode($appointment->timezone)); } else { $tz = false; } //calculate duration because without it some webaccess views are broken. duration is in min $localstart = $this->getLocaltimeByTZ($appointment->starttime, $tz); $localend = $this->getLocaltimeByTZ($appointment->endtime, $tz); $duration = ($localend - $localstart) / 60; //nokia sends an yearly event with 0 mins duration but as all day event, //so make it end next day if ($appointment->starttime == $appointment->endtime && isset($appointment->alldayevent) && $appointment->alldayevent) { $duration = 1440; $appointment->endtime = $appointment->starttime + 24 * 60 * 60; $localend = $localstart + 24 * 60 * 60; } // is the transmitted UID OL compatible? // if not, encapsulate the transmitted uid $appointment->uid = Utils::GetOLUidFromICalUid($appointment->uid); mapi_setprops($mapimessage, array(PR_MESSAGE_CLASS => "IPM.Appointment")); $appointmentmapping = MAPIMapping::GetAppointmentMapping(); $this->setPropsInMAPI($mapimessage, $appointment, $appointmentmapping); $appointmentprops = MAPIMapping::GetAppointmentProperties(); $appointmentprops = array_merge($this->getPropIdsFromStrings($appointmentmapping), $this->getPropIdsFromStrings($appointmentprops)); //appointment specific properties to be set $props = array(); //we also have to set the responsestatus and not only meetingstatus, so we use another mapi tag $props[$appointmentprops["responsestatus"]] = isset($appointment->responsestatus) ? $appointment->responsestatus : olResponseNone; //sensitivity is not enough to mark an appointment as private, so we use another mapi tag $private = isset($appointment->sensitivity) && $appointment->sensitivity == 0 ? false : true; // Set commonstart/commonend to start/end and remindertime to start, duration, private and cleanGlobalObjectId $props[$appointmentprops["commonstart"]] = $appointment->starttime; $props[$appointmentprops["commonend"]] = $appointment->endtime; $props[$appointmentprops["reminderstart"]] = $appointment->starttime; // Set reminder boolean to 'true' if reminder is set $props[$appointmentprops["reminderset"]] = isset($appointment->reminder) ? true : false; $props[$appointmentprops["duration"]] = $duration; $props[$appointmentprops["private"]] = $private; $props[$appointmentprops["uid"]] = $appointment->uid; // Set named prop 8510, unknown property, but enables deleting a single occurrence of a recurring // type in OLK2003. $props[$appointmentprops["sideeffects"]] = 369; if (isset($appointment->reminder) && $appointment->reminder >= 0) { // Set 'flagdueby' to correct value (start - reminderminutes) $props[$appointmentprops["flagdueby"]] = $appointment->starttime - $appointment->reminder * 60; $props[$appointmentprops["remindertime"]] = $appointment->reminder; } else { $props[$appointmentprops["reminderset"]] = false; } if (isset($appointment->asbody)) { $this->setASbody($appointment->asbody, $props, $appointmentprops); } if (isset($appointment->recurrence)) { // Set PR_ICON_INDEX to 1025 to show correct icon in category view $props[$appointmentprops["icon"]] = 1025; //if there aren't any exceptions, use the 'old style' set recurrence $noexceptions = true; $recurrence = new Recurrence($this->store, $mapimessage); $recur = array(); $this->setRecurrence($appointment, $recur); // set the recurrence type to that of the MAPI $props[$appointmentprops["recurrencetype"]] = $recur["recurrencetype"]; $starttime = $this->gmtime($localstart); $endtime = $this->gmtime($localend); //set recurrence start here because it's calculated differently for tasks and appointments $recur["start"] = $this->getDayStartOfTimestamp($this->getGMTTimeByTZ($localstart, $tz)); $recur["startocc"] = $starttime["tm_hour"] * 60 + $starttime["tm_min"]; $recur["endocc"] = $recur["startocc"] + $duration; // Note that this may be > 24*60 if multi-day //only tasks can regenerate $recur["regen"] = false; // Process exceptions. The PDA will send all exceptions for this recurring item. if (isset($appointment->exceptions)) { foreach ($appointment->exceptions as $exception) { // we always need the base date if (!isset($exception->exceptionstarttime)) { continue; } if (isset($exception->deleted) && $exception->deleted) { // Delete exception if (!isset($recur["deleted_occurences"])) { $recur["deleted_occurences"] = array(); } array_push($recur["deleted_occurences"], $this->getDayStartOfTimestamp($exception->exceptionstarttime)); } else { // Change exception $basedate = $this->getDayStartOfTimestamp($exception->exceptionstarttime); $mapiexception = array("basedate" => $basedate); //other exception properties which are not handled in recurrence $exceptionprops = array(); if (isset($exception->starttime)) { $mapiexception["start"] = $this->getLocaltimeByTZ($exception->starttime, $tz); $exceptionprops[$appointmentprops["starttime"]] = $exception->starttime; } if (isset($exception->endtime)) { $mapiexception["end"] = $this->getLocaltimeByTZ($exception->endtime, $tz); $exceptionprops[$appointmentprops["endtime"]] = $exception->endtime; } if (isset($exception->subject)) { $exceptionprops[$appointmentprops["subject"]] = $mapiexception["subject"] = u2w($exception->subject); } if (isset($exception->location)) { $exceptionprops[$appointmentprops["location"]] = $mapiexception["location"] = u2w($exception->location); } if (isset($exception->busystatus)) { $exceptionprops[$appointmentprops["busystatus"]] = $mapiexception["busystatus"] = $exception->busystatus; } if (isset($exception->reminder)) { $exceptionprops[$appointmentprops["reminderset"]] = $mapiexception["reminder_set"] = 1; $exceptionprops[$appointmentprops["remindertime"]] = $mapiexception["remind_before"] = $exception->reminder; } if (isset($exception->alldayevent)) { $exceptionprops[$appointmentprops["alldayevent"]] = $mapiexception["alldayevent"] = $exception->alldayevent; } if (!isset($recur["changed_occurences"])) { $recur["changed_occurences"] = array(); } if (isset($exception->body)) { $exceptionprops[$appointmentprops["body"]] = u2w($exception->body); } array_push($recur["changed_occurences"], $mapiexception); if (!empty($exceptionprops)) { $noexceptions = false; if ($recurrence->isException($basedate)) { $recurrence->modifyException($exceptionprops, $basedate); } else { $recurrence->createException($exceptionprops, $basedate); } } } } } //setRecurrence deletes the attachments from an appointment if ($noexceptions) { $recurrence->setRecurrence($tz, $recur); } } else { $props[$appointmentprops["isrecurring"]] = false; } //always set the PR_SENT_REPRESENTING_* props so that the attendee status update also works with the webaccess $p = array($appointmentprops["representingentryid"], $appointmentprops["representingname"], $appointmentprops["sentrepresentingaddt"], $appointmentprops["sentrepresentingemail"], $appointmentprops["sentrepresentinsrchk"]); $representingprops = $this->getProps($mapimessage, $p); if (!isset($representingprops[$appointmentprops["representingentryid"]])) { $props[$appointmentprops["representingname"]] = Request::GetAuthUser(); $props[$appointmentprops["sentrepresentingemail"]] = Request::GetAuthUser(); $props[$appointmentprops["sentrepresentingaddt"]] = "ZARAFA"; $props[$appointmentprops["representingentryid"]] = mapi_createoneoff(Request::GetAuthUser(), "ZARAFA", Request::GetAuthUser()); $props[$appointmentprops["sentrepresentinsrchk"]] = $props[$appointmentprops["sentrepresentingaddt"]] . ":" . $props[$appointmentprops["sentrepresentingemail"]]; } // Do attendees if (isset($appointment->attendees) && is_array($appointment->attendees)) { $recips = array(); // Outlook XP requires organizer in the attendee list as well $org = array(); $org[PR_ENTRYID] = isset($representingprops[$appointmentprops["representingentryid"]]) ? $representingprops[$appointmentprops["representingentryid"]] : $props[$appointmentprops["representingentryid"]]; $org[PR_DISPLAY_NAME] = isset($representingprops[$appointmentprops["representingname"]]) ? $representingprops[$appointmentprops["representingname"]] : $props[$appointmentprops["representingname"]]; $org[PR_ADDRTYPE] = isset($representingprops[$appointmentprops["sentrepresentingaddt"]]) ? $representingprops[$appointmentprops["sentrepresentingaddt"]] : $props[$appointmentprops["sentrepresentingaddt"]]; $org[PR_EMAIL_ADDRESS] = isset($representingprops[$appointmentprops["sentrepresentingemail"]]) ? $representingprops[$appointmentprops["sentrepresentingemail"]] : $props[$appointmentprops["sentrepresentingemail"]]; $org[PR_SEARCH_KEY] = isset($representingprops[$appointmentprops["sentrepresentinsrchk"]]) ? $representingprops[$appointmentprops["sentrepresentinsrchk"]] : $props[$appointmentprops["sentrepresentinsrchk"]]; $org[PR_RECIPIENT_FLAGS] = recipOrganizer | recipSendable; $org[PR_RECIPIENT_TYPE] = MAPI_TO; array_push($recips, $org); //open addresss book for user resolve $addrbook = $this->getAddressbook(); foreach ($appointment->attendees as $attendee) { $recip = array(); $recip[PR_EMAIL_ADDRESS] = u2w($attendee->email); // lookup information in GAB if possible so we have up-to-date name for given address $userinfo = array(array(PR_DISPLAY_NAME => $recip[PR_EMAIL_ADDRESS])); $userinfo = mapi_ab_resolvename($addrbook, $userinfo, EMS_AB_ADDRESS_LOOKUP); if (mapi_last_hresult() == NOERROR) { $recip[PR_DISPLAY_NAME] = $userinfo[0][PR_DISPLAY_NAME]; $recip[PR_EMAIL_ADDRESS] = $userinfo[0][PR_EMAIL_ADDRESS]; $recip[PR_SEARCH_KEY] = $userinfo[0][PR_SEARCH_KEY]; $recip[PR_ADDRTYPE] = $userinfo[0][PR_ADDRTYPE]; $recip[PR_ENTRYID] = $userinfo[0][PR_ENTRYID]; $recip[PR_RECIPIENT_TYPE] = MAPI_TO; $recip[PR_RECIPIENT_FLAGS] = recipSendable; } else { $recip[PR_DISPLAY_NAME] = u2w($attendee->name); $recip[PR_SEARCH_KEY] = "SMTP:" . $recip[PR_EMAIL_ADDRESS] . ""; $recip[PR_ADDRTYPE] = "SMTP"; $recip[PR_RECIPIENT_TYPE] = MAPI_TO; $recip[PR_ENTRYID] = mapi_createoneoff($recip[PR_DISPLAY_NAME], $recip[PR_ADDRTYPE], $recip[PR_EMAIL_ADDRESS]); } array_push($recips, $recip); } mapi_message_modifyrecipients($mapimessage, 0, $recips); $props[$appointmentprops["icon"]] = 1026; $props[$appointmentprops["mrwassent"]] = true; } mapi_setprops($mapimessage, $props); }
/** * Function which merges an exception mapi message to recurring message. * This will be used when we receive recurring meeting request and we already have an exception message * of same meeting in calendar and we need to remove that exception message and add it to attachment table * of recurring meeting. * * @param resource $recurringItem reference to MAPI_message of recurring item * @param resource $occurrenceItem reference to MAPI_message of occurrence * @param string $basedate basedate of occurrence * @param resource $store user store * @param boolean $isDelegate true if delegate is processing this meeting request */ function mergeException(&$recurringItem, &$occurrenceItem, $basedate, $store, $isDelegate = false) { $recurr = new Recurrence($store, $recurringItem); // Copy properties from meeting request $exception_props = mapi_getprops($occurrenceItem); // Get recipient list from message and add it to exception attachment $reciptable = mapi_message_getrecipienttable($occurrenceItem); $recips = mapi_table_queryallrows($reciptable, $this->recipprops); if ($recurr->isException($basedate)) { $recurr->modifyException($exception_props, $basedate, $recips, $occurrenceItem); } else { $recurr->createException($exception_props, $basedate, false, $recips, $occurrenceItem); } // Move the occurrenceItem to the waste basket $wastebasket = $this->openDefaultWastebasket($this->openDefaultStore()); $sourcefolder = mapi_msgstore_openentry($store, $exception_props[PR_PARENT_ENTRYID]); mapi_folder_copymessages($sourcefolder, array($exception_props[PR_ENTRYID]), $wastebasket, MESSAGE_MOVE); mapi_savechanges($recurringItem); }