/** * Publishes the infomation * @paam timestamp $starttime Time from which to publish data (usually now) * @paam integer $length Amount of seconds from $starttime we should publish */ function publishFB($starttime, $length) { $start = $starttime; $end = $starttime + $length; // Get all the items in the calendar that we need $calendaritems = array(); $restrict = array(RES_OR, array(array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_GE, ULPROPTAG => $this->proptags["startdate"], VALUE => $start)), array(RES_PROPERTY, array(RELOP => RELOP_LE, ULPROPTAG => $this->proptags["startdate"], VALUE => $end)))), array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_GE, ULPROPTAG => $this->proptags["duedate"], VALUE => $start)), array(RES_PROPERTY, array(RELOP => RELOP_LE, ULPROPTAG => $this->proptags["duedate"], VALUE => $end)))), array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_LT, ULPROPTAG => $this->proptags["startdate"], VALUE => $start)), array(RES_PROPERTY, array(RELOP => RELOP_GT, ULPROPTAG => $this->proptags["duedate"], VALUE => $end)))), array(RES_OR, array(array(RES_AND, array(array(RES_EXIST, array(ULPROPTAG => $this->proptags["enddate_recurring"])), array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => $this->proptags["recurring"], VALUE => true)), array(RES_PROPERTY, array(RELOP => RELOP_GE, ULPROPTAG => $this->proptags["enddate_recurring"], VALUE => $start)))), array(RES_AND, array(array(RES_NOT, array(array(RES_EXIST, array(ULPROPTAG => $this->proptags["enddate_recurring"])))), array(RES_PROPERTY, array(RELOP => RELOP_LE, ULPROPTAG => $this->proptags["startdate"], VALUE => $end)), array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => $this->proptags["recurring"], VALUE => true)))))))); // global OR $contents = mapi_folder_getcontentstable($this->calendar); mapi_table_restrict($contents, $restrict); while (1) { $rows = mapi_table_queryrows($contents, array_values($this->proptags), 0, 50); if (!is_array($rows)) { break; } if (empty($rows)) { break; } foreach ($rows as $row) { $occurrences = array(); if (isset($row[$this->proptags['recurring']]) && $row[$this->proptags['recurring']]) { $recur = new Recurrence($this->store, $row); $occurrences = $recur->getItems($starttime, $starttime + $length); } else { $occurrences[] = $row; } $calendaritems = array_merge($calendaritems, $occurrences); } } // $calendaritems now contains all the calendar items in the specified time // frame. We now need to merge these into a flat array of begin/end/status // objects. This also filters out all the 'free' items (status 0) $freebusy = $this->mergeItemsFB($calendaritems); // $freebusy now contains the start, end and status of all items, merged. // Get the FB interface try { $fbsupport = mapi_freebusysupport_open($this->session, $this->store); } catch (MAPIException $e) { if ($e->getCode() == MAPI_E_NOT_FOUND) { $e->setHandled(); if (function_exists("dump")) { dump("Error in opening freebusysupport object."); } } } // Open updater for this user if (isset($fbsupport)) { $updaters = mapi_freebusysupport_loadupdate($fbsupport, array($this->entryid)); $updater = $updaters[0]; // Send the data mapi_freebusyupdate_reset($updater); mapi_freebusyupdate_publish($updater, $freebusy); mapi_freebusyupdate_savechanges($updater, $start - 24 * 60 * 60, $end); // We're finished mapi_freebusysupport_close($fbsupport); } }
function add_eventUpdateRecurrences($event) { $event_id = $event->id; $sunday = getPostValueAsArray("recurrence_Sunday"); $monday = getPostValueAsArray("recurrence_Monday"); $tuesday = getPostValueAsArray("recurrence_Tuesday"); $wednesday = getPostValueAsArray("recurrence_Wednesday"); $thursday = getPostValueAsArray("recurrence_Thursday"); $friday = getPostValueAsArray("recurrence_Friday"); $saturday = getPostValueAsArray("recurrence_Saturday"); Recurrence::ClearForEvent($event_id); foreach ($sunday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Sunday", 'modifier' => "{$modifier}")); $recurrence->save(); } foreach ($monday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Monday", 'modifier' => "{$modifier}")); $recurrence->save(); } foreach ($tuesday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Tuesday", 'modifier' => "{$modifier}")); $recurrence->save(); } foreach ($wednesday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Wednesday", 'modifier' => "{$modifier}")); $recurrence->save(); } foreach ($thursday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Thursday", 'modifier' => "{$modifier}")); $recurrence->save(); } foreach ($friday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Friday", 'modifier' => "{$modifier}")); $recurrence->save(); } foreach ($saturday as $modifier) { $recurrence = Recurrence::Create('Recurrence', array('event_id' => "{$event_id}", 'day' => "Saturday", 'modifier' => "{$modifier}")); $recurrence->save(); } }
/** * 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 checks whether received meeting request is either conflicting with other appointments or not. *@return mixed(boolean/integer) true if normal meeting is conflicting or an integer which specifies no of instances * conflict of recurring meeting and false if meeting is not conflicting. */ function isMeetingConflicting($message = false, $userStore = false, $calFolder = false, $msgprops = false) { $returnValue = false; $conflicting = false; $noOfInstances = 0; if (!$message) { $message = $this->message; } if (!$userStore) { $userStore = $this->store; } if (!$calFolder) { $root = mapi_msgstore_openentry($userStore); $rootprops = mapi_getprops($root, array(PR_STORE_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_FREEBUSY_ENTRYIDS)); if (!isset($rootprops[PR_IPM_APPOINTMENT_ENTRYID])) { return; } $calFolder = mapi_msgstore_openentry($userStore, $rootprops[PR_IPM_APPOINTMENT_ENTRYID]); } if (!$msgprops) { $msgprops = mapi_getprops($message, array($this->proptags['goid'], $this->proptags['goid2'], $this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['recurring'], $this->proptags['clipstart'], $this->proptags['clipend'])); } if ($calFolder) { // Meeting request is recurring, so get all occurrence and check for each occurrence whether it conflicts with other appointments in Calendar. if (isset($msgprops[$this->proptags['recurring']]) && $msgprops[$this->proptags['recurring']]) { // Apply recurrence class and retrieve all occurrences(max: 30 occurrence because recurrence can also be set as 'no end date') $recurr = new Recurrence($userStore, $message); $items = $recurr->getItems($msgprops[$this->proptags['clipstart']], $msgprops[$this->proptags['clipend']] * (24 * 24 * 60), 30); foreach ($items as $item) { // Get all items in the timeframe that we want to book, and get the goid and busystatus for each item $calendarItems = $recurr->getCalendarItems($userStore, $calFolder, $item[$this->proptags['startdate']], $item[$this->proptags['duedate']], array($this->proptags['goid'], $this->proptags['busystatus'], PR_OWNER_APPT_ID)); foreach ($calendarItems as $calendarItem) { if ($calendarItem[$this->proptags['busystatus']] != fbFree) { /** * Only meeting requests have globalID, normal appointments do not have globalID * so if any normal appointment if found then it is assumed to be conflict. */ if (isset($calendarItem[$this->proptags['goid']])) { if ($calendarItem[$this->proptags['goid']] !== $msgprops[$this->proptags['goid']]) { $noOfInstances++; break; } } else { $noOfInstances++; break; } } } } $returnValue = $noOfInstances; } else { // Get all items in the timeframe that we want to book, and get the goid and busystatus for each item $items = getCalendarItems($userStore, $calFolder, $msgprops[$this->proptags['startdate']], $msgprops[$this->proptags['duedate']], array($this->proptags['goid'], $this->proptags['busystatus'], PR_OWNER_APPT_ID)); foreach ($items as $item) { if ($item[$this->proptags['busystatus']] != fbFree) { if (isset($item[$this->proptags['goid']])) { if ($item[$this->proptags['goid']] !== $msgprops[$this->proptags['goid']] && $item[$this->proptags['goid']] !== $msgprops[$this->proptags['goid2']]) { $conflicting = true; break; } } else { $conflicting = true; break; } } } if ($conflicting) { $returnValue = true; } } } return $returnValue; }
/** * Function which checks whether received meeting request is either conflicting with other appointments or not. * @return mixed(boolean/integer) true if normal meeting is conflicting or an integer which specifies no of instances * conflict of recurring meeting and false if meeting is not conflicting. * @param MAPIMessage $message meeting request item that should be checked for conflicts in calendar * @param MAPIStore $userStore store containing calendar folder that will be used for confilict checking * @param MAPIFolder $calFolder calendar folder for conflict checking * @return Mixed if boolean then true/false for indicating confict, if number then items that are conflicting with the message. */ function isMeetingConflicting($message = false, $userStore = false, $calFolder = false) { $returnValue = false; $noOfInstances = 0; if ($message === false) { $message = $this->message; } $messageProps = mapi_getprops($message, array(PR_MESSAGE_CLASS, $this->proptags['goid'], $this->proptags['goid2'], $this->proptags['startdate'], $this->proptags['duedate'], $this->proptags['recurring'], $this->proptags['clipstart'], $this->proptags['clipend'], PR_RCVD_REPRESENTING_NAME)); if ($userStore === false) { $userStore = $this->store; // check if delegate is processing the response if (isset($messageProps[PR_RCVD_REPRESENTING_NAME])) { $delegatorStore = $this->getDelegatorStore($messageProps[PR_RCVD_REPRESENTING_NAME], array(PR_IPM_APPOINTMENT_ENTRYID)); $userStore = $delegatorStore['store']; $calFolder = $delegatorStore[PR_IPM_APPOINTMENT_ENTRYID]; } } if ($calFolder === false) { $calFolder = $this->openDefaultCalendar($userStore); } if ($calFolder) { // Meeting request is recurring, so get all occurrence and check for each occurrence whether it conflicts with other appointments in Calendar. if (isset($messageProps[$this->proptags['recurring']]) && $messageProps[$this->proptags['recurring']] === true) { // Apply recurrence class and retrieve all occurrences(max: 30 occurrence because recurrence can also be set as 'no end date') $recurr = new Recurrence($userStore, $message); $items = $recurr->getItems($messageProps[$this->proptags['clipstart']], $messageProps[$this->proptags['clipend']] * (24 * 24 * 60), 30); foreach ($items as $item) { // Get all items in the timeframe that we want to book, and get the goid and busystatus for each item $calendarItems = $recurr->getCalendarItems($userStore, $calFolder, $item[$this->proptags['startdate']], $item[$this->proptags['duedate']], array($this->proptags['goid'], $this->proptags['busystatus'])); foreach ($calendarItems as $calendarItem) { if ($calendarItem[$this->proptags['busystatus']] !== fbFree) { /** * Only meeting requests have globalID, normal appointments do not have globalID * so if any normal appointment if found then it is assumed to be conflict. */ if (isset($calendarItem[$this->proptags['goid']])) { if ($calendarItem[$this->proptags['goid']] !== $messageProps[$this->proptags['goid']]) { $noOfInstances++; break; } } else { $noOfInstances++; break; } } } } if ($noOfInstances > 0) { $returnValue = $noOfInstances; } } else { // Get all items in the timeframe that we want to book, and get the goid and busystatus for each item $items = getCalendarItems($userStore, $calFolder, $messageProps[$this->proptags['startdate']], $messageProps[$this->proptags['duedate']], array($this->proptags['goid'], $this->proptags['busystatus'])); foreach ($items as $item) { if ($item[$this->proptags['busystatus']] !== fbFree) { if (isset($item[$this->proptags['goid']])) { if ($item[$this->proptags['goid']] !== $messageProps[$this->proptags['goid']] && $item[$this->proptags['goid']] !== $messageProps[$this->proptags['goid2']]) { $returnValue = true; break; } } else { $returnValue = true; break; } } } } } return $returnValue; }
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)); } }
function display_page_content() { $event_id = getRequestVarAtIndex(4); $event = Events::FindById($event_id); $event_types = EventTypes::FindAll(); $event_periods = EventPeriods::FindAll(); $year = getRequestVarAtIndex(2); $month = getRequestVarAtIndex(3); $recurrences = Recurrence::FindForEvent($event_id); $days = array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); $user = Users::GetCurrentUser(); ?> <script type="text/javascript"> //<![CDATA[ $().ready(function() { setupDateFields("<?php echo $event->eventperiod_id; ?> "); $.datepicker.setDefaults({ showButtonPanel: true, showOtherMonths: true, selectOtherMonths: true }); $( "#date_start" ).datepicker(); $( "#time_start" ).timepicker({timeFormat: 'hh:mm:ss tt',stepMinute: 5}); $( "#date_end" ).datepicker(); $( "#time_end" ).timepicker({timeFormat: 'hh:mm:ss tt',stepMinute: 5}); $( "#not_date" ).datepicker(); $("a#notdate_add").click(function() { var date = $("input[name='not_date']").val(); if (date != "") { $("input[name='not_date']").val(''); var all_dates_vis = $("span#notdates").html(); $("span#notdates").html("<label for=\"notdates[]\">"+date+" <a href=\"javascript:;\" onClick=\"$(this).parent().remove();\">X</a><input type=\"hidden\" name=\"notdates[]\" value=\""+date+"\" /></label>"+all_dates_vis); } }); $("#eventperiod_id").change(function() { var selected = $(this).val(); setupDateFields(selected); }); $("#edit_event").validate({ rules: { title: "required", date_start: "required", }, messages: { title: "Please enter a title for this event", date_start: "Please at least a start date for this event", } }); }); //]]> </script> <div id="edit-header" class="event"> <h1>Edit Event</h1> </div> <div id="calendar_div"></div> <form method="POST" id="edit_event"> <p class="display_name"> <label for="title">Title</label> <?php textField("title", $event->title, "required: true"); ?> </p> <?php if (ALLOW_EVENT_TYPES && count($event_types) > 1) { ?> <p> <label for="eventtype_id">Event Type</label> <select name="eventtype_id" id="eventtype_id"> <?php foreach ($event_types as $event_type) { echo "<option value='{$event_type->id}' "; if ($event_type->id == $event->eventtype_id) { echo " selected "; } echo ">{$event_type->name}</option>\r\n"; } ?> </select> </p> <?php } ?> <div id="eventdateselects" class="dropslide"> <p><label for="eventperiod_id">Event Period:</label> <select name="eventperiod_id" id="eventperiod_id"> <?php foreach ($event_periods as $event_period) { echo "<option value='{$event_period->id}' "; if ($event_period->id == $event->eventperiod_id) { echo " selected "; } echo ">{$event_period->name}</option>\r\n"; } ?> </select> </p> <p> <label for="date_start">Start Date / Time</label> <input type="text" name="date_start" id="date_start" style="width: 6.5em;" value="<?php echo $event->getDateStart("date"); ?> " class="required: true" /> <input type="text" name="time_start" id="time_start" style="width: 6.5em;" value="<?php echo $event->getDateStart("time"); ?> " /> <label for="date_start">End Date / Time</label> <input type="text" name="date_end" id="date_end" style="width: 6.5em;" value="<?php echo $event->getDateEnd("date"); ?> " /> <input type="text" name="time_end" id="time_end" style="width: 6.5em;" value="<?php echo $event->getDateEnd("time"); ?> " /> </p> <div id="recurrence_rules" <?php if ($event->eventperiod_id != 3) { echo "style=\"display: none; \""; } ?> > <p><label for="not_date">Exclusion Date(s)</label> <input type="text" name="not_date" id="not_date" style="width: 6.5em;"/> <a href="javascript:;" id="notdate_add">Add to list→</a> <span id="notdates"> <?php foreach (explode(",", $event->getNotDates()) as $date) { if ($date != "") { echo "<label for=\"{$date}\">{$date} <a href=\"javascript:;\" onClick=\"\$(this).parent().remove();\">×</a><input type=\"hidden\" name=\"notdates[]\" value=\"{$date}\" /></label>"; } } ?> </span> </p> <label>Recurrence Rules</label> <table> <tbody> <tr> <th> </th> <th>Sunday</th> <th>Monday</th> <th>Tuesday</th> <th>Wednesday</th> <th>Thursday</th> <th>Friday</th> <th>Saturday</th> </tr> <tr> <td>Every</td> <?php foreach ($days as $day) { echo "<td>"; get_recurrence_tag($recurrences, $day, 0); echo "</td>"; } ?> </tr> <tr> <td>First</td> <?php foreach ($days as $day) { echo "<td>"; get_recurrence_tag($recurrences, $day, 1); echo "</td>"; } ?> </tr> <tr> <td>Second</td> <?php foreach ($days as $day) { echo "<td>"; get_recurrence_tag($recurrences, $day, 2); echo "</td>"; } ?> </tr> <tr> <td>Third</td> <?php foreach ($days as $day) { echo "<td>"; get_recurrence_tag($recurrences, $day, 3); echo "</td>"; } ?> </tr> <tr> <td>Fourth</td> <?php foreach ($days as $day) { echo "<td>"; get_recurrence_tag($recurrences, $day, 4); echo "</td>"; } ?> </tr> <tr> <td>Last</td> <?php foreach ($days as $day) { echo "<td>"; get_recurrence_tag($recurrences, $day, 5); echo "</td>"; } ?> </tr> </tbody> </table> </div> </div> <p> <label for="name">Event Description</label><br /> <?php textArea("description", $event->description, 98, EDIT_WINDOW_HEIGHT); ?> </p> <?php require_once snippetPath("admin-insert_configs"); ?> <div id="edit-footer" class="eventnav clearfix"> <div class="column half"> <p> <input type="submit" class="submitbutton" name="submit" value="Edit Event" /> <br /> <input type="submit" class="submitbuttonsmall" name="submit" value="Edit and Return to List" /> </p> </div> <div class="column half last"> <?php if ($user->has_role()) { ?> <p><label for="delete">Delete this Event? <input name="delete" id="delete" class="boxes" type="checkbox" value="<?php echo $event->id; ?> "></label> <span class="hint">Check the box and click “Save” to delete this event from the database</span></p> <?php } ?> </div> </div> </form> <?php }
/** * Note: Static function, more like a utility function. * * Gets all the items (including recurring items) in the specified calendar in the given timeframe. Items are * included as a whole if they overlap the interval <$start, $end> (non-inclusive). This means that if the interval * is <08:00 - 14:00>, the item [6:00 - 8:00> is NOT included, nor is the item [14:00 - 16:00>. However, the item * [7:00 - 9:00> is included as a whole, and is NOT capped to [8:00 - 9:00>. * * @param $store resource The store in which the calendar resides * @param $calendar resource The calendar to get the items from * @param $viewstart int Timestamp of beginning of view window * @param $viewend int Timestamp of end of view window * @param $propsrequested array Array of properties to return * @param $rows array Array of rowdata as if they were returned directly from mapi_table_queryrows. Each recurring item is * expanded so that it seems that there are only many single appointments in the table. */ function getCalendarItems($store, $calendar, $viewstart, $viewend, $propsrequested) { $result = array(); $properties = getPropIdsFromStrings($store, array("duedate" => "PT_SYSTIME:PSETID_Appointment:0x820e", "startdate" => "PT_SYSTIME:PSETID_Appointment:0x820d", "enddate_recurring" => "PT_SYSTIME:PSETID_Appointment:0x8236", "recurring" => "PT_BOOLEAN:PSETID_Appointment:0x8223", "recurring_data" => "PT_BINARY:PSETID_Appointment:0x8216", "timezone_data" => "PT_BINARY:PSETID_Appointment:0x8233", "label" => "PT_LONG:PSETID_Appointment:0x8214")); // Create a restriction that will discard rows of appointments that are definitely not in our // requested time frame $table = mapi_folder_getcontentstable($calendar); $restriction = array(RES_OR, array(array(RES_AND, array(array(RES_PROPERTY, array(RELOP => RELOP_GT, ULPROPTAG => $properties["duedate"], VALUE => $viewstart)), array(RES_PROPERTY, array(RELOP => RELOP_LT, ULPROPTAG => $properties["startdate"], VALUE => $viewend)))), array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => $properties["recurring"], VALUE => true)))); // global OR // Get requested properties, plus whatever we need $proplist = array(PR_ENTRYID, $properties["recurring"], $properties["recurring_data"], $properties["timezone_data"]); $proplist = array_merge($proplist, $propsrequested); $propslist = array_unique($proplist); $rows = mapi_table_queryallrows($table, $proplist, $restriction); // $rows now contains all the items that MAY be in the window; a recurring item needs expansion before including in the output. foreach ($rows as $row) { $items = array(); if (isset($row[$properties["recurring"]]) && $row[$properties["recurring"]]) { // Recurring item $rec = new Recurrence($store, $row); // GetItems guarantees that the item overlaps the interval <$viewstart, $viewend> $occurrences = $rec->getItems($viewstart, $viewend); foreach ($occurrences as $occurrence) { // The occurrence takes all properties from the main row, but overrides some properties (like start and end obviously) $item = $occurrence + $row; array_push($items, $item); } } else { // Normal item, it matched the search criteria and therefore overlaps the interval <$viewstart, $viewend> array_push($items, $row); } $result = array_merge($result, $items); } // All items are guaranteed to overlap the interval <$viewstart, $viewend>. Note that we may be returning a few extra // properties that the caller did not request (recurring, etc). This shouldn't be a problem though. return $result; }
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); mapi_setprops($mapimessage, array(PR_MESSAGE_CLASS => "IPM.Appointment")); $this->_setPropsInMAPI($mapimessage, $appointment, $this->_appointmentmapping); // Get timezone info if (isset($appointment->timezone)) { $tz = $this->_getTZFromSyncBlob(base64_decode($appointment->timezone)); } else { $tz = false; } // Set commonstart/commonend to start/end and remindertime to start 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)); // 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 reminderminutes > 30 mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8503") => isset($appointment->reminder) && $appointment->reminder > 0 ? true : false)); if (isset($appointment->reminder) && $appointment->reminder > 0) { // 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)); } 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; } $localstart = $this->_getLocaltimeByTZ($appointment->starttime, $tz); $localend = $this->_getLocaltimeByTZ($appointment->endtime, $tz); $starttime = $this->gmtime($localstart); $endtime = $this->gmtime($localend); $duration = ($localend - $localstart) / 60; $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(); foreach ($appointment->attendees as $attendee) { $recip = array(); $recip[PR_DISPLAY_NAME] = u2w($attendee->name); $recip[PR_EMAIL_ADDRESS] = $attendee->email; $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)); } }
public function valid() { if ($this->cache === true) { // check to see if the current position has already been stored if (!empty($this->results[$this->position])) { return isset($this->results[$this->position]); } elseif ($next_date = parent::next()) { // if it hasn't been found, check to see if there are more // dates $this->results[] = $next_date; return isset($next_date); } } else { // check to see if there is another result and set that as the // result if ($next_date = parent::next()) { $this->result = $next_date; return isset($this->result); } } // end the foreach loop when all options are exhausted return false; }
function formatSpecialRecurrence() { // DO NOT USE THIS FUNCTION ON ITS OWN... it is called from ->getDateRangeStringWithRecurrence() // This function tries to deal with a few special instances... it calls ->formatRecurrence() when needed $event_recurrence = Recurrence::FindForEvent($this->id); $firstrecurrence_mod = ""; $firstrecurrence_day = ""; $recurrence_string = ""; $counter = 1; $countupto = count($event_recurrence); $daysofweek = array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"); $recurrence_def = array("Every", "First", "Second", "Third", "Fourth", "Last"); if (substr($this->getDateStart("date"), 0, 5) == "01/01" && substr($this->getDateEnd("date"), 0, 5) == "12/31") { // This date range encompasses the entire year return $recurrence_string = "All Year"; } else { // Ok, start the recurrence checking if ($countupto == "7") { return $recurrence_string = "All Week"; } else { if ($countupto == "6") { $first_event_recurrence = array_shift($event_recurrence); if ($first_event_recurrence->modifier == 0) { // Try to figure out which day this event is NOT on $recur_array = array(); // Turn the recurrence object into an array... foreach ($event_recurrence as $recurrence) { array_push($recur_array, $recurrence->day); } // Get the difference between the two $difference = array_difference($recur_array, $daysofweek); // What we have is in an array, so a foreach gets it out foreach ($difference as $theday) { $recurrence_string = "Every day but {$theday}"; } } else { // Not an "Every" instance, so use the normal recurrence function return $recurrence_string = $this->formatRecurrence(); } } else { if ($countupto == "2") { foreach ($event_recurrence as $recurrence) { if ($counter == 1) { // This is the first loop... // Just set some variables that will be checked on the second loop $firstrecurrence_mod = $recurrence->modifier; $firstrecurrence_day = $recurrence->day; $counter++; } else { // Now, check the variables before adding to the string if ($firstrecurrence_mod == $recurrence->modifier) { // The modifier is the same if ($firstrecurrence_day == $recurrence->day) { // The days are the same, like "First & Third Tuesdays" $recurrence_string .= $recurrence_def[$firstrecurrence_mod] . " & " . $recurrence_def[$recurrence->modifier] . " " . $recurrence->day . "s"; } else { // The days are not the same if ($recurrence->modifier == 0) { // Like "Every Monday & Wednesday" $recurrence_string .= "Every {$firstrecurrence_day} & {$recurrence->day}"; } else { // Make the days plural, like "Second Mondays & Wednesdays" $recurrence_string .= $recurrence_def[$recurrence->modifier] . " " . $firstrecurrence_day . "s & " . $recurrence->day . "s"; } } } else { // The modifer is different if ($firstrecurrence_day == $recurrence->day) { // The days are the same, like "First & Third Tuesdays" $recurrence_string .= $recurrence_def[$firstrecurrence_mod] . " & " . $recurrence_def[$recurrence->modifier] . " " . $recurrence->day . "s"; } else { // The days are not the same, like "First Tuesdays & Third Thursdays" $recurrence_string .= $recurrence_def[$firstrecurrence_mod] . " " . $firstrecurrence_day . "s & " . $recurrence_def[$recurrence->modifier] . " " . $recurrence->day . "s"; } } $counter++; } } // Clean up a few special instances this function may create if ($recurrence_string == "Every Sunday & Saturday") { return $recurrence_string = "Every Weekend"; } } else { return $recurrence_string = $this->formatRecurrence(); } } } } return $recurrence_string; }
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; } mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_BINARY:{00062002-0000-0000-C000-000000000046}:0x8233") => $this->_getMAPIBlobFromTZ($tz))); //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")); // START ADDED dw2412 Take care about notes if (isset($appointment->airsyncbasebody)) { switch ($appointment->airsyncbasebody->type) { case '3': $appointment->rtf = $appointment->airsyncbasebody->data; break; case '1': $appointment->body = $appointment->airsyncbasebody->data; break; } } if (isset($appointment->rtf)) { // start dw2412 // Nokia MfE 2.9.158 sends contact notes with RTF and Body element. // The RTF is empty, the body contains the note therefore we need to unpack the rtf // to see if it is realy empty and in case not, take the appointment body. $rtf_body = new rtf(); $rtf_body->loadrtf(base64_decode($appointment->rtf)); $rtf_body->output("ascii"); $rtf_body->parse(); if (isset($appointment->body) && isset($rtf_body->out) && $rtf_body->out == "" && $appointment->body != "") { unset($appointment->rtf); } // end dw2412 } // END ADDED dw2412 Take care about notes $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 reminderminutes > 30 mapi_setprops($mapimessage, array($this->_getPropIDFromString("PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8503") => isset($appointment->reminder) && $appointment->reminder > 0 ? true : false)); if (isset($appointment->reminder) && $appointment->reminder > 0) { // 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)); } 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; } // dw2412 Zarafa expects start & endtime in Localtime for the recurrence! We need localtime depending on tz provided. $starttime = $this->_localtimeByTZ($appointment->starttime, $tz, true); $endtime = $this->_localtimeByTZ($appointment->endtime, $tz, true); $recur["startocc"] = $starttime["tm_hour"] * 60 + $starttime["tm_min"]; $recur["endocc"] = $recur["startocc"] + $duration; // Note that this may be > 24*60 if multi-day // dw2412 "start" and "end" are in Local Time when passing to class.recurrence $recur["start"] = $this->_getLocaltimeByTz($appointment->starttime, $tz); if (isset($appointment->alldayevent) && $appointment->alldayevent) { $recur["start"] = $this->_getLocaltimeByTz($appointment->starttime, $tz); } else { $recur["start"] = $this->_getDayStartOfTimestamp($appointment->starttime); } $recur["end"] = $this->_getDayStartOfTimestamp(0x7fffffff); // Maximum value for end by default if (isset($appointment->recurrence->until)) { $recur["term"] = 0x21; // dw2412 "end" is in Local Time when passing to class.recurrence $recur["end"] = $this->_getLocaltimeByTz($appointment->recurrence->until, $tz); } 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(); } if (isset($appointment->alldayevent) && $appointment->alldayevent) { array_push($recur["deleted_occurences"], $this->_getLocaltimeByTZ($exception->exceptionstarttime, $tz)); } else { array_push($recur["deleted_occurences"], $this->_getLocaltimeByTZ($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(); foreach ($appointment->attendees as $attendee) { $recip = array(); $recip[PR_DISPLAY_NAME] = u2w($attendee->name); $recip[PR_EMAIL_ADDRESS] = u2w($attendee->email); $recip[PR_ADDRTYPE] = "SMTP"; // START CHANGED dw2412 to support AS 12.0 attendee type if (isset($attendee->type)) { $recip[PR_RECIPIENT_TYPE] = $attendee->attendeetype; } else { $recip[PR_RECIPIENT_TYPE] = MAPI_TO; } // END CHANGED dw2412 to support AS 12.0 attendee type $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)); } //START ADDED dw2412 Birthday & Anniversary create / update // update linked contacts (birthday & anniversary) $this->_setLinkedContact($mapimessage); //END ADDED dw2412 Birthday & Anniversary create / update }
public function parseRecurrences($event) { $recurring = new Recurrence($event['RRULE']); $exclusions = []; $additions = []; if (!empty($event['EXDATES'])) { foreach ($event['EXDATES'] as $exDate) { if (is_array($exDate)) { foreach ($exDate as $singleExDate) { $exclusions[] = $singleExDate->getTimestamp(); } } else { $exclusions[] = $exDate->getTimestamp(); } } } if (!empty($event['RDATES'])) { foreach ($event['RDATES'] as $rDate) { if (is_array($rDate)) { foreach ($rDate as $singleRDate) { $additions[] = $singleRDate->getTimestamp(); } } else { $additions[] = $rDate->getTimestamp(); } } } $until = $recurring->getUntil(); if ($until === false) { //forever... limit to 3 years $end = clone $event['DTSTART']; $end->add(new \DateInterval('P3Y')); // + 3 years $recurring->setUntil($end); $until = $recurring->getUntil(); } date_default_timezone_set($event['DTSTART']->getTimezone()->getName()); $frequency = new Freq($recurring->rrule, $event['DTSTART']->getTimestamp(), $exclusions, $additions); $recurrenceTimestamps = $frequency->getAllOccurrences(); $recurrences = []; foreach ($recurrenceTimestamps as $recurrenceTimestamp) { $tmp = new \DateTime("now", $event['DTSTART']->getTimezone()); $tmp->setTimestamp($recurrenceTimestamp); $recurrences[] = $tmp; } return $recurrences; }