/**
 * Add extra parts (not text; inlined or attached parts) to a mimepart object.
 *
 * @param Mail_mimePart $email reference to the object
 * @param array $parts array of parts
 *
 * @access private
 * @return void
 */
function add_extra_sub_parts(&$email, $parts)
{
    if (isset($parts)) {
        foreach ($parts as $part) {
            $new_part = null;
            // Only if it's an attachment we will add the text parts, because all the inline/no disposition have been already added
            if (isset($part->disposition) && $part->disposition == "attachment") {
                // it's an attachment
                $new_part = add_sub_part($email, $part);
            } else {
                if (isset($part->ctype_primary) && $part->ctype_primary != "text" && $part->ctype_primary != "multipart") {
                    // it's not a text part or a multipart
                    $new_part = add_sub_part($email, $part);
                }
            }
            if (isset($part->parts)) {
                // We add sub-parts to the new part (if any), not to the main message. Recursive calling
                if ($new_part === null) {
                    add_extra_sub_parts($email, $part->parts);
                } else {
                    add_extra_sub_parts($new_part, $part->parts);
                }
            }
        }
    }
}
Example #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("BackendIMAP->SendMail(): RFC822: %d bytes  forward-id: '%s' reply-id: '%s' parent-id: '%s' SaveInSent: '%s' ReplaceMIME: '%s'", strlen($sm->mime), Utils::PrintAsString($sm->forwardflag ? isset($sm->source->itemid) ? $sm->source->itemid : "error no itemid" : false), Utils::PrintAsString($sm->replyflag ? isset($sm->source->itemid) ? $sm->source->itemid : "error no itemid" : false), 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);
     }
     $sourceMessage = $sourceMail = false;
     // If we have a reference to a source message and we are not replacing mime (since we wouldn't use it)
     if (isset($sm->source->folderid) && isset($sm->source->itemid) && (!isset($sm->replacemime) || $sm->replacemime === false)) {
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): We have a source message and we try to fetch it"));
         $parent = $this->getImapIdFromFolderId($sm->source->folderid);
         if ($parent === false) {
             throw new StatusException(sprintf("BackendIMAP->SendMail(): Could not get imapid from source folderid '%'", $sm->source->folderid), SYNC_COMMONSTATUS_ITEMNOTFOUND);
         } else {
             $this->imap_reopen_folder($parent);
             $sourceMail = @imap_fetchheader($this->mbox, $sm->source->itemid, FT_UID) . @imap_body($this->mbox, $sm->source->itemid, FT_PEEK | FT_UID);
             $mobj = new Mail_mimeDecode($sourceMail);
             $sourceMessage = $mobj->decode(array('decode_headers' => false, 'decode_bodies' => true, 'include_bodies' => true, 'rfc_822bodies' => true, 'charset' => 'utf-8'));
             unset($mobj);
             //We will need $sourceMail if the message is forwarded and not inlined
             // If it's a reply, we mark the original message as answered
             if ($sm->replyflag) {
                 if (!@imap_setflag_full($this->mbox, $sm->source->itemid, "\\Answered", ST_UID)) {
                     ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->SendMail(): Unable to mark the message as Answered"));
                 }
             }
             // If it's a forward, we mark the original message as forwarded
             if ($sm->forwardflag) {
                 if (!@imap_setflag_full($this->mbox, $sm->source->itemid, "\\Forwarded", ST_UID)) {
                     ZLog::Write(LOGLEVEL_WARN, sprintf("BackendIMAP->SendMail(): Unable to mark the message as Forwarded"));
                 }
             }
         }
     }
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): We get the new message"));
     $mobj = new Mail_mimeDecode($sm->mime);
     $message = $mobj->decode(array('decode_headers' => true, 'decode_bodies' => true, 'include_bodies' => true, 'rfc_822bodies' => true, 'charset' => 'utf-8'));
     unset($mobj);
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): We get the From and To"));
     $Mail_RFC822 = new Mail_RFC822();
     $toaddr = "";
     $this->setFromHeaderValue($message->headers);
     $fromaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["from"]));
     if (isset($message->headers["to"])) {
         $toaddr = $this->parseAddr($Mail_RFC822->parseAddressList($message->headers["to"]));
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): To defined: %s", $toaddr));
     }
     unset($Mail_RFC822);
     // overwrite CC and BCC with the decoded versions, because we will parse/validate the address in the sending method
     if (isset($message->headers["cc"])) {
         $message->headers["cc"] = $message->headers["cc"];
     }
     if (isset($message->headers["bcc"])) {
         $message->headers["bcc"] = $message->headers["bcc"];
     }
     $this->setReturnPathValue($message->headers, $fromaddr);
     $finalBody = "";
     $finalHeaders = array();
     // if it's a S/MIME message I don't do anything with it
     if (is_smime($message)) {
         $mobj = new Mail_mimeDecode($sm->mime);
         $parts = $mobj->getSendArray();
         unset($mobj);
         if ($parts === false) {
             throw new StatusException(sprintf("BackendIMAP->SendMail(): Could not getSendArray for SMIME messages"), SYNC_COMMONSTATUS_MAILSUBMISSIONFAILED);
         } else {
             list($recipients, $finalHeaders, $finalBody) = $parts;
             $this->setFromHeaderValue($finalHeaders);
             $this->setReturnPathValue($finalHeaders, $fromaddr);
         }
     } else {
         //http://pear.php.net/manual/en/package.mail.mail-mime.example.php
         //http://pear.php.net/manual/en/package.mail.mail-mimedecode.decode.php
         //http://pear.php.net/manual/en/package.mail.mail-mimepart.addsubpart.php
         // I don't mind if the new message is multipart or not, I always will create a multipart. It's simpler
         $finalEmail = new Mail_mimePart('', array('content_type' => 'multipart/mixed'));
         if ($sm->replyflag && (!isset($sm->replacemime) || $sm->replacemime === false)) {
             ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): Replying message"));
             $this->addTextParts($finalEmail, $message, $sourceMessage, true);
             if (isset($message->parts)) {
                 // We add extra parts from the replying message
                 add_extra_sub_parts($finalEmail, $message->parts);
             }
             // A replied message doesn't include the original attachments
         } else {
             if ($sm->forwardflag && (!isset($sm->replacemime) || $sm->replacemime === false)) {
                 if (!defined('IMAP_INLINE_FORWARD') || IMAP_INLINE_FORWARD === false) {
                     ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->SendMail(): Forwarding message as attached file - eml");
                     $finalEmail->addSubPart($sourceMail, array('content_type' => 'message/rfc822', 'encoding' => 'base64', 'disposition' => 'attachment', 'dfilename' => 'forwarded_message.eml'));
                 } else {
                     ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->SendMail(): Forwarding inlined message");
                     $this->addTextParts($finalEmail, $message, $sourceMessage, false);
                     if (isset($message->parts)) {
                         // We add extra parts from the forwarding message
                         add_extra_sub_parts($finalEmail, $message->parts);
                     }
                     if (isset($sourceMessage->parts)) {
                         // We add extra parts from the forwarded message
                         add_extra_sub_parts($finalEmail, $sourceMessage->parts);
                     }
                 }
             } else {
                 ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): is a new message or we are replacing mime"));
                 $this->addTextPartsMessage($finalEmail, $message);
                 if (isset($message->parts)) {
                     // We add extra parts from the new message
                     add_extra_sub_parts($finalEmail, $message->parts);
                 }
             }
         }
         // We encode the final message
         $boundary = '=_' . md5(rand() . microtime());
         $finalEmail = $finalEmail->encode($boundary);
         $finalHeaders = array('Mime-Version' => '1.0');
         // We copy all the non-existent headers, minus content_type
         ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): Copying new headers"));
         foreach ($message->headers as $k => $v) {
             if (strcasecmp($k, 'content-type') != 0 && strcasecmp($k, 'content-transfer-encoding') != 0 && strcasecmp($k, 'mime-version') != 0) {
                 if (!isset($finalHeaders[$k])) {
                     $finalHeaders[ucwords($k)] = $v;
                 }
             }
         }
         foreach ($finalEmail['headers'] as $k => $v) {
             if (!isset($finalHeaders[$k])) {
                 $finalHeaders[$k] = $v;
             }
         }
         $finalBody = "This is a multi-part message in MIME format.\n" . $finalEmail['body'];
         unset($finalEmail);
     }
     unset($sourceMail);
     unset($message);
     unset($sourceMessage);
     ZLog::Write(LOGLEVEL_DEBUG, sprintf("BackendIMAP->SendMail(): Final mail to send:"));
     foreach ($finalHeaders as $k => $v) {
         ZLog::Write(LOGLEVEL_WBXML, sprintf("%s: %s", $k, $v));
     }
     foreach (preg_split("/((\r)?\n)/", $finalBody) as $bodyline) {
         ZLog::Write(LOGLEVEL_WBXML, sprintf("Body: %s", $bodyline));
     }
     $send = $this->sendMessage($fromaddr, $toaddr, $finalHeaders, $finalBody);
     if ($send) {
         if (isset($sm->saveinsent)) {
             $this->saveSentMessage($finalHeaders, $finalBody);
         } else {
             ZLog::Write(LOGLEVEL_DEBUG, "BackendIMAP->SendMail(): Not saving in SentFolder");
         }
     }
     unset($finalHeaders);
     unset($finalBody);
     return $send;
 }