function _setPropsInMAPI($mapimessage, $message, $mapping) { foreach ($mapping as $asprop => $mapiprop) { if (isset($message->{$asprop})) { $mapiprop = $this->_getPropIDFromString($mapiprop); // UTF8->windows1252.. this is ok for all numerical values if (mapi_prop_type($mapiprop) != PT_BINARY && mapi_prop_type($mapiprop) != PT_MV_BINARY) { if (is_array($message->{$asprop})) { $value = array_map("u2wi", $message->{$asprop}); } else { $value = u2wi($message->{$asprop}); } } else { $value = $message->{$asprop}; } // Make sure the php values are the correct type switch (mapi_prop_type($mapiprop)) { case PT_BINARY: case PT_STRING8: settype($value, "string"); break; case PT_BOOLEAN: settype($value, "boolean"); break; case PT_SYSTIME: case PT_LONG: settype($value, "integer"); break; } // decode base64 value if ($mapiprop == PR_RTF_COMPRESSED) { $value = base64_decode($value); if (strlen($value) == 0) { continue; } // PDA will sometimes give us an empty RTF, which we'll ignore. // Note that you can still remove notes because when you remove notes it gives // a valid compressed RTF with nothing in it. } mapi_setprops($mapimessage, array($mapiprop => $value)); } } }
/** * Sets the properties in a MAPI object according to an Sync object and a property mapping * * @param mixed $mapimessage * @param SyncObject $message * @param array $mapping * * @access private * @return */ private function setPropsInMAPI($mapimessage, $message, $mapping) { $mapiprops = $this->getPropIdsFromStrings($mapping); $unsetVars = $message->getUnsetVars(); $propsToDelete = array(); $propsToSet = array(); foreach ($mapiprops as $asprop => $mapiprop) { if (isset($message->{$asprop})) { // UTF8->windows1252.. this is ok for all numerical values if (mapi_prop_type($mapiprop) != PT_BINARY && mapi_prop_type($mapiprop) != PT_MV_BINARY) { if (is_array($message->{$asprop})) { $value = array_map("u2wi", $message->{$asprop}); } else { $value = u2wi($message->{$asprop}); } } else { $value = $message->{$asprop}; } // Make sure the php values are the correct type switch (mapi_prop_type($mapiprop)) { case PT_BINARY: case PT_STRING8: settype($value, "string"); break; case PT_BOOLEAN: settype($value, "boolean"); break; case PT_SYSTIME: case PT_LONG: settype($value, "integer"); break; } // decode base64 value if ($mapiprop == PR_RTF_COMPRESSED) { $value = base64_decode($value); if (strlen($value) == 0) { continue; } // PDA will sometimes give us an empty RTF, which we'll ignore. // Note that you can still remove notes because when you remove notes it gives // a valid compressed RTF with nothing in it. } // if an "empty array" is to be saved, it the mvprop should be deleted - fixes Mantis #468 if (is_array($value) && empty($value)) { $propsToDelete[] = $mapiprop; ZLog::Write(LOGLEVEL_DEBUG, sprintf("MAPIProvider->setPropsInMAPI(): Property '%s' to be deleted as it is an empty array", $asprop)); } else { // all properties will be set at once $propsToSet[$mapiprop] = $value; } } elseif (in_array($asprop, $unsetVars)) { $propsToDelete[] = $mapiprop; } } mapi_setprops($mapimessage, $propsToSet); if (mapi_last_hresult()) { Zlog::Write(LOGLEVEL_WARN, sprintf("Failed to set properties, trying to set them separately. Error code was:%x", mapi_last_hresult())); $this->setPropsIndividually($mapimessage, $propsToSet, $mapiprops); } mapi_deleteprops($mapimessage, $propsToDelete); //clean up unset($unsetVars, $propsToDelete); }
/** * Escapes a string * * @param string $data string to be escaped * * @access private * @return string */ function escape($data) { if (is_array($data)) { foreach ($data as $key => $val) { $data[$key] = $this->escape($val); } return $data; } $data = str_replace("\r\n", "\n", $data); $data = str_replace("\r", "\n", $data); $data = str_replace(array('\\', ';', ',', "\n"), array('\\\\', '\\;', '\\,', '\\n'), $data); return u2wi($data); }
/** * 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; }
/** * Adds the recipients to an email message from a RFC822 message headers. * * @param MIMEMessageHeader $headers * @param MAPIMessage $mapimessage */ private function addRecipients($headers, &$mapimessage) { $toaddr = $ccaddr = $bccaddr = array(); $Mail_RFC822 = new Mail_RFC822(); if (isset($headers["to"])) { $toaddr = $Mail_RFC822->parseAddressList($headers["to"]); } if (isset($headers["cc"])) { $ccaddr = $Mail_RFC822->parseAddressList($headers["cc"]); } if (isset($headers["bcc"])) { $bccaddr = $Mail_RFC822->parseAddressList($headers["bcc"]); } if (empty($toaddr)) { throw new StatusException(sprintf("ZarafaBackend->SendMail(): 'To' address in RFC822 message not found or unparsable. To header: '%s'", isset($headers["to"]) ? $headers["to"] : ''), SYNC_COMMONSTATUS_MESSHASNORECIP); } // Add recipients $recips = array(); foreach (array(MAPI_TO => $toaddr, MAPI_CC => $ccaddr, MAPI_BCC => $bccaddr) as $type => $addrlist) { foreach ($addrlist as $addr) { $mapirecip[PR_ADDRTYPE] = "SMTP"; $mapirecip[PR_EMAIL_ADDRESS] = $addr->mailbox . "@" . $addr->host; if (isset($addr->personal) && strlen($addr->personal) > 0) { $mapirecip[PR_DISPLAY_NAME] = u2wi($addr->personal); } else { $mapirecip[PR_DISPLAY_NAME] = $mapirecip[PR_EMAIL_ADDRESS]; } $mapirecip[PR_RECIPIENT_TYPE] = $type; $mapirecip[PR_ENTRYID] = mapi_createoneoff($mapirecip[PR_DISPLAY_NAME], $mapirecip[PR_ADDRTYPE], $mapirecip[PR_EMAIL_ADDRESS]); array_push($recips, $mapirecip); } } mapi_message_modifyrecipients($mapimessage, 0, $recips); }
function _storeAttachment($mapimessage, $part) { // attachment $attach = mapi_message_createattach($mapimessage); $filename = ""; // Filename is present in both Content-Type: name=.. and in Content-Disposition: filename= if (isset($part->ctype_parameters["name"])) { $filename = $part->ctype_parameters["name"]; } else { if (isset($part->d_parameters["name"])) { $filename = $part->d_parameters["filename"]; } else { if (isset($part->d_parameters["filename"])) { // sending appointment with nokia & android only filename is set $filename = $part->d_parameters["filename"]; } else { if (isset($part->d_parameters["filename*0"])) { for ($i = 0; $i < count($part->d_parameters); $i++) { if (isset($part->d_parameters["filename*" . $i])) { $filename .= $part->d_parameters["filename*" . $i]; } } } else { $filename = "untitled"; } } } } // Android just doesn't send content-type, so mimeDecode doesn't performs base64 decoding // on meeting requests text/calendar somewhere inside content-transfer-encoding if (isset($part->headers['content-transfer-encoding']) && strpos($part->headers['content-transfer-encoding'], 'base64')) { if (strpos($part->headers['content-transfer-encoding'], 'text/calendar') !== false) { $part->ctype_primary = 'text'; $part->ctype_secondary = 'calendar'; } if (!isset($part->headers['content-type'])) { $part->body = base64_decode($part->body); } } // Set filename and attachment type mapi_setprops($attach, array(PR_ATTACH_LONG_FILENAME => u2wi($filename), PR_ATTACH_METHOD => ATTACH_BY_VALUE)); // Set attachment data mapi_setprops($attach, array(PR_ATTACH_DATA_BIN => $part->body)); // Set MIME type mapi_setprops($attach, array(PR_ATTACH_MIME_TAG => $part->ctype_primary . "/" . $part->ctype_secondary)); mapi_savechanges($attach); }
/** * 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; }
function escape($data) { debugLog('iCalDir::escape:input:' . $data); if (is_array($data)) { foreach ($data as $key => $val) { $data[$key] = $this->escape($val); } return $data; } $data = str_replace("\r\n", "\n", $data); $data = str_replace("\r", "\n", $data); $data = str_replace(array('\\', ';', ',', "\n"), array('\\\\', '\\;', '\\,', '\\n'), $data); debugLog('iCalDir::escape:output:' . u2wi($data)); return u2wi($data); }