/** * Function which replaces attachments with copy_from in copy_to. *@param resource $copy_from MAPI_message from which attachments are to be copied. *@param resource $copy_to MAPI_message to which attachment are to be copied. *@param boolean $copyExceptions if true then all exceptions should also be sent as attachments */ function replaceAttachments($copy_from, $copy_to, $copyExceptions = true) { /* remove all old attachments */ $attachmentTable = mapi_message_getattachmenttable($copy_to); if ($attachmentTable) { $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME)); foreach ($attachments as $attach_props) { /* remove exceptions too? */ if (!$copyExceptions && $attach_props[PR_ATTACH_METHOD] == 5 && isset($attach_props[PR_EXCEPTION_STARTTIME])) { continue; } mapi_message_deleteattach($copy_to, $attach_props[PR_ATTACH_NUM]); } } $attachmentTable = false; /* copy new attachments */ $attachmentTable = mapi_message_getattachmenttable($copy_from); if ($attachmentTable) { $attachments = mapi_table_queryallrows($attachmentTable, array(PR_ATTACH_NUM, PR_ATTACH_METHOD, PR_EXCEPTION_STARTTIME)); foreach ($attachments as $attach_props) { if (!$copyExceptions && $attach_props[PR_ATTACH_METHOD] == 5 && isset($attach_props[PR_EXCEPTION_STARTTIME])) { continue; } $attach_old = mapi_message_openattach($copy_from, (int) $attach_props[PR_ATTACH_NUM]); $attach_newResourceMsg = mapi_message_createattach($copy_to); mapi_copyto($attach_old, array(), array(), $attach_newResourceMsg, 0); mapi_savechanges($attach_newResourceMsg); } } }
/** * Imports a move of a message. This occurs when a user moves an item to another folder * * Normally, we would implement this via the 'offical' importmessagemove() function on the ICS importer, * but the Zarafa importer does not support this. Therefore we currently implement it via a standard mapi * call. This causes a mirror 'add/delete' to be sent to the PDA at the next sync. * Manfred, 2010-10-21. For some mobiles import was causing duplicate messages in the destination folder * (Mantis #202). Therefore we will create a new message in the destination folder, copy properties * of the source message to the new one and then delete the source message. * * @param string $id * @param string $newfolder destination folder * * @access public * @return boolean * @throws StatusException */ public function ImportMessageMove($id, $newfolder) { if (strtolower($newfolder) == strtolower(bin2hex($this->folderid))) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, source and destination are equal", $id, $newfolder), SYNC_MOVEITEMSSTATUS_SAMESOURCEANDDEST); } // Get the entryid of the message we're moving $entryid = mapi_msgstore_entryidfromsourcekey($this->store, $this->folderid, hex2bin($id)); if (!$entryid) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to resolve source message id", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } //open the source message $srcmessage = mapi_msgstore_openentry($this->store, $entryid); if (!$srcmessage) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open source message: 0x%X", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } // get correct mapi store for the destination folder $dststore = ZPush::GetBackend()->GetMAPIStoreForFolderId(ZPush::GetAdditionalSyncFolderStore($newfolder), $newfolder); if ($dststore === false) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open store of destination folder", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } $dstentryid = mapi_msgstore_entryidfromsourcekey($dststore, hex2bin($newfolder)); if (!$dstentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to resolve destination folder", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } $dstfolder = mapi_msgstore_openentry($dststore, $dstentryid); if (!$dstfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open destination folder", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } $newmessage = mapi_folder_createmessage($dstfolder); if (!$newmessage) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to create message in destination folder: 0x%X", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } // Copy message mapi_copyto($srcmessage, array(), array(), $newmessage); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, copy to destination message failed: 0x%X", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_CANNOTMOVE); } $srcfolderentryid = mapi_msgstore_entryidfromsourcekey($this->store, $this->folderid); if (!$srcfolderentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to resolve source folder", $id, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } $srcfolder = mapi_msgstore_openentry($this->store, $srcfolderentryid); if (!$srcfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open source folder: 0x%X", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } // Save changes mapi_savechanges($newmessage); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, mapi_savechanges() failed: 0x%X", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_CANNOTMOVE); } // Delete the old message if (!mapi_folder_deletemessages($srcfolder, array($entryid))) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, delete of source message failed: 0x%X. Possible duplicates.", $id, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_SOURCEORDESTLOCKED); } $sourcekeyprops = mapi_getprops($newmessage, array(PR_SOURCE_KEY)); if (isset($sourcekeyprops[PR_SOURCE_KEY]) && $sourcekeyprops[PR_SOURCE_KEY]) { return bin2hex($sourcekeyprops[PR_SOURCE_KEY]); } return false; }
/** * 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)); }
/** * Function which saves the exception data in an attachment. * @param array $exception_props the exception data (like any other MAPI appointment) * @param array $exception_recips list of recipients * @param mapi_message $copy_attach_from mapi message from which attachments should be copied * @return array properties of the exception */ function createExceptionAttachment($exception_props, $exception_recips = array(), $copy_attach_from = false) { // Create new attachment. $attachment = mapi_message_createattach($this->message); $props = array(); $props[PR_ATTACHMENT_FLAGS] = 2; $props[PR_ATTACHMENT_HIDDEN] = true; $props[PR_ATTACHMENT_LINKID] = 0; $props[PR_ATTACH_FLAGS] = 0; $props[PR_ATTACH_METHOD] = 5; $props[PR_DISPLAY_NAME] = "Exception"; $props[PR_EXCEPTION_STARTTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["startdate"]]); $props[PR_EXCEPTION_ENDTIME] = $this->fromGMT($this->tz, $exception_props[$this->proptags["duedate"]]); mapi_message_setprops($attachment, $props); $imessage = mapi_attach_openobj($attachment, MAPI_CREATE | MAPI_MODIFY); if ($copy_attach_from) { $attachmentTable = mapi_message_getattachmenttable($copy_attach_from); 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($copy_attach_from, (int) $attach_props[PR_ATTACH_NUM]); $attach_newResourceMsg = mapi_message_createattach($imessage); mapi_copyto($attach_old, array(), array(), $attach_newResourceMsg, 0); mapi_savechanges($attach_newResourceMsg); } } } $props = $props + $exception_props; // FIXME: the following piece of code is written to fix the creation // of an exception. This is only a quickfix as it is not yet possible // to change an existing exception. // remove mv properties when needed foreach ($props as $propTag => $propVal) { if ((mapi_prop_type($propTag) & MV_FLAG) == MV_FLAG && is_null($propVal)) { unset($props[$propTag]); } } mapi_message_setprops($imessage, $props); $this->setExceptionRecipients($imessage, $exception_recips, true); mapi_message_savechanges($imessage); mapi_message_savechanges($attachment); }
function ImportMessageMove($id, $newfolder) { if (strtolower($newfolder) == strtolower(bin2hex($this->_folderid))) { //TODO status value 4 debugLog("Source and destination are equal"); return false; } // Get the entryid of the message we're moving $entryid = mapi_msgstore_entryidfromsourcekey($this->_store, $this->_folderid, hex2bin($id)); if (!$entryid) { debugLog("Unable to resolve source message id"); return false; } //open the source message $srcmessage = mapi_msgstore_openentry($this->_store, $entryid); if (!$srcmessage) { debugLog("Unable to open source message:" . sprintf("%x", mapi_last_hresult())); return false; } $dstentryid = mapi_msgstore_entryidfromsourcekey($this->_store, hex2bin($newfolder)); if (!$dstentryid) { debugLog("Unable to resolve destination folder"); return false; } $dstfolder = mapi_msgstore_openentry($this->_store, $dstentryid); if (!$dstfolder) { debugLog("Unable to open destination folder"); return false; } $newmessage = mapi_folder_createmessage($dstfolder); if (!$newmessage) { debugLog("Unable to create message in destination folder:" . sprintf("%x", mapi_last_hresult())); return false; } // Copy message mapi_copyto($srcmessage, array(), array(), $newmessage); if (mapi_last_hresult()) { debugLog("copy to failed:" . sprintf("%x", mapi_last_hresult())); return false; } $srcfolderentryid = mapi_msgstore_entryidfromsourcekey($this->_store, $this->_folderid); if (!$srcfolderentryid) { debugLog("Unable to resolve source folder"); return false; } $srcfolder = mapi_msgstore_openentry($this->_store, $srcfolderentryid); if (!$srcfolder) { debugLog("Unable to open source folder:" . sprintf("%x", mapi_last_hresult())); return false; } // Save changes mapi_savechanges($newmessage); if (mapi_last_hresult()) { debugLog("mapi_savechanges failed:" . sprintf("%x", mapi_last_hresult())); return false; } // Delete the old message if (!mapi_folder_deletemessages($srcfolder, array($entryid))) { debugLog("Failed to delete source message. Possible duplicates"); } $sourcekeyprops = mapi_getprops($newmessage, array(PR_SOURCE_KEY)); if (isset($sourcekeyprops[PR_SOURCE_KEY]) && $sourcekeyprops[PR_SOURCE_KEY]) { return bin2hex($sourcekeyprops[PR_SOURCE_KEY]); } return false; }
function sendResponse($type, $prefix) { // Create a message in our outbox $outgoing = $this->createOutgoingMessage(); $messageprops = mapi_getprops($this->message, array(PR_SUBJECT)); $attach = mapi_message_createattach($outgoing); mapi_setprops($attach, array(PR_ATTACH_METHOD => ATTACH_EMBEDDED_MSG, PR_DISPLAY_NAME => $messageprops[PR_SUBJECT], PR_ATTACHMENT_HIDDEN => true)); $sub = mapi_attach_openproperty($attach, PR_ATTACH_DATA_OBJ, IID_IMessage, 0, MAPI_CREATE | MAPI_MODIFY); mapi_copyto($this->message, array(), array(PR_SENT_REPRESENTING_NAME, PR_SENT_REPRESENTING_EMAIL_ADDRESS, PR_SENT_REPRESENTING_ADDRTYPE, PR_SENT_REPRESENTING_ENTRYID, PR_SENT_REPRESENTING_SEARCH_KEY), $outgoing); mapi_copyto($this->message, array(), array(), $sub); if (!$this->setRecipientsForResponse($outgoing, $type)) { return false; } switch ($type) { case tdmtTaskAcc: $messageclass = "IPM.TaskRequest.Accept"; break; case tdmtTaskDec: $messageclass = "IPM.TaskRequest.Decline"; break; case tdmtTaskUpd: $messageclass = "IPM.TaskRequest.Update"; break; } mapi_savechanges($sub); mapi_savechanges($attach); // Set Body $body = $this->getBody(); $stream = mapi_openpropertytostream($outgoing, PR_BODY, MAPI_CREATE | MAPI_MODIFY); mapi_stream_setsize($stream, strlen($body)); mapi_stream_write($stream, $body); mapi_stream_commit($stream); // Set subject, taskmode, message class, icon index, response time mapi_setprops($outgoing, array(PR_SUBJECT => $prefix . $messageprops[PR_SUBJECT], $this->props['taskmode'] => $type, PR_MESSAGE_CLASS => $messageclass, PR_ICON_INDEX => 0xffffffff, $this->props['assignedtime'] => time())); mapi_savechanges($outgoing); mapi_message_submitmessage($outgoing); return true; }
/** * Imports a move of a message. This occurs when a user moves an item to another folder * * Normally, we would implement this via the 'offical' importmessagemove() function on the ICS importer, * but the Zarafa/Kopano importer does not support this. Therefore we currently implement it via a standard mapi * call. This causes a mirror 'add/delete' to be sent to the PDA at the next sync. * Manfred, 2010-10-21. For some mobiles import was causing duplicate messages in the destination folder * (Mantis #202). Therefore we will create a new message in the destination folder, copy properties * of the source message to the new one and then delete the source message. * * @param string $id * @param string $newfolder destination folder * * @access public * @return boolean * @throws StatusException */ public function ImportMessageMove($id, $newfolder) { list(, $sk) = Utils::SplitMessageId($id); if (strtolower($newfolder) == strtolower(bin2hex($this->folderid))) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, source and destination are equal", $id, $newfolder), SYNC_MOVEITEMSSTATUS_SAMESOURCEANDDEST); } // Get the entryid of the message we're moving $entryid = mapi_msgstore_entryidfromsourcekey($this->store, $this->folderid, hex2bin($sk)); $srcmessage = false; if ($entryid) { //open the source message $srcmessage = mapi_msgstore_openentry($this->store, $entryid); } if (!$entryid || !$srcmessage) { $code = SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID; // if we move to the trash and the source message is not found, we can also just tell the mobile that we successfully moved to avoid errors (ZP-624) if ($newfolder == ZPush::GetBackend()->GetWasteBasket()) { $code = SYNC_MOVEITEMSSTATUS_SUCCESS; } $errorCase = !$entryid ? "resolve source message id" : "open source message"; throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to %s: 0x%X", $sk, $newfolder, $errorCase, mapi_last_hresult()), $code); } // check if the source message is in the current syncinterval if (!$this->isMessageInSyncInterval($sk)) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Source message is outside the sync interval. Move not performed.", $sk, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } // get correct mapi store for the destination folder $dststore = ZPush::GetBackend()->GetMAPIStoreForFolderId(ZPush::GetAdditionalSyncFolderStore($newfolder), $newfolder); if ($dststore === false) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open store of destination folder", $sk, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } $dstentryid = mapi_msgstore_entryidfromsourcekey($dststore, hex2bin($newfolder)); if (!$dstentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to resolve destination folder", $sk, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } $dstfolder = mapi_msgstore_openentry($dststore, $dstentryid); if (!$dstfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open destination folder", $sk, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } $newmessage = mapi_folder_createmessage($dstfolder); if (!$newmessage) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to create message in destination folder: 0x%X", $sk, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_INVALIDDESTID); } // Copy message mapi_copyto($srcmessage, array(), array(), $newmessage); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, copy to destination message failed: 0x%X", $sk, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_CANNOTMOVE); } $srcfolderentryid = mapi_msgstore_entryidfromsourcekey($this->store, $this->folderid); if (!$srcfolderentryid) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to resolve source folder", $sk, $newfolder), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } $srcfolder = mapi_msgstore_openentry($this->store, $srcfolderentryid); if (!$srcfolder) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, unable to open source folder: 0x%X", $sk, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_INVALIDSOURCEID); } // Save changes mapi_savechanges($newmessage); if (mapi_last_hresult()) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, mapi_savechanges() failed: 0x%X", $sk, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_CANNOTMOVE); } // Delete the old message if (!mapi_folder_deletemessages($srcfolder, array($entryid))) { throw new StatusException(sprintf("ImportChangesICS->ImportMessageMove('%s','%s'): Error, delete of source message failed: 0x%X. Possible duplicates.", $sk, $newfolder, mapi_last_hresult()), SYNC_MOVEITEMSSTATUS_SOURCEORDESTLOCKED); } $sourcekeyprops = mapi_getprops($newmessage, array(PR_SOURCE_KEY)); if (isset($sourcekeyprops[PR_SOURCE_KEY]) && $sourcekeyprops[PR_SOURCE_KEY]) { $prefix = ""; // prepend the destination short folderid, if it exists $destShortId = ZPush::GetDeviceManager()->GetFolderIdForBackendId($newfolder); if ($destShortId !== $newfolder) { $prefix = $destShortId . ":"; } return $prefix . bin2hex($sourcekeyprops[PR_SOURCE_KEY]); } return false; }
/** * Copies attachments from one message to another. * * @param MAPIMessage $toMessage * @param MAPIMessage $fromMessage * * @return void */ private function copyAttachments(&$toMessage, $fromMessage) { $attachtable = mapi_message_getattachmenttable($fromMessage); $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM)); foreach ($rows as $row) { if (isset($row[PR_ATTACH_NUM])) { $attach = mapi_message_openattach($fromMessage, $row[PR_ATTACH_NUM]); $newattach = mapi_message_createattach($toMessage); mapi_copyto($attach, array(), array(), $newattach, 0); mapi_savechanges($newattach); } } }