예제 #1
0
 /**
  * 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));
 }
예제 #3
0
파일: ics.php 프로젝트: nnaannoo/paskot
 function SendMail($rfc822, $forward = false, $reply = false, $parent = false)
 {
     if (WBXML_DEBUG == true) {
         debugLog("SendMail: forward: {$forward}   reply: {$reply}   parent: {$parent}\n" . $rfc822);
     }
     $mimeParams = array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8');
     $mimeObject = new Mail_mimeDecode($rfc822);
     $message = $mimeObject->decode($mimeParams);
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID));
     if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) {
         debugLog("Outbox not found to create message");
         return false;
     }
     $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]);
     if (!$outbox) {
         debugLog("Unable to open outbox");
         return false;
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     mapi_setprops($mapimessage, array(PR_SUBJECT => u2wi(isset($message->headers["subject"]) ? $message->headers["subject"] : ""), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => "IPM.Note", PR_MESSAGE_DELIVERY_TIME => time()));
     if (isset($message->headers["x-priority"])) {
         switch ($message->headers["x-priority"]) {
             case 1:
             case 2:
                 $priority = PRIO_URGENT;
                 $importance = IMPORTANCE_HIGH;
                 break;
             case 4:
             case 5:
                 $priority = PRIO_NONURGENT;
                 $importance = IMPORTANCE_LOW;
                 break;
             case 3:
             default:
                 $priority = PRIO_NORMAL;
                 $importance = IMPORTANCE_NORMAL;
                 break;
         }
         mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority));
     }
     $addresses = array();
     $toaddr = $ccaddr = $bccaddr = array();
     $Mail_RFC822 = new Mail_RFC822();
     if (isset($message->headers["to"])) {
         $toaddr = $Mail_RFC822->parseAddressList($message->headers["to"]);
     }
     if (isset($message->headers["cc"])) {
         $ccaddr = $Mail_RFC822->parseAddressList($message->headers["cc"]);
     }
     if (isset($message->headers["bcc"])) {
         $bccaddr = $Mail_RFC822->parseAddressList($message->headers["bcc"]);
     }
     // Add recipients
     $recips = array();
     if (isset($toaddr)) {
         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);
     // Loop through message subparts.
     $body = "";
     $body_html = "";
     if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) {
         $mparts = $message->parts;
         for ($i = 0; $i < count($mparts); $i++) {
             $part = $mparts[$i];
             // palm pre & iPhone send forwarded messages in another subpart which are also parsed
             if ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "alternative" || $part->ctype_secondary == "related")) {
                 foreach ($part->parts as $spart) {
                     $mparts[] = $spart;
                 }
                 continue;
             }
             // standard body
             if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body) && (!isset($part->disposition) || $part->disposition != "attachment")) {
                 $body .= u2wi($part->body);
                 // assume only one text body
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "html") {
                 $body_html .= u2wi($part->body);
             } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") {
                 $zptnef = new ZPush_tnef($this->_defaultstore);
                 $mapiprops = array();
                 $zptnef->extractProps($part->body, $mapiprops);
                 if (is_array($mapiprops) && !empty($mapiprops)) {
                     //check if it is a recurring item
                     $tnefrecurr = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x5");
                     if (isset($mapiprops[$tnefrecurr])) {
                         $this->_handleRecurringItem($mapimessage, $mapiprops);
                     }
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     debugLog("TNEF: Mapi props array was empty");
                 }
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") {
                 $zpical = new ZPush_ical($this->_defaultstore);
                 $mapiprops = array();
                 $zpical->extractProps($part->body, $mapiprops);
                 // iPhone sends a second ICS which we ignore if we can
                 if (!isset($mapiprops[PR_MESSAGE_CLASS]) && strlen(trim($body)) == 0) {
                     debugLog("Secondary iPhone response is being ignored!! Mail dropped!");
                     return true;
                 }
                 if (!checkMapiExtVersion("6.30") && is_array($mapiprops) && !empty($mapiprops)) {
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     // store ics as attachment
                     //see icalTimezoneFix function in compat.php for more information
                     $part->body = icalTimezoneFix($part->body);
                     $this->_storeAttachment($mapimessage, $part);
                     debugLog("Sending ICS file as attachment");
                 }
             } else {
                 $this->_storeAttachment($mapimessage, $part);
             }
         }
     } else {
         if ($message->ctype_primary == "text" && $message->ctype_secondary == "html") {
             $body_html .= u2wi($message->body);
         } else {
             $body = u2wi($message->body);
         }
     }
     // some devices only transmit a html body
     if (strlen($body) == 0 && strlen($body_html) > 0) {
         debugLog("only html body sent, transformed into plain text");
         $body = strip_tags($body_html);
     }
     if ($forward) {
         $orig = $forward;
     }
     if ($reply) {
         $orig = $reply;
     }
     if (isset($orig) && $orig) {
         // Append the original text body for reply/forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig));
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         if ($fwmessage) {
             //update icon when forwarding or replying message
             if ($forward) {
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262));
             } elseif ($reply) {
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261));
             }
             mapi_savechanges($fwmessage);
             $stream = mapi_openproperty($fwmessage, PR_BODY, IID_IStream, 0, 0);
             $fwbody = "";
             while (1) {
                 $data = mapi_stream_read($stream, 1024);
                 if (strlen($data) == 0) {
                     break;
                 }
                 $fwbody .= $data;
             }
             $stream = mapi_openproperty($fwmessage, PR_HTML, IID_IStream, 0, 0);
             $fwbody_html = "";
             while (1) {
                 $data = mapi_stream_read($stream, 1024);
                 if (strlen($data) == 0) {
                     break;
                 }
                 $fwbody_html .= $data;
             }
             if ($forward) {
                 // During a forward, we have to add the forward header ourselves. This is because
                 // normally the forwarded message is added as an attachment. However, we don't want this
                 // because it would be rather complicated to copy over the entire original message due
                 // to the lack of IMessage::CopyTo ..
                 $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME));
                 $fwheader = "\r\n\r\n";
                 $fwheader .= "-----Original Message-----\r\n";
                 if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) {
                     $fwheader .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) {
                     $fwheader .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) {
                     $fwheader .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) {
                     $fwheader .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_SUBJECT])) {
                     $fwheader .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n";
                 }
                 $fwheader .= "\r\n";
                 // add fwheader to body and body_html
                 $body .= $fwheader;
                 if (strlen($body_html) > 0) {
                     $body_html .= str_ireplace("\r\n", "<br>", $fwheader);
                 }
             }
             if (strlen($body) > 0) {
                 $body .= $fwbody;
             }
             if (strlen($body_html) > 0) {
                 $body_html .= $fwbody_html;
             }
         } else {
             debugLog("Unable to open item with id {$orig} for forward/reply");
         }
     }
     if ($forward) {
         // Add attachments from the original message in a forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig));
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         $attachtable = mapi_message_getattachmenttable($fwmessage);
         $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM));
         foreach ($rows as $row) {
             if (isset($row[PR_ATTACH_NUM])) {
                 $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]);
                 $newattach = mapi_message_createattach($mapimessage);
                 // Copy all attachments from old to new attachment
                 $attachprops = mapi_getprops($attach);
                 mapi_setprops($newattach, $attachprops);
                 if (isset($attachprops[mapi_prop_tag(PT_ERROR, mapi_prop_id(PR_ATTACH_DATA_BIN))])) {
                     // Data is in a stream
                     $srcstream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN);
                     $dststream = mapi_openpropertytostream($newattach, PR_ATTACH_DATA_BIN, MAPI_MODIFY | MAPI_CREATE);
                     while (1) {
                         $data = mapi_stream_read($srcstream, 4096);
                         if (strlen($data) == 0) {
                             break;
                         }
                         mapi_stream_write($dststream, $data);
                     }
                     mapi_stream_commit($dststream);
                 }
                 mapi_savechanges($newattach);
             }
         }
     }
     //set PR_INTERNET_CPID to 65001 (utf-8) if store supports it and to 1252 otherwise
     $internetcpid = 1252;
     if (defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
         $internetcpid = 65001;
     }
     mapi_setprops($mapimessage, array(PR_BODY => $body, PR_INTERNET_CPID => $internetcpid));
     if (strlen($body_html) > 0) {
         mapi_setprops($mapimessage, array(PR_HTML => $body_html));
     }
     mapi_savechanges($mapimessage);
     mapi_message_submitmessage($mapimessage);
     return true;
 }
예제 #4
0
 /**
  * Sends an e-mail
  * This messages needs to be saved into the 'sent items' folder
  *
  * @param SyncSendMail  $sm     SyncSendMail object
  *
  * @access public
  * @return boolean
  * @throws StatusException
  */
 public function SendMail($sm)
 {
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZarafaBackend->SendMail(): RFC822: %d bytes  forward-id: '%s' reply-id: '%s' parent-id: '%s' SaveInSent: '%s' ReplaceMIME: '%s'", strlen($sm->mime), Utils::PrintAsString($sm->forwardflag), Utils::PrintAsString($sm->replyflag), Utils::PrintAsString(isset($sm->source->folderid) ? $sm->source->folderid : false), Utils::PrintAsString($sm->saveinsent), Utils::PrintAsString(isset($sm->replacemime))));
     // by splitting the message in several lines we can easily grep later
     foreach (preg_split("/((\r)?\n)/", $sm->mime) as $rfc822line) {
         ZLog::Write(LOGLEVEL_WBXML, "RFC822: " . $rfc822line);
     }
     $mimeParams = array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8');
     $mimeObject = new Mail_mimeDecode($sm->mime);
     $message = $mimeObject->decode($mimeParams);
     $sendMailProps = MAPIMapping::GetSendMailProperties();
     $sendMailProps = getPropIdsFromStrings($this->store, $sendMailProps);
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->store, array($sendMailProps["outboxentryid"], $sendMailProps["ipmsentmailentryid"]));
     if (isset($storeprops[$sendMailProps["outboxentryid"]])) {
         $outbox = mapi_msgstore_openentry($this->store, $storeprops[$sendMailProps["outboxentryid"]]);
     }
     if (!$outbox) {
         throw new StatusException(sprintf("ZarafaBackend->SendMail(): No Outbox found or unable to create message: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_SERVERERROR);
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     //message properties to be set
     $mapiprops = array();
     // only save the outgoing in sent items folder if the mobile requests it
     $mapiprops[$sendMailProps["sentmailentryid"]] = $storeprops[$sendMailProps["ipmsentmailentryid"]];
     // Check if imtomapi function is available and use it to send the mime message.
     // It is available since ZCP 7.0.6
     // @see http://jira.zarafa.com/browse/ZCP-9508
     if (function_exists('mapi_feature') && mapi_feature('INETMAPI_IMTOMAPI')) {
         ZLog::Write(LOGLEVEL_DEBUG, "Use the mapi_inetmapi_imtomapi function");
         $ab = mapi_openaddressbook($this->session);
         mapi_inetmapi_imtomapi($this->session, $this->store, $ab, $mapimessage, $sm->mime, array());
         // Set the appSeqNr so that tracking tab can be updated for meeting request updates
         // @see http://jira.zarafa.com/browse/ZP-68
         $meetingRequestProps = MAPIMapping::GetMeetingRequestProperties();
         $meetingRequestProps = getPropIdsFromStrings($this->store, $meetingRequestProps);
         $props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS, $meetingRequestProps["goidtag"]));
         if (stripos($props[PR_MESSAGE_CLASS], "IPM.Schedule.Meeting.Resp.") === 0) {
             // search for calendar items using goid
             $mr = new Meetingrequest($this->store, $mapimessage);
             $appointments = $mr->findCalendarItems($props[$meetingRequestProps["goidtag"]]);
             if (is_array($appointments) && !empty($appointments)) {
                 $app = mapi_msgstore_openentry($this->store, $appointments[0]);
                 $appprops = mapi_getprops($app, array($meetingRequestProps["appSeqNr"]));
                 if (isset($appprops[$meetingRequestProps["appSeqNr"]]) && $appprops[$meetingRequestProps["appSeqNr"]]) {
                     $mapiprops[$meetingRequestProps["appSeqNr"]] = $appprops[$meetingRequestProps["appSeqNr"]];
                     ZLog::Write(LOGLEVEL_DEBUG, sprintf("Set sequence number to:%d", $appprops[$meetingRequestProps["appSeqNr"]]));
                 }
             }
         }
         // Delete the PR_SENT_REPRESENTING_* properties because some android devices
         // do not send neither From nor Sender header causing empty PR_SENT_REPRESENTING_NAME and
         // PR_SENT_REPRESENTING_EMAIL_ADDRESS properties and "broken" PR_SENT_REPRESENTING_ENTRYID
         // which results in spooler not being able to send the message.
         // @see http://jira.zarafa.com/browse/ZP-85
         mapi_deleteprops($mapimessage, array($sendMailProps["sentrepresentingname"], $sendMailProps["sentrepresentingemail"], $sendMailProps["representingentryid"], $sendMailProps["sentrepresentingaddt"], $sendMailProps["sentrepresentinsrchk"]));
         if (isset($sm->source->itemid) && $sm->source->itemid) {
             $entryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($sm->source->folderid), hex2bin($sm->source->itemid));
             if ($entryid) {
                 $fwmessage = mapi_msgstore_openentry($this->store, $entryid);
             }
             if (!isset($fwmessage) || !$fwmessage) {
                 throw new StatusException(sprintf("ZarafaBackend->SendMail(): Could not open message id '%s' in folder id '%s' to be replied/forwarded: 0x%X", $sm->source->itemid, $sm->source->folderid, mapi_last_hresult()), SYNC_COMMONSTATUS_ITEMNOTFOUND);
             }
             //update icon when forwarding or replying message
             if ($sm->forwardflag) {
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262));
             } elseif ($sm->replyflag) {
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261));
             }
             mapi_savechanges($fwmessage);
             // only attach the original message if the mobile does not send it itself
             if (!isset($sm->replacemime)) {
                 // get message's body in order to append forward or reply text
                 $body = MAPIUtils::readPropStream($mapimessage, PR_BODY);
                 $bodyHtml = MAPIUtils::readPropStream($mapimessage, PR_HTML);
                 $cpid = mapi_getprops($fwmessage, array($sendMailProps["internetcpid"]));
                 if ($sm->forwardflag) {
                     // attach the original attachments to the outgoing message
                     $this->copyAttachments($mapimessage, $fwmessage);
                 }
                 if (strlen($body) > 0) {
                     $fwbody = MAPIUtils::readPropStream($fwmessage, PR_BODY);
                     $fwbody = isset($cpid[$sendMailProps["internetcpid"]]) ? Utils::ConvertCodepageStringToUtf8($cpid[$sendMailProps["internetcpid"]], $fwbody) : w2u($fwbody);
                     $mapiprops[$sendMailProps["body"]] = $body . "\r\n\r\n" . $fwbody;
                 }
                 if (strlen($bodyHtml) > 0) {
                     $fwbodyHtml = MAPIUtils::readPropStream($fwmessage, PR_HTML);
                     $fwbodyHtml = isset($cpid[$sendMailProps["internetcpid"]]) ? Utils::ConvertCodepageStringToUtf8($cpid[$sendMailProps["internetcpid"]], $fwbodyHtml) : w2u($fwbodyHtml);
                     $mapiprops[$sendMailProps["html"]] = $bodyHtml . "<br><br>" . $fwbodyHtml;
                 }
             }
         }
         mapi_setprops($mapimessage, $mapiprops);
         mapi_message_savechanges($mapimessage);
         mapi_message_submitmessage($mapimessage);
         $hr = mapi_last_hresult();
         if ($hr) {
             throw new StatusException(sprintf("ZarafaBackend->SendMail(): Error saving/submitting the message to the Outbox: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED);
         }
         ZLog::Write(LOGLEVEL_DEBUG, "ZarafaBackend->SendMail(): email submitted");
         return true;
     }
     $mapiprops[$sendMailProps["subject"]] = u2wi(isset($message->headers["subject"]) ? $message->headers["subject"] : "");
     $mapiprops[$sendMailProps["messageclass"]] = "IPM.Note";
     $mapiprops[$sendMailProps["deliverytime"]] = time();
     if (isset($message->headers["x-priority"])) {
         $this->getImportanceAndPriority($message->headers["x-priority"], $mapiprops, $sendMailProps);
     }
     $this->addRecipients($message->headers, $mapimessage);
     // Loop through message subparts.
     $body = "";
     $body_html = "";
     if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) {
         $mparts = $message->parts;
         for ($i = 0; $i < count($mparts); $i++) {
             $part = $mparts[$i];
             // palm pre & iPhone send forwarded messages in another subpart which are also parsed
             if ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "alternative" || $part->ctype_secondary == "related")) {
                 foreach ($part->parts as $spart) {
                     $mparts[] = $spart;
                 }
                 continue;
             }
             // standard body
             if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body) && (!isset($part->disposition) || $part->disposition != "attachment")) {
                 $body .= u2wi($part->body);
                 // assume only one text body
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "html") {
                 $body_html .= u2wi($part->body);
             } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") {
                 if (!isset($tnefAndIcalProps)) {
                     $tnefAndIcalProps = MAPIMapping::GetTnefAndIcalProperties();
                     $tnefAndIcalProps = getPropIdsFromStrings($this->store, $tnefAndIcalProps);
                 }
                 require_once 'tnefparser.php';
                 $zptnef = new TNEFParser($this->store, $tnefAndIcalProps);
                 $zptnef->ExtractProps($part->body, $mapiprops);
                 if (is_array($mapiprops) && !empty($mapiprops)) {
                     //check if it is a recurring item
                     if (isset($mapiprops[$tnefAndIcalProps["tnefrecurr"]])) {
                         MAPIUtils::handleRecurringItem($mapiprops, $tnefAndIcalProps);
                     }
                 } else {
                     ZLog::Write(LOGLEVEL_WARN, "ZarafaBackend->Sendmail(): TNEFParser: Mapi property array was empty");
                 }
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") {
                 if (!isset($tnefAndIcalProps)) {
                     $tnefAndIcalProps = MAPIMapping::GetTnefAndIcalProperties();
                     $tnefAndIcalProps = getPropIdsFromStrings($this->store, $tnefAndIcalProps);
                 }
                 require_once 'icalparser.php';
                 $zpical = new ICalParser($this->store, $tnefAndIcalProps);
                 $zpical->ExtractProps($part->body, $mapiprops);
                 // iPhone sends a second ICS which we ignore if we can
                 if (!isset($mapiprops[PR_MESSAGE_CLASS]) && strlen(trim($body)) == 0) {
                     ZLog::Write(LOGLEVEL_WARN, "ZarafaBackend->Sendmail(): Secondary iPhone response is being ignored!! Mail dropped!");
                     return true;
                 }
                 if (!Utils::CheckMapiExtVersion("6.30") && is_array($mapiprops) && !empty($mapiprops)) {
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     // store ics as attachment
                     //see Utils::IcalTimezoneFix() in utils.php for more information
                     $part->body = Utils::IcalTimezoneFix($part->body);
                     MAPIUtils::StoreAttachment($mapimessage, $part);
                     ZLog::Write(LOGLEVEL_INFO, "ZarafaBackend->Sendmail(): Sending ICS file as attachment");
                 }
             } else {
                 MAPIUtils::StoreAttachment($mapimessage, $part);
             }
         }
     } else {
         if ($message->ctype_primary == "text" && $message->ctype_secondary == "html") {
             $body_html .= u2wi($message->body);
         } else {
             $body = u2wi($message->body);
         }
     }
     // some devices only transmit a html body
     if (strlen($body) == 0 && strlen($body_html) > 0) {
         ZLog::Write(LOGLEVEL_WARN, "ZarafaBackend->SendMail(): only html body sent, transformed into plain text");
         $body = strip_tags($body_html);
     }
     if (isset($sm->source->itemid) && $sm->source->itemid) {
         // Append the original text body for reply/forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($sm->source->folderid), hex2bin($sm->source->itemid));
         if ($entryid) {
             $fwmessage = mapi_msgstore_openentry($this->store, $entryid);
         }
         if (!isset($fwmessage) || !$fwmessage) {
             throw new StatusException(sprintf("ZarafaBackend->SendMail(): Could not open message id '%s' in folder id '%s' to be replied/forwarded: 0x%X", $sm->source->itemid, $sm->source->folderid, mapi_last_hresult()), SYNC_COMMONSTATUS_ITEMNOTFOUND);
         }
         //update icon when forwarding or replying message
         if ($sm->forwardflag) {
             mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262));
         } elseif ($sm->replyflag) {
             mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261));
         }
         mapi_savechanges($fwmessage);
         // only attach the original message if the mobile does not send it itself
         if (!isset($sm->replacemime)) {
             $fwbody = MAPIUtils::readPropStream($fwmessage, PR_BODY);
             $fwbodyHtml = MAPIUtils::readPropStream($fwmessage, PR_HTML);
             if ($sm->forwardflag) {
                 // During a forward, we have to add the forward header ourselves. This is because
                 // normally the forwarded message is added as an attachment. However, we don't want this
                 // because it would be rather complicated to copy over the entire original message due
                 // to the lack of IMessage::CopyTo ..
                 $fwheader = $this->getForwardHeaders($fwmessage);
                 // add fwheader to body and body_html
                 $body .= $fwheader;
                 if (strlen($body_html) > 0) {
                     $body_html .= str_ireplace("\r\n", "<br>", $fwheader);
                 }
                 // attach the original attachments to the outgoing message
                 $this->copyAttachments($mapimessage, $fwmessage);
             }
             if (strlen($body) > 0) {
                 $body .= $fwbody;
             }
             if (strlen($body_html) > 0) {
                 $body_html .= $fwbodyHtml;
             }
         }
     }
     //set PR_INTERNET_CPID to 65001 (utf-8) if store supports it and to 1252 otherwise
     $internetcpid = INTERNET_CPID_WINDOWS1252;
     if (defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
         $internetcpid = INTERNET_CPID_UTF8;
     }
     $mapiprops[$sendMailProps["body"]] = $body;
     $mapiprops[$sendMailProps["internetcpid"]] = $internetcpid;
     if (strlen($body_html) > 0) {
         $mapiprops[$sendMailProps["html"]] = $body_html;
     }
     //TODO if setting all properties fails, try setting them infividually like in mapiprovider
     mapi_setprops($mapimessage, $mapiprops);
     mapi_savechanges($mapimessage);
     mapi_message_submitmessage($mapimessage);
     if (mapi_last_hresult()) {
         throw new StatusException(sprintf("ZarafaBackend->SendMail(): Error saving/submitting the message to the Outbox: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED);
     }
     ZLog::Write(LOGLEVEL_DEBUG, "ZarafaBackend->SendMail(): email submitted");
     return true;
 }
예제 #5
0
파일: ics.php 프로젝트: jkreska/test1
 function SendMail($rfc822, $forward = false, $reply = false, $parent = false)
 {
     $mimeParams = array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\r\n", 'charset' => 'utf-8');
     $mimeObject = new Mail_mimeDecode($mimeParams['input'], $mimeParams['crlf']);
     $message = $mimeObject->decode($mimeParams);
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID));
     if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) {
         debugLog("Outbox not found to create message");
         return false;
     }
     $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]);
     if (!$outbox) {
         debugLog("Unable to open outbox");
         return false;
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     mapi_setprops($mapimessage, array(PR_SUBJECT => u2w($mimeObject->_decodeHeader($message->headers["subject"])), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => "IPM.Note", PR_MESSAGE_DELIVERY_TIME => time()));
     if (isset($message->headers["x-priority"])) {
         switch ($message->headers["x-priority"]) {
             case 1:
             case 2:
                 $priority = PRIO_URGENT;
                 $importance = IMPORTANCE_HIGH;
                 break;
             case 4:
             case 5:
                 $priority = PRIO_NONURGENT;
                 $importance = IMPORTANCE_LOW;
                 break;
             case 3:
             default:
                 $priority = PRIO_NORMAL;
                 $importance = IMPORTANCE_NORMAL;
                 break;
         }
         mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority));
     }
     $addresses = array();
     $toaddr = $ccaddr = $bccaddr = array();
     if (isset($message->headers["to"])) {
         $toaddr = Mail_RFC822::parseAddressList($message->headers["to"]);
     }
     if (isset($message->headers["cc"])) {
         $ccaddr = Mail_RFC822::parseAddressList($message->headers["cc"]);
     }
     if (isset($message->headers["bcc"])) {
         $bccaddr = Mail_RFC822::parseAddressList($message->headers["bcc"]);
     }
     // Add recipients
     $recips = array();
     if (isset($toaddr)) {
         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] = u2w($mimeObject->_decodeHeader($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);
     // Loop through subparts. We currently only support real single-level
     // multiparts and partly multipart/related/mixed for attachments.
     // The PDA currently only does this because you are adding
     // an attachment and the type will be multipart/mixed or multipart/alternative.
     $body = "";
     if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) {
         foreach ($message->parts as $part) {
             if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body)) {
                 // discard any other kind of text, like html
                 $body .= u2w($part->body);
                 // assume only one text body
             } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") {
                 $zptnef = new ZPush_tnef($this->_defaultstore);
                 $mapiprops = array();
                 $zptnef->extractProps($part->body, $mapiprops);
                 if (is_array($mapiprops) && !empty($mapiprops)) {
                     //check if it is a recurring item
                     $tnefrecurr = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x5");
                     if (isset($mapiprops[$tnefrecurr])) {
                         $this->_handleRecurringItem($mapimessage, $mapiprops);
                     }
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     debugLog("TNEF: Mapi props array was empty");
                 }
             } elseif ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "related")) {
                 if (is_array($part->parts)) {
                     foreach ($part->parts as $part2) {
                         if (isset($part2->disposition) && ($part2->disposition == "inline" || $part2->disposition == "attachment")) {
                             $this->_storeAttachment($mapimessage, $part2);
                         }
                     }
                 }
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") {
                 $zpical = new ZPush_ical($this->_defaultstore);
                 $mapiprops = array();
                 $zpical->extractProps($part->body, $mapiprops);
                 if (is_array($mapiprops) && !empty($mapiprops)) {
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     debugLog("ICAL: Mapi props array was empty");
                 }
             } else {
                 $this->_storeAttachment($mapimessage, $part);
             }
         }
     } else {
         $body = u2w($message->body);
     }
     if ($forward) {
         $orig = $forward;
     }
     if ($reply) {
         $orig = $reply;
     }
     if (isset($orig) && $orig) {
         // Append the original text body for reply/forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig));
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         if ($fwmessage) {
             //update icon when forwarding or replying message
             if ($forward) {
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262));
             } elseif ($reply) {
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261));
             }
             mapi_savechanges($fwmessage);
             $stream = mapi_openproperty($fwmessage, PR_BODY, IID_IStream, 0, 0);
             $fwbody = "";
             while (1) {
                 $data = mapi_stream_read($stream, 1024);
                 if (strlen($data) == 0) {
                     break;
                 }
                 $fwbody .= $data;
             }
             if (strlen($body) > 0) {
                 if ($forward) {
                     // During a forward, we have to add the forward header ourselves. This is because
                     // normally the forwarded message is added as an attachment. However, we don't want this
                     // because it would be rather complicated to copy over the entire original message due
                     // to the lack of IMessage::CopyTo ..
                     $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME));
                     $body .= "\r\n\r\n";
                     $body .= "-----Original Message-----\r\n";
                     if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) {
                         $body .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) {
                         $body .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) {
                         $body .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) {
                         $body .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_SUBJECT])) {
                         $body .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n";
                     }
                     $body .= "\r\n";
                 }
                 $body .= $fwbody;
             }
         } else {
             debugLog("Unable to open item with id {$orig} for forward/reply");
         }
     }
     if ($forward) {
         // Add attachments from the original message in a forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig));
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         $attachtable = mapi_message_getattachmenttable($fwmessage);
         $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM));
         foreach ($rows as $row) {
             if (isset($row[PR_ATTACH_NUM])) {
                 $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]);
                 $newattach = mapi_message_createattach($mapimessage);
                 // Copy all attachments from old to new attachment
                 $attachprops = mapi_getprops($attach);
                 mapi_setprops($newattach, $attachprops);
                 if (isset($attachprops[mapi_prop_tag(PT_ERROR, mapi_prop_id(PR_ATTACH_DATA_BIN))])) {
                     // Data is in a stream
                     $srcstream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN);
                     $dststream = mapi_openpropertytostream($newattach, PR_ATTACH_DATA_BIN, MAPI_MODIFY | MAPI_CREATE);
                     while (1) {
                         $data = mapi_stream_read($srcstream, 4096);
                         if (strlen($data) == 0) {
                             break;
                         }
                         mapi_stream_write($dststream, $data);
                     }
                     mapi_stream_commit($dststream);
                 }
                 mapi_savechanges($newattach);
             }
         }
     }
     mapi_setprops($mapimessage, array(PR_BODY => $body));
     mapi_savechanges($mapimessage);
     mapi_message_submitmessage($mapimessage);
     return true;
 }
 function createOutgoingMessage()
 {
     // Open our default store for this user (that's the only store we can submit in)
     $store = $this->getDefaultStore();
     $storeprops = mapi_getprops($store, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID));
     $outbox = mapi_msgstore_openentry($store, $storeprops[PR_IPM_OUTBOX_ENTRYID]);
     if (!$outbox) {
         return false;
     }
     $outgoing = mapi_folder_createmessage($outbox);
     if (!$outgoing) {
         return false;
     }
     // Set SENT_REPRESENTING in case we're sending as a delegate
     $ownerstore = $this->getTaskFolderStore();
     $sentreprprops = $this->getSentReprProps($ownerstore);
     mapi_setprops($outgoing, $sentreprprops);
     mapi_setprops($outgoing, array(PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID]));
     return $outgoing;
 }
예제 #7
0
 function SendMail($rfc822, $forward = false, $reply = false, $parent = false)
 {
     $message = Mail_mimeDecode::decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'input' => $rfc822, 'crlf' => "\r\n", 'charset' => 'utf-8'));
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID));
     if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) {
         debugLog("Outbox not found to create message");
         return false;
     }
     $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]);
     if (!$outbox) {
         debugLog("Unable to open outbox");
         return false;
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     mapi_setprops($mapimessage, array(PR_SUBJECT => u2w($message->headers["subject"]), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => "IPM.Note", PR_MESSAGE_DELIVERY_TIME => time()));
     if (isset($message->headers["x-priority"])) {
         switch ($message->headers["x-priority"]) {
             case 1:
             case 2:
                 $priority = PRIO_URGENT;
                 $importance = IMPORTANCE_HIGH;
                 break;
             case 4:
             case 5:
                 $priority = PRIO_NONURGENT;
                 $importance = IMPORTANCE_LOW;
                 break;
             case 3:
             default:
                 $priority = PRIO_NORMAL;
                 $importance = IMPORTANCE_NORMAL;
                 break;
         }
         mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority));
     }
     $addresses = array();
     $toaddr = $ccaddr = $bccaddr = array();
     if (isset($message->headers["to"])) {
         $toaddr = Mail_RFC822::parseAddressList($message->headers["to"]);
     }
     if (isset($message->headers["cc"])) {
         $ccaddr = Mail_RFC822::parseAddressList($message->headers["cc"]);
     }
     if (isset($message->headers["bcc"])) {
         $bccaddr = Mail_RFC822::parseAddressList($message->headers["bcc"]);
     }
     // Add recipients
     $recips = array();
     if (isset($toaddr)) {
         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] = u2w($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);
     // Loop through subparts. We currently only support single-level
     // multiparts. The PDA currently only does this because you are adding
     // an attachment and the type will be multipart/mixed.
     if ($message->ctype_primary == "multipart" && $message->ctype_secondary == "mixed") {
         foreach ($message->parts as $part) {
             if ($part->ctype_primary == "text") {
                 $body = u2w($part->body);
             } else {
                 // attachment
                 $attach = mapi_message_createattach($mapimessage);
                 // 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 {
                         $filename = "untitled";
                     }
                 }
                 // Set filename and attachment type
                 mapi_setprops($attach, array(PR_ATTACH_LONG_FILENAME => u2w($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);
             }
         }
     } else {
         $body = u2w($message->body);
     }
     if ($forward) {
         $orig = $forward;
     }
     if ($reply) {
         $orig = $reply;
     }
     if (isset($orig) && $orig) {
         // Append the original text body for reply/forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig));
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         if ($fwmessage) {
             $messageprops = mapi_getprops($fwmessage, array(PR_BODY));
             if (isset($messageprops[PR_BODY])) {
                 if ($forward) {
                     // During a forward, we have to add the forward header ourselves. This is because
                     // normally the forwarded message is added as an attachment. However, we don't want this
                     // because it would be rather complicated to copy over the entire original message due
                     // to the lack of IMessage::CopyTo ..
                     $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME));
                     $body .= "\r\n\r\n";
                     $body .= "-----Original Message-----\r\n";
                     if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) {
                         $body .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) {
                         $body .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) {
                         $body .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) {
                         $body .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n";
                     }
                     if (isset($fwmessageprops[PR_SUBJECT])) {
                         $body .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n";
                     }
                     $body .= "\r\n";
                 }
                 $body .= $messageprops[PR_BODY];
             }
         } else {
             debugLog("Unable to open item with id {$orig} for forward/reply");
         }
     }
     if ($forward) {
         // Add attachments from the original message in a forward
         $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($parent), hex2bin($orig));
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         $attachtable = mapi_message_getattachmenttable($fwmessage);
         $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM));
         foreach ($rows as $row) {
             if (isset($row[PR_ATTACH_NUM])) {
                 $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]);
                 $newattach = mapi_message_createattach($mapimessage);
                 // Copy all attachments from old to new attachment
                 $attachprops = mapi_getprops($attach);
                 mapi_setprops($newattach, $attachprops);
                 if (isset($attachprops[mapi_prop_tag(PT_ERROR, mapi_prop_id(PR_ATTACH_DATA_BIN))])) {
                     // Data is in a stream
                     $srcstream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN);
                     $dststream = mapi_openpropertytostream($newattach, PR_ATTACH_DATA_BIN, MAPI_MODIFY | MAPI_CREATE);
                     while (1) {
                         $data = mapi_stream_read($srcstream, 4096);
                         if (strlen($data) == 0) {
                             break;
                         }
                         mapi_stream_write($dststream, $data);
                     }
                     mapi_stream_commit($dststream);
                 }
                 mapi_savechanges($newattach);
             }
         }
     }
     mapi_setprops($mapimessage, array(PR_BODY => $body));
     mapi_savechanges($mapimessage);
     mapi_message_submitmessage($mapimessage);
     return true;
 }
예제 #8
0
 /**
  * Updates the chunk data in the hidden folder if it changed.
  * If the chunkId is not available, it's created.
  *
  * @param string    $folderid
  * @param string    $chunkName      The name of the chunk (used to find/update the chunk message).
  *                                  The name is to be saved in the 'subject' of the chunk message.
  * @param int       $amountEntries  Amount of entries in the chunkdata.
  * @param string    $chunkData      The data containing all the data.
  * @param string    $chunkCRC       A checksum of the chunk data. To be saved in the 'location' of
  *                                  the chunk message. Used to identify changed chunks.
  * @param string    $gabId          Id that uniquely identifies the GAB. If not set or null the default GAB is assumed.
  * @param string    $gabName        String that uniquely identifies the GAB. If not set the default GAB is assumed.
  *
  * @access protected
  * @return boolean
  */
 protected function setChunkData($folderid, $chunkName, $amountEntries, $chunkData, $chunkCRC, $gabId = null, $gabName = 'default')
 {
     $log = sprintf("Kopano->setChunkData: %s\tEntries: %d\t Size: %d B\tCRC: %s  -  ", $chunkName, $amountEntries, strlen($chunkData), $chunkCRC);
     // find the chunk message in the folder
     $store = $this->getStore($gabId, $gabName);
     if (!$store) {
         return false;
     }
     $chunkdata = $this->findChunk($store, $folderid, $chunkName);
     $message = false;
     // message not found, create it
     if (empty($chunkdata)) {
         $folder = $this->getFolder($store, $folderid);
         $message = mapi_folder_createmessage($folder);
         mapi_setprops($message, array(PR_MESSAGE_CLASS => "IPM.Appointment", $this->mapiprops['chunktype'] => $this->chunkType, PR_SUBJECT => $chunkName, $this->mapiprops['createtime'] => time(), $this->mapiprops['reminderset'] => 0, $this->mapiprops['isrecurring'] => 0, $this->mapiprops['busystatus'] => 0));
         $log .= "creating - ";
     } else {
         // we need to update the chunk if the CRC does not match!
         if ($chunkdata[$this->mapiprops['chunkCRC']] != $chunkCRC) {
             $message = mapi_msgstore_openentry($store, $chunkdata[PR_ENTRYID]);
             $log .= "opening - ";
         } else {
             $log .= "unchanged";
         }
     }
     // update chunk if necessary
     if ($message) {
         mapi_setprops($message, array($this->mapiprops['chunkCRC'] => $chunkCRC, PR_BODY => $chunkData, $this->mapiprops['updatetime'] => time()));
         @mapi_savechanges($message);
         if (mapi_last_hresult()) {
             $log .= sprintf("error saving: 0x%08X", mapi_last_hresult());
         } else {
             $log .= "saved";
         }
     }
     // output log
     $this->log($log);
     return true;
 }
예제 #9
0
 /**
  * Sends an e-mail
  * This messages needs to be saved into the 'sent items' folder
  *
  * @param SyncSendMail  $sm     SyncSendMail object
  *
  * @access public
  * @return boolean
  * @throws StatusException
  */
 public function SendMail($sm)
 {
     // Check if imtomapi function is available and use it to send the mime message.
     // It is available since ZCP 7.0.6
     // @see http://jira.zarafa.com/browse/ZCP-9508
     if (!(function_exists('mapi_feature') && mapi_feature('INETMAPI_IMTOMAPI'))) {
         throw new StatusException("ZarafaBackend->SendMail(): ZCP version is too old, INETMAPI_IMTOMAPI is not available. Install at least ZCP version 7.0.6 or later.", SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED, null, LOGLEVEL_FATAL);
         return false;
     }
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZarafaBackend->SendMail(): RFC822: %d bytes  forward-id: '%s' reply-id: '%s' parent-id: '%s' SaveInSent: '%s' ReplaceMIME: '%s'", strlen($sm->mime), Utils::PrintAsString($sm->forwardflag), Utils::PrintAsString($sm->replyflag), Utils::PrintAsString(isset($sm->source->folderid) ? $sm->source->folderid : false), Utils::PrintAsString($sm->saveinsent), Utils::PrintAsString(isset($sm->replacemime))));
     // by splitting the message in several lines we can easily grep later
     foreach (preg_split("/((\r)?\n)/", $sm->mime) as $rfc822line) {
         ZLog::Write(LOGLEVEL_WBXML, "RFC822: " . $rfc822line);
     }
     $sendMailProps = MAPIMapping::GetSendMailProperties();
     $sendMailProps = getPropIdsFromStrings($this->store, $sendMailProps);
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->store, array($sendMailProps["outboxentryid"], $sendMailProps["ipmsentmailentryid"]));
     if (isset($storeprops[$sendMailProps["outboxentryid"]])) {
         $outbox = mapi_msgstore_openentry($this->store, $storeprops[$sendMailProps["outboxentryid"]]);
     }
     if (!$outbox) {
         throw new StatusException(sprintf("ZarafaBackend->SendMail(): No Outbox found or unable to create message: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_SERVERERROR);
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     //message properties to be set
     $mapiprops = array();
     // only save the outgoing in sent items folder if the mobile requests it
     $mapiprops[$sendMailProps["sentmailentryid"]] = $storeprops[$sendMailProps["ipmsentmailentryid"]];
     ZLog::Write(LOGLEVEL_DEBUG, "Use the mapi_inetmapi_imtomapi function");
     $ab = mapi_openaddressbook($this->session);
     mapi_inetmapi_imtomapi($this->session, $this->store, $ab, $mapimessage, $sm->mime, array());
     // Set the appSeqNr so that tracking tab can be updated for meeting request updates
     // @see http://jira.zarafa.com/browse/ZP-68
     $meetingRequestProps = MAPIMapping::GetMeetingRequestProperties();
     $meetingRequestProps = getPropIdsFromStrings($this->store, $meetingRequestProps);
     $props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS, $meetingRequestProps["goidtag"], $sendMailProps["internetcpid"]));
     // Convert sent message's body to UTF-8.
     // @see http://jira.zarafa.com/browse/ZP-505
     if (isset($props[$sendMailProps["internetcpid"]]) && $props[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sent email cpid is not unicode (%d). Set it to unicode and convert email body.", $props[$sendMailProps["internetcpid"]]));
         $mapiprops[$sendMailProps["internetcpid"]] = INTERNET_CPID_UTF8;
         $body = MAPIUtils::readPropStream($mapimessage, PR_BODY);
         $body = Utils::ConvertCodepageStringToUtf8($props[$sendMailProps["internetcpid"]], $body);
         $mapiprops[$sendMailProps["body"]] = $body;
         $bodyHtml = MAPIUtils::readPropStream($mapimessage, PR_HTML);
         $bodyHtml = Utils::ConvertCodepageStringToUtf8($props[$sendMailProps["internetcpid"]], $bodyHtml);
         $mapiprops[$sendMailProps["html"]] = $bodyHtml;
         mapi_setprops($mapimessage, $mapiprops);
     }
     if (stripos($props[PR_MESSAGE_CLASS], "IPM.Schedule.Meeting.Resp.") === 0) {
         // search for calendar items using goid
         $mr = new Meetingrequest($this->store, $mapimessage);
         $appointments = $mr->findCalendarItems($props[$meetingRequestProps["goidtag"]]);
         if (is_array($appointments) && !empty($appointments)) {
             $app = mapi_msgstore_openentry($this->store, $appointments[0]);
             $appprops = mapi_getprops($app, array($meetingRequestProps["appSeqNr"]));
             if (isset($appprops[$meetingRequestProps["appSeqNr"]]) && $appprops[$meetingRequestProps["appSeqNr"]]) {
                 $mapiprops[$meetingRequestProps["appSeqNr"]] = $appprops[$meetingRequestProps["appSeqNr"]];
                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("Set sequence number to:%d", $appprops[$meetingRequestProps["appSeqNr"]]));
             }
         }
     }
     // Delete the PR_SENT_REPRESENTING_* properties because some android devices
     // do not send neither From nor Sender header causing empty PR_SENT_REPRESENTING_NAME and
     // PR_SENT_REPRESENTING_EMAIL_ADDRESS properties and "broken" PR_SENT_REPRESENTING_ENTRYID
     // which results in spooler not being able to send the message.
     // @see http://jira.zarafa.com/browse/ZP-85
     mapi_deleteprops($mapimessage, array($sendMailProps["sentrepresentingname"], $sendMailProps["sentrepresentingemail"], $sendMailProps["representingentryid"], $sendMailProps["sentrepresentingaddt"], $sendMailProps["sentrepresentinsrchk"]));
     if (isset($sm->source->itemid) && $sm->source->itemid) {
         // answering an email in a public/shared folder
         if (!$this->Setup(ZPush::GetAdditionalSyncFolderStore($sm->source->folderid))) {
             throw new StatusException(sprintf("ZarafaBackend->SendMail() could not Setup() the backend for folder id '%s'", $sm->source->folderid), SYNC_COMMONSTATUS_SERVERERROR);
         }
         $entryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($sm->source->folderid), hex2bin($sm->source->itemid));
         if ($entryid) {
             $fwmessage = mapi_msgstore_openentry($this->store, $entryid);
         }
         if (!isset($fwmessage) || !$fwmessage) {
             throw new StatusException(sprintf("ZarafaBackend->SendMail(): Could not open message id '%s' in folder id '%s' to be replied/forwarded: 0x%X", $sm->source->itemid, $sm->source->folderid, mapi_last_hresult()), SYNC_COMMONSTATUS_ITEMNOTFOUND);
         }
         //update icon when forwarding or replying message
         if ($sm->forwardflag) {
             mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262));
         } elseif ($sm->replyflag) {
             mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261));
         }
         mapi_savechanges($fwmessage);
         // only attach the original message if the mobile does not send it itself
         if (!isset($sm->replacemime)) {
             // get message's body in order to append forward or reply text
             if (!isset($body)) {
                 $body = MAPIUtils::readPropStream($mapimessage, PR_BODY);
             }
             if (!isset($bodyHtml)) {
                 $bodyHtml = MAPIUtils::readPropStream($mapimessage, PR_HTML);
             }
             $cpid = mapi_getprops($fwmessage, array($sendMailProps["internetcpid"]));
             if ($sm->forwardflag) {
                 // attach the original attachments to the outgoing message
                 $this->copyAttachments($mapimessage, $fwmessage);
             }
             // regarding the conversion @see ZP-470
             if (strlen($body) > 0) {
                 $fwbody = MAPIUtils::readPropStream($fwmessage, PR_BODY);
                 // if only the old message's cpid is set, convert from old charset to utf-8
                 if (isset($cpid[$sendMailProps["internetcpid"]]) && $cpid[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8) {
                     ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZarafaBackend->SendMail(): convert plain forwarded message charset (only fw set) from '%s' to '65001'", $cpid[$sendMailProps["internetcpid"]]));
                     $fwbody = Utils::ConvertCodepageStringToUtf8($cpid[$sendMailProps["internetcpid"]], $fwbody);
                 } else {
                     ZLog::Write(LOGLEVEL_DEBUG, "ZarafaBackend->SendMail(): no charset conversion done for plain forwarded message");
                     $fwbody = w2u($fwbody);
                 }
                 $mapiprops[$sendMailProps["body"]] = $body . "\r\n\r\n" . $fwbody;
             }
             if (strlen($bodyHtml) > 0) {
                 $fwbodyHtml = MAPIUtils::readPropStream($fwmessage, PR_HTML);
                 // if only new message's cpid is set, convert to UTF-8
                 if (isset($cpid[$sendMailProps["internetcpid"]]) && $cpid[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8) {
                     ZLog::Write(LOGLEVEL_DEBUG, sprintf("ZarafaBackend->SendMail(): convert html forwarded message charset (only fw set) from '%s' to '65001'", $cpid[$sendMailProps["internetcpid"]]));
                     $fwbodyHtml = Utils::ConvertCodepageStringToUtf8($cpid[$sendMailProps["internetcpid"]], $fwbodyHtml);
                 } else {
                     ZLog::Write(LOGLEVEL_DEBUG, "ZarafaBackend->SendMail(): no charset conversion done for html forwarded message");
                     $fwbodyHtml = w2u($fwbodyHtml);
                 }
                 $mapiprops[$sendMailProps["html"]] = $bodyHtml . "<br><br>" . $fwbodyHtml;
             }
         }
     }
     mapi_setprops($mapimessage, $mapiprops);
     mapi_message_savechanges($mapimessage);
     mapi_message_submitmessage($mapimessage);
     $hr = mapi_last_hresult();
     if ($hr) {
         throw new StatusException(sprintf("ZarafaBackend->SendMail(): Error saving/submitting the message to the Outbox: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED);
     }
     ZLog::Write(LOGLEVEL_DEBUG, "ZarafaBackend->SendMail(): email submitted");
     return true;
 }
예제 #10
0
 /**
  * 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;
 }
예제 #11
0
    }
    if (isset($props[$properties["business_address"]])) {
        $props[$properties["mailing_address"]] = 2;
        setMailingAdress($props[$properties["business_address_street"]], $props[$properties["business_address_postal_code"]], $props[$properties["business_address_city"]], $props[$properties["business_address_state"]], $props[$properties["business_address_country"]], $props[$properties["business_address"]], $props, $properties);
    } elseif (isset($props[$properties["home_address"]])) {
        $props[$properties["mailing_address"]] = 1;
        setMailingAdress($props[$properties["home_address_street"]], $props[$properties["home_address_postal_code"]], $props[$properties["home_address_city"]], $props[$properties["home_address_state"]], $props[$properties["home_address_country"]], $props[$properties["home_address"]], $props, $properties);
    } elseif (isset($props[$properties["other_address"]])) {
        $props[$properties["mailing_address"]] = 3;
        setMailingAdress($props[$properties["other_address_street"]], $props[$properties["other_address_postal_code"]], $props[$properties["other_address_city"]], $props[$properties["other_address_state"]], $props[$properties["other_address_country"]], $props[$properties["other_address"]], $props, $properties);
    }
    // if the display name is set, then it is a valid contact: save it to the folder
    if (isset($props[$properties["display_name"]])) {
        $props[$properties["message_class"]] = "IPM.Contact";
        $props[$properties["icon_index"]] = "512";
        $message = mapi_folder_createmessage($folder);
        mapi_setprops($message, $props);
        mapi_savechanges($message);
        printf("New contact added \"%s\".\n", $props[$properties["display_name"]]);
    }
    $i++;
}
// EOF
function getPropIdsFromStrings($store, $mapping)
{
    $props = array();
    $ids = array("name" => array(), "id" => array(), "guid" => array(), "type" => array());
    // this array stores all the information needed to retrieve a named property
    $num = 0;
    // caching
    $guids = array();
function import($store, $csv_file, $delete_old_items, $categories)
{
    $folder = getContactsFolder($store);
    // open the csv file and start reading
    $fh = fopen($csv_file, "r");
    if (!$fh) {
        trigger_error("Can't read CSV file \"" . $csv_file . "\".", E_USER_ERROR);
    }
    // Delete all existing items if requested.
    if ($delete_old_items) {
        mapi_folder_emptyfolder($folder, DEL_ASSOCIATED);
        printf("Old items deleted.\n");
    }
    $properties = getProperties();
    $properties = replaceStringPropertyTags($store, $properties);
    //composed properties which require more work
    $special_properties = getSpecialPropertyNames();
    $csv_mapping = getMapping();
    $i = 1;
    while (!feof($fh)) {
        $line = fgetcsv($fh, CSV_MAX_LENGTH, CSV_DELIMITER, CSV_ENCLOSURE);
        // print_r($line);
        if (!$line) {
            continue;
        }
        if ($i == 1 && defined('FIELD_NAMES') && FIELD_NAMES) {
            $i++;
            continue;
        }
        $propValues = array();
        //set "simple" properties
        foreach ($csv_mapping as $property => $cnt) {
            if (!in_array($property, $special_properties)) {
                setProperty($property, $line[$csv_mapping[$property]], $propValues, $properties);
            }
        }
        // set display name
        if (isset($csv_mapping["display_name"]) && isset($line[$csv_mapping["display_name"]])) {
            $name = to_windows1252($line[$csv_mapping["display_name"]]);
            $propValues[$properties["display_name"]] = $propValues[$properties["subject"]] = $propValues[$properties["fileas"]] = $name;
            $propValues[$properties["fileas_selection"]] = -1;
        } else {
            $propValues[$properties["display_name"]] = $propValues[$properties["subject"]] = $propValues[$properties["fileas"]] = "";
            if (isset($propValues[$properties["given_name"]])) {
                $propValues[$properties["display_name"]] .= $propValues[$properties["given_name"]];
                $propValues[$properties["subject"]] .= $propValues[$properties["given_name"]];
            }
            if (isset($propValues[$properties["surname"]])) {
                if (strlen($propValues[$properties["display_name"]]) > 0) {
                    $propValues[$properties["display_name"]] .= " " . $propValues[$properties["surname"]];
                    $propValues[$properties["subject"]] .= " " . $propValues[$properties["surname"]];
                } else {
                    $propValues[$properties["display_name"]] .= $propValues[$properties["surname"]];
                    $propValues[$properties["subject"]] .= $propValues[$properties["surname"]];
                }
            }
            if (isset($propValues[$properties["surname"]])) {
                $propValues[$properties["fileas"]] .= $propValues[$properties["surname"]];
            }
            if (isset($propValues[$properties["given_name"]])) {
                if (strlen($propValues[$properties["fileas"]]) > 0) {
                    $propValues[$properties["fileas"]] .= ", " . $propValues[$properties["given_name"]];
                } else {
                    $propValues[$properties["fileas"]] .= $propValues[$properties["given_name"]];
                }
            }
        }
        $nremails = array();
        $abprovidertype = 0;
        if (isset($csv_mapping["email_address_1"]) && isset($line[$csv_mapping["email_address_1"]])) {
            setEmailAddress($line[$csv_mapping["email_address_1"]], $propValues[$properties["display_name"]], 1, $propValues, $properties, $nremails, $abprovidertype);
        }
        if (isset($csv_mapping["email_address_2"]) && isset($line[$csv_mapping["email_address_2"]])) {
            setEmailAddress($line[$csv_mapping["email_address_2"]], $propValues[$properties["display_name"]], 2, $propValues, $properties, $nremails, $abprovidertype);
        }
        if (isset($csv_mapping["email_address_3"]) && isset($line[$csv_mapping["email_address_3"]])) {
            setEmailAddress($line[$csv_mapping["email_address_3"]], $propValues[$properties["display_name"]], 3, $propValues, $properties, $nremails, $abprovidertype);
        }
        if (!empty($nremails)) {
            $propValues[$properties["address_book_mv"]] = $nremails;
        }
        $propValues[$properties["address_book_long"]] = $abprovidertype;
        //set addresses
        if (isset($csv_mapping["home_address_street2"])) {
            mergeStreet("home", $line[$csv_mapping["home_address_street2"]], $propValues, $properties);
        }
        if (isset($csv_mapping["home_address_street3"])) {
            mergeStreet("home", $line[$csv_mapping["home_address_street3"]], $propValues, $properties);
        }
        if (!isset($propValues[$properties["home_address"]]) && isset($propValues[$properties["home_address_street"]]) && isset($propValues[$properties["home_address_postal_code"]]) && isset($propValues[$properties["home_address_city"]]) && isset($propValues[$properties["home_address_state"]]) && isset($propValues[$properties["home_address_country"]])) {
            buildAddressString("home", $propValues[$properties["home_address_street"]], $propValues[$properties["home_address_postal_code"]], $propValues[$properties["home_address_city"]], $propValues[$properties["home_address_state"]], $propValues[$properties["home_address_country"]], $propValues, $properties);
        }
        if (isset($csv_mapping["business_address_street2"])) {
            mergeStreet("business", $line[$csv_mapping["business_address_street2"]], $propValues, $properties);
        }
        if (isset($csv_mapping["business_address_street3"])) {
            mergeStreet("business", $line[$csv_mapping["business_address_street3"]], $propValues, $properties);
        }
        if (!isset($propValues[$properties["business_address"]]) && isset($propValues[$properties["business_address_street"]]) && isset($propValues[$properties["business_address_postal_code"]]) && isset($propValues[$properties["business_address_city"]]) && isset($propValues[$properties["business_address_state"]]) && isset($propValues[$properties["business_address_country"]])) {
            buildAddressString("business", $propValues[$properties["business_address_street"]], $propValues[$properties["business_address_postal_code"]], $propValues[$properties["business_address_city"]], $propValues[$properties["business_address_state"]], $propValues[$properties["business_address_country"]], $propValues, $properties);
        }
        if (isset($csv_mapping["other_address_street2"])) {
            mergeStreet("other", $line[$csv_mapping["other_address_street2"]], $propValues, $properties);
        }
        if (isset($csv_mapping["other_address_street3"])) {
            mergeStreet("other", $line[$csv_mapping["other_address_street3"]], $propValues, $properties);
        }
        if (!isset($propValues[$properties["other_address"]]) && isset($propValues[$properties["other_address_street"]]) && isset($propValues[$properties["other_address_postal_code"]]) && isset($propValues[$properties["other_address_city"]]) && isset($propValues[$properties["other_address_state"]]) && isset($propValues[$properties["other_address_country"]])) {
            buildAddressString("other", $propValues[$properties["other_address_street"]], $propValues[$properties["other_address_postal_code"]], $propValues[$properties["other_address_city"]], $propValues[$properties["other_address_state"]], $propValues[$properties["other_address_country"]], $propValues, $properties);
        }
        if (isset($propValues[$properties["home_address"]])) {
            $propValues[$properties["mailing_address"]] = 1;
            setMailingAdress($propValues[$properties["home_address_street"]], $propValues[$properties["home_address_postal_code"]], $propValues[$properties["home_address_city"]], $propValues[$properties["home_address_state"]], $propValues[$properties["home_address_country"]], $propValues[$properties["home_address"]], $propValues, $properties);
        } elseif (isset($propValues[$properties["business_address"]])) {
            $propValues[$properties["mailing_address"]] = 2;
            setMailingAdress($propValues[$properties["business_address_street"]], $propValues[$properties["business_address_postal_code"]], $propValues[$properties["business_address_city"]], $propValues[$properties["business_address_state"]], $propValues[$properties["business_address_country"]], $propValues[$properties["business_address"]], $propValues, $properties);
        } elseif (isset($propValues[$properties["other_address"]])) {
            $propValues[$properties["mailing_address"]] = 3;
            setMailingAdress($propValues[$properties["other_address_street"]], $propValues[$properties["other_address_postal_code"]], $propValues[$properties["other_address_city"]], $propValues[$properties["other_address_state"]], $propValues[$properties["other_address_country"]], $propValues[$properties["other_address"]], $propValues, $properties);
        }
        if (isset($categories) && !empty($categories)) {
            setProperty("categories", $categories, $propValues, $properties);
        }
        // if the display name is set, then it is a valid contact: save it to the folder
        if (isset($propValues[$properties["display_name"]])) {
            $propValues[$properties["message_class"]] = "IPM.Contact";
            $propValues[$properties["icon_index"]] = "512";
            $message = mapi_folder_createmessage($folder);
            mapi_setprops($message, $propValues);
            mapi_savechanges($message);
            printf("New contact added: \"%s\".\n", $propValues[$properties["display_name"]]);
        }
        $i++;
    }
}
 /**
  * Creates a new card
  * 
  * @param mixed $addressBookId 
  * @param string $cardUri 
  * @param string $cardData 
  * @return bool 
  */
 public function createCard($addressBookId, $cardUri, $cardData)
 {
     $this->logger->info("createCard - {$cardUri}\n{$cardData}");
     if (READ_ONLY) {
         $this->logger->warn("createCard failed: read-only");
         return false;
     }
     $folder = mapi_msgstore_openentry($this->bridge->getStore($addressBookId), $addressBookId);
     $contact = mapi_folder_createmessage($folder);
     if (mapi_last_hresult() != 0) {
         $this->logger->fatal("MAPI error - cannot create contact: " . get_mapi_error_name());
         return false;
     }
     $this->logger->trace("Getting properties from vcard");
     $mapiProperties = $this->bridge->vcardToMapiProperties($cardData);
     $mapiProperties[PR_CARDDAV_URI] = $cardUri;
     if (SAVE_RAW_VCARD) {
         // Save RAW vCard
         $this->logger->debug("Saving raw vcard");
         $mapiProperties[PR_CARDDAV_RAW_DATA] = $cardData;
         $mapiProperties[PR_CARDDAV_RAW_DATA_GENERATION_TIME] = time();
     }
     // Handle contact picture
     $contactPicture = NULL;
     if (isset($mapiProperties['ContactPicture'])) {
         $this->logger->debug("Contact picture detected");
         $contactPicture = $mapiProperties['ContactPicture'];
         unset($mapiProperties['ContactPicture']);
         $this->bridge->setContactPicture($contact, $contactPicture);
     }
     // Do not set empty properties
     $this->logger->trace("Removing empty properties");
     foreach ($mapiProperties as $p => $v) {
         if (empty($v)) {
             unset($mapiProperties[$p]);
         }
     }
     // Add missing properties for new contacts
     $this->logger->trace("Adding missing properties for new contacts");
     $p = $this->bridge->getExtendedProperties();
     $mapiProperties[$p["icon_index"]] = "512";
     $mapiProperties[$p["message_class"]] = 'IPM.Contact';
     $mapiProperties[PR_LAST_MODIFICATION_TIME] = time();
     // message flags ?
     mapi_setprops($contact, $mapiProperties);
     mapi_savechanges($contact);
     return mapi_last_hresult() == 0;
 }
 /**
  * Function will create a new outgoing message that will be used to send meeting mail.
  * @param MAPIStore $store (optional) store that is used when creating response, if delegate is creating outgoing mail
  * then this would point to delegate store.
  * @return MAPIMessage outgoing mail that is created and can be used for sending it.
  */
 function createOutgoingMessage($store = false)
 {
     // get logged in user's store that will be used to send mail, for delegate this will be
     // delegate store
     $userStore = $this->openDefaultStore();
     $sentprops = array();
     $outbox = $this->openDefaultOutbox($userStore);
     $outgoing = mapi_folder_createmessage($outbox);
     // check if $store is set and it is not equal to $defaultStore (means its the delegation case)
     if ($store !== false) {
         $storeProps = mapi_getprops($store, array(PR_ENTRYID));
         $userStoreProps = mapi_getprops($userStore, array(PR_ENTRYID));
         // @FIXME use entryid comparison functions here
         if ($storeProps[PR_ENTRYID] !== $userStoreProps[PR_ENTRYID]) {
             // get the delegator properties and set it into outgoing mail
             $delegatorDetails = $this->getOwnerAddress($store, false);
             if ($delegatorDetails) {
                 list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $delegatorDetails;
                 $sentprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
                 $sentprops[PR_SENT_REPRESENTING_NAME] = $ownername;
                 $sentprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
                 $sentprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
                 $sentprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
             }
             // get the delegate properties and set it into outgoing mail
             $delegateDetails = $this->getOwnerAddress($userStore, false);
             if ($delegateDetails) {
                 list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $delegateDetails;
                 $sentprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
                 $sentprops[PR_SENDER_NAME] = $ownername;
                 $sentprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
                 $sentprops[PR_SENDER_ENTRYID] = $ownerentryid;
                 $sentprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
             }
         }
     } else {
         // normal user is sending mail, so both set of properties will be same
         $userDetails = $this->getOwnerAddress($userStore);
         if ($userDetails) {
             list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $userDetails;
             $sentprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
             $sentprops[PR_SENT_REPRESENTING_NAME] = $ownername;
             $sentprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
             $sentprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
             $sentprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
             $sentprops[PR_SENDER_EMAIL_ADDRESS] = $owneremailaddr;
             $sentprops[PR_SENDER_NAME] = $ownername;
             $sentprops[PR_SENDER_ADDRTYPE] = $owneraddrtype;
             $sentprops[PR_SENDER_ENTRYID] = $ownerentryid;
             $sentprops[PR_SENDER_SEARCH_KEY] = $ownersearchkey;
         }
     }
     $sentprops[PR_SENTMAIL_ENTRYID] = $this->getDefaultSentmailEntryID($userStore);
     mapi_setprops($outgoing, $sentprops);
     return $outgoing;
 }
예제 #15
0
 function SendMail($rfc822, $smartdata = array(), $protocolversion = false)
 {
     if (WBXML_DEBUG === true && $protocolversion <= 14.0) {
         debugLog("SendMail: task " . $smartdata['task'] . " itemid: " . (isset($smartdata['itemid']) ? $smartdata['itemid'] : "") . " parent: " . (isset($smartdata['folderid']) ? $smartdata['folderid'] : "") . "\n" . $rfc822);
     }
     $mimeParams = array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'charset' => 'utf-8');
     $mimeObject = new Mail_mimeDecode($rfc822);
     $message = $mimeObject->decode($mimeParams);
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->_defaultstore, array(PR_IPM_OUTBOX_ENTRYID, PR_IPM_SENTMAIL_ENTRYID));
     if (!isset($storeprops[PR_IPM_OUTBOX_ENTRYID])) {
         debugLog("Outbox not found to create message");
         return false;
     }
     $outbox = mapi_msgstore_openentry($this->_defaultstore, $storeprops[PR_IPM_OUTBOX_ENTRYID]);
     if (!$outbox) {
         debugLog("Unable to open outbox");
         return false;
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     mapi_setprops($mapimessage, array(PR_SUBJECT => u2w($mimeObject->_decodeHeader(isset($message->headers["subject"]) ? $message->headers["subject"] : "")), PR_SENTMAIL_ENTRYID => $storeprops[PR_IPM_SENTMAIL_ENTRYID], PR_MESSAGE_CLASS => 'IPM.Note', PR_MESSAGE_DELIVERY_TIME => time()));
     if (isset($message->headers["x-priority"])) {
         switch ($message->headers["x-priority"]) {
             case 1:
             case 2:
                 $priority = PRIO_URGENT;
                 $importance = IMPORTANCE_HIGH;
                 break;
             case 4:
             case 5:
                 $priority = PRIO_NONURGENT;
                 $importance = IMPORTANCE_LOW;
                 break;
             case 3:
             default:
                 $priority = PRIO_NORMAL;
                 $importance = IMPORTANCE_NORMAL;
                 break;
         }
         mapi_setprops($mapimessage, array(PR_IMPORTANCE => $importance, PR_PRIORITY => $priority));
     }
     $addresses = array();
     $toaddr = $ccaddr = $bccaddr = array();
     $Mail_RFC822 = new Mail_RFC822();
     if (isset($message->headers["to"])) {
         $toaddr = $Mail_RFC822->parseAddressList($message->headers["to"]);
     }
     if (isset($message->headers["cc"])) {
         $ccaddr = $Mail_RFC822->parseAddressList($message->headers["cc"]);
     }
     if (isset($message->headers["bcc"])) {
         $bccaddr = $Mail_RFC822->parseAddressList($message->headers["bcc"]);
     }
     if (count($toaddr) == 0 && count($ccaddr) == 0 && count($bccaddr) == 0) {
         debugLog("Sendmail: Message has got no recipients (no to, no cc and no bcc!)");
         return 119;
     }
     // Add recipients
     $recips = array();
     if (isset($toaddr)) {
         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] = u2w($mimeObject->_decodeHeader($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);
     // Loop through message subparts.
     $body = "";
     $body_html = "";
     if ($message->ctype_primary == "multipart" && ($message->ctype_secondary == "signed" || $message->ctype_secondary == "mixed" || $message->ctype_secondary == "alternative")) {
         $mparts = $message->parts;
         for ($i = 0; $i < count($mparts); $i++) {
             $part = $mparts[$i];
             // palm pre & iPhone send forwarded messages in another subpart which are also parsed
             if ($part->ctype_primary == "multipart" && ($part->ctype_secondary == "mixed" || $part->ctype_secondary == "alternative" || $part->ctype_secondary == "related")) {
                 foreach ($part->parts as $spart) {
                     $mparts[] = $spart;
                 }
                 continue;
             }
             // standard body
             if ($part->ctype_primary == "text" && $part->ctype_secondary == "plain" && isset($part->body) && (!isset($part->disposition) || $part->disposition != "attachment")) {
                 $body .= u2w($part->body);
                 // assume only one text body
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "html") {
                 $body_html .= u2w($part->body);
             } elseif ($part->ctype_primary == "ms-tnef" || $part->ctype_secondary == "ms-tnef") {
                 $zptnef = new ZPush_tnef($this->_defaultstore);
                 $mapiprops = array();
                 $zptnef->extractProps($part->body, $mapiprops);
                 if (is_array($mapiprops) && !empty($mapiprops)) {
                     //check if it is a recurring item
                     $tnefrecurr = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x5");
                     if (isset($mapiprops[$tnefrecurr])) {
                         $this->_handleRecurringItem($mapimessage, $mapiprops);
                     }
                     debugLog(print_r($mapiprops, true));
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     debugLog("TNEF: Mapi props array was empty");
                 }
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "calendar") {
                 $zpical = new ZPush_ical($this->_defaultstore);
                 $mapiprops = array();
                 $zpical->extractProps($part->body, $mapiprops);
                 // iPhone sends a second ICS which we ignore if we can
                 if (!isset($mapiprops[PR_MESSAGE_CLASS]) && strlen(trim($body)) == 0) {
                     debugLog("Secondary iPhone response is being ignored!! Mail dropped!");
                     return true;
                 }
                 if (!checkMapiExtVersion("6.30") && is_array($mapiprops) && !empty($mapiprops)) {
                     mapi_setprops($mapimessage, $mapiprops);
                 } else {
                     // store ics as attachment
                     $this->_storeAttachment($mapimessage, $part);
                     debugLog("Sending ICS file as attachment");
                 }
             } elseif ($part->ctype_primary == "text" && $part->ctype_secondary == "x-vCalendar") {
                 $zpical = new ZPush_ical($this->_defaultstore);
                 $mapiprops = array();
                 $zpical->extractProps($part->body, $mapiprops);
                 if (is_array($mapiprops) && !empty($mapiprops)) {
                     // dw2412 Nokia sends incomplete iCal calendar item, so we have to add properties like
                     // message class and icon index
                     if (isset($mapiprops[PR_MESSAGE_CLASS]) && $mapiprops[PR_MESSAGE_CLASS] == "IPM.Note" || !isset($mapiprops[PR_MESSAGE_CLASS])) {
                         $mapiprops[PR_ICON_INDEX] = 0x404;
                         $mapiprops[PR_OWNER_APPT_ID] = 0;
                         $mapiprops[PR_MESSAGE_CLASS] = "IPM.Schedule.Meeting.Request";
                     }
                     // dw2412 Nokia sends no location information field in case user did not type in some
                     // thing in this field...
                     $namedIntentedBusyStatus = GetPropIDFromString($this->_defaultstore, "PT_LONG:{00062002-0000-0000-C000-000000000046}:8224");
                     if (!isset($mapiprops[$namedIntentedBusyStatus])) {
                         $mapiprops[$namedIntentedBusyStatus] = 0;
                     }
                     $namedLocation = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{00062002-0000-0000-C000-000000000046}:0x8208");
                     if (!isset($mapiprops[$namedLocation])) {
                         $mapiprops[$namedLocation] = "";
                     }
                     $tnefLocation = GetPropIDFromString($this->_defaultstore, "PT_STRING8:{6ED8DA90-450B-101B-98DA-00AA003F1305}:0x2");
                     if (!isset($mapiprops[$tnefLocation])) {
                         $mapiprops[$tnefLocation] = "";
                     }
                     $useTNEF = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8582");
                     $mapiprops[$useTNEF] = true;
                 } else {
                     debugLog("ICAL: Mapi props array was empty");
                 }
             } elseif ($part->ctype_primary == 'application' && $part->ctype_secondary == 'x-pkcs7-signature') {
                 $rfc822_p7m = $this->_rfc822tosmimep7m($rfc822);
                 $smimepart = (object) array('ctype_primary' => 'multipart', 'ctype_secondary' => 'signed', 'body' => $rfc822_p7m);
                 debugLog(print_r($smimepart, true));
                 $mapiprops = array();
                 $mapiprops[PR_MESSAGE_CLASS] = "IPM.Note.SMIME.MultipartSigned";
                 $hideattachments = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8514");
                 $mapiprops[$hideattachments] = true;
                 mapi_setprops($mapimessage, $mapiprops);
                 $this->_storeAttachment($mapimessage, $smimepart);
             } else {
                 $this->_storeAttachment($mapimessage, $part);
             }
         }
     } else {
         // start dw2412 handle smime encrypted emails...
         if ($message->ctype_primary == "application" && $message->ctype_secondary == "x-pkcs7-mime") {
             $mapiprops = array();
             $mapiprops[PR_MESSAGE_CLASS] = "IPM.Note.SMIME";
             $hideattachments = GetPropIDFromString($this->_defaultstore, "PT_BOOLEAN:{00062008-0000-0000-C000-000000000046}:0x8514");
             $mapiprops[$hideattachments] = true;
             $mapicontenttype = mapi_prop_tag(PT_STRING8, 0x85e8);
             $mapiprops[$mapicontenttype] = $message->headers['content-type'];
             mapi_setprops($mapimessage, $mapiprops);
             $this->_storeAttachment($mapimessage, $message);
         }
         // end dw2412 handle encrypted emails
         // start dw2412 handle windows mobile html replies...
         // standard body
         if ($message->ctype_primary == "text" && $message->ctype_secondary == "plain" && isset($message->body) && (!isset($message->disposition) || $message->disposition != "attachment")) {
             $body = u2w($message->body);
             // assume only one text body
         } elseif ($message->ctype_primary == "text" && $message->ctype_secondary == "html") {
             $body_html = u2w($message->body);
         }
         // end dw2412 handle windows mobile html replies...
         // $body = u2w($message->body);
     }
     // some devices only transmit a html body
     if (strlen($body) == 0 && strlen($body_html) > 0) {
         debugLog("only html body sent, transformed into plain text");
         $body = strip_tags($body_html);
     }
     // START ADDED dw2412 update/create conversation index
     $conversationindex = false;
     // END ADDED dw2412 update/create conversation index
     if (isset($smartdata['itemid']) && $smartdata['itemid'] || isset($smartdata['longid']) && $smartdata['longid']) {
         // Append the original text body for reply/forward
         if (isset($smartdata['longid'])) {
             $entryid = hex2bin($smartdata['longid']);
         } else {
             $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($smartdata['folderid']), hex2bin($smartdata['itemid']));
         }
         if (($fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid)) === false) {
             debugLog("Sendmail: Provided EntryID cannot be opened. Return error code 150.");
             switch ($smartdata['task']) {
                 case 'forward':
                     return 150;
                 case 'reply':
                     return 150;
             }
         }
         if ($fwmessage) {
             // START CHANGED dw2412 LAST Verb Exec Props included
             //update icon when forwarding or replying message
             if ($smartdata['task'] == 'forward') {
                 mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x68, PR_LAST_VERB_EXECUTION_TIME => time()));
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 262));
             } elseif ($smartdata['task'] == 'reply') {
                 // START ADDED dw2412 update/create conversation index
                 $fwmessageprops = mapi_getprops($fwmessage, array(PR_CONVERSATION_INDEX));
                 if (isset($fwmessageprops[PR_CONVERSATION_INDEX])) {
                     $conversationindex = $fwmessageprops[PR_CONVERSATION_INDEX];
                 }
                 // END ADDED dw2412 update/create conversation index
                 if (sizeof($recips) > 1) {
                     mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x67, PR_LAST_VERB_EXECUTION_TIME => time()));
                 } else {
                     mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x66, PR_LAST_VERB_EXECUTION_TIME => time()));
                 }
                 mapi_setprops($fwmessage, array(PR_ICON_INDEX => 261));
             } else {
                 mapi_setprops($fwmessage, array(PR_LAST_VERB_EXECUTED => 0x0, PR_LAST_VERB_EXECUTION_TIME => time()));
             }
             // END CHANGED dw2412 LAST Verb Exec Props included
             mapi_savechanges($fwmessage);
             $stream = mapi_openproperty($fwmessage, PR_BODY, IID_IStream, 0, 0);
             $fwbody = "";
             while (1) {
                 $data = mapi_stream_read($stream, 1024);
                 if (strlen($data) == 0) {
                     break;
                 }
                 $fwbody .= $data;
             }
             $stream = mapi_openproperty($fwmessage, PR_HTML, IID_IStream, 0, 0);
             $fwbody_html = "";
             while (1) {
                 $data = mapi_stream_read($stream, 1024);
                 if (strlen($data) == 0) {
                     break;
                 }
                 $fwbody_html .= $data;
             }
             $stream = mapi_openproperty($fwmessage, PR_HTML, IID_IStream, 0, 0);
             $fwbody_html = "";
             while (1) {
                 $data = mapi_stream_read($stream, 1024);
                 if (strlen($data) == 0) {
                     break;
                 }
                 $fwbody_html .= $data;
             }
             // dw2412 Enable this only in case of AS2.5 Protocol... in AS12 this seem
             // being done already by winmobile client.
             if ($smartdata['task'] == 'forward' && $protocolversion <= 2.5) {
                 // During a forward, we have to add the forward header ourselves. This is because
                 // normally the forwarded message is added as an attachment. However, we don't want this
                 // because it would be rather complicated to copy over the entire original message due
                 // to the lack of IMessage::CopyTo ..
                 $fwmessageprops = mapi_getprops($fwmessage, array(PR_SENT_REPRESENTING_NAME, PR_DISPLAY_TO, PR_DISPLAY_CC, PR_SUBJECT, PR_CLIENT_SUBMIT_TIME));
                 $fwheader = "\r\n\r\n";
                 $fwheader .= "-----Original Message-----\r\n";
                 if (isset($fwmessageprops[PR_SENT_REPRESENTING_NAME])) {
                     $fwheader .= "From: " . $fwmessageprops[PR_SENT_REPRESENTING_NAME] . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_DISPLAY_TO]) && strlen($fwmessageprops[PR_DISPLAY_TO]) > 0) {
                     $fwheader .= "To: " . $fwmessageprops[PR_DISPLAY_TO] . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_DISPLAY_CC]) && strlen($fwmessageprops[PR_DISPLAY_CC]) > 0) {
                     $fwheader .= "Cc: " . $fwmessageprops[PR_DISPLAY_CC] . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_CLIENT_SUBMIT_TIME])) {
                     $fwheader .= "Sent: " . strftime("%x %X", $fwmessageprops[PR_CLIENT_SUBMIT_TIME]) . "\r\n";
                 }
                 if (isset($fwmessageprops[PR_SUBJECT])) {
                     $fwheader .= "Subject: " . $fwmessageprops[PR_SUBJECT] . "\r\n";
                 }
                 $fwheader .= "\r\n";
                 // add fwheader to body and body_html
                 $body .= $fwheader;
                 if (strlen($body_html) > 0) {
                     $body_html .= str_ireplace("\r\n", "<br>", $fwheader);
                 }
             }
             if (strlen($body) > 0) {
                 $body .= $fwbody;
             }
             if (strlen($body_html) > 0) {
                 $body_html .= $fwbody_html;
             }
         } else {
             debugLog("Unable to open item with id {$orig} for forward/reply");
         }
     }
     if ($smartdata['task'] == 'forward') {
         // Add attachments from the original message in a forward
         if (isset($smartdata['longid'])) {
             $entryid = hex2bin($smartdata['longid']);
         } else {
             $entryid = mapi_msgstore_entryidfromsourcekey($this->_defaultstore, hex2bin($smartdata['folderid']), hex2bin($smartdata['itemid']));
         }
         $fwmessage = mapi_msgstore_openentry($this->_defaultstore, $entryid);
         $attachtable = mapi_message_getattachmenttable($fwmessage);
         $rows = mapi_table_queryallrows($attachtable, array(PR_ATTACH_NUM));
         foreach ($rows as $row) {
             if (isset($row[PR_ATTACH_NUM])) {
                 $attach = mapi_message_openattach($fwmessage, $row[PR_ATTACH_NUM]);
                 $newattach = mapi_message_createattach($mapimessage);
                 // Copy all attachments from old to new attachment
                 $attachprops = mapi_getprops($attach);
                 mapi_setprops($newattach, $attachprops);
                 if (isset($attachprops[mapi_prop_tag(PT_ERROR, mapi_prop_id(PR_ATTACH_DATA_BIN))])) {
                     // Data is in a stream
                     $srcstream = mapi_openpropertytostream($attach, PR_ATTACH_DATA_BIN);
                     $dststream = mapi_openpropertytostream($newattach, PR_ATTACH_DATA_BIN, MAPI_MODIFY | MAPI_CREATE);
                     while (1) {
                         $data = mapi_stream_read($srcstream, 4096);
                         if (strlen($data) == 0) {
                             break;
                         }
                         mapi_stream_write($dststream, $data);
                     }
                     mapi_stream_commit($dststream);
                 }
                 mapi_savechanges($newattach);
             }
         }
     }
     // START ADDED dw2412 update/create conversation index
     if (CONVERSATIONINDEX == true) {
         $ci = new ConversationIndex();
         if ($conversationindex) {
             $ci->Decode($conversationindex);
             $ci->Update();
         } else {
             $ci->Create();
         }
         mapi_setprops($mapimessage, array(PR_CONVERSATION_INDEX => $ci->Encode()));
     }
     // END ADDED dw2412 update/create conversation index
     //set PR_INTERNET_CPID to 65001 (utf-8) if store supports it and to 1252 otherwise
     $internetcpid = 1252;
     if (defined('STORE_SUPPORTS_UNICODE') && STORE_SUPPORTS_UNICODE == true) {
         $internetcpid = 65001;
     }
     mapi_setprops($mapimessage, array(PR_BODY => $body, PR_INTERNET_CPID => $internetcpid));
     if (strlen($body_html) > 0) {
         mapi_setprops($mapimessage, array(PR_HTML => $body_html));
     }
     if (mapi_savechanges($mapimessage) === false || mapi_message_submitmessage($mapimessage) === false) {
         switch ($smartdata['task']) {
             case 'reply':
                 debugLog("Sendmail: Message reply failed, sending failed at all");
                 return 121;
             default:
                 debugLog("Sendmail: Message failed to be saved/submitted, sending failed at all");
                 return 120;
         }
     }
     return true;
 }
 function createOutgoingMessage()
 {
     $sentprops = array();
     $outbox = $this->openDefaultOutbox($this->openDefaultStore());
     $outgoing = mapi_folder_createmessage($outbox);
     if (!$outgoing) {
         return false;
     }
     $addrinfo = $this->getOwnerAddress($this->store);
     if ($addrinfo) {
         list($ownername, $owneremailaddr, $owneraddrtype, $ownerentryid, $ownersearchkey) = $addrinfo;
         $sentprops[PR_SENT_REPRESENTING_EMAIL_ADDRESS] = $owneremailaddr;
         $sentprops[PR_SENT_REPRESENTING_NAME] = $ownername;
         $sentprops[PR_SENT_REPRESENTING_ADDRTYPE] = $owneraddrtype;
         $sentprops[PR_SENT_REPRESENTING_ENTRYID] = $ownerentryid;
         $sentprops[PR_SENT_REPRESENTING_SEARCH_KEY] = $ownersearchkey;
     }
     $sentprops[PR_SENTMAIL_ENTRYID] = $this->getDefaultSentmailEntryID($this->openDefaultStore());
     mapi_setprops($outgoing, $sentprops);
     return $outgoing;
 }
예제 #17
0
 /**
  * Sends an e-mail
  * This messages needs to be saved into the 'sent items' folder
  *
  * @param SyncSendMail  $sm     SyncSendMail object
  *
  * @access public
  * @return boolean
  * @throws StatusException
  */
 public function SendMail($sm)
 {
     // Check if imtomapi function is available and use it to send the mime message.
     // It is available since ZCP 7.0.6
     // @see http://jira.zarafa.com/browse/ZCP-9508
     if (!(function_exists('mapi_feature') && mapi_feature('INETMAPI_IMTOMAPI'))) {
         throw new StatusException("KopanoBackend->SendMail(): ZCP/KC version is too old, INETMAPI_IMTOMAPI is not available. Install at least ZCP version 7.0.6 or later.", SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED, null, LOGLEVEL_FATAL);
         return false;
     }
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->SendMail(): RFC822: %d bytes  forward-id: '%s' reply-id: '%s' parent-id: '%s' SaveInSent: '%s' ReplaceMIME: '%s'", strlen($sm->mime), Utils::PrintAsString($sm->forwardflag), Utils::PrintAsString($sm->replyflag), Utils::PrintAsString(isset($sm->source->folderid) ? $sm->source->folderid : false), Utils::PrintAsString($sm->saveinsent), Utils::PrintAsString(isset($sm->replacemime))));
     // Send-As functionality - https://jira.z-hub.io/browse/ZP-908
     $sendingAsSomeone = false;
     if (defined('KOE_CAPABILITY_SENDAS') && KOE_CAPABILITY_SENDAS) {
         $senderEmail = array();
         // KOE: grep for the Sender header indicating we should send-as
         // the 'X-Push-Sender-Name' header is not used
         if (preg_match("/^X-Push-Sender:\\s(.*?)\$/im", $sm->mime, $senderEmail)) {
             $sendAsEmail = trim($senderEmail[1]);
             ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->SendMail(): Send-As '%s' requested by KOE", $sendAsEmail));
             $sm->mime = preg_replace("/^From: .*?\$/im", "From: " . $sendAsEmail, $sm->mime, 1);
             $sendingAsSomeone = true;
         } elseif (isset($sm->source->folderid)) {
             // get the owner of this folder - System is not allowed
             $sharedUser = ZPush::GetAdditionalSyncFolderStore($sm->source->folderid);
             if ($sharedUser != false && $sharedUser != 'SYSTEM') {
                 $folders = ZPush::GetAdditionalSyncFolders();
                 if (isset($folders[$sm->source->folderid]) && $folders[$sm->source->folderid]->Flags & DeviceManager::FLD_FLAGS_REPLYASUSER) {
                     $sendAs = $this->resolveRecipientGAL($sharedUser, 1);
                     if (isset($sendAs[0])) {
                         ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->SendMail(): Server side Send-As activated for shared folder. Sending as '%s'.", $sendAs[0]->emailaddress));
                         $sm->mime = preg_replace("/^From: .*?\$/im", "From: " . $sendAs[0]->emailaddress, $sm->mime, 1);
                         $sendingAsSomeone = true;
                     }
                 }
             }
         }
     }
     // by splitting the message in several lines we can easily grep later
     foreach (preg_split("/((\r)?\n)/", $sm->mime) as $rfc822line) {
         ZLog::Write(LOGLEVEL_WBXML, "RFC822: " . $rfc822line);
     }
     $sendMailProps = MAPIMapping::GetSendMailProperties();
     $sendMailProps = getPropIdsFromStrings($this->defaultstore, $sendMailProps);
     // Open the outbox and create the message there
     $storeprops = mapi_getprops($this->defaultstore, array($sendMailProps["outboxentryid"], $sendMailProps["ipmsentmailentryid"]));
     if (isset($storeprops[$sendMailProps["outboxentryid"]])) {
         $outbox = mapi_msgstore_openentry($this->defaultstore, $storeprops[$sendMailProps["outboxentryid"]]);
     }
     if (!$outbox) {
         throw new StatusException(sprintf("KopanoBackend->SendMail(): No Outbox found or unable to create message: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_SERVERERROR);
     }
     $mapimessage = mapi_folder_createmessage($outbox);
     //message properties to be set
     $mapiprops = array();
     // only save the outgoing in sent items folder if the mobile requests it
     $mapiprops[$sendMailProps["sentmailentryid"]] = $storeprops[$sendMailProps["ipmsentmailentryid"]];
     ZLog::Write(LOGLEVEL_DEBUG, "Use the mapi_inetmapi_imtomapi function");
     $ab = mapi_openaddressbook($this->session);
     mapi_inetmapi_imtomapi($this->session, $this->defaultstore, $ab, $mapimessage, $sm->mime, array());
     // Set the appSeqNr so that tracking tab can be updated for meeting request updates
     // @see http://jira.zarafa.com/browse/ZP-68
     $meetingRequestProps = MAPIMapping::GetMeetingRequestProperties();
     $meetingRequestProps = getPropIdsFromStrings($this->defaultstore, $meetingRequestProps);
     $props = mapi_getprops($mapimessage, array(PR_MESSAGE_CLASS, $meetingRequestProps["goidtag"], $sendMailProps["internetcpid"], $sendMailProps["body"], $sendMailProps["html"], $sendMailProps["rtf"], $sendMailProps["rtfinsync"]));
     // Convert sent message's body to UTF-8 if it was a HTML message.
     // @see http://jira.zarafa.com/browse/ZP-505 and http://jira.zarafa.com/browse/ZP-555
     if (isset($props[$sendMailProps["internetcpid"]]) && $props[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8 && MAPIUtils::GetNativeBodyType($props) == SYNC_BODYPREFERENCE_HTML) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("Sent email cpid is not unicode (%d). Set it to unicode and convert email html body.", $props[$sendMailProps["internetcpid"]]));
         $mapiprops[$sendMailProps["internetcpid"]] = INTERNET_CPID_UTF8;
         $bodyHtml = MAPIUtils::readPropStream($mapimessage, PR_HTML);
         $bodyHtml = Utils::ConvertCodepageStringToUtf8($props[$sendMailProps["internetcpid"]], $bodyHtml);
         $mapiprops[$sendMailProps["html"]] = $bodyHtml;
         mapi_setprops($mapimessage, $mapiprops);
     }
     if (stripos($props[PR_MESSAGE_CLASS], "IPM.Schedule.Meeting.Resp.") === 0) {
         // search for calendar items using goid
         $mr = new Meetingrequest($this->defaultstore, $mapimessage);
         $appointments = $mr->findCalendarItems($props[$meetingRequestProps["goidtag"]]);
         if (is_array($appointments) && !empty($appointments)) {
             $app = mapi_msgstore_openentry($this->defaultstore, $appointments[0]);
             $appprops = mapi_getprops($app, array($meetingRequestProps["appSeqNr"]));
             if (isset($appprops[$meetingRequestProps["appSeqNr"]]) && $appprops[$meetingRequestProps["appSeqNr"]]) {
                 $mapiprops[$meetingRequestProps["appSeqNr"]] = $appprops[$meetingRequestProps["appSeqNr"]];
                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("Set sequence number to:%d", $appprops[$meetingRequestProps["appSeqNr"]]));
             }
         }
     }
     // Delete the PR_SENT_REPRESENTING_* properties because some android devices
     // do not send neither From nor Sender header causing empty PR_SENT_REPRESENTING_NAME and
     // PR_SENT_REPRESENTING_EMAIL_ADDRESS properties and "broken" PR_SENT_REPRESENTING_ENTRYID
     // which results in spooler not being able to send the message.
     // @see http://jira.zarafa.com/browse/ZP-85
     // If using KOE send-as feature, we keep this properties because they actually are the send-as
     if (!$sendingAsSomeone) {
         mapi_deleteprops($mapimessage, array($sendMailProps["sentrepresentingname"], $sendMailProps["sentrepresentingemail"], $sendMailProps["representingentryid"], $sendMailProps["sentrepresentingaddt"], $sendMailProps["sentrepresentinsrchk"]));
     }
     if (isset($sm->source->itemid) && $sm->source->itemid) {
         // answering an email in a public/shared folder
         // TODO as the store is setup, we should actually user $this->store instead of $this->defaultstore - nevertheless we need to make sure this store is able to send mail (has an outbox)
         if (!$this->Setup(ZPush::GetAdditionalSyncFolderStore($sm->source->folderid))) {
             throw new StatusException(sprintf("KopanoBackend->SendMail() could not Setup() the backend for folder id '%s'", $sm->source->folderid), SYNC_COMMONSTATUS_SERVERERROR);
         }
         $entryid = mapi_msgstore_entryidfromsourcekey($this->store, hex2bin($sm->source->folderid), hex2bin($sm->source->itemid));
         if ($entryid) {
             $fwmessage = mapi_msgstore_openentry($this->store, $entryid);
         }
         if (isset($fwmessage) && $fwmessage) {
             // update icon and last_verb when forwarding or replying message
             // reply-all (verb 103) is not supported, as we cannot really detect this case
             if ($sm->forwardflag) {
                 $updateProps = array(PR_ICON_INDEX => 262, PR_LAST_VERB_EXECUTED => 104);
             } elseif ($sm->replyflag) {
                 $updateProps = array(PR_ICON_INDEX => 261, PR_LAST_VERB_EXECUTED => 102);
             }
             if (isset($updateProps)) {
                 $updateProps[PR_LAST_VERB_EXECUTION_TIME] = time();
                 mapi_setprops($fwmessage, $updateProps);
                 mapi_savechanges($fwmessage);
             }
             // only attach the original message if the mobile does not send it itself
             if (!isset($sm->replacemime)) {
                 // get message's body in order to append forward or reply text
                 if (!isset($body)) {
                     $body = MAPIUtils::readPropStream($mapimessage, PR_BODY);
                 }
                 if (!isset($bodyHtml)) {
                     $bodyHtml = MAPIUtils::readPropStream($mapimessage, PR_HTML);
                 }
                 $cpid = mapi_getprops($fwmessage, array($sendMailProps["internetcpid"]));
                 if ($sm->forwardflag) {
                     // attach the original attachments to the outgoing message
                     $this->copyAttachments($mapimessage, $fwmessage);
                 }
                 // regarding the conversion @see ZP-470
                 if (strlen($body) > 0) {
                     $fwbody = MAPIUtils::readPropStream($fwmessage, PR_BODY);
                     // if only the old message's cpid is set, convert from old charset to utf-8
                     if (isset($cpid[$sendMailProps["internetcpid"]]) && $cpid[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8) {
                         ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->SendMail(): convert plain forwarded message charset (only fw set) from '%s' to '65001'", $cpid[$sendMailProps["internetcpid"]]));
                         $fwbody = Utils::ConvertCodepageStringToUtf8($cpid[$sendMailProps["internetcpid"]], $fwbody);
                     } else {
                         ZLog::Write(LOGLEVEL_DEBUG, "KopanoBackend->SendMail(): no charset conversion done for plain forwarded message");
                         $fwbody = w2u($fwbody);
                     }
                     $mapiprops[$sendMailProps["body"]] = $body . "\r\n\r\n" . $fwbody;
                 }
                 if (strlen($bodyHtml) > 0) {
                     $fwbodyHtml = MAPIUtils::readPropStream($fwmessage, PR_HTML);
                     // if only new message's cpid is set, convert to UTF-8
                     if (isset($cpid[$sendMailProps["internetcpid"]]) && $cpid[$sendMailProps["internetcpid"]] != INTERNET_CPID_UTF8) {
                         ZLog::Write(LOGLEVEL_DEBUG, sprintf("KopanoBackend->SendMail(): convert html forwarded message charset (only fw set) from '%s' to '65001'", $cpid[$sendMailProps["internetcpid"]]));
                         $fwbodyHtml = Utils::ConvertCodepageStringToUtf8($cpid[$sendMailProps["internetcpid"]], $fwbodyHtml);
                     } else {
                         ZLog::Write(LOGLEVEL_DEBUG, "KopanoBackend->SendMail(): no charset conversion done for html forwarded message");
                         $fwbodyHtml = w2u($fwbodyHtml);
                     }
                     $mapiprops[$sendMailProps["html"]] = $bodyHtml . "<br><br>" . $fwbodyHtml;
                 }
             }
         } else {
             // no fwmessage could be opened and we need it because we do not replace mime
             if (!isset($sm->replacemime) || $sm->replacemime == false) {
                 throw new StatusException(sprintf("KopanoBackend->SendMail(): Could not open message id '%s' in folder id '%s' to be replied/forwarded: 0x%X", $sm->source->itemid, $sm->source->folderid, mapi_last_hresult()), SYNC_COMMONSTATUS_ITEMNOTFOUND);
             }
         }
     }
     mapi_setprops($mapimessage, $mapiprops);
     mapi_message_savechanges($mapimessage);
     mapi_message_submitmessage($mapimessage);
     $hr = mapi_last_hresult();
     if ($hr) {
         throw new StatusException(sprintf("KopanoBackend->SendMail(): Error saving/submitting the message to the Outbox: 0x%X", mapi_last_hresult()), SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED);
     }
     ZLog::Write(LOGLEVEL_DEBUG, "KopanoBackend->SendMail(): email submitted");
     return true;
 }