/** * 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) && $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); } else { ZLog::Write(LOGLEVEL_WARN, "FreeBusyPublish is not available"); } }
function readFBfromGAL($emailaddress, $starttime, $endtime) { $rows = $this->readResolveRecipientfromGAL($emailaddress); $fbsupport = mapi_freebusysupport_open($this->_session); foreach ($rows as $entry) { $fbDataArray = mapi_freebusysupport_loaddata($fbsupport, array($entry[PR_ENTRYID])); $res['displayname'] = $entry[PR_DISPLAY_NAME]; $res['emailaddress'] = $entry[PR_SMTP_ADDRESS]; $res['type'] = 1; $res['entries'] = array(); if ($fbDataArray[0] != NULL) { foreach ($fbDataArray as $fbDataUser) { $rangeuser1 = mapi_freebusydata_getpublishrange($fbDataUser); if ($rangeuser1 == NULL) { return $result; } $enumblock = mapi_freebusydata_enumblocks($fbDataUser, $starttime, $endtime); mapi_freebusyenumblock_reset($enumblock); while (true) { $blocks = mapi_freebusyenumblock_next($enumblock, 100); if (!$blocks) { break; } foreach ($blocks as $blockItem) { if ($blockItem['start'] < $starttime) { $blockItem['start'] = $starttime; } if ($blockItem['end'] > $endtime) { $blockItem['end'] = $endtime; } $res['entries'][] = $blockItem; } } } } $result[$emailaddress][] = $res; } mapi_freebusysupport_close($fbsupport); return $result; }
function getFreeBusyInfo($entryID, $start, $end) { $result = array(); $fbsupport = mapi_freebusysupport_open($this->session); if (mapi_last_hresult() != NOERROR) { if (function_exists("dump")) { dump("Error in opening freebusysupport object."); } return $result; } $fbDataArray = mapi_freebusysupport_loaddata($fbsupport, array($entryID)); if ($fbDataArray[0] != NULL) { foreach ($fbDataArray as $fbDataUser) { $rangeuser1 = mapi_freebusydata_getpublishrange($fbDataUser); if ($rangeuser1 == NULL) { return $result; } $enumblock = mapi_freebusydata_enumblocks($fbDataUser, $start, $end); mapi_freebusyenumblock_reset($enumblock); while (true) { $blocks = mapi_freebusyenumblock_next($enumblock, 100); if (!$blocks) { break; } foreach ($blocks as $blockItem) { $result[] = $blockItem; } } } } mapi_freebusysupport_close($fbsupport); return $result; }
/** * Gets the availability of a user for the given time window. * * @param string $to * @param SyncResolveRecipient $resolveRecipient * @param SyncResolveRecipientsOptions $resolveRecipientsOptions * * @access private * @return SyncResolveRecipientsAvailability */ private function getAvailability($to, $resolveRecipient, $resolveRecipientsOptions) { $availability = new SyncResolveRecipientsAvailability(); $availability->status = SYNC_RESOLVERECIPSSTATUS_AVAILABILITY_SUCCESS; if (!isset($resolveRecipient->id)) { // TODO this shouldn't happen but try to get the recipient in such a case } $fbsupport = mapi_freebusysupport_open($this->session); if (mapi_last_hresult()) { ZLog::Write(LOGLEVEL_WARN, sprintf("Unable to open free busy support (0x%08X)", mapi_last_hresult())); $availability->status = SYNC_RESOLVERECIPSSTATUS_AVAILABILITY_FAILED; return $availability; } $fbDataArray = mapi_freebusysupport_loaddata($fbsupport, array($resolveRecipient->id)); $start = strtotime($resolveRecipientsOptions->availability->starttime); $end = strtotime($resolveRecipientsOptions->availability->endtime); // Each digit in the MergedFreeBusy indicates the free/busy status for the user for every 30 minute interval. $timeslots = intval(ceil(($end - $start) / self::HALFHOURSECONDS)); if ($timeslots > self::MAXFREEBUSYSLOTS) { throw new StatusException("KopanoBackend->getAvailability(): the requested free busy range is too large.", SYNC_RESOLVERECIPSSTATUS_PROTOCOLERROR); } $mergedFreeBusy = str_pad(fbNoData, $timeslots, fbNoData); if (is_array($fbDataArray) && !empty($fbDataArray)) { foreach ($fbDataArray as $fbDataUser) { if ($fbDataUser == null) { ZLog::Write(LOGLEVEL_INFO, sprintf("KopanoBackend->getAvailability(): freebusy user is null for '%s'. Unable to retrieve his availability.", $resolveRecipient->displayname)); continue; } $rangeuser = mapi_freebusydata_getpublishrange($fbDataUser); if ($rangeuser == null) { ZLog::Write(LOGLEVEL_INFO, sprintf("KopanoBackend->getAvailability(): Unable to retrieve mapi_freebusydata_getpublishrange (0x%X) for '%s'", mapi_last_hresult(), $resolveRecipient->displayname)); $availability->status = SYNC_RESOLVERECIPSSTATUS_AVAILABILITY_FAILED; return $availability; } // if free busy information is available for the whole requested period, // assume that the user is free for the requested range. if ($rangeuser['start'] <= $start && $rangeuser['end'] >= $end) { $mergedFreeBusy = str_pad(fbFree, $timeslots, fbFree); } elseif ($rangeuser['end'] <= $start || $rangeuser['start'] >= $end) { $mergedFreeBusy = str_pad(fbNoData, $timeslots, fbNoData); } elseif ($rangeuser['start'] > $start && $rangeuser['end'] >= $end) { $missingSlots = intval(ceil(($rangeuser['start'] - $start) / self::HALFHOURSECONDS)); $mergedFreeBusy = str_pad(fbNoData, $missingSlots, fbNoData) . str_pad(fbFree, $timeslots - $missingSlots, fbFree); } elseif ($rangeuser['start'] <= $start && $rangeuser['end'] < $end) { $missingSlots = intval(ceil(($rangeuser['end'] - $end) / self::HALFHOURSECONDS)); $mergedFreeBusy = str_pad(fbFree, $timeslots - $missingSlots, fbFree) . str_pad(fbNoData, $missingSlots, fbNoData); } else { $missingBeginSlots = intval(ceil(($rangeuser['start'] - $start) / self::HALFHOURSECONDS)); $missingEndSlots = intval(ceil(($rangeuser['end'] - $end) / self::HALFHOURSECONDS)); $mergedFreeBusy = str_pad(fbNoData, $missingBeginSlots, fbNoData) . str_pad(fbFree, $timeslots - $missingBeginSlots - $missingEndSlots, fbFree) . str_pad(fbNoData, $missingEndSlots, fbNoData); } $enumblock = mapi_freebusydata_enumblocks($fbDataUser, $start, $end); mapi_freebusyenumblock_reset($enumblock); while (true) { $blocks = mapi_freebusyenumblock_next($enumblock, self::FREEBUSYENUMBLOCKS); if (!$blocks) { break; } foreach ($blocks as $blockItem) { // calculate which timeslot of mergedFreeBusy should be replaced. $blockDuration = ($blockItem['end'] - $blockItem['start']) / self::HALFHOURSECONDS; $startSlot = intval(floor(($blockItem['start'] - $start) / self::HALFHOURSECONDS)); $endSlot = intval(floor(($blockItem['end'] - $start) / self::HALFHOURSECONDS)); // check if the end slot is the exact begin of the next slot from request; in such case it's necessary to reduce the endslot. if ($start + $endSlot * self::HALFHOURSECONDS == $blockItem['end'] && $endSlot > $startSlot) { $endSlot--; } for ($i = $startSlot; $i <= $endSlot; $i++) { // only set the new slot's free busy status if it's higher than the current one if ($blockItem['status'] > $mergedFreeBusy[$i]) { $mergedFreeBusy[$i] = $blockItem['status']; } } } } } } mapi_freebusysupport_close($fbsupport); $availability->mergedfreebusy = $mergedFreeBusy; return $availability; }