/** * Constructor * * @param mapisession $session * @param mapistore $store * @param string (opt) * * @access public * @throws StatusException */ public function ExportChangesICS($session, $store, $folderid = false) { // Open a hierarchy or a contents exporter depending on whether a folderid was specified $this->session = $session; $this->folderid = $folderid; $this->store = $store; $this->restriction = false; try { if ($folderid) { $entryid = mapi_msgstore_entryidfromsourcekey($store, $folderid); } else { $storeprops = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID)); $entryid = $storeprops[PR_IPM_SUBTREE_ENTRYID]; } $folder = false; if ($entryid) { $folder = mapi_msgstore_openentry($this->store, $entryid); } // Get the actual ICS exporter if ($folderid) { if ($folder) { $this->exporter = mapi_openproperty($folder, PR_CONTENTS_SYNCHRONIZER, IID_IExchangeExportChanges, 0, 0); } else { $this->exporter = false; } } else { $this->exporter = mapi_openproperty($folder, PR_HIERARCHY_SYNCHRONIZER, IID_IExchangeExportChanges, 0, 0); } } catch (MAPIException $me) { $this->exporter = false; // We return the general error SYNC_FSSTATUS_CODEUNKNOWN (12) which is also SYNC_STATUS_FOLDERHIERARCHYCHANGED (12) // if this happened while doing content sync, the mobile will try to resync the folderhierarchy throw new StatusException(sprintf("ExportChangesICS('%s','%s','%s'): Error, unable to open folder: 0x%X", $session, $store, Utils::PrintAsString($folderid), mapi_last_hresult()), SYNC_FSSTATUS_CODEUNKNOWN); } }
function isUnicodeStore($store) { $supportmask = mapi_getprops($store, array(PR_STORE_SUPPORT_MASK)); if (isset($supportmask[PR_STORE_SUPPORT_MASK]) && $supportmask[PR_STORE_SUPPORT_MASK] & STORE_UNICODE_OK) { print "Store supports properties containing Unicode characters.\n"; define('STORE_SUPPORTS_UNICODE', true); } else { print "Store does not support properties containing Unicode characters.\n"; define('STORE_SUPPORTS_UNICODE', false); } }
/** * Publishing the FreeBusy information of the default calendar. The * folderentryid argument is used to check if the default calendar * should be updated or not. * * @param $store MAPIobject Store object of the store that needs publishing * @param $folderentryid binary entryid of the folder that needs to be updated. */ function publishFreeBusy($store, $l_rSession, $folderentryid = false) { // Publish updated free/busy information // First get default calendar from the root folder $rootFolder = mapi_msgstore_openentry($store, null); $rootFolderProps = mapi_getprops($rootFolder, array(PR_IPM_APPOINTMENT_ENTRYID)); // If no folderentryid supplied or if the supplied entryid matches the default calendar. if (!$folderentryid || $rootFolderProps[PR_IPM_APPOINTMENT_ENTRYID] == $folderentryid) { // Get the calendar and owner entryID $calendar = mapi_msgstore_openentry($store, $rootFolderProps[PR_IPM_APPOINTMENT_ENTRYID]); $storeProps = mapi_msgstore_getprops($store, array(PR_MAILBOX_OWNER_ENTRYID)); if (isset($storeProps[PR_MAILBOX_OWNER_ENTRYID])) { // Lets share! $pub = new FreeBusyPublish($l_rSession, $store, $calendar, $storeProps[PR_MAILBOX_OWNER_ENTRYID]); $pub->publishFB(time() - 7 * 24 * 60 * 60, 6 * 30 * 24 * 60 * 60); // publish from one week ago, 6 months ahead } } }
/** * Checks if the user is not disabled for Z-Push. * * @access private * @throws FatalException if user is disabled for Z-Push * * @return boolean */ private function isZPushEnabled() { $addressbook = $this->getAddressbook(); $userEntryid = mapi_getprops($this->store, array(PR_MAILBOX_OWNER_ENTRYID)); $mailuser = mapi_ab_openentry($addressbook, $userEntryid[PR_MAILBOX_OWNER_ENTRYID]); $enabledFeatures = mapi_getprops($mailuser, array(PR_EC_DISABLED_FEATURES)); if (isset($enabledFeatures[PR_EC_DISABLED_FEATURES]) && is_array($enabledFeatures[PR_EC_DISABLED_FEATURES]) && in_array(self::ZPUSH_ENABLED, $enabledFeatures[PR_EC_DISABLED_FEATURES])) { throw new FatalException("User is disabled for Z-Push."); } return true; }
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); }
/** * Get the private contact folder of all users */ function getPrivateContactFolders($session, $defaultstore) { $addrbook = mapi_openaddressbook($session); $addr_entryid = mapi_ab_getdefaultdir($addrbook); $abcontainer = mapi_ab_openentry($addrbook, $addr_entryid); $contentstable = mapi_folder_getcontentstable($abcontainer); // restrict table on only MAPI_MAILUSER accounts mapi_table_restrict($contentstable, array(RES_PROPERTY, array(RELOP => RELOP_EQ, ULPROPTAG => PR_OBJECT_TYPE, VALUE => array(PR_OBJECT_TYPE => MAPI_MAILUSER)))); // sort table on display name mapi_table_sort($contentstable, array(PR_DISPLAY_NAME => TABLE_SORT_ASCEND)); $users = mapi_table_queryrows($contentstable, array(PR_ACCOUNT, PR_ENTRYID, PR_DISPLAY_NAME), 0, mapi_table_getrowcount($contentstable)); $contactArray = array(); for ($i = 0; $i < sizeof($users); $i++) { $store_entryid = mapi_msgstore_createentryid($defaultstore, $users[$i][PR_ACCOUNT]); $store = mapi_openmsgstore($session, $store_entryid); $rootcontainer = mapi_msgstore_openentry($store); if ($rootcontainer) { $props = mapi_getprops($rootcontainer, array(PR_IPM_CONTACT_ENTRYID)); if (isset($props[PR_IPM_CONTACT_ENTRYID])) { $entryid = $props[PR_IPM_CONTACT_ENTRYID]; $folder = mapi_msgstore_openentry($store, $entryid); if ($folder) { $table = mapi_folder_getcontentstable($folder); $totalrow = mapi_table_getrowcount($table); $rows = array(); $contacts = array(); $properties = getContactProperties($defaultstore); if ($totalrow > 0) { $rows = mapi_table_queryrows($table, $properties, 0, $totalrow); for ($j = 0; $j < sizeof($rows); $j++) { $rows[$j][268370178] = md5($rows[$j][268370178]); } for ($k = 0; $k < sizeof($rows); $k++) { // do not add private contacts if (!array_key_exists(-2119827445, $rows[$k]) || array_key_exists(-2119827445, $rows[$k]) && $rows[$k][-2119827445] != 1) { foreach ($rows[$k] as $key => $value) { $attribute = mapKey($key); if ($attribute != "") { $contacts[$k][$attribute] = $value; } } } } $contactArray[] = array("username" => $users[$i][PR_ACCOUNT], "contacts" => $contacts); } } } } } // print_r($contactArray); return $contactArray; }
/** * Gets the required inbox properties. * * @access private * @return array */ private function getInboxProps() { if (!isset($this->inboxProps) || empty($this->inboxProps)) { ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->getInboxProps(): Getting inbox properties."); $inbox = mapi_msgstore_getreceivefolder($this->store); $this->inboxProps = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_TASK_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_JOURNAL_ENTRYID)); } return $this->inboxProps; }
/** * Imports a change on a folder * * @param object $folder SyncFolder * * @access public * @return string id of the folder * @throws StatusException */ public function ImportFolderChange($folder) { $id = isset($folder->serverid) ? $folder->serverid : false; $parent = $folder->parentid; $displayname = u2wi($folder->displayname); $type = $folder->type; if (Utils::IsSystemFolder($type)) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, system folder can not be created/modified", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname), SYNC_FSSTATUS_SYSTEMFOLDER); } // create a new folder if $id is not set if (!$id) { // the root folder is "0" - get IPM_SUBTREE if ($parent == "0") { $parentprops = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID)); if (isset($parentprops[PR_IPM_SUBTREE_ENTRYID])) { $parentfentryid = $parentprops[PR_IPM_SUBTREE_ENTRYID]; } } else { $parentfentryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($parent)); } if (!$parentfentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open parent folder (no entry id)", Utils::PrintAsString(false), $folder->parentid, $displayname), SYNC_FSSTATUS_PARENTNOTFOUND); } $parentfolder = mapi_msgstore_openentry($this->store, $parentfentryid); if (!$parentfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open parent folder (open entry)", Utils::PrintAsString(false), $folder->parentid, $displayname), SYNC_FSSTATUS_PARENTNOTFOUND); } // mapi_folder_createfolder() fails if a folder with this name already exists -> MAPI_E_COLLISION $newfolder = mapi_folder_createfolder($parentfolder, $displayname, ""); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, mapi_folder_createfolder() failed: 0x%X", Utils::PrintAsString(false), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_FOLDEREXISTS); } mapi_setprops($newfolder, array(PR_CONTAINER_CLASS => MAPIUtils::GetContainerClassFromFolderType($type))); $props = mapi_getprops($newfolder, array(PR_SOURCE_KEY)); if (isset($props[PR_SOURCE_KEY])) { $sourcekey = bin2hex($props[PR_SOURCE_KEY]); ZLog::Write(LOGLEVEL_DEBUG, sprintf("Created folder '%s' with id: '%s'", $displayname, $sourcekey)); return $sourcekey; } else { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, folder created but PR_SOURCE_KEY not available: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } return false; } // update folder $entryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($id)); if (!$entryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open folder (no entry id): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_PARENTNOTFOUND); } $folder = mapi_msgstore_openentry($this->store, $entryid); if (!$folder) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open folder (open entry): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_PARENTNOTFOUND); } $props = mapi_getprops($folder, array(PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, PR_DISPLAY_NAME, PR_CONTAINER_CLASS)); if (!isset($props[PR_SOURCE_KEY]) || !isset($props[PR_PARENT_SOURCE_KEY]) || !isset($props[PR_DISPLAY_NAME]) || !isset($props[PR_CONTAINER_CLASS])) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, folder data not available: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } if ($parent == "0") { $parentprops = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID)); $parentfentryid = $parentprops[PR_IPM_SUBTREE_ENTRYID]; $mapifolder = mapi_msgstore_openentry($this->store, $parentfentryid); $rootfolderprops = mapi_getprops($mapifolder, array(PR_SOURCE_KEY)); $parent = bin2hex($rootfolderprops[PR_SOURCE_KEY]); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesICS->ImportFolderChange(): resolved AS parent '0' to sourcekey '%s'", $parent)); } // In theory the parent id could change, which means that the folder was moved. // It is unknown if any device supports this, so we do currently not implement it (no known device is able to do this) if (bin2hex($props[PR_PARENT_SOURCE_KEY]) !== $parent) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Folder was moved to another location, which is currently not supported. Please report this to the Z-Push dev team together with the WBXML log and your device details (model, firmware etc).", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_UNKNOWNERROR); } $props = array(PR_DISPLAY_NAME => $displayname); mapi_setprops($folder, $props); mapi_savechanges($folder); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, mapi_savechanges() failed: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } ZLog::Write(LOGLEVEL_DEBUG, "Imported changes for folder: {$id}"); return $id; }
/** * Function will open FINDER_ROOT folder in root container * public folder's don't have FINDER_ROOT folder * * @see getSearchFoldersRoot($store) function in the webaccess * * @return mapiFolderObject root folder for search folders */ private function getSearchFoldersRoot() { // check if we can create search folders $storeProps = mapi_getprops($this->store, array(PR_STORE_SUPPORT_MASK, PR_FINDER_ENTRYID)); if (($storeProps[PR_STORE_SUPPORT_MASK] & STORE_SEARCH_OK) != STORE_SEARCH_OK) { ZLog::Write(LOGLEVEL_WARN, "Store doesn't support search folders. Public store doesn't have FINDER_ROOT folder"); return false; } // open search folders root $searchRootFolder = mapi_msgstore_openentry($this->store, $storeProps[PR_FINDER_ENTRYID]); if (mapi_last_hresult() != NOERROR) { ZLog::Write(LOGLEVEL_WARN, sprintf("Unable to open search folder (0x%X)", mapi_last_hresult())); return false; } return $searchRootFolder; }
/** * Saves the recurrence data to the recurrence property * @param array $properties the recurrence data. * @return string binary string */ function saveRecurrence() { // Only save if a message was passed if (!isset($this->message)) { return; } // Abort if no recurrence was set if (!isset($this->recur["type"]) && !isset($this->recur["subtype"])) { return; } if (!isset($this->recur["start"]) && !isset($this->recur["end"])) { return; } if (!isset($this->recur["startocc"]) && !isset($this->recur["endocc"])) { return; } $rdata = pack("CCCCCCV", 0x4, 0x30, 0x4, 0x30, (int) $this->recur["type"], 0x20, (int) $this->recur["subtype"]); $weekstart = 1; //monday $forwardcount = 0; $restocc = 0; $dayofweek = (int) gmdate("w", (int) $this->recur["start"]); //0 (for Sunday) through 6 (for Saturday) $term = (int) $this->recur["type"]; switch ($term) { case 0xa: // Daily if (!isset($this->recur["everyn"])) { return; } if ($this->recur["subtype"] == 1) { // Daily every workday $rdata .= pack("VVVV", 6 * 24 * 60, 1, 0, 0x3e); } else { // Daily every N days (everyN in minutes) $everyn = (int) $this->recur["everyn"] / 1440; // Calc first occ $firstocc = $this->unixDataToRecurData($this->recur["start"]) % (int) $this->recur["everyn"]; $rdata .= pack("VVV", $firstocc, (int) $this->recur["everyn"], $this->recur["regen"] ? 1 : 0); } break; case 0xb: // Weekly if (!isset($this->recur["everyn"])) { return; } if (!$this->recur["regen"] && !isset($this->recur["weekdays"])) { return; } // No need to calculate startdate if sliding flag was set. if (!$this->recur['regen']) { // Calculate start date of recurrence // Find the first day that matches one of the weekdays selected $daycount = 0; $dayskip = -1; for ($j = 0; $j < 7; $j++) { if ((int) $this->recur["weekdays"] & 1 << ($dayofweek + $j) % 7) { if ($dayskip == -1) { $dayskip = $j; } $daycount++; } } // $dayskip is the number of days to skip from the startdate until the first occurrence // $daycount is the number of days per week that an occurrence occurs $weekskip = 0; if ($dayofweek < $weekstart && $dayskip > 0 || $dayofweek + $dayskip > 6) { $weekskip = 1; } // Check if the recurrence ends after a number of occurences, in that case we must calculate the // remaining occurences based on the start of the recurrence. if ((int) $this->recur["term"] == 0x22) { // $weekskip is the amount of weeks to skip from the startdate before the first occurence // $forwardcount is the maximum number of week occurrences we can go ahead after the first occurrence that // is still inside the recurrence. We subtract one to make sure that the last week is never forwarded over // (eg when numoccur = 2, and daycount = 1) $forwardcount = floor((int) ($this->recur["numoccur"] - 1) / $daycount); // $restocc is the number of occurrences left after $forwardcount whole weeks of occurrences, minus one // for the occurrence on the first day $restocc = (int) $this->recur["numoccur"] - $forwardcount * $daycount - 1; // $forwardcount is now the number of weeks we can go forward and still be inside the recurrence $forwardcount *= (int) $this->recur["everyn"]; } // The real start is start + dayskip + weekskip-1 (since dayskip will already bring us into the next week) $this->recur["start"] = (int) $this->recur["start"] + $dayskip * 24 * 60 * 60 + $weekskip * ((int) $this->recur["everyn"] - 1) * 7 * 24 * 60 * 60; } // Calc first occ $firstocc = $this->unixDataToRecurData($this->recur["start"]) % ((int) $this->recur["everyn"] * 7 * 24 * 60); $firstocc -= ((int) gmdate("w", (int) $this->recur["start"]) - 1) * 24 * 60; if ($this->recur["regen"]) { $rdata .= pack("VVV", $firstocc, (int) $this->recur["everyn"], 1); } else { $rdata .= pack("VVVV", $firstocc, (int) $this->recur["everyn"], 0, (int) $this->recur["weekdays"]); } break; case 0xc: // Monthly // Monthly case 0xd: // Yearly if (!isset($this->recur["everyn"])) { return; } if ($term == 0xd && !isset($this->recur["month"])) { return; } if ($term == 0xc) { $everyn = (int) $this->recur["everyn"]; } else { $everyn = $this->recur["regen"] ? (int) $this->recur["everyn"] * 12 : 12; } // Get montday/month/year of original start $curmonthday = gmdate("j", (int) $this->recur["start"]); $curyear = gmdate("Y", (int) $this->recur["start"]); $curmonth = gmdate("n", (int) $this->recur["start"]); // Check if the recurrence ends after a number of occurences, in that case we must calculate the // remaining occurences based on the start of the recurrence. if ((int) $this->recur["term"] == 0x22) { // $forwardcount is the number of occurrences we can skip and still be inside the recurrence range (minus // one to make sure there are always at least one occurrence left) $forwardcount = ((int) $this->recur["numoccur"] - 1) * $everyn; } // Get month for yearly on D'th day of month M if ($term == 0xd) { $selmonth = floor((int) $this->recur["month"] / (24 * 60 * 29)) + 1; // 1=jan, 2=feb, eg } switch ((int) $this->recur["subtype"]) { // on D day of every M month case 2: if (!isset($this->recur["monthday"])) { return; } // Recalc startdate // Set on the right begin day // Go the beginning of the month $this->recur["start"] -= ($curmonthday - 1) * 24 * 60 * 60; // Go the the correct month day $this->recur["start"] += ((int) $this->recur["monthday"] - 1) * 24 * 60 * 60; // If the previous calculation gave us a start date *before* the original start date, then we need to skip to the next occurrence if ($term == 0xc && (int) $this->recur["monthday"] < $curmonthday || $term == 0xd && ($selmonth < $curmonth || $selmonth == $curmonth && (int) $this->recur["monthday"] < $curmonthday)) { if ($term == 0xd) { $count = $everyn - ($curmonth - $selmonth); } else { $count = $everyn; } // Monthly, go to next occurrence in 'everyn' months // Forward by $count months. This is done by getting the number of days in that month and forwarding that many days for ($i = 0; $i < $count; $i++) { $this->recur["start"] += $this->getMonthInSeconds($curyear, $curmonth); if ($curmonth == 12) { $curyear++; $curmonth = 0; } $curmonth++; } } // "start" is now pointing to the first occurrence, except that it will overshoot if the // month in which it occurs has less days than specified as the day of the month. So 31st // of each month will overshoot in february (29 days). We compensate for that by checking // if the day of the month we got is wrong, and then back up to the last day of the previous // month. if ((int) $this->recur["monthday"] >= 28 && (int) $this->recur["monthday"] <= 31 && gmdate("j", (int) $this->recur["start"]) < (int) $this->recur["monthday"]) { $this->recur["start"] -= gmdate("j", (int) $this->recur["start"]) * 24 * 60 * 60; } // "start" is now the first occurrence if ($term == 0xc) { // Calc first occ $monthIndex = (12 % $everyn * (((int) gmdate("Y", $this->recur["start"]) - 1601) % $everyn) % $everyn + ((int) gmdate("n", $this->recur["start"]) - 1)) % $everyn; $firstocc = 0; for ($i = 0; $i < $monthIndex; $i++) { $firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i % 12 + 1) / 60; } $rdata .= pack("VVVV", $firstocc, $everyn, $this->recur["regen"], (int) $this->recur["monthday"]); } else { // Calc first occ $firstocc = 0; $monthIndex = (int) gmdate("n", $this->recur["start"]); for ($i = 1; $i < $monthIndex; $i++) { $firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i) / 60; } $rdata .= pack("VVVV", $firstocc, $everyn, $this->recur["regen"], (int) $this->recur["monthday"]); } break; case 3: // monthly: on Nth weekday of every M month // yearly: on Nth weekday of M month if (!isset($this->recur["weekdays"]) && !isset($this->recur["nday"])) { return; } $weekdays = (int) $this->recur["weekdays"]; $nday = (int) $this->recur["nday"]; // Calc startdate $monthbegindow = (int) $this->recur["start"]; if ($nday == 5) { // Set date on the last day of the last month $monthbegindow += (gmdate("t", $monthbegindow) - gmdate("j", $monthbegindow)) * 24 * 60 * 60; } else { // Set on the first day of the month $monthbegindow -= (gmdate("j", $monthbegindow) - 1) * 24 * 60 * 60; } if ($term == 0xd) { // Set on right month if ($selmonth < $curmonth) { $tmp = 12 - $curmonth + $selmonth; } else { $tmp = $selmonth - $curmonth; } for ($i = 0; $i < $tmp; $i++) { $monthbegindow += $this->getMonthInSeconds($curyear, $curmonth); if ($curmonth == 12) { $curyear++; $curmonth = 0; } $curmonth++; } } else { // Check or you exist in the right month for ($i = 0; $i < 7; $i++) { if ($nday == 5 && 1 << (gmdate("w", $monthbegindow) - $i) % 7 & $weekdays) { $day = gmdate("j", $monthbegindow) - $i; break; } else { if ($nday != 5 && 1 << (gmdate("w", $monthbegindow) + $i) % 7 & $weekdays) { $day = ($nday - 1) * 7 + ($i + 1); break; } } } // Goto the next X month if (isset($day) && $day < gmdate("j", (int) $this->recur["start"])) { if ($nday == 5) { $monthbegindow += 24 * 60 * 60; if ($curmonth == 12) { $curyear++; $curmonth = 0; } $curmonth++; } for ($i = 0; $i < $everyn; $i++) { $monthbegindow += $this->getMonthInSeconds($curyear, $curmonth); if ($curmonth == 12) { $curyear++; $curmonth = 0; } $curmonth++; } if ($nday == 5) { $monthbegindow -= 24 * 60 * 60; } } } //FIXME: weekstart? $day = 0; // Set start on the right day for ($i = 0; $i < 7; $i++) { if ($nday == 5 && 1 << (gmdate("w", $monthbegindow) - $i) % 7 & $weekdays) { $day = $i; break; } else { if ($nday != 5 && 1 << (gmdate("w", $monthbegindow) + $i) % 7 & $weekdays) { $day = ($nday - 1) * 7 + ($i + 1); break; } } } if ($nday == 5) { $monthbegindow -= $day * 24 * 60 * 60; } else { $monthbegindow += ($day - 1) * 24 * 60 * 60; } $firstocc = 0; if ($term == 0xc) { // Calc first occ $monthIndex = (12 % $everyn * (((int) gmdate("Y", $this->recur["start"]) - 1601) % $everyn) % $everyn + ((int) gmdate("n", $this->recur["start"]) - 1)) % $everyn; for ($i = 0; $i < $monthIndex; $i++) { $firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i % 12 + 1) / 60; } $rdata .= pack("VVVVV", $firstocc, $everyn, 0, $weekdays, $nday); } else { // Calc first occ $monthIndex = (int) gmdate("n", $this->recur["start"]); for ($i = 1; $i < $monthIndex; $i++) { $firstocc += $this->getMonthInSeconds(1601 + floor($i / 12), $i) / 60; } $rdata .= pack("VVVVV", $firstocc, $everyn, 0, $weekdays, $nday); } break; } break; } if (!isset($this->recur["term"])) { return; } // Terminate $term = (int) $this->recur["term"]; $rdata .= pack("CCCC", $term, 0x20, 0x0, 0x0); switch ($term) { // After the given enddate case 0x21: $rdata .= pack("V", 10); break; // After a number of times // After a number of times case 0x22: if (!isset($this->recur["numoccur"])) { return; } $rdata .= pack("V", (int) $this->recur["numoccur"]); break; // Never ends // Never ends case 0x23: $rdata .= pack("V", 0); break; } // Strange little thing for the recurrence type "every workday" if ((int) $this->recur["type"] == 0xb && (int) $this->recur["subtype"] == 1) { $rdata .= pack("V", 1); } else { // Other recurrences $rdata .= pack("V", 0); } // Exception data // Get all exceptions $deleted_items = $this->recur["deleted_occurences"]; $changed_items = $this->recur["changed_occurences"]; // Merge deleted and changed items into one list $items = $deleted_items; foreach ($changed_items as $changed_item) { array_push($items, $changed_item["basedate"]); } sort($items); // Add the merged list in to the rdata $rdata .= pack("V", count($items)); foreach ($items as $item) { $rdata .= pack("V", $this->unixDataToRecurData($item)); } // Loop through the changed exceptions (not deleted) $rdata .= pack("V", count($changed_items)); $items = array(); foreach ($changed_items as $changed_item) { $items[] = $this->dayStartOf($changed_item["start"]); } sort($items); // Add the changed items list int the rdata foreach ($items as $item) { $rdata .= pack("V", $this->unixDataToRecurData($item)); } // Set start date $rdata .= pack("V", $this->unixDataToRecurData((int) $this->recur["start"])); // Set enddate switch ($term) { // After the given enddate case 0x21: $rdata .= pack("V", $this->unixDataToRecurData((int) $this->recur["end"])); break; // After a number of times // After a number of times case 0x22: // @todo: calculate enddate with intval($this->recur["startocc"]) + intval($this->recur["duration"]) > 24 hour $occenddate = (int) $this->recur["start"]; switch ((int) $this->recur["type"]) { case 0xa: //daily if ($this->recur["subtype"] == 1) { // Daily every workday $restocc = (int) $this->recur["numoccur"]; // Get starting weekday $nowtime = $this->gmtime($occenddate); $j = $nowtime["tm_wday"]; while (1) { if ($j % 7 > 0 && $j % 7 < 6) { $restocc--; } $j++; if ($restocc <= 0) { break; } $occenddate += 24 * 60 * 60; } } else { // -1 because the first day already counts (from 1-1-1980 to 1-1-1980 is 1 occurrence) $occenddate += (int) $this->recur["everyn"] * 60 * ((int) $this->recur["numoccur"] - 1); } break; case 0xb: //weekly // Needed values // $forwardcount - number of weeks we can skip forward // $restocc - number of remaning occurrences after the week skip // Add the weeks till the last item $occenddate += $forwardcount * 7 * 24 * 60 * 60; $dayofweek = gmdate("w", $occenddate); // Loop through the last occurrences until we have had them all for ($j = 1; $restocc > 0; $j++) { // Jump to the next week (which may be N weeks away) when going over the week boundary if (($dayofweek + $j) % 7 == $weekstart) { $occenddate += ((int) $this->recur["everyn"] - 1) * 7 * 24 * 60 * 60; } // If this is a matching day, once less occurrence to process if ((int) $this->recur["weekdays"] & 1 << ($dayofweek + $j) % 7) { $restocc--; } // Next day $occenddate += 24 * 60 * 60; } break; case 0xc: //monthly //monthly case 0xd: //yearly $curyear = gmdate("Y", (int) $this->recur["start"]); $curmonth = gmdate("n", (int) $this->recur["start"]); // $forwardcount = months switch ((int) $this->recur["subtype"]) { case 2: // on D day of every M month while ($forwardcount > 0) { $occenddate += $this->getMonthInSeconds($curyear, $curmonth); if ($curmonth >= 12) { $curmonth = 1; $curyear++; } else { $curmonth++; } $forwardcount--; } // compensation between 28 and 31 if ((int) $this->recur["monthday"] >= 28 && (int) $this->recur["monthday"] <= 31 && gmdate("j", $occenddate) < (int) $this->recur["monthday"]) { if (gmdate("j", $occenddate) < 28) { $occenddate -= gmdate("j", $occenddate) * 24 * 60 * 60; } else { $occenddate += (gmdate("t", $occenddate) - gmdate("j", $occenddate)) * 24 * 60 * 60; } } break; case 3: // on Nth weekday of every M month $nday = (int) $this->recur["nday"]; //1 tot 5 $weekdays = (int) $this->recur["weekdays"]; while ($forwardcount > 0) { $occenddate += $this->getMonthInSeconds($curyear, $curmonth); if ($curmonth >= 12) { $curmonth = 1; $curyear++; } else { $curmonth++; } $forwardcount--; } if ($nday == 5) { // Set date on the last day of the last month $occenddate += (gmdate("t", $occenddate) - gmdate("j", $occenddate)) * 24 * 60 * 60; } else { // Set date on the first day of the last month $occenddate -= (gmdate("j", $occenddate) - 1) * 24 * 60 * 60; } for ($i = 0; $i < 7; $i++) { if ($nday == 5 && 1 << (gmdate("w", $occenddate) - $i) % 7 & $weekdays) { $occenddate -= $i * 24 * 60 * 60; break; } else { if ($nday != 5 && 1 << (gmdate("w", $occenddate) + $i) % 7 & $weekdays) { $occenddate += ($i + ($nday - 1) * 7) * 24 * 60 * 60; break; } } } break; //case 3: } break; } if (defined("PHP_INT_MAX") && $occenddate > PHP_INT_MAX) { $occenddate = PHP_INT_MAX; } $this->recur["end"] = $occenddate; $rdata .= pack("V", $this->unixDataToRecurData((int) $this->recur["end"])); break; // Never ends // Never ends case 0x23: default: $this->recur["end"] = 0x7fffffff; // max date -> 2038 $rdata .= pack("V", 0x5ae980df); break; } // UTC date $utcstart = $this->toGMT($this->tz, (int) $this->recur["start"]); $utcend = $this->toGMT($this->tz, (int) $this->recur["end"]); //utc date+time $utcfirstoccstartdatetime = isset($this->recur["startocc"]) ? $utcstart + (int) $this->recur["startocc"] * 60 : $utcstart; $utcfirstoccenddatetime = isset($this->recur["endocc"]) ? $utcstart + (int) $this->recur["endocc"] * 60 : $utcstart; // update reminder time mapi_setprops($this->message, array($this->proptags["reminder_time"] => $utcfirstoccstartdatetime)); // update first occurrence date mapi_setprops($this->message, array($this->proptags["startdate"] => $utcfirstoccstartdatetime)); mapi_setprops($this->message, array($this->proptags["duedate"] => $utcfirstoccenddatetime)); mapi_setprops($this->message, array($this->proptags["commonstart"] => $utcfirstoccstartdatetime)); mapi_setprops($this->message, array($this->proptags["commonend"] => $utcfirstoccenddatetime)); // Set Outlook properties, if it is an appointment if (isset($this->recur["message_class"]) && $this->recur["message_class"] == "IPM.Appointment") { // update real begin and real end date mapi_setprops($this->message, array($this->proptags["startdate_recurring"] => $utcstart)); mapi_setprops($this->message, array($this->proptags["enddate_recurring"] => $utcend)); // recurrencetype // Strange enough is the property recurrencetype, (type-0x9) and not the CDO recurrencetype mapi_setprops($this->message, array($this->proptags["recurrencetype"] => (int) $this->recur["type"] - 0x9)); // set named prop 'side_effects' to 369, needed for Outlook to ask for single or total recurrence when deleting mapi_setprops($this->message, array($this->proptags["side_effects"] => 369)); } else { mapi_setprops($this->message, array($this->proptags["side_effects"] => 3441)); } // FlagDueBy is datetime of the first reminder occurrence. Outlook gives on this time a reminder popup dialog // Any change of the recurrence (including changing and deleting exceptions) causes the flagdueby to be reset // to the 'next' occurrence; this makes sure that deleting the next ocurrence will correctly set the reminder to // the occurrence after that. The 'next' occurrence is defined as being the first occurrence that starts at moment X (server time) // with the reminder flag set. $reminderprops = mapi_getprops($this->message, array($this->proptags["reminder_minutes"])); if (isset($reminderprops[$this->proptags["reminder_minutes"]])) { $occ = false; $occurrences = $this->getItems(time(), 0x7ff00000, 3, true); for ($i = 0, $len = count($occurrences); $i < $len; $i++) { // This will actually also give us appointments that have already started, but not yet ended. Since we want the next // reminder that occurs after time(), we may have to skip the first few entries. We get 3 entries since that is the maximum // number that would be needed (assuming reminder for item X cannot be before the previous occurrence starts). Worst case: // time() is currently after start but before end of item, but reminder of next item has already passed (reminder for next item // can be DURING the previous item, eg daily allday events). In that case, the first and second items must be skipped. if ($occurrences[$i][$this->proptags["startdate"]] - $reminderprops[$this->proptags["reminder_minutes"]] * 60 > time()) { $occ = $occurrences[$i]; break; } } if ($occ) { mapi_setprops($this->message, array($this->proptags["flagdueby"] => $occ[$this->proptags["startdate"]] - $reminderprops[$this->proptags["reminder_minutes"]] * 60)); } else { // Last reminder passed, no reminders any more. mapi_setprops($this->message, array($this->proptags["reminder"] => false, $this->proptags["flagdueby"] => 0x7ff00000)); } } // Default data // Second item (0x08) indicates the Outlook version (see documentation at the bottom of this file for more information) $rdata .= pack("VCCCC", 0x3006, 0x8, 0x30, 0x0, 0x0); if (isset($this->recur["startocc"]) && isset($this->recur["endocc"])) { // Set start and endtime in minutes $rdata .= pack("VV", (int) $this->recur["startocc"], (int) $this->recur["endocc"]); } // Detailed exception data $changed_items = $this->recur["changed_occurences"]; $rdata .= pack("v", count($changed_items)); foreach ($changed_items as $changed_item) { // Set start and end time of exception $rdata .= pack("V", $this->unixDataToRecurData($changed_item["start"])); $rdata .= pack("V", $this->unixDataToRecurData($changed_item["end"])); $rdata .= pack("V", $this->unixDataToRecurData($changed_item["basedate"])); //Bitmask $bitmask = 0; // Check for changed strings if (isset($changed_item["subject"])) { $bitmask |= 1 << 0; } if (isset($changed_item["remind_before"])) { $bitmask |= 1 << 2; } if (isset($changed_item["reminder_set"])) { $bitmask |= 1 << 3; } if (isset($changed_item["location"])) { $bitmask |= 1 << 4; } if (isset($changed_item["busystatus"])) { $bitmask |= 1 << 5; } if (isset($changed_item["alldayevent"])) { $bitmask |= 1 << 7; } if (isset($changed_item["label"])) { $bitmask |= 1 << 8; } $rdata .= pack("v", $bitmask); // Set "subject" if (isset($changed_item["subject"])) { // convert utf-8 to non-unicode blob string (us-ascii?) $subject = iconv("UTF-8", "windows-1252//TRANSLIT", $changed_item["subject"]); $length = strlen($subject); $rdata .= pack("vv", $length + 1, $length); $rdata .= pack("a" . $length, $subject); } if (isset($changed_item["remind_before"])) { $rdata .= pack("V", $changed_item["remind_before"]); } if (isset($changed_item["reminder_set"])) { $rdata .= pack("V", $changed_item["reminder_set"]); } if (isset($changed_item["location"])) { $location = iconv("UTF-8", "windows-1252//TRANSLIT", $changed_item["location"]); $length = strlen($location); $rdata .= pack("vv", $length + 1, $length); $rdata .= pack("a" . $length, $location); } if (isset($changed_item["busystatus"])) { $rdata .= pack("V", $changed_item["busystatus"]); } if (isset($changed_item["alldayevent"])) { $rdata .= pack("V", $changed_item["alldayevent"]); } if (isset($changed_item["label"])) { $rdata .= pack("V", $changed_item["label"]); } } $rdata .= pack("V", 0); // write extended data foreach ($changed_items as $changed_item) { $rdata .= pack("V", 0); if (isset($changed_item["subject"]) || isset($changed_item["location"])) { $rdata .= pack("V", $this->unixDataToRecurData($changed_item["start"])); $rdata .= pack("V", $this->unixDataToRecurData($changed_item["end"])); $rdata .= pack("V", $this->unixDataToRecurData($changed_item["basedate"])); } if (isset($changed_item["subject"])) { $subject = iconv("UTF-8", "UCS-2LE", $changed_item["subject"]); $length = iconv_strlen($subject, "UCS-2LE"); $rdata .= pack("v", $length); $rdata .= pack("a" . $length * 2, $subject); } if (isset($changed_item["location"])) { $location = iconv("UTF-8", "UCS-2LE", $changed_item["location"]); $length = iconv_strlen($location, "UCS-2LE"); $rdata .= pack("v", $length); $rdata .= pack("a" . $length * 2, $location); } if (isset($changed_item["subject"]) || isset($changed_item["location"])) { $rdata .= pack("V", 0); } } $rdata .= pack("V", 0); // Set props mapi_setprops($this->message, array($this->proptags["recurring_data"] => $rdata, $this->proptags["recurring"] => true)); if (isset($this->tz) && $this->tz) { $timezone = "GMT"; if ($this->tz["timezone"] != 0) { // Create user readable timezone information $timezone = sprintf("(GMT %s%02d:%02d)", -$this->tz["timezone"] > 0 ? "+" : "-", abs($this->tz["timezone"] / 60), abs($this->tz["timezone"] % 60)); } mapi_setprops($this->message, array($this->proptags["timezone_data"] => $this->getTimezoneData($this->tz), $this->proptags["timezone"] => $timezone)); } }
function _isUnicodeStore() { $supportmask = mapi_getprops($this->_defaultstore, array(PR_STORE_SUPPORT_MASK)); if (isset($supportmask[PR_STORE_SUPPORT_MASK]) && $supportmask[PR_STORE_SUPPORT_MASK] & STORE_UNICODE_OK) { debugLog("Store supports properties containing Unicode characters."); define('STORE_SUPPORTS_UNICODE', true); //setlocale to UTF-8 in order to support properties containing Unicode characters //dw2412 this is nice but it does not work if for Heartbeat sync where during the sync something reverts the locale to i.e. "C" // since setlocale works on process level... setlocale(LC_CTYPE, 'en_US.utf-8'); } }
/** * Returns an SMTP address from an entry id * * @param string $entryid * * @access private * @return string */ private function getSMTPAddressFromEntryID($entryid) { $ab = mapi_openaddressbook($this->session); $mailuser = mapi_ab_openentry($ab, $entryid); if (!$mailuser) { return ""; } $props = mapi_getprops($mailuser, array(PR_ADDRTYPE, PR_SMTP_ADDRESS, PR_EMAIL_ADDRESS)); $addrtype = isset($props[PR_ADDRTYPE]) ? $props[PR_ADDRTYPE] : ""; if (isset($props[PR_SMTP_ADDRESS])) { return $props[PR_SMTP_ADDRESS]; } if ($addrtype == "SMTP" && isset($props[PR_EMAIL_ADDRESS])) { return $props[PR_EMAIL_ADDRESS]; } return ""; }
$l_aTableRows = mapi_table_queryallrows($l_rTableStores, array(PR_ENTRYID, PR_DEFAULT_STORE)); echo (mapi_last_hresult() == 0 ? "Fetching Deleted Folder..." : "Some error in fetching...") . "\n"; $l_bbnEntryID = false; // Either boolean or binary // Loop through returned rows for ($i = 0; $i < count($l_aTableRows); $i++) { // Check to see if this entry is the default store if (isset($l_aTableRows[$i][PR_DEFAULT_STORE]) && $l_aTableRows[$i][PR_DEFAULT_STORE] == true) { $storeEntryId = $l_aTableRows[$i][PR_ENTRYID]; break; } } // check if default root store's entry id found if ($storeEntryId) { $store = mapi_openmsgstore($l_rSession, $storeEntryId); $delStoreProps = mapi_getprops($store, array(PR_IPM_WASTEBASKET_ENTRYID)); $deletedFolder = mapi_msgstore_openentry($store, $delStoreProps[PR_IPM_WASTEBASKET_ENTRYID]); $table = mapi_folder_getcontentstable($deletedFolder); $delRows = mapi_table_queryallrows($table, array(PR_ENTRYID, PR_CREATION_TIME)); echo (mapi_last_hresult() == 0 ? "Fetching messages from Deleted Folder..." : "Some error in fetching...") . "\n"; if (count($delRows) > 0) { $delEntryIds = array(); echo 'Total messages in deleted folder found are : ' . count($delRows) . "\n"; for ($i = 0; $i < count($delRows); $i++) { if (greaterDate(date("Y-m-d G:i:s", $delRows[$i][PR_CREATION_TIME]), $daysBeforeDeleted)) { array_push($delEntryIds, $delRows[$i][PR_ENTRYID]); } } if (count($delEntryIds) > 0) { echo "\nDeleting all " . count($delEntryIds) . " messages...\n"; mapi_folder_deletemessages($deletedFolder, $delEntryIds);
/** * Convert vObject to an array of properties * @param array $properties * @param object $vCard */ public function propertiesToVObject($contact, &$vCard) { $this->logger->debug("Generating contact vCard from properties"); $p = $this->bridge->getExtendedProperties(); $contactProperties = mapi_getprops($contact); // $this->bridge->getProperties($contactId); $dump = print_r($contactProperties, true); $this->logger->trace("Contact properties:\n{$contactProperties}"); // Version check switch ($this->version) { case 2: $vCard->add('VERSION', '2.1'); break; case 3: $vCard->add('VERSION', '3.0'); break; case 4: $vCard->add('VERSION', '4.0'); break; default: $this->logger->fatal("Unrecognised VCard version: " . $this->version); return; } // Private contact ? if (isset($contactProperties[$p['private']]) && $contactProperties[$p['private']]) { $vCard->add('CLASS', 'PRIVATE'); // Not in VCARD 4.0 but keep it for compatibility } // Mandatory FN $this->setVCard($vCard, 'FN', $contactProperties, $p['display_name']); // Contact name and pro information // N property /* Special note: The structured property value corresponds, in sequence, to the Family Names (also known as surnames), Given Names, Additional Names, Honorific Prefixes, and Honorific Suffixes. The text components are separated by the SEMICOLON character (U+003B). Individual text components can include multiple text values separated by the COMMA character (U+002C). This property is based on the semantics of the X.520 individual name attributes [CCITT.X520.1988]. The property SHOULD be present in the vCard object when the name of the object the vCard represents follows the X.520 model. The SORT-AS parameter MAY be applied to this property. */ $contactInfos = array(); $contactInfos[] = isset($contactProperties[$p['surname']]) ? $contactProperties[$p['surname']] : ''; $contactInfos[] = isset($contactProperties[$p['given_name']]) ? $contactProperties[$p['given_name']] : ''; $contactInfos[] = isset($contactProperties[$p['middle_name']]) ? $contactProperties[$p['middle_name']] : ''; $contactInfos[] = isset($contactProperties[$p['display_name_prefix']]) ? $contactProperties[$p['display_name_prefix']] : ''; $contactInfos[] = isset($contactProperties[$p['generation']]) ? $contactProperties[$p['generation']] : ''; $element = new Sabre_VObject_Property("N"); $element->setValue(implode(';', $contactInfos)); // $element->offsetSet("SORT-AS", '"' . $contactProperties[$p['fileas']] . '"'); $vCard->add($element); $this->setVCard($vCard, 'SORT-AS', $contactProperties, $p['fileas']); $this->setVCard($vCard, 'NICKNAME', $contactProperties, $p['nickname']); $this->setVCard($vCard, 'TITLE', $contactProperties, $p['title']); $this->setVCard($vCard, 'ROLE', $contactProperties, $p['profession']); $this->setVCard($vCard, 'ORG', $contactProperties, $p['company_name']); $this->setVCard($vCard, 'OFFICE', $contactProperties, $p['office_location']); if ($this->version >= 4) { if (isset($contactProperties[$p['assistant']])) { if (!empty($contactProperties[$p['assistant']])) { $element = new Sabre_VObject_Property('RELATED'); $element->setValue($contactProperties[$p['assistant']]); $element->offsetSet('TYPE', 'assistant'); // Not RFC compliant $vCard->add($element); } } if (isset($contactProperties[$p['manager_name']])) { if (!empty($contactProperties[$p['manager_name']])) { $element = new Sabre_VObject_Property('RELATED'); $element->setValue($contactProperties[$p['manager_name']]); $element->offsetSet('TYPE', 'manager'); // Not RFC compliant $vCard->add($element); } } if (isset($contactProperties[$p['spouse_name']])) { if (!empty($contactProperties[$p['spouse_name']])) { $element = new Sabre_VObject_Property('RELATED'); $element->setValue($contactProperties[$p['spouse_name']]); $element->offsetSet('TYPE', 'spouse'); $vCard->add($element); } } } // older syntax - may be needed by some clients so keep it! $this->setVCard($vCard, 'X-MS-ASSISTANT', $contactProperties, $p['assistant']); $this->setVCard($vCard, 'X-MS-MANAGER', $contactProperties, $p['manager_name']); $this->setVCard($vCard, 'X-MS-SPOUSE', $contactProperties, $p['spouse_name']); // Dates if (isset($contactProperties[$p['birthday']]) && $contactProperties[$p['birthday']] > 0) { $vCard->add('BDAY', date(DATE_PATTERN, $contactProperties[$p['birthday']])); } if (isset($contactProperties[$p['wedding_anniversary']]) && $contactProperties[$p['wedding_anniversary']] > 0) { if ($this->version >= 4) { $vCard->add('ANNIVERSARY', date(DATE_PATTERN, $contactProperties[$p['wedding_anniversary']])); } else { $vCard->add('X-ANNIVERSARY', date(DATE_PATTERN, $contactProperties[$p['wedding_anniversary']])); } } // Telephone numbers // webaccess can handle 19 telephone numbers... $this->setVCard($vCard, 'TEL;TYPE=HOME,VOICE', $contactProperties, $p['home_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=HOME,VOICE', $contactProperties, $p['home2_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=CELL', $contactProperties, $p['cellular_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK,VOICE', $contactProperties, $p['office_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK,VOICE', $contactProperties, $p['business2_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK,FAX', $contactProperties, $p['business_fax_number']); $this->setVCard($vCard, 'TEL;TYPE=HOME,FAX', $contactProperties, $p['home_fax_number']); $this->setVCard($vCard, 'TEL;TYPE=PAGER', $contactProperties, $p['pager_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=ISDN', $contactProperties, $p['isdn_number']); $this->setVCard($vCard, 'TEL;TYPE=WORK', $contactProperties, $p['company_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=CAR', $contactProperties, $p['car_telephone_number']); $this->setVCard($vCard, 'TEL;TYPE=SECR', $contactProperties, $p['assistant_telephone_number']); // There are unmatched telephone numbers in zarafa, use them! $unmatchedProperties = array("callback_telephone_number", "other_telephone_number", "primary_fax_number", "primary_telephone_number", "radio_telephone_number", "telex_telephone_number", "ttytdd_telephone_number"); if (in_array(DEFAULT_TELEPHONE_NUMBER_PROPERTY, $unmatchedProperties)) { // unmatched found a match! $this->setVCard($vCard, 'TEL', $contactProperties, $p[DEFAULT_TELEPHONE_NUMBER_PROPERTY]); } $this->setVCardAddress($vCard, 'HOME', $contactProperties, 'home'); $this->setVCardAddress($vCard, 'WORK', $contactProperties, 'business'); $this->setVCardAddress($vCard, 'OTHER', $contactProperties, 'other'); // emails for ($i = 1; $i <= 3; $i++) { if (isset($contactProperties[$p["email_address_{$i}"]])) { // Zarafa needs an email display name $emailProperty = new Sabre_VObject_Property('EMAIL', $contactProperties[$p["email_address_{$i}"]]); // Get display name $dn = isset($contactProperties[$p["email_address_display_name_{$i}"]]) ? $contactProperties[$p["email_address_display_name_{$i}"]] : $contactProperties[$p['display_name']]; $emailProperty->offsetSet("X-CN", '"' . $dn . '"'); $vCard->add($emailProperty); } } // URL and Instant Messenging (vCard 3.0 extension) $this->setVCard($vCard, 'URL', $contactProperties, $p["webpage"]); $this->setVCard($vCard, 'IMPP', $contactProperties, $p["im"]); // Categories $contactCategories = ''; if (isset($contactProperties[$p['categories']])) { if (is_array($contactProperties[$p['categories']])) { $contactCategories = implode(',', $contactProperties[$p['categories']]); } else { $contactCategories = $contactProperties[$p['categories']]; } } if ($contactCategories != '') { $vCard->add('CATEGORIES', $contactCategories); } // Contact picture? $hasattachProp = mapi_getprops($contact, array(PR_HASATTACH)); $photo = NULL; $photoMime = ''; if (isset($hasattachProp[PR_HASATTACH]) && $hasattachProp[PR_HASATTACH]) { $attachmentTable = mapi_message_getattachmenttable($contact); $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD, PR_ATTACH_CONTENT_ID, PR_ATTACH_MIME_TAG, PR_ATTACHMENT_CONTACTPHOTO, PR_EC_WA_ATTACHMENT_HIDDEN_OVERRIDE)); $dump = print_r($attachments, true); $this->logger->trace("Contact attachments:\n{$dump}"); foreach ($attachments as $attachmentRow) { if (isset($attachmentRow[PR_ATTACHMENT_CONTACTPHOTO]) && $attachmentRow[PR_ATTACHMENT_CONTACTPHOTO]) { $attach = mapi_message_openattach($contact, $attachmentRow[PR_ATTACH_NUM]); $photo = mapi_attach_openbin($attach, PR_ATTACH_DATA_BIN); if (isset($attachmentRow[PR_ATTACH_MIME_TAG])) { $photoMime = $attachmentRow[PR_ATTACH_MIME_TAG]; } else { $photoMime = 'image/jpeg'; } break; } } } if ($photo != NULL) { // SogoConnector does not like image/jpeg if ($photoMime == 'image/jpeg') { $photoMime = 'JPEG'; } $this->logger->trace("Adding contact picture to VCard"); $photoEncoded = base64_encode($photo); $photoProperty = new Sabre_VObject_Property('PHOTO', $photoEncoded); $photoProperty->offsetSet('TYPE', $photoMime); $photoProperty->offsetSet('ENCODING', 'b'); $vCard->add($photoProperty); } // Misc $vCard->add('UID', "urn:uuid:" . substr($contactProperties[PR_CARDDAV_URI], 0, -4)); // $this->entryIdToStr($contactProperties[PR_ENTRYID])); $this->setVCard($vCard, 'NOTE', $contactProperties, $p['notes']); $vCard->add('PRODID', VCARD_PRODUCT_ID); $vCard->add('REV', date('c', $contactProperties[$p['last_modification_time']])); }
/** * Resolves recipient from the contact list and gets his certificates. * * @param string $to * * @return SyncResolveRecipient|boolean */ private function resolveRecipientContact($to) { // go through all contact folders of the user and // check if there's a contact with the given email address $root = mapi_msgstore_openentry($this->defaultstore); if (!$root) { ZLog::Write(LOGLEVEL_ERROR, sprintf("Unable to open default store: 0x%X", mapi_last_hresult)); } $rootprops = mapi_getprops($root, array(PR_IPM_CONTACT_ENTRYID)); $contacts = $this->getContactsFromFolder($this->defaultstore, $rootprops[PR_IPM_CONTACT_ENTRYID], $to); $recipients = array(); if ($contacts !== false) { // create resolve recipient object foreach ($contacts as $contact) { $certificates = isset($contact[PR_USER_X509_CERTIFICATE]) && is_array($contact[PR_USER_X509_CERTIFICATE]) && count($contact[PR_USER_X509_CERTIFICATE]) ? $this->getCertificates($contact[PR_USER_X509_CERTIFICATE], 1) : false; if ($certificates !== false) { return $this->createResolveRecipient(SYNC_RESOLVERECIPIENTS_TYPE_CONTACT, u2w($contact[PR_DISPLAY_NAME]), $to, $certificates); } } } $contactfolder = mapi_msgstore_openentry($this->defaultstore, $rootprops[PR_IPM_CONTACT_ENTRYID]); $subfolders = MAPIUtils::GetSubfoldersForType($contactfolder, "IPF.Contact"); foreach ($subfolders as $folder) { $contacts = $this->getContactsFromFolder($this->defaultstore, $folder[PR_ENTRYID], $to); if ($contacts !== false) { foreach ($contacts as $contact) { $certificates = isset($contact[PR_USER_X509_CERTIFICATE]) && is_array($contact[PR_USER_X509_CERTIFICATE]) && count($contact[PR_USER_X509_CERTIFICATE]) ? $this->getCertificates($contact[PR_USER_X509_CERTIFICATE], 1) : false; if ($certificates !== false) { return $this->createResolveRecipient(SYNC_RESOLVERECIPIENTS_TYPE_CONTACT, u2w($contact[PR_DISPLAY_NAME]), $to, $certificates); } } } } // search contacts in public folders $storestables = mapi_getmsgstorestable($this->session); $result = mapi_last_hresult(); if ($result == NOERROR) { $rows = mapi_table_queryallrows($storestables, array(PR_ENTRYID, PR_DEFAULT_STORE, PR_MDB_PROVIDER)); foreach ($rows as $row) { if (isset($row[PR_MDB_PROVIDER]) && $row[PR_MDB_PROVIDER] == ZARAFA_STORE_PUBLIC_GUID) { // TODO refactor public store $publicstore = mapi_openmsgstore($this->session, $row[PR_ENTRYID]); $publicfolder = mapi_msgstore_openentry($publicstore); $subfolders = MAPIUtils::GetSubfoldersForType($publicfolder, "IPF.Contact"); if ($subfolders !== false) { foreach ($subfolders as $folder) { $contacts = $this->getContactsFromFolder($publicstore, $folder[PR_ENTRYID], $to); if ($contacts !== false) { foreach ($contacts as $contact) { $certificates = isset($contact[PR_USER_X509_CERTIFICATE]) && is_array($contact[PR_USER_X509_CERTIFICATE]) && count($contact[PR_USER_X509_CERTIFICATE]) ? $this->getCertificates($contact[PR_USER_X509_CERTIFICATE], 1) : false; if ($certificates !== false) { return $this->createResolveRecipient(SYNC_RESOLVERECIPIENTS_TYPE_CONTACT, u2w($contact[PR_DISPLAY_NAME]), $to, $certificates); } } } } } break; } } } else { ZLog::Write(LOGLEVEL_WARN, sprintf("Unable to open public store: 0x%X", $result)); } $certificates = $this->getCertificates(false); return $this->createResolveRecipient(SYNC_RESOLVERECIPIENTS_TYPE_CONTACT, $to, $to, $certificates); }
function _isUnicodeStore() { $supportmask = mapi_getprops($this->_defaultstore, array(PR_STORE_SUPPORT_MASK)); if (isset($supportmask[PR_STORE_SUPPORT_MASK]) && $supportmask[PR_STORE_SUPPORT_MASK] & STORE_UNICODE_OK) { debugLog("Store supports properties containing Unicode characters."); define('STORE_SUPPORTS_UNICODE', true); //setlocale to UTF-8 in order to support properties containing Unicode characters setlocale(LC_CTYPE, "en_US.UTF-8"); } }
/** * Function which applies the provided recipients to the exception, also checks for deleted recipients. * * The $exception_recips should be an array containing all recipients which must be applied * to the exception. This will copy all recipients from the original message and then start filter * out all recipients which are not provided by the $exception_recips list. * * @param resource $message exception attachment of recurring item * @param array $exception_recips list of recipients */ function setAllExceptionRecipients($message, $exception_recips) { $deletedRecipients = array(); $useMessageRecipients = false; $recipientTable = mapi_message_getrecipienttable($message); $recipientRows = mapi_table_queryallrows($recipientTable, $this->recipprops); if (empty($recipientRows)) { $useMessageRecipients = true; $recipientTable = mapi_message_getrecipienttable($this->message); $recipientRows = mapi_table_queryallrows($recipientTable, $this->recipprops); } // Add organizer to meeting only if it is not organized. $msgprops = mapi_getprops($message, array(PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_ADDRTYPE, $this->proptags['responsestatus'])); if (isset($msgprops[$this->proptags['responsestatus']]) && $msgprops[$this->proptags['responsestatus']] != olResponseOrganized) { $this->addOrganizer($msgprops, $exception_recips); } if (!empty($exception_recips)) { foreach ($recipientRows as $key => $recipient) { $found = false; foreach ($exception_recips as $excep_recip) { if (isset($recipient[PR_SEARCH_KEY]) && isset($excep_recip[PR_SEARCH_KEY]) && $recipient[PR_SEARCH_KEY] == $excep_recip[PR_SEARCH_KEY]) { $found = true; } } if (!$found) { $foundInDeletedRecipients = false; // Look if the $recipient is in the list of deleted recipients if (!empty($deletedRecipients)) { foreach ($deletedRecipients as $recip) { if ($recip[PR_SEARCH_KEY] == $recipient[PR_SEARCH_KEY]) { $foundInDeletedRecipients = true; break; } } } // If recipient is not in list of deleted recipient, add him if (!$foundInDeletedRecipients) { if (!isset($recipient[PR_RECIPIENT_FLAGS]) || $recipient[PR_RECIPIENT_FLAGS] != (recipReserved | recipExceptionalDeleted | recipSendable)) { $recipient[PR_RECIPIENT_FLAGS] = recipSendable | recipExceptionalDeleted; } else { $recipient[PR_RECIPIENT_FLAGS] = recipReserved | recipExceptionalDeleted | recipSendable; } $recipient[PR_RECIPIENT_TRACKSTATUS] = olRecipientTrackStatusNone; // No Response required $deletedRecipients[] = $recipient; } } // When $message contains a non-empty recipienttable, we must delete the recipients // before re-adding them. However, when $message is doesn't contain any recipients, // we are using the recipient table of the original message ($this->message) // rather then $message. In that case, we don't need to remove the recipients // from the $message, as the recipient table is already empty, and // mapi_message_modifyrecipients() will throw an error. if ($useMessageRecipients === false) { mapi_message_modifyrecipients($message, MODRECIP_REMOVE, array($recipient)); } } $exception_recips = array_merge($exception_recips, $deletedRecipients); } else { $exception_recips = $recipientRows; } if (!empty($exception_recips)) { // Set the new list of recipients on the exception message, this also removes the existing recipients mapi_message_modifyrecipients($message, 0, $exception_recips); } }
function _getFoldersRecursive($mapifolder, $parent, &$list) { $hierarchytable = mapi_folder_gethierarchytable($mapifolder); $folderprops = mapi_getprops($mapifolder, array(PR_ENTRYID)); if (!$hierarchytable) { return false; } $rows = mapi_table_queryallrows($hierarchytable, array(PR_DISPLAY_NAME, PR_SUBFOLDERS, PR_ENTRYID)); foreach ($rows as $row) { $folder = array(); $folder["mod"] = $row[PR_DISPLAY_NAME]; $folder["id"] = bin2hex($row[PR_ENTRYID]); $folder["parent"] = $parent; array_push($list, $folder); if (isset($row[PR_SUBFOLDERS]) && $row[PR_SUBFOLDERS]) { $this->_getFoldersRecursive(mapi_msgstore_openentry($this->_defaultstore, $row[PR_ENTRYID]), $folderprops[PR_ENTRYID], $list); } } return true; }
function zpa_remove_device($adminStore, $session, $user, $deviceid) { $userEntryId = @mapi_msgstore_createentryid($adminStore, $user); $userStore = @mapi_openmsgstore($session, $userEntryId); $hresult = mapi_last_hresult(); if ($hresult != NOERROR) { echo "Could not open store for {$user}. The script will exit.\n"; exit(1); } $devicesprops = mapi_getprops($userStore, array(0x6880101e, 0x6881101e, 0x6882101e, 0x6883101e, 0x68841003, 0x6885101e, 0x6886101e, 0x6887101e, 0x68881040, 0x68891040)); if (isset($devicesprops[0x6881101e]) && is_array($devicesprops[0x6881101e])) { $ak = array_search($deviceid, $devicesprops[0x6881101e]); if ($ak !== false) { if (count($devicesprops[0x6880101e]) == 1) { mapi_deleteprops($userStore, array(0x6880101e, 0x6881101e, 0x6882101e, 0x6883101e, 0x68841003, 0x6885101e, 0x6886101e, 0x6887101e, 0x68881040, 0x68891040)); } else { unset($devicesprops[0x6880101e][$ak], $devicesprops[0x6881101e][$ak], $devicesprops[0x6882101e][$ak], $devicesprops[0x6883101e][$ak], $devicesprops[0x68841003][$ak], $devicesprops[0x6885101e][$ak], $devicesprops[0x6886101e][$ak], $devicesprops[0x6887101e][$ak], $devicesprops[0x68881040][$ak], $devicesprops[0x68891040][$ak]); mapi_setprops($userStore, array(0x6880101e => isset($devicesprops[0x6880101e]) ? $devicesprops[0x6880101e] : array(), 0x6881101e => isset($devicesprops[0x6881101e]) ? $devicesprops[0x6881101e] : array(), 0x6882101e => isset($devicesprops[0x6882101e]) ? $devicesprops[0x6882101e] : array(), 0x6883101e => isset($devicesprops[0x6883101e]) ? $devicesprops[0x6883101e] : array(), 0x68841003 => isset($devicesprops[0x68841003]) ? $devicesprops[0x68841003] : array(), 0x6885101e => isset($devicesprops[0x6885101e]) ? $devicesprops[0x6885101e] : array(), 0x6886101e => isset($devicesprops[0x6886101e]) ? $devicesprops[0x6886101e] : array(), 0x6887101e => isset($devicesprops[0x6887101e]) ? $devicesprops[0x6887101e] : array(), 0x68881040 => isset($devicesprops[0x68881040]) ? $devicesprops[0x68881040] : array(), 0x68891040 => isset($devicesprops[0x68891040]) ? $devicesprops[0x68891040] : array())); } $hresult = mapi_last_hresult(); if ($hresult != NOERROR) { echo "Could not remove device from list for {$user}. Errorcode 0x" . sprintf("%x", $hresult) . ". The script will exit.\n"; exit(1); } else { echo "Removed device from list.\n"; } } else { echo "No device found with the given id.\n"; exit(1); } } else { echo "No devices found for the user {$user}.\n"; exit(1); } }
function sendCompleteUpdate($prefix, $action, $prefixComplete) { $messageprops = mapi_getprops($this->message, array($this->props['taskstate'])); if (!isset($messageprops[$this->props['taskstate']]) || $messageprops[$this->props['taskstate']] != tdsOWN) { return false; } // Can only decline assignee task mapi_setprops($this->message, array($this->props['complete'] => true, $this->props['datecompleted'] => $action["dateCompleted"], $this->props['status'] => 2, $this->props['percent_complete'] => 1)); $this->doUpdate($prefix, $prefixComplete); }
/** * Function which clones current occurrence and sets appropriate properties. * The original recurring item is moved to next occurrence. *@param boolean $markComplete true if existing occurrence has to be mark complete else false. */ function regenerateTask($markComplete) { // Get all properties $taskItemProps = mapi_getprops($this->message); if (isset($this->action["subject"])) { $taskItemProps[$this->proptags["subject"]] = $this->action["subject"]; } if (isset($this->action["importance"])) { $taskItemProps[$this->proptags["importance"]] = $this->action["importance"]; } if (isset($this->action["startdate"])) { $taskItemProps[$this->proptags["startdate"]] = $this->action["startdate"]; $taskItemProps[$this->proptags["commonstart"]] = $this->action["startdate"]; } if (isset($this->action["duedate"])) { $taskItemProps[$this->proptags["duedate"]] = $this->action["duedate"]; $taskItemProps[$this->proptags["commonend"]] = $this->action["duedate"]; } $folder = mapi_msgstore_openentry($this->store, $taskItemProps[PR_PARENT_ENTRYID]); $newMessage = mapi_folder_createmessage($folder); $taskItemProps[$this->proptags["status"]] = $markComplete ? olTaskComplete : olTaskNotStarted; $taskItemProps[$this->proptags["complete"]] = $markComplete; $taskItemProps[$this->proptags["percent_complete"]] = $markComplete ? 1 : 0; // This occurrence has been marked as 'Complete' so disable reminder if ($markComplete) { $taskItemProps[$this->proptags["reset_reminder"]] = false; $taskItemProps[$this->proptags["reminder"]] = false; $taskItemProps[$this->proptags["datecompleted"]] = $this->action["datecompleted"]; unset($this->action[$this->proptags['datecompleted']]); } // Recurrence ends for this item $taskItemProps[$this->proptags["dead_occurrence"]] = true; $taskItemProps[$this->proptags["task_f_creator"]] = true; //OL props $taskItemProps[$this->proptags["side_effects"]] = 1296; $taskItemProps[$this->proptags["icon_index"]] = 1280; // Copy recipients $recipienttable = mapi_message_getrecipienttable($this->message); $recipients = mapi_table_queryallrows($recipienttable, array(PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_RECIPIENT_ENTRYID, PR_RECIPIENT_TYPE, PR_SEND_INTERNET_ENCODING, PR_SEND_RICH_INFO, PR_RECIPIENT_DISPLAY_NAME, PR_ADDRTYPE, PR_DISPLAY_TYPE, PR_RECIPIENT_TRACKSTATUS, PR_RECIPIENT_TRACKSTATUS_TIME, PR_RECIPIENT_FLAGS, PR_ROWID)); $copy_to_recipientTable = mapi_message_getrecipienttable($newMessage); $copy_to_recipientRows = mapi_table_queryallrows($copy_to_recipientTable, array(PR_ROWID)); foreach ($copy_to_recipientRows as $recipient) { mapi_message_modifyrecipients($newMessage, MODRECIP_REMOVE, array($recipient)); } mapi_message_modifyrecipients($newMessage, MODRECIP_ADD, $recipients); // Copy attachments $attachmentTable = mapi_message_getattachmenttable($this->message); if ($attachmentTable) { $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE, PR_ATTACH_LONG_FILENAME, PR_ATTACHMENT_HIDDEN, PR_DISPLAY_NAME, PR_ATTACH_METHOD)); foreach ($attachments as $attach_props) { $attach_old = mapi_message_openattach($this->message, (int) $attach_props[PR_ATTACH_NUM]); $attach_newResourceMsg = mapi_message_createattach($newMessage); mapi_copyto($attach_old, array(), array(), $attach_newResourceMsg, 0); mapi_savechanges($attach_newResourceMsg); } } mapi_setprops($newMessage, $taskItemProps); mapi_savechanges($newMessage); // Update body of original message $msgbody = mapi_message_openproperty($this->message, PR_BODY); $msgbody = trim($this->windows1252_to_utf8($msgbody), ""); $separator = "------------\r\n"; if (!empty($msgbody) && strrpos($msgbody, $separator) === false) { $msgbody = $separator . $msgbody; $stream = mapi_openpropertytostream($this->message, PR_BODY, MAPI_CREATE | MAPI_MODIFY); mapi_stream_setsize($stream, strlen($msgbody)); mapi_stream_write($stream, $msgbody); mapi_stream_commit($stream); } // We need these properties to notify client return mapi_getprops($newMessage, array(PR_ENTRYID, PR_PARENT_ENTRYID, PR_STORE_ENTRYID)); }
if (!$store) { print "Unable to open system store\n"; exit(1); } $userstoreentryid = mapi_msgstore_createentryid($store, $argv[1]); if (!$userstoreentryid) { print "Unknown user\n"; exit(1); } $userstore = mapi_openmsgstore($session, $userstoreentryid); if (!$userstore) { print "Unable to open user store\n"; exit(1); } $inbox = mapi_msgstore_getreceivefolder($userstore); $root = mapi_msgstore_openentry($userstore); $storeprops = mapi_getprops($userstore, array(PR_IPM_SENTMAIL_ENTRYID, PR_IPM_OUTBOX_ENTRYID, PR_IPM_WASTEBASKET_ENTRYID)); $inboxprops = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_IPM_JOURNAL_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_TASK_ENTRYID)); $rootprops = mapi_getprops($root, array(PR_ADDITIONAL_REN_ENTRYIDS)); $trans_array = translate($argv[2]); renamefolder($userstore, $storeprops[PR_IPM_SENTMAIL_ENTRYID], $trans_array["Sent Items"]); renamefolder($userstore, $storeprops[PR_IPM_OUTBOX_ENTRYID], $trans_array["Outbox"]); renamefolder($userstore, $storeprops[PR_IPM_WASTEBASKET_ENTRYID], $trans_array["Deleted Items"]); renamefolder($userstore, $inboxprops[PR_ENTRYID], $trans_array["Inbox"]); renamefolder($userstore, $inboxprops[PR_IPM_APPOINTMENT_ENTRYID], $trans_array["Calendar"]); renamefolder($userstore, $inboxprops[PR_IPM_CONTACT_ENTRYID], $trans_array["Contacts"]); renamefolder($userstore, $inboxprops[PR_IPM_DRAFTS_ENTRYID], $trans_array["Drafts"]); renamefolder($userstore, $inboxprops[PR_IPM_JOURNAL_ENTRYID], $trans_array["Journal"]); renamefolder($userstore, $inboxprops[PR_IPM_NOTE_ENTRYID], $trans_array["Notes"]); renamefolder($userstore, $inboxprops[PR_IPM_TASK_ENTRYID], $trans_array["Tasks"]); renamefolder($userstore, $rootprops[PR_ADDITIONAL_REN_ENTRYIDS][4], $trans_array["Junk E-mail"]);
/** * 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 UpdateFB($addressbook, $session, $rootstore, $entryid) { $abentry = mapi_ab_openentry($addressbook, $entryid); if (!$abentry) { print "Unable to open entry in addressbook\n"; return false; } $abprops = mapi_getprops($abentry, array(PR_ACCOUNT)); $storeid = mapi_msgstore_createentryid($rootstore, $abprops[PR_ACCOUNT]); if (!$storeid) { print "Unable to get store entryid\n"; return false; } $store = mapi_openmsgstore($session, $storeid); if (!$store) { print "Unable to open store\n"; return false; } $root = mapi_msgstore_openentry($store); if (!$root) { print "Unable to open root folder\n"; return false; } $rootprops = mapi_getprops($root, array(PR_IPM_APPOINTMENT_ENTRYID)); $calendar = mapi_msgstore_openentry($store, $rootprops[PR_IPM_APPOINTMENT_ENTRYID]); $fbupdate = new FreeBusyPublish($session, $store, $calendar, $entryid); $fbupdate->publishFB(0, 0); // publish from one week ago, 6 months ahead return true; }
/** * Checks if a store supports properties containing unicode characters * * @param MAPIStore $store * * @access public * @return */ public static function IsUnicodeStore($store) { $supportmask = mapi_getprops($store, array(PR_STORE_SUPPORT_MASK)); if (isset($supportmask[PR_STORE_SUPPORT_MASK]) && $supportmask[PR_STORE_SUPPORT_MASK] & STORE_UNICODE_OK) { ZLog::Write(LOGLEVEL_DEBUG, "Store supports properties containing Unicode characters."); define('STORE_SUPPORTS_UNICODE', true); //setlocale to UTF-8 in order to support properties containing Unicode characters setlocale(LC_CTYPE, "en_US.UTF-8"); define('STORE_INTERNET_CPID', INTERNET_CPID_UTF8); } }
function buildEMLAttachment($attach) { $msgembedded = mapi_attach_openobj($attach); $msgprops = mapi_getprops($msgembedded, array(PR_MESSAGE_CLASS, PR_CLIENT_SUBMIT_TIME, PR_DISPLAY_TO, PR_SUBJECT, PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS)); $msgembeddedrcpttable = mapi_message_getrecipienttable($msgembedded); $msgto = $msgprops[PR_DISPLAY_TO]; if ($msgembeddedrcpttable) { $msgembeddedrecipients = mapi_table_queryrows($msgembeddedrcpttable, array(PR_ADDRTYPE, PR_ENTRYID, PR_DISPLAY_NAME, PR_EMAIL_ADDRESS, PR_SMTP_ADDRESS, PR_RECIPIENT_TYPE, PR_RECIPIENT_FLAGS, PR_PROPOSEDNEWTIME, PR_PROPOSENEWTIME_START, PR_PROPOSENEWTIME_END, PR_RECIPIENT_TRACKSTATUS), 0, 99999999); foreach ($msgembeddedrecipients as $rcpt) { if ($rcpt[PR_DISPLAY_NAME] == $msgprops[PR_DISPLAY_TO]) { $msgto = $rcpt[PR_DISPLAY_NAME]; if (isset($rcpt[PR_EMAIL_ADDRESS]) && $rcpt[PR_EMAIL_ADDRESS] != $msgprops[PR_DISPLAY_TO]) { $msgto .= " <" . $rcpt[PR_EMAIL_ADDRESS] . ">"; } break; } } } $msgsubject = $msgprops[PR_SUBJECT]; $msgfrom = $msgprops[PR_SENT_REPRESENTING_NAME]; if (isset($msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS]) && $msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] != $msgprops[PR_SENT_REPRESENTING_NAME]) { $msgfrom .= " <" . $msgprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] . ">"; } $msgtime = $msgprops[PR_CLIENT_SUBMIT_TIME]; $msgembeddedbody = eml_ReadMessage($msgembedded); $msgembeddedattachtable = mapi_message_getattachmenttable($msgembedded); $msgembeddedattachtablerows = mapi_table_queryallrows($msgembeddedattachtable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD)); if ($msgembeddedattachtablerows) { $boundary = '=_zpush_static'; $headercontenttype = "multipart/mixed"; $msgembeddedbody['body'] = "Unfortunately your mobile is not able to handle MIME Messages\n" . "--" . $boundary . "\n" . "Content-Type: " . $msgembeddedbody['content'] . "; charset=utf-8\n" . "Content-Transfer-Encoding: quoted-printable\n\n" . $msgembeddedbody['body'] . "\n"; foreach ($msgembeddedattachtablerows as $msgembeddedattachtablerow) { $msgembeddedattach = mapi_message_openattach($msgembedded, $msgembeddedattachtablerow[PR_ATTACH_NUM]); if (!$msgembeddedattach) { debugLog("Unable to open attachment number {$attachnum}"); } else { $msgembeddedattachprops = mapi_getprops($msgembeddedattach, array(PR_ATTACH_MIME_TAG, PR_ATTACH_LONG_FILENAME, PR_ATTACH_FILENAME, PR_DISPLAY_NAME)); if (isset($msgembeddedattachprops[PR_ATTACH_LONG_FILENAME])) { $attachfilename = w2u($msgembeddedattachprops[PR_ATTACH_LONG_FILENAME]); } else { if (isset($msgembeddedattachprops[PR_ATTACH_FILENAME])) { $attachfilename = w2u($msgembeddedattachprops[PR_ATTACH_FILENAME]); } else { if (isset($msgembeddedattachprops[PR_DISPLAY_NAME])) { $attachfilename = w2u($msgembeddedattachprops[PR_DISPLAY_NAME]); } else { $attachfilename = w2u("untitled"); } } } if ($msgembeddedattachtablerow[PR_ATTACH_METHOD] == ATTACH_EMBEDDED_MSG) { $attachfilename .= w2u(".eml"); } $msgembeddedbody['body'] .= "--" . $boundary . "\n" . "Content-Type: " . $msgembeddedattachprops[PR_ATTACH_MIME_TAG] . ";\n" . " name=\"" . $attachfilename . "\"\n" . "Content-Transfer-Encoding: base64\n" . "Content-Disposition: attachment;\n" . " filename=\"" . $attachfilename . "\"\n\n"; $msgembeddedattachstream = mapi_openpropertytostream($msgembeddedattach, PR_ATTACH_DATA_BIN); $msgembeddedattachment = ""; while (1) { $msgembeddedattachdata = mapi_stream_read($msgembeddedattachstream, 4096); if (byte_strlen($msgembeddedattachdata) == 0) { break; } $msgembeddedattachment .= $msgembeddedattachdata; } $msgembeddedbody['body'] .= chunk_split(base64_encode($msgembeddedattachment)) . "\n"; unset($msgembeddedattachment); } } $msgembeddedbody['body'] .= "--" . $boundary . "--\n"; } else { $headercontenttype = $msgembeddedbody['content'] . "; charset=utf-8"; $boundary = ''; } $msgembeddedheader = "Subject: " . $msgsubject . "\n" . "From: " . $msgfrom . "\n" . "To: " . $msgto . "\n" . "Date: " . gmstrftime("%a, %d %b %Y %T +0000", $msgprops[PR_CLIENT_SUBMIT_TIME]) . "\n" . "MIME-Version: 1.0\n" . "Content-Type: " . $headercontenttype . ";\n" . ($boundary ? " boundary=\"" . $boundary . "\"\n" : "") . "\n"; $stream = mapi_stream_create(); mapi_stream_setsize($stream, byte_strlen($msgembeddedheader . $msgembeddedbody['body'])); mapi_stream_write($stream, $msgembeddedheader . $msgembeddedbody['body']); mapi_stream_seek($stream, 0, STREAM_SEEK_SET); return $stream; }
/** * A wrapper for mapi_inetmapi_imtoinet function * * @param MAPIMessage $mapimessage * @param SyncObject $message * * @access private * @return boolean */ private function imtoinet($mapimessage, &$message) { // if it is a signed message get a full attachment generated by ZCP $props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS)); if (isset($props[PR_MESSAGE_CLASS]) && $props[PR_MESSAGE_CLASS] && strpos(strtolower($props[PR_MESSAGE_CLASS]), 'multipartsigned')) { // find the required attachment $attachtable = mapi_message_getattachmenttable($mapimessage); mapi_table_restrict($attachtable, MAPIUtils::GetSignedAttachmentRestriction()); if (mapi_table_getrowcount($attachtable) == 1) { $rows = mapi_table_queryrows($attachtable, array(PR_ATTACH_NUM, PR_ATTACH_SIZE), 0, 1); if (isset($rows[0][PR_ATTACH_NUM])) { $mapiattach = mapi_message_openattach($mapimessage, $rows[0][PR_ATTACH_NUM]); $stream = mapi_openpropertytostream($mapiattach, PR_ATTACH_DATA_BIN); $streamsize = $rows[0][PR_ATTACH_SIZE]; } } } elseif (function_exists("mapi_inetmapi_imtoinet")) { $addrbook = $this->getAddressbook(); $stream = mapi_inetmapi_imtoinet($this->session, $addrbook, $mapimessage, array('use_tnef' => -1)); $mstreamstat = mapi_stream_stat($stream); $streamsize = $mstreamstat["cb"]; } if (isset($stream) && isset($streamsize)) { if (Request::GetProtocolVersion() >= 12.0) { if (!isset($message->asbody)) { $message->asbody = new SyncBaseBody(); } //TODO data should be wrapped in a MapiStreamWrapper $message->asbody->data = mapi_stream_read($stream, $streamsize); $message->asbody->estimatedDataSize = $streamsize; $message->asbody->truncated = 0; } else { $message->mimetruncated = 0; //TODO mimedata should be a wrapped in a MapiStreamWrapper $message->mimedata = mapi_stream_read($stream, $streamsize); $message->mimesize = $streamsize; } unset($message->body, $message->bodytruncated); return true; } else { ZLog::Write(LOGLEVEL_ERROR, sprintf("Error opening attachment for imtoinet")); } return false; }
/** * Imports a change on a folder * * @param object $folder SyncFolder * * @access public * @return string id of the folder * @throws StatusException */ public function ImportFolderChange($folder) { $id = isset($folder->serverid) ? $folder->serverid : false; $parent = $folder->parentid; $displayname = u2wi($folder->displayname); $type = $folder->type; if (Utils::IsSystemFolder($type)) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, system folder can not be created/modified", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname), SYNC_FSSTATUS_SYSTEMFOLDER); } // create a new folder if $id is not set if (!$id) { // the root folder is "0" - get IPM_SUBTREE if ($parent == "0") { $parentprops = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID)); if (isset($parentprops[PR_IPM_SUBTREE_ENTRYID])) { $parentfentryid = $parentprops[PR_IPM_SUBTREE_ENTRYID]; } } else { $parentfentryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($parent)); } if (!$parentfentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open parent folder (no entry id)", Utils::PrintAsString(false), $folder->parentid, $displayname), SYNC_FSSTATUS_PARENTNOTFOUND); } $parentfolder = mapi_msgstore_openentry($this->store, $parentfentryid); if (!$parentfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open parent folder (open entry)", Utils::PrintAsString(false), $folder->parentid, $displayname), SYNC_FSSTATUS_PARENTNOTFOUND); } // mapi_folder_createfolder() fails if a folder with this name already exists -> MAPI_E_COLLISION $newfolder = mapi_folder_createfolder($parentfolder, $displayname, ""); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, mapi_folder_createfolder() failed: 0x%X", Utils::PrintAsString(false), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_FOLDEREXISTS); } mapi_setprops($newfolder, array(PR_CONTAINER_CLASS => MAPIUtils::GetContainerClassFromFolderType($type))); $props = mapi_getprops($newfolder, array(PR_SOURCE_KEY)); if (isset($props[PR_SOURCE_KEY])) { $sourcekey = bin2hex($props[PR_SOURCE_KEY]); ZLog::Write(LOGLEVEL_DEBUG, sprintf("Created folder '%s' with id: '%s'", $displayname, $sourcekey)); return $sourcekey; } else { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, folder created but PR_SOURCE_KEY not available: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } return false; } // open folder for update $entryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($id)); if (!$entryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open folder (no entry id): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_PARENTNOTFOUND); } // check if this is a MAPI default folder if ($this->mapiprovider->IsMAPIDefaultFolder($entryid)) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, MAPI default folder can not be created/modified", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname), SYNC_FSSTATUS_SYSTEMFOLDER); } $mfolder = mapi_msgstore_openentry($this->store, $entryid); if (!$mfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open folder (open entry): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_PARENTNOTFOUND); } $props = mapi_getprops($mfolder, array(PR_SOURCE_KEY, PR_PARENT_SOURCE_KEY, PR_DISPLAY_NAME, PR_CONTAINER_CLASS)); if (!isset($props[PR_SOURCE_KEY]) || !isset($props[PR_PARENT_SOURCE_KEY]) || !isset($props[PR_DISPLAY_NAME]) || !isset($props[PR_CONTAINER_CLASS])) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, folder data not available: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } // get the real parent source key from mapi if ($parent == "0") { $parentprops = mapi_getprops($this->store, array(PR_IPM_SUBTREE_ENTRYID)); $parentfentryid = $parentprops[PR_IPM_SUBTREE_ENTRYID]; $mapifolder = mapi_msgstore_openentry($this->store, $parentfentryid); $rootfolderprops = mapi_getprops($mapifolder, array(PR_SOURCE_KEY)); $parent = bin2hex($rootfolderprops[PR_SOURCE_KEY]); ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesICS->ImportFolderChange(): resolved AS parent '0' to sourcekey '%s'", $parent)); } // a changed parent id means that the folder should be moved if (bin2hex($props[PR_PARENT_SOURCE_KEY]) !== $parent) { $sourceparentfentryid = mapi_msgstore_entryidfromsourcekey($this->store, $props[PR_PARENT_SOURCE_KEY]); if (!$sourceparentfentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open parent source folder (no entry id): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_PARENTNOTFOUND); } $sourceparentfolder = mapi_msgstore_openentry($this->store, $sourceparentfentryid); if (!$sourceparentfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open parent source folder (open entry): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_PARENTNOTFOUND); } $destparentfentryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($parent)); if (!$sourceparentfentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open destination folder (no entry id): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } $destfolder = mapi_msgstore_openentry($this->store, $destparentfentryid); if (!$destfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to open destination folder (open entry): 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } // mapi_folder_copyfolder() fails if a folder with this name already exists -> MAPI_E_COLLISION if (!mapi_folder_copyfolder($sourceparentfolder, $entryid, $destfolder, $displayname, FOLDER_MOVE)) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, unable to move folder: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_FOLDEREXISTS); } $folderProps = mapi_getprops($mfolder, array(PR_SOURCE_KEY)); return $folderProps[PR_SOURCE_KEY]; } // update the display name $props = array(PR_DISPLAY_NAME => $displayname); mapi_setprops($mfolder, $props); mapi_savechanges($mfolder); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderChange('%s','%s','%s'): Error, mapi_savechanges() failed: 0x%X", Utils::PrintAsString($folder->serverid), $folder->parentid, $displayname, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } ZLog::Write(LOGLEVEL_DEBUG, "Imported changes for folder: {$id}"); return $id; }
/** * Returns an SMTP address from an entry id * * @param string $entryid * * @access private * @return string */ private function getSMTPAddressFromEntryID($entryid) { $addrbook = $this->getAddressbook(); $mailuser = mapi_ab_openentry($addrbook, $entryid); if (!$mailuser) { return ""; } $props = mapi_getprops($mailuser, array(PR_ADDRTYPE, PR_SMTP_ADDRESS, PR_EMAIL_ADDRESS)); $addrtype = isset($props[PR_ADDRTYPE]) ? $props[PR_ADDRTYPE] : ""; if (isset($props[PR_SMTP_ADDRESS])) { return $props[PR_SMTP_ADDRESS]; } if ($addrtype == "SMTP" && isset($props[PR_EMAIL_ADDRESS])) { return $props[PR_EMAIL_ADDRESS]; } elseif ($addrtype == "ZARAFA" && isset($props[PR_EMAIL_ADDRESS])) { $userinfo = mapi_zarafa_getuser_by_name($this->store, $props[PR_EMAIL_ADDRESS]); if (is_array($userinfo) && isset($userinfo["emailaddress"])) { return $userinfo["emailaddress"]; } } return ""; }
if (isset($storeprops[PR_IPM_WASTEBASKET_ENTRYID])) { $folderentryids[0] = $storeprops[PR_IPM_WASTEBASKET_ENTRYID]; } if (isset($storeprops[PR_IPM_SENTMAIL_ENTRYID])) { $folderentryids[1] = $storeprops[PR_IPM_SENTMAIL_ENTRYID]; } if (isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) { $folderentryids[2] = $storeprops[PR_IPM_OUTBOX_ENTRYID]; } $rootfolder = mapi_msgstore_openentry($userstore); $rootprops = mapi_getprops($rootfolder, array(PR_FREEBUSY_ENTRYIDS)); if (isset($rootprops[PR_FREEBUSY_ENTRYIDS])) { $freebusy = $rootprops[PR_FREEBUSY_ENTRYIDS][3]; } $inbox = mapi_msgstore_getreceivefolder($userstore); $inboxprops = mapi_getprops($inbox, array(PR_ENTRYID, PR_IPM_TASK_ENTRYID, PR_IPM_CONTACT_ENTRYID, PR_IPM_NOTE_ENTRYID, PR_IPM_JOURNAL_ENTRYID, PR_IPM_APPOINTMENT_ENTRYID, PR_IPM_DRAFTS_ENTRYID, PR_ADDITIONAL_REN_ENTRYIDS)); if (isset($inboxprops[PR_ENTRYID])) { $folderentryids[3] = $inboxprops[PR_ENTRYID]; } if (isset($inboxprops[PR_IPM_TASK_ENTRYID])) { $folderentryids[4] = $inboxprops[PR_IPM_TASK_ENTRYID]; } if (isset($inboxprops[PR_IPM_CONTACT_ENTRYID])) { $folderentryids[5] = $inboxprops[PR_IPM_CONTACT_ENTRYID]; } if (isset($inboxprops[PR_IPM_NOTE_ENTRYID])) { $folderentryids[6] = $inboxprops[PR_IPM_NOTE_ENTRYID]; } if (isset($inboxprops[PR_IPM_JOURNAL_ENTRYID])) { $folderentryids[7] = $inboxprops[PR_IPM_JOURNAL_ENTRYID]; }