Example #1
0
 /**
  * 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
        }
    }
}
Example #4
0
 /**
  * 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);
 }
Example #6
0
/**
 * 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;
}
Example #7
0
 /**
  * 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;
 }
Example #8
0
 /**
  * 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;
 }
Example #9
0
 /**
  * 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));
     }
 }
Example #11
0
 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');
     }
 }
Example #12
0
 /**
  * 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 "";
 }
Example #13
0
$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);
Example #14
0
 /**
  * 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']]));
 }
Example #15
0
 /**
  * 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);
 }
Example #16
0
 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");
     }
 }
Example #17
0
 /**
  * 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);
     }
 }
Example #18
0
 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;
 }
Example #25
0
 /**
  * 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);
     }
 }
Example #26
0
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;
 }
Example #28
0
 /**
  * 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];
}