/** * 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); } }
/** * Imports a folder deletion * * @param string $id * @param string $parent id is ignored in ICS * * @access public * @return int SYNC_FOLDERHIERARCHY_STATUS * @throws StatusException */ public function ImportFolderDeletion($id, $parent = false) { ZLog::Write(LOGLEVEL_DEBUG, sprintf("ImportChangesICS->ImportFolderDeletion('%s','%s'): importing folder deletetion", $id, $parent)); $folderentryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($id)); if (!$folderentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderDeletion('%s','%s'): Error, unable to resolve folder", $id, $parent, mapi_last_hresult()), SYNC_FSSTATUS_FOLDERDOESNOTEXIST); } // get the folder type from the MAPIProvider $type = $this->mapiprovider->GetFolderType($folderentryid); if (Utils::IsSystemFolder($type)) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderDeletion('%s','%s'): Error deleting system/default folder", $id, $parent), SYNC_FSSTATUS_SYSTEMFOLDER); } $ret = mapi_importhierarchychanges_importfolderdeletion($this->importer, 0, array(PR_SOURCE_KEY => hex2bin($id))); if (!$ret) { throw new StatusException(sprintf("ImportChangesICS->ImportFolderDeletion('%s','%s'): Error deleting folder: 0x%X", $id, $parent, mapi_last_hresult()), SYNC_FSSTATUS_SERVERERROR); } return $ret; }
private function hasSecretaryACLs($store, $folderid) { $entryid = mapi_msgstore_entryidfromsourcekey($store, hex2bin($folderid)); if (!$entryid) { return false; } $folder = mapi_msgstore_openentry($store, $entryid); if (!$folder) { return false; } $props = mapi_getprops($folder, array(PR_RIGHTS)); if (isset($props[PR_RIGHTS]) && $props[PR_RIGHTS] & ecRightsReadAny && $props[PR_RIGHTS] & ecRightsCreate && $props[PR_RIGHTS] & ecRightsEditOwned && $props[PR_RIGHTS] & ecRightsDeleteOwned && $props[PR_RIGHTS] & ecRightsEditAny && $props[PR_RIGHTS] & ecRightsDeleteAny && $props[PR_RIGHTS] & ecRightsFolderVisible) { return true; } return false; }
function MeetingResponse($requestid, $folderid, $response, &$calendarid) { // Use standard meeting response code to process meeting request $reqentryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid), hex2bin($requestid)); $mapimessage = mapi_msgstore_openentry($this->_defaultstore, $reqentryid); if (!$mapimessage) { debugLog("Unable to open request message for response"); return false; } $meetingrequest = new Meetingrequest($this->_defaultstore, $mapimessage); if (!$meetingrequest->isMeetingRequest()) { debugLog("Attempt to respond to non-meeting request"); return false; } if ($meetingrequest->isLocalOrganiser()) { debugLog("Attempt to response to meeting request that we organized"); return false; } // Process the meeting response. We don't have to send the actual meeting response // e-mail, because the device will send it itself. switch ($response) { case 1: // accept // accept default: $entryid = $meetingrequest->doAccept(false, false, false, false, false, false, true); // last true is the $userAction break; case 2: // tentative $entryid = $meetingrequest->doAccept(true, false, false, false, false, false, true); // last true is the $userAction break; case 3: // decline $meetingrequest->doDecline(false); break; } // F/B will be updated on logoff // We have to return the ID of the new calendar item, so do that here if (isset($entryid)) { $newitem = mapi_msgstore_openentry($this->_defaultstore, $entryid); $newprops = mapi_getprops($newitem, array(PR_SOURCE_KEY)); $calendarid = bin2hex($newprops[PR_SOURCE_KEY]); } // on recurring items, the MeetingRequest class responds with a wrong entryid if ($requestid == $calendarid) { debugLog("returned calender id is the same as the requestid - re-searching"); $goidprop = GetPropIDFromString($this->_defaultstore, "PT_BINARY:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x3"); $messageprops = mapi_getprops($mapimessage, array($goidprop, PR_OWNER_APPT_ID)); $goid = $messageprops[$goidprop]; if (isset($messageprops[PR_OWNER_APPT_ID])) { $apptid = $messageprops[PR_OWNER_APPT_ID]; } else { $apptid = false; } //findCalendarItems signature was changed in 6.40.8, Mantis #485 $items = checkMapiExtVersion("6.40.8") ? $meetingrequest->findCalendarItems($goid) : $meetingrequest->findCalendarItems($goid, $apptid); if (is_array($items)) { $newitem = mapi_msgstore_openentry($this->_defaultstore, $items[0]); $newprops = mapi_getprops($newitem, array(PR_SOURCE_KEY)); $calendarid = bin2hex($newprops[PR_SOURCE_KEY]); debugLog("found other calendar entryid"); } } // delete meeting request from Inbox $folderentryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid)); $folder = mapi_msgstore_openentry($this->_defaultstore, $folderentryid); mapi_folder_deletemessages($folder, array($reqentryid), 0); return true; }
/** * Imports a single message * * @param array $props * @param long $flags * @param object $retmapimessage * * @access public * @return long */ public function ImportMessageChange($props, $flags, &$retmapimessage) { $sourcekey = $props[PR_SOURCE_KEY]; $parentsourcekey = $props[PR_PARENT_SOURCE_KEY]; $entryid = mapi_msgstore_entryidfromsourcekey($this->store, $parentsourcekey, $sourcekey); if (!$entryid) { return SYNC_E_IGNORE; } $mapimessage = mapi_msgstore_openentry($this->store, $entryid); try { $message = $this->mapiprovider->GetMessage($mapimessage, $this->contentparameters); } catch (SyncObjectBrokenException $mbe) { $brokenSO = $mbe->GetSyncObject(); if (!$brokenSO) { ZLog::Write(LOGLEVEL_ERROR, sprintf("PHPWrapper->ImportMessageChange(): Catched SyncObjectBrokenException but broken SyncObject available")); } else { if (!isset($brokenSO->id)) { $brokenSO->id = "Unknown ID"; ZLog::Write(LOGLEVEL_ERROR, sprintf("PHPWrapper->ImportMessageChange(): Catched SyncObjectBrokenException but no ID of object set")); } ZPush::GetDeviceManager()->AnnounceIgnoredMessage(false, $brokenSO->id, $brokenSO); } // tell MAPI to ignore the message return SYNC_E_IGNORE; } // substitute the MAPI SYNC_NEW_MESSAGE flag by a z-push proprietary flag if ($flags == SYNC_NEW_MESSAGE) { $message->flags = SYNC_NEWMESSAGE; } else { $message->flags = $flags; } $this->importer->ImportMessageChange(bin2hex($sourcekey), $message); // Tell MAPI it doesn't need to do anything itself, as we've done all the work already. return SYNC_E_IGNORE; }
/** * Returns categories for a message. * * @param binary $parentsourcekey * @param binary $sourcekey * * @access public * @return array or false on failure */ public function GetMessageCategories($parentsourcekey, $sourcekey) { $entryid = mapi_msgstore_entryidfromsourcekey($this->store, $parentsourcekey, $sourcekey); if (!$entryid) { ZLog::Write(LOGLEVEL_INFO, sprintf("MAPIProvider->GetMessageCategories(): Couldn't retrieve message, sourcekey: '%s', parentsourcekey: '%s'", bin2hex($sourcekey), bin2hex($parentsourcekey))); return false; } $mapimessage = mapi_msgstore_openentry($this->store, $entryid); $emailMapping = MAPIMapping::GetEmailMapping(); $emailMapping = array("categories" => $emailMapping["categories"]); $messageCategories = $this->getProps($mapimessage, $emailMapping); if (isset($messageCategories[$emailMapping["categories"]]) && is_array($messageCategories[$emailMapping["categories"]])) { return $messageCategories[$emailMapping["categories"]]; } return false; }
function MeetingResponse($requestid, $folderid, $response, &$calendarid) { // Use standard meeting response code to process meeting request $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid), hex2bin($requestid)); $mapimessage = mapi_msgstore_openentry($this->_defaultstore, $entryid); if (!$mapimessage) { debugLog("Unable to open request message for response"); return false; } $meetingrequest = new Meetingrequest($this->_defaultstore, $mapimessage); if (!$meetingrequest->isMeetingRequest()) { debugLog("Attempt to respond to non-meeting request"); return false; } if ($meetingrequest->isLocalOrganiser()) { debugLog("Attempt to response to meeting request that we organized"); return false; } // Process the meeting response. We don't have to send the actual meeting response // e-mail, because the device will send it itself. switch ($response) { case 1: // accept // accept default: $entryid = $meetingrequest->doAccept(false, false, $meetingrequest->isInCalendar()); break; case 2: // tentative $meetingrequest->doAccept(true, false, $meetingrequest->isInCalendar()); break; case 3: // decline $meetingrequest->doDecline(false); break; } // Update F/B $root = mapi_msgstore_openentry($this->_defaultstore); $rootprops = mapi_getprops($root, array(PR_IPM_APPOINTMENT_ENTRYID)); $calendar = mapi_msgstore_openentry($this->_defaultstore, $rootprops[PR_IPM_APPOINTMENT_ENTRYID]); $storeprops = mapi_getprops($this->_defaultstore, array(PR_USER_ENTRYID)); $pub = new FreeBusyPublish($this->_session, $this->_defaultstore, $calendar, $storeprops[PR_USER_ENTRYID]); $pub->publishFB(time() - 7 * 24 * 60 * 60, 6 * 30 * 24 * 60 * 60); // publish from one week ago, 6 months ahead // We have to return the ID of the new calendar item, so do that here $newitem = mapi_msgstore_openentry($this->_defaultstore, $entryid); $newprops = mapi_getprops($newitem, array(PR_SOURCE_KEY)); $calendarid = bin2hex($newprops[PR_SOURCE_KEY]); return true; }
function MeetingResponse($requestid, $folderid, $response, &$calendarid) { // Use standard meeting response code to process meeting request $reqentryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid), hex2bin($requestid)); $mapimessage = mapi_msgstore_openentry($this->_defaultstore, $reqentryid); if (!$mapimessage) { debugLog("Unable to open request message for response"); return false; } $meetingrequest = new Meetingrequest($this->_defaultstore, $mapimessage); if (!$meetingrequest->isMeetingRequest()) { debugLog("Attempt to respond to non-meeting request"); return false; } if ($meetingrequest->isLocalOrganiser()) { debugLog("Attempt to response to meeting request that we organized"); return false; } // Process the meeting response. We don't have to send the actual meeting response // e-mail, because the device will send it itself. switch ($response) { case 1: // accept // accept default: $entryid = $meetingrequest->doAccept(false, false, false, false, false, false, true); // last true is the $userAction break; case 2: // tentative $entryid = $meetingrequest->doAccept(true, false, false, false, false, false, true); // last true is the $userAction break; case 3: // decline $meetingrequest->doDecline(false); break; } // F/B will be updated on logoff // We have to return the ID of the new calendar item, so do that here $newitem = mapi_msgstore_openentry($this->_defaultstore, $entryid); $newprops = mapi_getprops($newitem, array(PR_SOURCE_KEY)); $calendarid = bin2hex($newprops[PR_SOURCE_KEY]); // delete meeting request from Inbox $folderentryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($folderid)); $folder = mapi_msgstore_openentry($this->_defaultstore, $folderentryid); mapi_folder_deletemessages($folder, array($reqentryid), 0); return true; }
private function getMessage($id, $announceErrors = true) { if (!$id) { return false; } $message = false; list($fsk, $sk) = Utils::SplitMessageId($id); $sourcekey = hex2bin($sk); $parentsourcekey = hex2bin(ZPush::GetDeviceManager()->GetBackendIdForFolderId($fsk)); // Backwards compatibility for old style folder ids if (empty($parentsourcekey)) { $parentsourcekey = $this->folderid; } $entryid = mapi_msgstore_entryidfromsourcekey($this->store, $parentsourcekey, $sourcekey); if (!$entryid) { ZLog::Write(LOGLEVEL_INFO, sprintf("ReplyBackImExporter->getMessage(): Couldn't retrieve message from MAPIProvider, sourcekey: '%s', parentsourcekey: '%s'", bin2hex($sourcekey), bin2hex($parentsourcekey), bin2hex($entryid))); return false; } $mapimessage = mapi_msgstore_openentry($this->store, $entryid); try { ZLog::Write(LOGLEVEL_DEBUG, sprintf("ReplyBackImExporter->getMessage(): Getting message from MAPIProvider, sourcekey: '%s', parentsourcekey: '%s', entryid: '%s'", bin2hex($sourcekey), bin2hex($parentsourcekey), bin2hex($entryid))); $message = $this->mapiprovider->GetMessage($mapimessage, $this->contentparameters); } catch (SyncObjectBrokenException $mbe) { if ($announceErrors) { $brokenSO = $mbe->GetSyncObject(); if (!$brokenSO) { ZLog::Write(LOGLEVEL_ERROR, sprintf("ReplyBackImExporter->getMessage(): Catched SyncObjectBrokenException but broken SyncObject available")); } else { if (!isset($brokenSO->id)) { $brokenSO->id = "Unknown ID"; ZLog::Write(LOGLEVEL_ERROR, sprintf("ReplyBackImExporter->getMessage(): Catched SyncObjectBrokenException but no ID of object set")); } ZPush::GetDeviceManager()->AnnounceIgnoredMessage(false, $brokenSO->id, $brokenSO); } return false; } } return $message; }
/** * Imports a single folder change * * @param mixed $props sourcekey of the changed folder * * @access public * @return */ function ImportFolderChange($props) { $sourcekey = $props[PR_SOURCE_KEY]; $entryid = mapi_msgstore_entryidfromsourcekey($this->store, $sourcekey); $mapifolder = mapi_msgstore_openentry($this->store, $entryid); $folder = $this->mapiprovider->GetFolder($mapifolder); // do not import folder if there is something "wrong" with it if ($folder === false) { return 0; } $this->importer->ImportFolderChange($folder); return 0; }
/** * Opens a folder. * * @param ressource $store * @param string $folderid * * @access private * @return ressource */ private function getFolder($store, $folderid) { if (!isset($this->folderCache[$folderid])) { $folderentryid = mapi_msgstore_entryidfromsourcekey($store, hex2bin($folderid)); if (!$folderentryid) { $this->Terminate(sprintf("Kopano->getFolder(): Error, unable to open folder (no entry id): 0x%08X", mapi_last_hresult())); } $this->folderCache[$folderid] = mapi_msgstore_openentry($store, $folderentryid); } return $this->folderCache[$folderid]; }
/** * Checks if the logged in user has read permissions on a folder. * * @param ressource $store * @param string $folderid * * @access public * @return boolean */ public function HasReadACLs($store, $folderid) { $entryid = mapi_msgstore_entryidfromsourcekey($store, hex2bin($folderid)); if (!$entryid) { ZLog::Write(LOGLEVEL_WARN, sprintf("KopanoBackend->HasReadACLs(): error, no entryid resolved for %s on store %s", $folderid, $store)); return false; } $folder = mapi_msgstore_openentry($store, $entryid); if (!$folder) { ZLog::Write(LOGLEVEL_WARN, sprintf("KopanoBackend->HasReadACLs(): error, could not open folder with entryid %s on store %s", bin2hex($entryid), $store)); return false; } $props = mapi_getprops($folder, array(PR_RIGHTS)); if (isset($props[PR_RIGHTS]) && $props[PR_RIGHTS] & ecRightsReadAny) { return true; } return false; }