/**
  * Sets the message body
  *
  * @param MAPIMessage       $mapimessage
  * @param ContentParameters $contentparameters
  * @param SyncObject        $message
  */
 private function setMessageBody($mapimessage, $contentparameters, &$message)
 {
     //get the available body preference types
     $bpTypes = $contentparameters->GetBodyPreference();
     if ($bpTypes !== false) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BodyPreference types: %s", implode(', ', $bpTypes)));
         //do not send mime data if the client requests it
         if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_NEVER && ($key = array_search(SYNC_BODYPREFERENCE_MIME, $bpTypes) !== false)) {
             unset($bpTypes[$key]);
             ZLog::Write(LOGLEVEL_DEBUG, sprintf("Remove mime body preference type because the device required no mime support. BodyPreference types: %s", implode(', ', $bpTypes)));
         }
         //get the best fitting preference type
         $bpReturnType = Utils::GetBodyPreferenceBestMatch($bpTypes);
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("GetBodyPreferenceBestMatch: %d", $bpReturnType));
         $bpo = $contentparameters->BodyPreference($bpReturnType);
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("bpo: truncation size:'%d', allornone:'%d', preview:'%d'", $bpo->GetTruncationSize(), $bpo->GetAllOrNone(), $bpo->GetPreview()));
         $this->setMessageBodyForType($mapimessage, $bpReturnType, $message);
         //only set the truncation size data if device set it in request
         if ($bpo->GetTruncationSize() != false && $bpReturnType != SYNC_BODYPREFERENCE_MIME && $message->asbody->estimatedDataSize > $bpo->GetTruncationSize() && $contentparameters->GetTruncation() != SYNC_TRUNCATION_ALL) {
             $message->asbody->data = Utils::Utf8_truncate($message->asbody->data, $bpo->GetTruncationSize());
             $message->asbody->truncated = 1;
         }
         // set the preview or windows phones won't show the preview of an email
         if (Request::GetProtocolVersion() >= 14.0 && $bpo->GetPreview()) {
             $message->asbody->preview = Utils::Utf8_truncate(MAPIUtils::readPropStream($mapimessage, PR_BODY), $bpo->GetPreview());
         }
     } else {
         // Override 'body' for truncation
         $truncsize = Utils::GetTruncSize($contentparameters->GetTruncation());
         $this->setMessageBodyForType($mapimessage, SYNC_BODYPREFERENCE_PLAIN, $message);
         if ($message->bodysize > $truncsize) {
             $message->body = Utils::Utf8_truncate($message->body, $truncsize);
             $message->bodytruncated = 1;
         }
         if (!isset($message->body) || strlen($message->body) == 0) {
             $message->body = " ";
         }
         if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_ALWAYS) {
             //set the html body for iphone in AS 2.5 version
             $this->imtoinet($mapimessage, $message);
         }
     }
 }
示例#2
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;
 }
示例#3
0
 /**
  * Gets the properties from a MAPI object and sets them in the Sync object according to mapping
  *
  * @param SyncObject        &$message
  * @param mixed             $mapimessage
  * @param array             $mapping
  *
  * @access private
  * @return
  */
 private function getPropsFromMAPI(&$message, $mapimessage, $mapping)
 {
     $messageprops = $this->getProps($mapimessage, $mapping);
     foreach ($mapping as $asprop => $mapiprop) {
         // Get long strings via openproperty
         if (isset($messageprops[mapi_prop_tag(PT_ERROR, mapi_prop_id($mapiprop))])) {
             if ($messageprops[mapi_prop_tag(PT_ERROR, mapi_prop_id($mapiprop))] == MAPI_E_NOT_ENOUGH_MEMORY_32BIT || $messageprops[mapi_prop_tag(PT_ERROR, mapi_prop_id($mapiprop))] == MAPI_E_NOT_ENOUGH_MEMORY_64BIT) {
                 $messageprops[$mapiprop] = MAPIUtils::readPropStream($mapimessage, $mapiprop);
             }
         }
         if (isset($messageprops[$mapiprop])) {
             if (mapi_prop_type($mapiprop) == PT_BOOLEAN) {
                 // Force to actual '0' or '1'
                 if ($messageprops[$mapiprop]) {
                     $message->{$asprop} = 1;
                 } else {
                     $message->{$asprop} = 0;
                 }
             } else {
                 // Special handling for PR_MESSAGE_FLAGS
                 if ($mapiprop == PR_MESSAGE_FLAGS) {
                     $message->{$asprop} = $messageprops[$mapiprop] & 1;
                 } else {
                     if ($mapiprop == PR_RTF_COMPRESSED) {
                         //do not send rtf to the mobile
                         continue;
                     } else {
                         if (is_array($messageprops[$mapiprop])) {
                             $message->{$asprop} = array_map("w2u", $messageprops[$mapiprop]);
                         } else {
                             if (mapi_prop_type($mapiprop) != PT_BINARY && mapi_prop_type($mapiprop) != PT_MV_BINARY) {
                                 $message->{$asprop} = w2u($messageprops[$mapiprop]);
                             } else {
                                 $message->{$asprop} = $messageprops[$mapiprop];
                             }
                         }
                     }
                 }
             }
         }
     }
 }
示例#4
0
 /**
  * Sets the message body.
  *
  * @param MAPIMessage       $mapimessage
  * @param ContentParameters $contentparameters
  * @param SyncObject        $message
  */
 private function setMessageBody($mapimessage, $contentparameters, &$message)
 {
     //get the available body preference types
     $bpTypes = $contentparameters->GetBodyPreference();
     if ($bpTypes !== false) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BodyPreference types: %s", implode(', ', $bpTypes)));
         //do not send mime data if the client requests it
         if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_NEVER && ($key = array_search(SYNC_BODYPREFERENCE_MIME, $bpTypes) !== false)) {
             unset($bpTypes[$key]);
             ZLog::Write(LOGLEVEL_DEBUG, sprintf("Remove mime body preference type because the device required no mime support. BodyPreference types: %s", implode(', ', $bpTypes)));
         }
         //get the best fitting preference type
         $bpReturnType = Utils::GetBodyPreferenceBestMatch($bpTypes);
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("GetBodyPreferenceBestMatch: %d", $bpReturnType));
         $bpo = $contentparameters->BodyPreference($bpReturnType);
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("bpo: truncation size:'%d', allornone:'%d', preview:'%d'", $bpo->GetTruncationSize(), $bpo->GetAllOrNone(), $bpo->GetPreview()));
         $this->setMessageBodyForType($mapimessage, $bpReturnType, $message);
         //only set the truncation size data if device set it in request
         if ($bpo->GetTruncationSize() != false && $bpReturnType != SYNC_BODYPREFERENCE_MIME && $message->asbody->estimatedDataSize > $bpo->GetTruncationSize()) {
             // Truncated plaintext requests are used on iOS for the preview in the email list. All images and links should be removed - see https://jira.z-hub.io/browse/ZP-1025
             if ($bpReturnType == SYNC_BODYPREFERENCE_PLAIN) {
                 ZLog::Write(LOGLEVEL_DEBUG, "MAPIProvider->setMessageBody(): truncated plain-text body requested, stripping all links and images");
                 // Get more data because of the filtering it's most probably going down in size. It's going to be truncated to the correct size below.
                 $plainbody = stream_get_contents($message->asbody->data, $bpo->GetTruncationSize() * 3);
                 $message->asbody->data = StringStreamWrapper::Open(preg_replace('/<http(s){0,1}:\\/\\/.*?>/i', '', $plainbody));
             }
             // truncate data stream
             ftruncate($message->asbody->data, $bpo->GetTruncationSize());
             $message->asbody->truncated = 1;
         }
         // set the preview or windows phones won't show the preview of an email
         if (Request::GetProtocolVersion() >= 14.0 && $bpo->GetPreview()) {
             $message->asbody->preview = Utils::Utf8_truncate(MAPIUtils::readPropStream($mapimessage, PR_BODY), $bpo->GetPreview());
         }
     } else {
         // Override 'body' for truncation
         $truncsize = Utils::GetTruncSize($contentparameters->GetTruncation());
         $this->setMessageBodyForType($mapimessage, SYNC_BODYPREFERENCE_PLAIN, $message);
         if ($message->bodysize > $truncsize) {
             $message->body = Utils::Utf8_truncate($message->body, $truncsize);
             $message->bodytruncated = 1;
         }
         if (!isset($message->body) || strlen($message->body) == 0) {
             $message->body = " ";
         }
         if ($contentparameters->GetMimeSupport() == SYNC_MIMESUPPORT_ALWAYS) {
             //set the html body for iphone in AS 2.5 version
             $this->imtoinet($mapimessage, $message);
         }
     }
 }
示例#5
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;
 }
示例#6
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;
 }