function resolve($session, $name) { $ab = mapi_openaddressbook($session); $resolved = mapi_ab_resolvename($ab, array(array(PR_DISPLAY_NAME => $name)), EMS_AB_ADDRESS_LOOKUP); $id = false; if ($resolved) { $id = $resolved[0][PR_ENTRYID]; } return $id; }
/** * 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 getDelegatorStore($messageprops) { // Find the organiser of appointment in addressbook $delegatorName = array(array(PR_DISPLAY_NAME => $messageprops[PR_RCVD_REPRESENTING_NAME])); $ab = mapi_openaddressbook($this->session); $user = mapi_ab_resolvename($ab, $delegatorName, EMS_AB_ADDRESS_LOOKUP); // Get StoreEntryID by username $delegatorEntryid = mapi_msgstore_createentryid($this->store, $user[0][PR_EMAIL_ADDRESS]); // Open store of the delegator $delegatorStore = mapi_openmsgstore($this->session, $delegatorEntryid); // Open root folder $delegatorRoot = mapi_msgstore_openentry($delegatorStore, null); // Get calendar entryID $delegatorRootProps = mapi_getprops($delegatorRoot, array(PR_IPM_APPOINTMENT_ENTRYID)); // Open the calendar Folder $calFolder = mapi_msgstore_openentry($delegatorStore, $delegatorRootProps[PR_IPM_APPOINTMENT_ENTRYID]); return array('store' => $delegatorStore, 'calFolder' => $calFolder); }
/** * Function adds recipients in recips array from the string. * * @param array $recips recipient array. * @param string $recipString recipient string attendees. * @param int $type type of the recipient, MAPI_TO/MAPI_CC. */ function setRecipsFromString(&$recips, $recipString, $recipType = MAPI_TO) { $ab = mapi_openaddressbook($this->session); $recipArray = explode(';', $recipString); foreach ($recipArray as $recip) { $recip = trim($recip); if (!empty($recip)) { try { $userName = array(array(PR_DISPLAY_NAME => $recip)); $user = mapi_ab_resolvename($ab, $userName, EMS_AB_ADDRESS_LOOKUP); $extraRecipient = array(); $extraRecipient[PR_RECIPIENT_TYPE] = $recipType; $extraRecipient[PR_ENTRYID] = $user[0][PR_ENTRYID]; $extraRecipient[PR_DISPLAY_NAME] = $user[0][PR_DISPLAY_NAME]; $extraRecipient[PR_OBJECT_TYPE] = $user[0][PR_OBJECT_TYPE]; $extraRecipient[PR_EMAIL_ADDRESS] = $user[0][PR_EMAIL_ADDRESS]; $extraRecipient[PR_SMTP_ADDRESS] = $user[0][PR_SMTP_ADDRESS]; $extraRecipient[PR_ADDRTYPE] = $user[0][PR_ADDRTYPE]; array_push($recips, $extraRecipient); } catch (MAPIException $e) { // We couldn't resolve the user, fallback to filling // in the properties which we do know. $extraRecipient = array(); $extraRecipient[PR_RECIPIENT_TYPE] = $recipType; $extraRecipient[PR_DISPLAY_NAME] = $recip; array_push($recips, $extraRecipient); } } } }
function _setAppointment($mapimessage, $appointment) { // MAPI stores months as the amount of minutes until the beginning of the month in a // non-leapyear. Why this is, is totally unclear. $monthminutes = array(0, 44640, 84960, 129600, 172800, 217440, 260640, 305280, 348480, 393120, 437760, 480960); // 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 = getOLUidFromICalUid($appointment->uid); mapi_setprops($mapimessage, array(PR_MESSAGE_CLASS => "IPM.Appointment")); $this->_setPropsInMAPI($mapimessage, $appointment, $this->_appointmentmapping); //we also have to set the responsestatus and not only meetingstatus, so we use another mapi tag if (isset($appointment->meetingstatus)) { mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_LONG:{00062002-0000-0000-C000-000000000046}:0x8218") => $appointment->meetingstatus)); } //sensitivity is not enough to mark an appointment as private, so we use another mapi tag if (isset($appointment->sensitivity) && $appointment->sensitivity == 0) { $private = false; } else { $private = true; } // Set commonstart/commonend to start/end and remindertime to start, duration, private and cleanGlobalObjectId mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8516") => $appointment->starttime, $this->_getPropIDFromString("PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8517") => $appointment->endtime, $this->_getPropIDFromString("PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8502") => $appointment->starttime, $this->_getPropIDFromString("PT_LONG:{00062002-0000-0000-C000-000000000046}:0x8213") => $duration, $this->_getPropIDFromString("PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8506") => $private, $this->_getPropIDFromString("PT_BINARY:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x23") => $appointment->uid)); // Set named prop 8510, unknown property, but enables deleting a single occurrence of a recurring // type in OLK2003. mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_LONG:{00062008-0000-0000-C000-000000000046}:0x8510") => 369)); // Set reminder boolean to 'true' if reminder is set mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8503") => isset($appointment->reminder) ? true : false)); if (isset($appointment->reminder) && $appointment->reminder > 0) { //start is in seconds and reminder in minutes, so it needs to be multiplied by 60 // Set 'flagdueby' to correct value (start - reminderminutes) mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_SYSTIME:{00062008-0000-0000-C000-000000000046}:0x8560") => $appointment->starttime - $appointment->reminder * 60)); } if (isset($appointment->recurrence)) { // Set PR_ICON_INDEX to 1025 to show correct icon in category view mapi_setprops($mapimessage, array(PR_ICON_INDEX => 1025)); $recurrence = new Recurrence($this->_store, $mapimessage); if (!isset($appointment->recurrence->interval)) { $appointment->recurrence->interval = 1; } switch ($appointment->recurrence->type) { case 0: $recur["type"] = 10; if (isset($appointment->recurrence->dayofweek)) { $recur["subtype"] = 1; } else { $recur["subtype"] = 0; } $recur["everyn"] = $appointment->recurrence->interval * (60 * 24); break; case 1: $recur["type"] = 11; $recur["subtype"] = 1; $recur["everyn"] = $appointment->recurrence->interval; break; case 2: $recur["type"] = 12; $recur["subtype"] = 2; $recur["everyn"] = $appointment->recurrence->interval; break; case 3: $recur["type"] = 12; $recur["subtype"] = 3; $recur["everyn"] = $appointment->recurrence->interval; break; case 4: $recur["type"] = 13; $recur["subtype"] = 1; $recur["everyn"] = $appointment->recurrence->interval * 12; break; case 5: $recur["type"] = 13; $recur["subtype"] = 2; $recur["everyn"] = $appointment->recurrence->interval * 12; break; case 6: $recur["type"] = 13; $recur["subtype"] = 3; $recur["everyn"] = $appointment->recurrence->interval * 12; break; } $starttime = $this->gmtime($localstart); $endtime = $this->gmtime($localend); $recur["startocc"] = $starttime["tm_hour"] * 60 + $starttime["tm_min"]; $recur["endocc"] = $recur["startocc"] + $duration; // Note that this may be > 24*60 if multi-day // "start" and "end" are in GMT when passing to class.recurrence $recur["start"] = $this->_getDayStartOfTimestamp($this->_getGMTTimeByTz($localstart, $tz)); $recur["end"] = $this->_getDayStartOfTimestamp(0x7fffffff); // Maximum GMT value for end by default if (isset($appointment->recurrence->until)) { $recur["term"] = 0x21; $recur["end"] = $appointment->recurrence->until; } else { if (isset($appointment->recurrence->occurrences)) { $recur["term"] = 0x22; $recur["numoccur"] = $appointment->recurrence->occurrences; } else { $recur["term"] = 0x23; } } if (isset($appointment->recurrence->dayofweek)) { $recur["weekdays"] = $appointment->recurrence->dayofweek; } if (isset($appointment->recurrence->weekofmonth)) { $recur["nday"] = $appointment->recurrence->weekofmonth; } if (isset($appointment->recurrence->monthofyear)) { $recur["month"] = $monthminutes[$appointment->recurrence->monthofyear - 1]; } if (isset($appointment->recurrence->dayofmonth)) { $recur["monthday"] = $appointment->recurrence->dayofmonth; } // 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 $mapiexception = array("basedate" => $this->_getDayStartOfTimestamp($exception->exceptionstarttime)); if (isset($exception->starttime)) { $mapiexception["start"] = $this->_getLocaltimeByTZ($exception->starttime, $tz); } if (isset($exception->endtime)) { $mapiexception["end"] = $this->_getLocaltimeByTZ($exception->endtime, $tz); } if (isset($exception->subject)) { $mapiexception["subject"] = u2w($exception->subject); } if (isset($exception->location)) { $mapiexception["location"] = u2w($exception->location); } if (isset($exception->busystatus)) { $mapiexception["busystatus"] = $exception->busystatus; } if (isset($exception->reminder)) { $mapiexception["reminder_set"] = 1; $mapiexception["remind_before"] = $exception->reminder; } if (isset($exception->alldayevent)) { $mapiexception["alldayevent"] = $exception->alldayevent; } if (!isset($recur["changed_occurences"])) { $recur["changed_occurences"] = array(); } array_push($recur["changed_occurences"], $mapiexception); } } } $recurrence->setRecurrence($tz, $recur); } else { $isrecurringtag = $this->_getPropIDFromString("PT_BOOLEAN:{00062002-0000-0000-C000-000000000046}:0x8223"); mapi_setprops($mapimessage, array($isrecurringtag => false)); } // Do attendees if (isset($appointment->attendees) && is_array($appointment->attendees)) { $recips = array(); //open addresss book for user resolve $addrbook = mapi_openaddressbook($this->_session); 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; } else { $recip[PR_DISPLAY_NAME] = u2w($attendee->name); $recip[PR_SEARCH_KEY] = $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); mapi_setprops($mapimessage, array(PR_ICON_INDEX => 1026, $this->_getPropIDFromString("PT_BOOLEAN:{00062002-0000-0000-C000-000000000046}:0x8229") => true)); } }