setContentTypeParameter() public method

Add/remove a content type parameter to this part.
public setContentTypeParameter ( string $label, string $data )
$label string The content-type parameter label.
$data string The content-type parameter data. If null, removes the parameter (@since 2.8.0).
Example #1
0
 private function load()
 {
     $headers = [];
     $fetch_query = new \Horde_Imap_Client_Fetch_Query();
     $fetch_query->bodyPart($this->attachmentId);
     $fetch_query->mimeHeader($this->attachmentId);
     $headers = array_merge($headers, ['importance', 'list-post', 'x-priority']);
     $headers[] = 'content-type';
     $fetch_query->headers('imp', $headers, ['cache' => true]);
     // $list is an array of Horde_Imap_Client_Data_Fetch objects.
     $ids = new \Horde_Imap_Client_Ids($this->messageId);
     $headers = $this->conn->fetch($this->mailBox, $fetch_query, ['ids' => $ids]);
     /** @var $fetch Horde_Imap_Client_Data_Fetch */
     if (!isset($headers[$this->messageId])) {
         throw new DoesNotExistException('Unable to load the attachment.');
     }
     $fetch = $headers[$this->messageId];
     $mimeHeaders = $fetch->getMimeHeader($this->attachmentId, Horde_Imap_Client_Data_Fetch::HEADER_PARSE);
     $this->mimePart = new \Horde_Mime_Part();
     // To prevent potential problems with the SOP we serve all files with the
     // MIME type "application/octet-stream"
     $this->mimePart->setType('application/octet-stream');
     // Serve all files with a content-disposition of "attachment" to prevent Cross-Site Scripting
     $this->mimePart->setDisposition('attachment');
     // Extract headers from part
     $contentDisposition = $mimeHeaders->getValue('content-disposition', \Horde_Mime_Headers::VALUE_PARAMS);
     if (!is_null($contentDisposition)) {
         $vars = ['filename'];
         foreach ($contentDisposition as $key => $val) {
             if (in_array($key, $vars)) {
                 $this->mimePart->setDispositionParameter($key, $val);
             }
         }
     } else {
         $contentDisposition = $mimeHeaders->getValue('content-type', \Horde_Mime_Headers::VALUE_PARAMS);
         $vars = ['name'];
         foreach ($contentDisposition as $key => $val) {
             if (in_array($key, $vars)) {
                 $this->mimePart->setContentTypeParameter($key, $val);
             }
         }
     }
     /* Content transfer encoding. */
     if ($tmp = $mimeHeaders->getValue('content-transfer-encoding')) {
         $this->mimePart->setTransferEncoding($tmp);
     }
     $body = $fetch->getBodyPart($this->attachmentId);
     $this->mimePart->setContents($body);
 }
Example #2
0
 /**
  * Recursively parse BODYSTRUCTURE data from a FETCH return (see
  * RFC 3501 [7.4.2]).
  *
  * @param Horde_Imap_Client_Tokenize $data  Data returned from the server.
  *
  * @return array  The array of bodystructure information.
  */
 protected function _parseBodystructure(Horde_Imap_Client_Tokenize $data)
 {
     $ob = new Horde_Mime_Part();
     // If index 0 is an array, this is a multipart part.
     if (is_object($entry = $data->rewind())) {
         // Keep going through array values until we find a non-array.
         do {
             $ob->addPart($this->_parseBodystructure($entry));
         } while (is_object($entry = $data->next()));
         // The first string entry after an array entry gives us the
         // subpart type.
         $ob->setType('multipart/' . $entry);
         // After the subtype is further extension information. This
         // information MAY not appear for BODYSTRUCTURE requests.
         // This is parameter information.
         if (is_object($tmp = $data->next())) {
             foreach ($this->_parseStructureParams($tmp, 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
     } else {
         $ob->setType($entry . '/' . $data->next());
         if (is_object($tmp = $data->next())) {
             foreach ($this->_parseStructureParams($tmp, 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setContentId($tmp);
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setDescription(Horde_Mime::decode($tmp));
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setTransferEncoding($tmp);
         }
         $ob->setBytes($data->next());
         // If the type is 'message/rfc822' or 'text/*', several extra
         // fields are included
         switch ($ob->getPrimaryType()) {
             case 'message':
                 if ($ob->getSubType() == 'rfc822') {
                     $data->next();
                     // Ignore: envelope
                     $ob->addPart($this->_parseBodystructure($data->next()));
                     $data->next();
                     // Ignore: lines
                 }
                 break;
             case 'text':
                 $data->next();
                 // Ignore: lines
                 break;
         }
         // After the subtype is further extension information. This
         // information MAY appear for BODYSTRUCTURE requests.
         $data->next();
         // Ignore: MD5
     }
     // This is disposition information
     if (is_object($tmp = $data->next())) {
         $ob->setDisposition($tmp->rewind());
         foreach ($this->_parseStructureParams($tmp->next(), 'content-disposition') as $key => $val) {
             $ob->setDispositionParameter($key, $val);
         }
     }
     // This is language information. It is either a single value or a list
     // of values.
     if (($tmp = $data->next()) !== false) {
         $ob->setLanguage($tmp);
     }
     $data->next();
     // Ignore: location (RFC 2557)
     return $ob;
 }
Example #3
0
 /**
  * Builds the body MIME part of a multipart message.
  *
  * @param Horde_View $view        A view to render the HTML and plain text
  *                                templates for the messate.
  * @param string $template        The template base name for the view.
  * @param Horde_Mime_Part $image  The MIME part of a related image.
  *
  * @return Horde_Mime_Part  A multipart/alternative MIME part.
  */
 public static function buildMimeMessage(Horde_View $view, $template, Horde_Mime_Part $image)
 {
     $multipart = new Horde_Mime_Part();
     $multipart->setType('multipart/alternative');
     $bodyText = new Horde_Mime_Part();
     $bodyText->setType('text/plain');
     $bodyText->setCharset('UTF-8');
     $bodyText->setContents($view->render($template . '.plain.php'));
     $bodyText->setDisposition('inline');
     $multipart->addPart($bodyText);
     $bodyHtml = new Horde_Mime_Part();
     $bodyHtml->setType('text/html');
     $bodyHtml->setCharset('UTF-8');
     $bodyHtml->setContents($view->render($template . '.html.php'));
     $bodyHtml->setDisposition('inline');
     $related = new Horde_Mime_Part();
     $related->setType('multipart/related');
     $related->setContentTypeParameter('start', $bodyHtml->setContentId());
     $related->addPart($bodyHtml);
     $related->addPart($image);
     $multipart->addPart($related);
     return $multipart;
 }
Example #4
0
File: Pgp.php Project: horde/horde
 /**
  * Encrypts a MIME part using PGP.
  *
  * @param Horde_Mime_Part $mime_part  The object to encrypt.
  * @param array $params               The parameters required for
  *                                    encryption
  *                                    ({@see _encryptMessage()}).
  *
  * @return mixed  A Horde_Mime_Part object that is encrypted according to
  *                RFC 3156.
  * @throws Horde_Crypt_Exception
  */
 public function encryptMIMEPart($mime_part, $params = array())
 {
     $params = array_merge($params, array('type' => 'message'));
     $signenc_body = $mime_part->toString(array('canonical' => true, 'headers' => true));
     $message_encrypt = $this->encrypt($signenc_body, $params);
     /* Set up MIME Structure according to RFC 3156. */
     $part = new Horde_Mime_Part();
     $part->setType('multipart/encrypted');
     $part->setHeaderCharset('UTF-8');
     $part->setContentTypeParameter('protocol', 'application/pgp-encrypted');
     $part->setDescription(Horde_Crypt_Translation::t("PGP Encrypted Data"));
     $part->setContents("This message is in MIME format and has been PGP encrypted.\n");
     $part1 = new Horde_Mime_Part();
     $part1->setType('application/pgp-encrypted');
     $part1->setCharset(null);
     $part1->setContents("Version: 1\n", array('encoding' => '7bit'));
     $part->addPart($part1);
     $part2 = new Horde_Mime_Part();
     $part2->setType('application/octet-stream');
     $part2->setCharset(null);
     $part2->setContents($message_encrypt, array('encoding' => '7bit'));
     $part2->setDisposition('inline');
     $part->addPart($part2);
     return $part;
 }
Example #5
0
 /**
  * Sends out iTip task notification to the assignee.
  *
  * Can be used to send task invitations, updates, and cancellations.
  *
  * @param Nag_Task $task  The task in question.
  * @param Horde_Notification_Handler $notification
  *        A notification object used to show result status.
  * @param integer $action
  *        The type of notification to send. One of the Nag::ITIP_* values.
  * @param Horde_Date $instance
  *        If cancelling a single instance of a recurring task, the date of
  *        this instance.
  * @param  string $range  The range parameter if this is a recurring event.
  *                        Possible values are self::RANGE_THISANDFUTURE
  */
 public static function sendITipNotifications(Nag_Task $task, Horde_Notification_Handler $notification, $action, Horde_Date $instance = null, $range = null)
 {
     global $injector, $registry, $nag_shares;
     if (!$task->assignee) {
         return;
     }
     $ident = $injector->getInstance('Horde_Core_Factory_Identity')->create($task->creator);
     if (!$ident->getValue('from_addr')) {
         $notification->push(sprintf(_("You do not have an email address configured in your Personal Information Preferences. You must set one %shere%s before event notifications can be sent."), $registry->getServiceLink('prefs', 'kronolith')->add(array('app' => 'horde', 'group' => 'identities'))->link(), '</a>'), 'horde.error', array('content.raw'));
         return;
     }
     // Generate image mime part first and only once, because we
     // need the Content-ID.
     $image = self::getImagePart('big_invitation.png');
     $share = $nag_shares->getShare($task->tasklist);
     $view = new Horde_View(array('templatePath' => NAG_TEMPLATES . '/itip'));
     new Horde_View_Helper_Text($view);
     $view->identity = $ident;
     $view->task = $task;
     $view->imageId = $image->getContentId();
     $email = Nag::getUserEmail($task->assignee);
     if (strpos($email, '@') === false) {
         continue;
     }
     /* Determine all notification-specific strings. */
     $method = 'REQUEST';
     switch ($action) {
         case self::ITIP_CANCEL:
             /* Cancellation. */
             $method = 'CANCEL';
             $filename = 'task-cancellation.ics';
             $view->subject = sprintf(_("Cancelled: %s"), $task->name);
             if (empty($instance)) {
                 $view->header = sprintf(_("%s has cancelled \"%s\"."), $ident->getName(), $task->name);
             } else {
                 $view->header = sprintf(_("%s has cancelled an instance of the recurring \"%s\"."), $ident->getName(), $task->name);
             }
             break;
         case self::ITIP_UPDATE:
             if (!empty($task->organizer) && $task->organizer != Nag::getUserEmail($task->creator)) {
                 // Sending a progress update.
                 $method = 'REPLY';
             } else {
                 $method = 'UPDATE';
             }
         case self::ITIP_REQUEST:
         default:
             if (empty($task->status) || $task->status == self::RESPONSE_NONE) {
                 /* Invitation. */
                 $filename = 'task-invitation.ics';
                 $view->subject = $task->name;
                 $view->header = sprintf(_("%s wishes to make you aware of \"%s\"."), $ident->getName(), $task->name);
             } else {
                 $filename = 'task-update.ics';
                 $view->subject = sprintf(_("Updated: %s."), $task->name);
                 $view->header = sprintf(_("%s wants to notify you about changes of \"%s\"."), $ident->getName(), $task->name);
             }
             break;
     }
     $view->attendees = $email;
     $view->organizer = empty($task->organizer) ? $registry->convertUserName($task->creator, false) : $task->organizer;
     /* Build the iCalendar data */
     $iCal = new Horde_Icalendar();
     $iCal->setAttribute('METHOD', $method);
     $vevent = $task->toiCalendar($iCal);
     $iCal->addComponent($vevent);
     /* text/calendar part */
     $ics = new Horde_Mime_Part();
     $ics->setType('text/calendar');
     $ics->setContents($iCal->exportvCalendar());
     $ics->setName($filename);
     $ics->setContentTypeParameter('METHOD', $method);
     $ics->setCharset('UTF-8');
     $ics->setEOL("\r\n");
     /* application/ics part */
     $ics2 = clone $ics;
     $ics2->setType('application/ics');
     /* multipart/mixed part */
     $multipart = new Horde_Mime_Part();
     $multipart->setType('multipart/mixed');
     $inner = self::buildMimeMessage($view, 'notification', $image);
     $inner->addPart($ics);
     $multipart->addPart($inner);
     $multipart->addPart($ics2);
     $recipient = $method != 'REPLY' ? new Horde_Mail_Rfc822_Address($email) : new Horde_Mail_Rfc822_Address($task->organizer);
     $mail = new Horde_Mime_Mail(array('Subject' => $view->subject, 'To' => $recipient, 'From' => $ident->getDefaultFromAddress(true), 'User-Agent' => 'Nag ' . $registry->getVersion()));
     $mail->setBasePart($multipart);
     try {
         $mail->send($injector->getInstance('Horde_Mail'));
         $notification->push(sprintf(_("The task request notification to %s was successfully sent."), $recipient), 'horde.success');
     } catch (Horde_Mime_Exception $e) {
         $notification->push(sprintf(_("There was an error sending a task request notification to %s: %s"), $recipient, $e->getMessage(), $e->getCode()), 'horde.error');
     }
 }
Example #6
0
 /**
  * Converts an HTML part to a multipart/related part, if necessary.
  *
  * @param Horde_Domhtml $html    HTML data.
  * @param Horde_Mime_Part $part  The HTML part.
  *
  * @return Horde_Mime_Part  The part to add to the compose output.
  */
 protected function _convertToRelated(Horde_Domhtml $html, Horde_Mime_Part $part)
 {
     $r_part = false;
     foreach ($this as $atc) {
         if ($atc->related) {
             $r_part = true;
             break;
         }
     }
     if (!$r_part) {
         return $part;
     }
     /* Create new multipart/related part. */
     $related = new Horde_Mime_Part();
     $related->setType('multipart/related');
     /* Get the CID for the 'root' part. Although by default the first part
      * is the root part (RFC 2387 [3.2]), we may as well be explicit and
      * put the CID in the 'start' parameter. */
     $related->setContentTypeParameter('start', $part->setContentId());
     $related[] = $part;
     /* HTML iteration is from child->parent, so need to gather related
      * parts and add at end after sorting to generate a more sensible
      * attachment list. */
     $add = array();
     foreach ($html as $node) {
         if ($node instanceof DOMElement && $node->hasAttribute(self::RELATED_ATTR)) {
             list($attr_name, $atc_id) = explode(';', $node->getAttribute(self::RELATED_ATTR));
             /* If attachment can't be found, ignore. */
             if ($r_atc = $this[$atc_id]) {
                 if ($r_atc->linked) {
                     $attr = strval($r_atc->link_url);
                 } else {
                     $related_part = $r_atc->getPart(true);
                     $attr = 'cid:' . $related_part->setContentId();
                     $add[] = $related_part;
                 }
                 $node->setAttribute($attr_name, $attr);
             }
             $node->removeAttribute(self::RELATED_ATTR);
         }
     }
     foreach (array_reverse($add) as $val) {
         $related[] = $val;
     }
     return $related;
 }
Example #7
0
 /**
  * Recursively parse BODYSTRUCTURE data from a FETCH return (see
  * RFC 3501 [7.4.2]).
  *
  * @param Horde_Imap_Client_Tokenize $data  Data returned from the server.
  *
  * @return Horde_Mime_Part  Mime part object.
  */
 protected function _parseBodystructure(Horde_Imap_Client_Tokenize $data)
 {
     $ob = new Horde_Mime_Part();
     // If index 0 is an array, this is a multipart part.
     if (($entry = $data->next()) === true) {
         do {
             $ob->addPart($this->_parseBodystructure($data));
         } while (($entry = $data->next()) === true);
         // The subpart type.
         $ob->setType('multipart/' . $entry);
         // After the subtype is further extension information. This
         // information MAY appear for BODYSTRUCTURE requests.
         // This is parameter information.
         if (($tmp = $data->next()) === false) {
             return $ob;
         } elseif ($tmp === true) {
             foreach ($this->_parseStructureParams($data, 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
     } else {
         $ob->setType($entry . '/' . $data->next());
         if ($data->next() === true) {
             foreach ($this->_parseStructureParams($data, 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setContentId($tmp);
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setDescription(Horde_Mime::decode($tmp));
         }
         if (!is_null($tmp = $data->next())) {
             $ob->setTransferEncoding($tmp);
         }
         $ob->setBytes($data->next());
         // If the type is 'message/rfc822' or 'text/*', several extra
         // fields are included
         switch ($ob->getPrimaryType()) {
             case 'message':
                 if ($ob->getSubType() == 'rfc822') {
                     if ($data->next() === true) {
                         // Ignore: envelope
                         $data->flushIterator(false);
                     }
                     if ($data->next() === true) {
                         $ob->addPart($this->_parseBodystructure($data));
                     }
                     $data->next();
                     // Ignore: lines
                 }
                 break;
             case 'text':
                 $data->next();
                 // Ignore: lines
                 break;
         }
         // After the subtype is further extension information. This
         // information MAY appear for BODYSTRUCTURE requests.
         // Ignore: MD5
         if ($data->next() === false) {
             return $ob;
         }
     }
     // This is disposition information
     if (($tmp = $data->next()) === false) {
         return $ob;
     } elseif ($tmp === true) {
         $ob->setDisposition($data->next());
         if ($data->next() === true) {
             foreach ($this->_parseStructureParams($data, 'content-disposition') as $key => $val) {
                 $ob->setDispositionParameter($key, $val);
             }
         }
         $data->next();
     }
     // This is language information. It is either a single value or a list
     // of values.
     if (($tmp = $data->next()) === false) {
         return $ob;
     } elseif (!is_null($tmp)) {
         $ob->setLanguage($tmp === true ? $data->flushIterator() : $tmp);
     }
     // Ignore location (RFC 2557) and consume closing paren.
     $data->flushIterator(false);
     return $ob;
 }
Example #8
0
 /**
  * Generate the MDN according to the specifications listed in RFC
  * 3798 [3].
  *
  * @param boolean $action   Was this MDN type a result of a manual
  *                          action on part of the user?
  * @param boolean $sending  Was this MDN sent as a result of a manual
  *                          action on part of the user?
  * @param string $type      The type of action performed by the user.
  *                          Per RFC 3798 [3.2.6.2] the following types are
  *                          valid:
  *                            - deleted
  *                            - displayed
  * @param string $name      The name of the local server.
  * @param Horde_Mail_Transport $mailer  Mail transport object.
  * @param array $opts       Additional options:
  *   - charset: (string) Default charset.
  *              DEFAULT: NONE
  *   - from_addr: (string) From address.
  *                DEFAULT: NONE
  * @param array $mod        The list of modifications. Per RFC 3798
  *                          [3.2.6.3] the following modifications are
  *                          valid:
  *                            - error
  * @param array $err        If $mod is 'error', the additional
  *                          information to provide. Key is the type of
  *                          modification, value is the text.
  */
 public function generate($action, $sending, $type, $name, $mailer, array $opts = array(), array $mod = array(), array $err = array())
 {
     $opts = array_merge(array('charset' => null, 'from_addr' => null), $opts);
     if (!($hdr = $this->_headers[self::MDN_HEADER])) {
         throw new RuntimeException('Need at least one address to send MDN to.');
     }
     $to = $hdr->getAddressList(true);
     $ua = Horde_Mime_Headers_UserAgent::create();
     if ($orig_recip = $this->_headers['Original-Recipient']) {
         $orig_recip = $orig_recip->value_single;
     }
     /* Set up the mail headers. */
     $msg_headers = new Horde_Mime_Headers();
     $msg_headers->addHeaderOb(Horde_Mime_Headers_MessageId::create());
     $msg_headers->addHeaderOb($ua);
     /* RFC 3834 [5.2] */
     $msg_headers->addHeader('Auto-Submitted', 'auto-replied');
     $msg_headers->addHeaderOb(Horde_Mime_Headers_Date::create());
     if ($opts['from_addr']) {
         $msg_headers->addHeader('From', $opts['from_addr']);
     }
     $msg_headers->addHeader('To', $to);
     $msg_headers->addHeader('Subject', Horde_Mime_Translation::t("Disposition Notification"));
     /* MDNs are a subtype of 'multipart/report'. */
     $msg = new Horde_Mime_Part();
     $msg->setType('multipart/report');
     $msg->setContentTypeParameter('report-type', 'disposition-notification');
     /* The first part is a human readable message. */
     $part_one = new Horde_Mime_Part();
     $part_one->setType('text/plain');
     $part_one->setCharset($opts['charset']);
     if ($type == 'displayed') {
         $contents = sprintf(Horde_Mime_Translation::t("The message sent on %s to %s with subject \"%s\" has been displayed.\n\nThis is no guarantee that the message has been read or understood."), $this->_headers['Date'], $this->_headers['To'], $this->_headers['Subject']);
         $flowed = new Horde_Text_Flowed($contents, $opts['charset']);
         $flowed->setDelSp(true);
         $part_one->setContentTypeParameter('format', 'flowed');
         $part_one->setContentTypeParameter('DelSp', 'Yes');
         $part_one->setContents($flowed->toFlowed());
     }
     // TODO: Messages for other notification types.
     $msg[] = $part_one;
     /* The second part is a machine-parseable description. */
     $part_two = new Horde_Mime_Part();
     $part_two->setType('message/disposition-notification');
     $part_two_h = new Horde_Mime_Headers();
     $part_two_h->addHeader('Reporting-UA', $name . '; ' . $ua);
     if (!empty($orig_recip)) {
         $part_two_h->addHeader('Original-Recipient', 'rfc822;' . $orig_recip);
     }
     if ($opts['from_addr']) {
         $part_two_h->addHeader('Final-Recipient', 'rfc822;' . $opts['from_addr']);
     }
     if ($msg_id = $this->_headers['Message-ID']) {
         $part_two_h->addHeader('Original-Message-ID', strval($msg_id));
     }
     /* Create the Disposition field now (RFC 3798 [3.2.6]). */
     $dispo = ($action ? 'manual-action' : 'automatic-action') . '/' . ($sending ? 'MDN-sent-manually' : 'MDN-sent-automatically') . '; ' . $type;
     if (!empty($mod)) {
         $dispo .= '/' . implode(', ', $mod);
     }
     $part_two_h->addHeader('Disposition', $dispo);
     if (in_array('error', $mod) && isset($err['error'])) {
         $part_two_h->addHeader('Error', $err['error']);
     }
     $part_two->setContents(trim($part_two_h->toString()) . "\n");
     $msg[] = $part_two;
     /* The third part is the text of the original message.  RFC 3798 [3]
      * allows us to return only a portion of the entire message - this
      * is left up to the user. */
     $part_three = new Horde_Mime_Part();
     $part_three->setType('message/rfc822');
     $part_three_text = array(trim($this->_headers->toString()) . "\n");
     if (!empty($this->_msgtext)) {
         $part_three_text[] = "\n" . $this->_msgtext;
     }
     $part_three->setContents($part_three_text);
     $msg[] = $part_three;
     return $msg->send($to, $msg_headers, $mailer);
 }
Example #9
0
 /**
  * Parses an armored message into a Horde_Mime_Part object.
  *
  * @param mixed $text  Either the text to parse or a Horde_Stream object.
  *
  * @return mixed  Either null if no PGP data was found, or a
  *                Horde_Mime_Part object. For detached signature data:
  *                the full contents of the armored text (data + sig) is
  *                contained in the SIG_RAW metadata, and the charset is
  *                contained in the SIG_CHARSET metadata, within the
  *                application/pgp-signature part.
  */
 public function parseToPart($text, $charset = 'UTF-8')
 {
     $parts = $this->parse($text);
     if (empty($parts) || count($parts) == 1 && $parts[0]['type'] == self::ARMOR_TEXT) {
         return null;
     }
     $new_part = new Horde_Mime_Part();
     $new_part->setType('multipart/mixed');
     foreach ($parts as $val) {
         switch ($val['type']) {
             case self::ARMOR_TEXT:
                 $part = new Horde_Mime_Part();
                 $part->setType('text/plain');
                 $part->setCharset($charset);
                 $part->setContents(implode("\n", $val['data']));
                 $new_part->addPart($part);
                 break;
             case self::ARMOR_PUBLIC_KEY:
                 $part = new Horde_Mime_Part();
                 $part->setType('application/pgp-keys');
                 $part->setContents(implode("\n", $val['data']));
                 $new_part->addPart($part);
                 break;
             case self::ARMOR_MESSAGE:
                 $part = new Horde_Mime_Part();
                 $part->setType('multipart/encrypted');
                 $part->setMetadata(self::PGP_ARMOR, true);
                 $part->setContentTypeParameter('protocol', 'application/pgp-encrypted');
                 $part1 = new Horde_Mime_Part();
                 $part1->setType('application/pgp-encrypted');
                 $part1->setContents("Version: 1\n");
                 $part2 = new Horde_Mime_Part();
                 $part2->setType('application/octet-stream');
                 $part2->setContents(implode("\n", $val['data']));
                 $part2->setDisposition('inline');
                 $part->addPart($part1);
                 $part->addPart($part2);
                 $new_part->addPart($part);
                 break;
             case self::ARMOR_SIGNED_MESSAGE:
                 if (($sig = current($parts)) && $sig['type'] == self::ARMOR_SIGNATURE) {
                     $part = new Horde_Mime_Part();
                     $part->setType('multipart/signed');
                     // TODO: add micalg parameter
                     $part->setContentTypeParameter('protocol', 'application/pgp-signature');
                     $part1 = new Horde_Mime_Part();
                     $part1->setType('text/plain');
                     $part1->setCharset($charset);
                     $part1_data = implode("\n", $val['data']);
                     $part1->setContents(substr($part1_data, strpos($part1_data, "\n\n") + 2));
                     $part2 = new Horde_Mime_Part();
                     $part2->setType('application/pgp-signature');
                     $part2->setContents(implode("\n", $sig['data']));
                     $part2->setMetadata(self::SIG_CHARSET, $charset);
                     $part2->setMetadata(self::SIG_RAW, implode("\n", $val['data']) . "\n" . implode("\n", $sig['data']));
                     $part->addPart($part1);
                     $part->addPart($part2);
                     $new_part->addPart($part);
                     next($parts);
                 }
         }
     }
     return $new_part;
 }
Example #10
0
 /**
  * Creates a MIME object from the text of one part of a MIME message.
  *
  * @param string $header  The header text.
  * @param string $body    The body text.
  * @param array $opts     Additional options:
  * <pre>
  *   - ctype: (string) The default content-type.
  *   - forcemime: (boolean) If true, the message data is assumed to be
  *                MIME data. If not, a MIME-Version header must exist to
  *                be parsed as a MIME message.
  *   - level: (integer) Current nesting level.
  *   - no_body: (boolean) If true, don't set body contents of parts.
  * </pre>
  *
  * @return Horde_Mime_Part  The MIME part object.
  */
 protected static function _getStructure($header, $body, array $opts = array())
 {
     $opts = array_merge(array('ctype' => 'text/plain', 'forcemime' => false, 'level' => 0, 'no_body' => false), $opts);
     /* Parse headers text into a Horde_Mime_Headers object. */
     $hdrs = Horde_Mime_Headers::parseHeaders($header);
     $ob = new Horde_Mime_Part();
     /* This is not a MIME message. */
     if (!$opts['forcemime'] && !isset($hdrs['MIME-Version'])) {
         $ob->setType('text/plain');
         if ($len = strlen($body)) {
             if ($opts['no_body']) {
                 $ob->setBytes($len);
             } else {
                 $ob->setContents($body);
             }
         }
         return $ob;
     }
     /* Content type. */
     if ($tmp = $hdrs['Content-Type']) {
         $ob->setType($tmp->value);
         foreach ($tmp->params as $key => $val) {
             $ob->setContentTypeParameter($key, $val);
         }
     } else {
         $ob->setType($opts['ctype']);
     }
     /* Content transfer encoding. */
     if ($tmp = $hdrs['Content-Transfer-Encoding']) {
         $ob->setTransferEncoding(strval($tmp));
     }
     /* Content-Description. */
     if ($tmp = $hdrs['Content-Description']) {
         $ob->setDescription(strval($tmp));
     }
     /* Content-Disposition. */
     if ($tmp = $hdrs['Content-Disposition']) {
         $ob->setDisposition($tmp->value);
         foreach ($tmp->params as $key => $val) {
             $ob->setDispositionParameter($key, $val);
         }
     }
     /* Content-Duration */
     if ($tmp = $hdrs['Content-Duration']) {
         $ob->setDuration(strval($tmp));
     }
     /* Content-ID. */
     if ($tmp = $hdrs['Content-Id']) {
         $ob->setContentId(strval($tmp));
     }
     if (($len = strlen($body)) && $ob->getPrimaryType() != 'multipart') {
         if ($opts['no_body']) {
             $ob->setBytes($len);
         } else {
             $ob->setContents($body);
         }
     }
     if (++$opts['level'] >= self::NESTING_LIMIT) {
         return $ob;
     }
     /* Process subparts. */
     switch ($ob->getPrimaryType()) {
         case 'message':
             if ($ob->getSubType() == 'rfc822') {
                 $ob[] = self::parseMessage($body, array('forcemime' => true, 'no_body' => $opts['no_body']));
             }
             break;
         case 'multipart':
             $boundary = $ob->getContentTypeParameter('boundary');
             if (!is_null($boundary)) {
                 foreach (self::_findBoundary($body, 0, $boundary) as $val) {
                     if (!isset($val['length'])) {
                         break;
                     }
                     $subpart = substr($body, $val['start'], $val['length']);
                     $hdr_pos = self::_findHeader($subpart, self::EOL);
                     $ob[] = self::_getStructure(substr($subpart, 0, $hdr_pos), substr($subpart, $hdr_pos + 2), array('ctype' => $ob->getSubType() == 'digest' ? 'message/rfc822' : 'text/plain', 'forcemime' => true, 'level' => $opts['level'], 'no_body' => $opts['no_body']));
                 }
             }
             break;
     }
     return $ob;
 }
Example #11
0
 public function testNullCharactersNotAllowedInMimeHeaderData()
 {
     $part = new Horde_Mime_Part();
     $part->setType("text/plain");
     $this->assertEquals('text/plain', $part->getType());
     $part->setDisposition("inline");
     $this->assertEquals('inline', $part->getDisposition());
     $part->setDispositionParameter('size', '123' . "" . '456');
     $this->assertEquals(123456, $part->getDispositionParameter('size'));
     $part->setDispositionParameter('foo', "foobar");
     $this->assertEquals('foobar', $part->getDispositionParameter('foo'));
     $part->setCharset("utf-8");
     $this->assertEquals('utf-8', $part->getCharset());
     $part->setName("foobar");
     $this->assertEquals('foobar', $part->getName());
     $this->assertEquals('foobar', $part->getDispositionParameter('filename'));
     $this->assertEquals('foobar', $part->getContentTypeParameter('name'));
     $part->setLanguage("en");
     $this->assertEquals(array('en'), $part->getLanguage());
     $part->setLanguage(array("en", "de"));
     $this->assertEquals(array('en', 'de'), $part->getLanguage());
     $part->setDuration('123' . "" . '456');
     $this->assertEquals(123456, $part->getDuration());
     $part->setBytes('123' . "" . '456');
     $this->assertEquals(123456, $part->getBytes());
     $part->setDescription("foobar");
     $this->assertEquals('foobar', $part->getDescription());
     $part->setContentTypeParameter('foo', "foobar");
     $this->assertEquals('foobar', $part->getContentTypeParameter('foo'));
     $part->setContentId("foobar");
     $this->assertEquals('foobar', $part->getContentId());
 }
Example #12
0
 /**
  * Encrypt a MIME part using S/MIME. This produces S/MIME Version 3.2
  * compatible data (see RFC 5751 [3.3]).
  *
  * @param Horde_Mime_Part $mime_part  The object to encrypt.
  * @param array $params               The parameters required for
  *                                    encryption.
  *
  * @return Horde_Mime_Part  An encrypted MIME part object.
  * @throws Horde_Crypt_Exception
  */
 public function encryptMIMEPart($mime_part, $params = array())
 {
     /* Sign the part as a message */
     $message = $this->encrypt($mime_part->toString(array('headers' => true, 'canonical' => true)), $params);
     $msg = new Horde_Mime_Part();
     $msg->setCharset($this->_params['email_charset']);
     $msg->setHeaderCharset('UTF-8');
     $msg->setDescription(Horde_Crypt_Translation::t("S/MIME Encrypted Message"));
     $msg->setDisposition('inline');
     $msg->setType('application/pkcs7-mime');
     $msg->setContentTypeParameter('smime-type', 'enveloped-data');
     $msg->setContents(substr($message, strpos($message, "\n\n") + 2), array('encoding' => 'base64'));
     return $msg;
 }
Example #13
0
 /**
  * Generate the MDN according to the specifications listed in RFC
  * 3798 [3].
  *
  * @param boolean $action   Was this MDN type a result of a manual
  *                          action on part of the user?
  * @param boolean $sending  Was this MDN sent as a result of a manual
  *                          action on part of the user?
  * @param string $type      The type of action performed by the user.
  *                          Per RFC 3798 [3.2.6.2] the following types are
  *                          valid:
  *                            - deleted
  *                            - displayed
  * @param string $name      The name of the local server.
  * @param Mail $mailer      A Mail driver.
  * @param array $opts       Additional options:
  *   - charset: (string) Default charset.
  *              DEFAULT: NONE
  *   - from_addr: (string) From address.
  *                DEFAULT: NONE
  * @param array $mod        The list of modifications. Per RFC 3798
  *                          [3.2.6.3] the following modifications are
  *                          valid:
  *                            - error
  * @param array $err        If $mod is 'error', the additional
  *                          information to provide. Key is the type of
  *                          modification, value is the text.
  *
  * @throws Horde_Mime_Exception
  */
 public function generate($action, $sending, $type, $name, $mailer, array $opts = array(), array $mod = array(), array $err = array())
 {
     $opts = array_merge(array('charset' => null, 'from_addr' => null), $opts);
     $to = $this->getMdnReturnAddr();
     $ua = $this->_headers->getUserAgent();
     $orig_recip = $this->_headers->getValue('Original-Recipient');
     if (!empty($orig_recip) && is_array($orig_recip)) {
         $orig_recip = $orig_recip[0];
     }
     $msg_id = $this->_headers->getValue('Message-ID');
     /* Create the Disposition field now (RFC 3798 [3.2.6]). */
     $dispo = 'Disposition: ' . ($action ? 'manual-action' : 'automatic-action') . '/' . ($sending ? 'MDN-sent-manually' : 'MDN-sent-automatically') . '; ' . $type;
     if (!empty($mod)) {
         $dispo .= '/' . implode(', ', $mod);
     }
     /* Set up the mail headers. */
     $msg_headers = new Horde_Mime_Headers();
     $msg_headers->addMessageIdHeader();
     $msg_headers->addUserAgentHeader($ua);
     $msg_headers->addHeader('Date', date('r'));
     if ($opts['from_addr']) {
         $msg_headers->addHeader('From', $opts['from_addr']);
     }
     $msg_headers->addHeader('To', $this->getMdnReturnAddr());
     $msg_headers->addHeader('Subject', Horde_Mime_Translation::t("Disposition Notification"));
     /* MDNs are a subtype of 'multipart/report'. */
     $msg = new Horde_Mime_Part();
     $msg->setType('multipart/report');
     $msg->setContentTypeParameter('report-type', 'disposition-notification');
     /* The first part is a human readable message. */
     $part_one = new Horde_Mime_Part();
     $part_one->setType('text/plain');
     $part_one->setCharset($opts['charset']);
     if ($type == 'displayed') {
         $contents = sprintf(Horde_Mime_Translation::t("The message sent on %s to %s with subject \"%s\" has been displayed.\n\nThis is no guarantee that the message has been read or understood."), $this->_headers->getValue('Date'), $this->_headers->getValue('To'), $this->_headers->getValue('Subject'));
         $flowed = new Horde_Text_Flowed($contents, $opts['charset']);
         $flowed->setDelSp(true);
         $part_one->setContentTypeParameter('format', 'flowed');
         $part_one->setContentTypeParameter('DelSp', 'Yes');
         $part_one->setContents($flowed->toFlowed());
     }
     // TODO: Messages for other notification types.
     $msg->addPart($part_one);
     /* The second part is a machine-parseable description. */
     $part_two = new Horde_Mime_Part();
     $part_two->setType('message/disposition-notification');
     $part_two_text = array('Reporting-UA: ' . $name . '; ' . $ua . "\n");
     if (!empty($orig_recip)) {
         $part_two_text[] = 'Original-Recipient: rfc822;' . $orig_recip . "\n";
     }
     if ($opts['from_addr']) {
         $part_two_text[] = 'Final-Recipient: rfc822;' . $opts['from_addr'] . "\n";
     }
     if (!empty($msg_id)) {
         $part_two_text[] = 'Original-Message-ID: rfc822;' . $msg_id . "\n";
     }
     $part_two_text[] = $dispo . "\n";
     if (in_array('error', $mod) && isset($err['error'])) {
         $part_two_text[] = 'Error: ' . $err['error'] . "\n";
     }
     $part_two->setContents($part_two_text);
     $msg->addPart($part_two);
     /* The third part is the text of the original message.  RFC 3798 [3]
      * allows us to return only a portion of the entire message - this
      * is left up to the user. */
     $part_three = new Horde_Mime_Part();
     $part_three->setType('message/rfc822');
     $part_three_text = array($this->_headers->toString());
     if (!empty($this->_msgtext)) {
         $part_three_text[] = $part_three->getEOL() . $this->_msgtext;
     }
     $part_three->setContents($part_three_text);
     $msg->addPart($part_three);
     return $msg->send($to, $msg_headers, $mailer);
 }
Example #14
0
 /**
  * Creates a structure object from the text of one part of a MIME message.
  *
  * @param string $header      The header text.
  * @param string $body        The body text.
  * @param string $ctype       The default content-type.
  * @param boolean $forcemime  If true, the message data is assumed to be
  *                            MIME data. If not, a MIME-Version header
  *                            must exist to be parsed as a MIME message.
  *
  * @return Horde_Mime_Part  TODO
  */
 protected static function _getStructure($header, $body, $ctype = 'application/octet-stream', $forcemime = false)
 {
     /* Parse headers text into a Horde_Mime_Headers object. */
     $hdrs = Horde_Mime_Headers::parseHeaders($header);
     $ob = new Horde_Mime_Part();
     /* This is not a MIME message. */
     if (!$forcemime && !$hdrs->getValue('mime-version')) {
         $ob->setType('text/plain');
         if (!empty($body)) {
             $ob->setContents($body);
             $ob->setBytes(strlen(str_replace(array("\r\n", "\n"), array("\n", "\r\n"), $body)));
         }
         return $ob;
     }
     /* Content type. */
     if ($tmp = $hdrs->getValue('content-type', Horde_Mime_Headers::VALUE_BASE)) {
         $ob->setType($tmp);
         $ctype_params = $hdrs->getValue('content-type', Horde_Mime_Headers::VALUE_PARAMS);
         foreach ($ctype_params as $key => $val) {
             $ob->setContentTypeParameter($key, $val);
         }
     } else {
         $ob->setType($ctype);
         $ctype_params = array();
     }
     /* Content transfer encoding. */
     if ($tmp = $hdrs->getValue('content-transfer-encoding')) {
         $ob->setTransferEncoding($tmp);
     }
     /* Content-Description. */
     if ($tmp = $hdrs->getValue('content-description')) {
         $ob->setDescription($tmp);
     }
     /* Content-Disposition. */
     if ($tmp = $hdrs->getValue('content-disposition', Horde_Mime_Headers::VALUE_BASE)) {
         $ob->setDisposition($tmp);
         foreach ($hdrs->getValue('content-disposition', Horde_Mime_Headers::VALUE_PARAMS) as $key => $val) {
             $ob->setDispositionParameter($key, $val);
         }
     }
     /* Content-Duration */
     if ($tmp = $hdrs->getValue('content-duration')) {
         $ob->setDuration($tmp);
     }
     /* Content-ID. */
     if ($tmp = $hdrs->getValue('content-id')) {
         $ob->setContentId($tmp);
     }
     /* Get file size (if 'body' text is set). */
     if (!empty($body) && $ob->getPrimaryType() != 'multipart') {
         $ob->setContents($body);
         if ($ob->getType() != '/message/rfc822') {
             $ob->setBytes(strlen(str_replace(array("\r\n", "\n"), array("\n", "\r\n"), $body)));
         }
     }
     /* Process subparts. */
     switch ($ob->getPrimaryType()) {
         case 'message':
             if ($ob->getSubType() == 'rfc822') {
                 $ob->addPart(self::parseMessage($body, array('forcemime' => true)));
             }
             break;
         case 'multipart':
             if (isset($ctype_params['boundary'])) {
                 $b_find = self::_findBoundary($body, 0, $ctype_params['boundary']);
                 foreach ($b_find as $val) {
                     $subpart = substr($body, $val['start'], $val['length']);
                     list($hdr_pos, $eol) = self::_findHeader($subpart);
                     $ob->addPart(self::_getStructure(substr($subpart, 0, $hdr_pos), substr($subpart, $hdr_pos + $eol), $ob->getSubType() == 'digest' ? 'message/rfc822' : 'text/plain', true));
                 }
             }
             break;
     }
     return $ob;
 }
Example #15
0
 /**
  * Parse the output from imap_fetchstructure() into a MIME Part object.
  *
  * @param object $data  Data from imap_fetchstructure().
  *
  * @return Horde_Mime_Part  A MIME Part object.
  */
 protected function _parseStructure($data)
 {
     $ob = new Horde_Mime_Part();
     $ob->setType(Horde_String::lower($data->type) . '/' . Horde_String::lower($data->subType));
     // Optional for multipart-parts, required for all others
     if (isset($data->parameters)) {
         $params = array();
         foreach ($data->parameters as $key => $value) {
             $params[Horde_String::lower($key)] = $value;
         }
         $params = Horde_Mime::decodeParam('content-type', $params);
         foreach ($params['params'] as $key => $value) {
             $ob->setContentTypeParameter($key, $value);
         }
     }
     // Optional entries. 'location' and 'language' not supported
     if (isset($data->disposition)) {
         $ob->setDisposition($data->disposition);
         if (isset($data->dparameters)) {
             $dparams = array();
             foreach ($data->dparameters as $key => $value) {
                 $dparams[Horde_String::lower($key)] = $value;
             }
             $dparams = Horde_Mime::decodeParam('content-disposition', $dparams);
             foreach ($dparams['params'] as $key => $value) {
                 $ob->setDispositionParameter($key, $value);
             }
         }
     }
     if ($ob->getPrimaryType() == 'multipart') {
         // multipart/* specific entries
         foreach ($data->subParts as $val) {
             $ob->addPart($this->_parseStructure($val));
         }
     } else {
         // Required options
         if (isset($data->partID)) {
             $ob->setContentId($data->partID);
         }
         $ob->setTransferEncoding(Horde_String::lower($data->encoding));
         $ob->setBytes($data->bytes);
         if ($ob->getType() == 'message/rfc822') {
             $ob->addPart($this->_parseStructure(reset($data->subParts)));
         }
     }
     return $ob;
 }
Example #16
0
 /**
  * Recursively parse BODYSTRUCTURE data from a FETCH return (see
  * RFC 3501 [7.4.2]).
  *
  * @param array $data  The tokenized information from the server.
  *
  * @return array  The array of bodystructure information.
  */
 protected function _parseStructure($data)
 {
     $ob = new Horde_Mime_Part();
     // If index 0 is an array, this is a multipart part.
     if (is_array($data[0])) {
         // Keep going through array values until we find a non-array.
         for ($i = 0, $cnt = count($data); $i < $cnt; ++$i) {
             if (!is_array($data[$i])) {
                 break;
             }
             $ob->addPart($this->_parseStructure($data[$i]));
         }
         // The first string entry after an array entry gives us the
         // subpart type.
         $ob->setType('multipart/' . $data[$i]);
         // After the subtype is further extension information. This
         // information MAY not appear for BODYSTRUCTURE requests.
         // This is parameter information.
         if (isset($data[++$i]) && is_array($data[$i])) {
             foreach ($this->_parseStructureParams($data[$i], 'content-type') as $key => $val) {
                 $ob->setContentTypeParameter($key, $val);
             }
         }
         // This is disposition information.
         if (isset($data[++$i]) && is_array($data[$i])) {
             $ob->setDisposition($data[$i][0]);
             foreach ($this->_parseStructureParams($data[$i][1], 'content-disposition') as $key => $val) {
                 $ob->setDispositionParameter($key, $val);
             }
         }
         // This is language information. It is either a single value or
         // a list of values.
         if (isset($data[++$i])) {
             $ob->setLanguage($data[$i]);
         }
         // Ignore: location (RFC 2557)
         // There can be further information returned in the future, but
         // for now we are done.
     } else {
         $ob->setType($data[0] . '/' . $data[1]);
         foreach ($this->_parseStructureParams($data[2], 'content-type') as $key => $val) {
             $ob->setContentTypeParameter($key, $val);
         }
         if ($data[3] !== null) {
             $ob->setContentId($data[3]);
         }
         if ($data[4] !== null) {
             $ob->setDescription(Horde_Mime::decode($data[4]));
         }
         if ($data[5] !== null) {
             $ob->setTransferEncoding($data[5]);
         }
         if ($data[6] !== null) {
             $ob->setBytes($data[6]);
         }
         // If the type is 'message/rfc822' or 'text/*', several extra
         // fields are included
         switch ($ob->getPrimaryType()) {
             case 'message':
                 if ($ob->getSubType() == 'rfc822') {
                     // Ignore: envelope
                     $ob->addPart($this->_parseStructure($data[8]));
                     // Ignore: lines
                     $i = 10;
                 } else {
                     $i = 7;
                 }
                 break;
             case 'text':
                 // Ignore: lines
                 $i = 8;
                 break;
             default:
                 $i = 7;
                 break;
         }
         // After the subtype is further extension information. This
         // information MAY appear for BODYSTRUCTURE requests.
         // Ignore: MD5
         // This is disposition information
         if (isset($data[++$i]) && is_array($data[$i])) {
             $ob->setDisposition($data[$i][0]);
             foreach ($this->_parseStructureParams($data[$i][1], 'content-disposition') as $key => $val) {
                 $ob->setDispositionParameter($key, $val);
             }
         }
         // This is language information. It is either a single value or
         // a list of values.
         if (isset($data[++$i])) {
             $ob->setLanguage($data[$i]);
         }
         // Ignore: location (RFC 2557)
     }
     return $ob;
 }
Example #17
0
 $related->setType('multipart/related');
 /* Create the HTML part. */
 $htmlpart = new Horde_Mime_Part();
 $htmlpart->setType('text/html');
 $htmlpart->setCharset('UTF-8');
 /* The image part */
 $imgpart = new Horde_Mime_Part();
 $imgpart->setType($image->getType('screen'));
 $imgpart->setContents($image->raw('screen'));
 $img_tag = '<img src="cid:' . $imgpart->setContentID() . '" /><p />';
 $comments = $htmlpart->replaceEOL(Horde_Util::getFormData('ecard_comments'));
 if (!Horde_Util::getFormData('rtemode')) {
     $comments = '<pre>' . htmlspecialchars($comments, ENT_COMPAT, 'UTF-8') . '</pre>';
 }
 $htmlpart->setContents('<html>' . $img_tag . $comments . '</html>');
 $related->setContentTypeParameter('start', $htmlpart->setContentID());
 $related->addPart($htmlpart);
 $related->addPart($imgpart);
 /* Create the multipart/alternative part. */
 $alternative = new Horde_Mime_Part();
 $alternative->setType('multipart/alternative');
 $alternative->addPart($textpart);
 $alternative->addPart($related);
 /* Add them to the mail message */
 $alt = new Horde_Mime_Mail(array('Subject' => _("Ecard - ") . Horde_Util::getFormData('image_desc'), 'To' => $to, 'From' => $from));
 $alt->setBasePart($alternative);
 /* Send. */
 try {
     $alt->send($injector->getInstance('Horde_Mail'));
 } catch (Horde_Mime_Exception $e) {
     $notification->push(sprintf(_("There was an error sending your message: %s"), $e->getMessage()), 'horde.error');
Example #18
0
File: Mime.php Project: horde/horde
 /**
  * Create the base MIME part used for encryption (RFC 3156 [4]).
  *
  * @param Horde_Pgp_Element_Message $encrypted  Encrypted data.
  *
  * @return Horde_Mime_Part  Base encrypted MIME part.
  */
 protected function _encryptBase($encrypted)
 {
     $base = new Horde_Mime_Part();
     $base->setType('multipart/encrypted');
     $base->setHeaderCharset('UTF-8');
     $base->setContentTypeParameter('protocol', 'application/pgp-encrypted');
     $part1 = new Horde_Mime_Part();
     $part1->setType('application/pgp-encrypted');
     $part1->setCharset(null);
     $part1->setContents("Version: 1\n", array('encoding' => '7bit'));
     $base[] = $part1;
     $part2 = new Horde_Mime_Part();
     $part2->setType('application/octet-stream');
     $part2->setCharset(null);
     $part2->setContents(strval($encrypted), array('encoding' => '7bit'));
     $part2->setDisposition('inline');
     $base[] = $part2;
     return $base;
 }
Example #19
0
 /**
  * Sends this message.
  *
  * @param Mail $mailer     A Mail object.
  * @param boolean $resend  If true, the message id and date are re-used;
  *                         If false, they will be updated.
  * @param boolean $flowed  Send message in flowed text format.
  *
  * @throws Horde_Mime_Exception
  */
 public function send($mailer, $resend = false, $flowed = true)
 {
     /* Add mandatory headers if missing. */
     $has_header = $this->_headers->getValue('Message-ID');
     if (!$resend || !$has_header) {
         if ($has_header) {
             $this->_headers->removeHeader('Message-ID');
         }
         $this->_headers->addMessageIdHeader();
     }
     if (!$this->_headers->getValue('User-Agent')) {
         $this->_headers->addUserAgentHeader();
     }
     $has_header = $this->_headers->getValue('Date');
     if (!$resend || !$has_header) {
         if ($has_header) {
             $this->_headers->removeHeader('Date');
         }
         $this->_headers->addHeader('Date', date('r'));
     }
     if (isset($this->_base)) {
         $basepart = $this->_base;
     } else {
         /* Send in flowed format. */
         if ($flowed && !empty($this->_body)) {
             $flowed = new Horde_Text_Flowed($this->_body->getContents(), $this->_body->getCharset());
             $flowed->setDelSp(true);
             $this->_body->setContentTypeParameter('format', 'flowed');
             $this->_body->setContentTypeParameter('DelSp', 'Yes');
             $this->_body->setContents($flowed->toFlowed());
         }
         /* Build mime message. */
         $body = new Horde_Mime_Part();
         if (!empty($this->_body) && !empty($this->_htmlBody)) {
             $body->setType('multipart/alternative');
             $this->_body->setDescription(Horde_Mime_Translation::t("Plaintext Version of Message"));
             $body->addPart($this->_body);
             $this->_htmlBody->setDescription(Horde_Mime_Translation::t("HTML Version of Message"));
             $body->addPart($this->_htmlBody);
         } elseif (!empty($this->_htmlBody)) {
             $body = $this->_htmlBody;
         } elseif (!empty($this->_body)) {
             $body = $this->_body;
         }
         if (count($this->_parts)) {
             $basepart = new Horde_Mime_Part();
             $basepart->setType('multipart/mixed');
             $basepart->isBasePart(true);
             if ($body) {
                 $basepart->addPart($body);
             }
             foreach ($this->_parts as $mime_part) {
                 $basepart->addPart($mime_part);
             }
         } else {
             $basepart = $body;
             $basepart->isBasePart(true);
         }
     }
     $basepart->setHeaderCharset($this->_charset);
     /* Build recipients. */
     $recipients = clone $this->_recipients;
     foreach (array('to', 'cc') as $header) {
         $recipients->add($this->_headers->getOb($header));
     }
     if ($this->_bcc) {
         $recipients->add($this->_bcc);
     }
     /* Trick Horde_Mime_Part into re-generating the message headers. */
     $this->_headers->removeHeader('MIME-Version');
     /* Send message. */
     $recipients->unique();
     $basepart->send($recipients->writeAddress(), $this->_headers, $mailer);
     /* Remember the basepart */
     $this->_base = $basepart;
 }
Example #20
0
 /**
  * Variables required in form input:
  *   - identity (TODO: ? Code uses it, but it is never set anywhere)
  *   - imple_submit: itip_action(s)
  *   - mime_id
  *   - muid
  *
  * @return boolean  True on success.
  */
 protected function _handle(Horde_Variables $vars)
 {
     global $injector, $notification, $registry;
     $actions = (array) $vars->imple_submit;
     $result = false;
     $vCal = new Horde_Icalendar();
     /* Retrieve the calendar data from the message. */
     try {
         $contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices_Mailbox($vars));
         $mime_part = $contents->getMIMEPart($vars->mime_id);
         if (empty($mime_part)) {
             throw new IMP_Exception(_("Cannot retrieve calendar data from message."));
         } elseif (!$vCal->parsevCalendar($mime_part->getContents(), 'VCALENDAR', $mime_part->getCharset())) {
             throw new IMP_Exception(_("The calendar data is invalid"));
         }
         $components = $vCal->getComponents();
     } catch (Exception $e) {
         $notification->push($e, 'horde.error');
         $actions = array();
     }
     foreach ($actions as $key => $action) {
         $pos = strpos($key, '[');
         $key = substr($key, $pos + 1, strlen($key) - $pos - 2);
         switch ($action) {
             case 'delete':
                 // vEvent cancellation.
                 if ($registry->hasMethod('calendar/delete')) {
                     $guid = $components[$key]->getAttribute('UID');
                     $recurrenceId = null;
                     try {
                         // This is a cancellation of a recurring event instance.
                         $recurrenceId = $components[$key]->getAttribute('RECURRENCE-ID');
                         $atts = $components[$key]->getAttribute('RECURRENCE-ID', true);
                         $range = null;
                         foreach ($atts as $att) {
                             if (array_key_exists('RANGE', $att)) {
                                 $range = $att['RANGE'];
                             }
                         }
                     } catch (Horde_Icalendar_Exception $e) {
                     }
                     try {
                         $registry->call('calendar/delete', array($guid, $recurrenceId, $range));
                         $notification->push(_("Event successfully deleted."), 'horde.success');
                         $result = true;
                     } catch (Horde_Exception $e) {
                         $notification->push(sprintf(_("There was an error deleting the event: %s"), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 break;
             case 'update':
                 // vEvent reply.
                 if ($registry->hasMethod('calendar/updateAttendee')) {
                     try {
                         $from = $contents->getHeader()->getOb('from');
                         $registry->call('calendar/updateAttendee', array($components[$key], $from[0]->bare_address));
                         $notification->push(_("Respondent Status Updated."), 'horde.success');
                         $result = true;
                     } catch (Horde_Exception $e) {
                         $notification->push(sprintf(_("There was an error updating the event: %s"), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 break;
             case 'import':
             case 'accept-import':
                 // vFreebusy reply.
                 // vFreebusy publish.
                 // vEvent request.
                 // vEvent publish.
                 // vTodo publish.
                 // vJournal publish.
                 switch ($components[$key]->getType()) {
                     case 'vEvent':
                         $result = $this->_handlevEvent($key, $components, $mime_part);
                         // Must check for exceptions.
                         foreach ($components as $k => $component) {
                             try {
                                 if ($component->getType() == 'vEvent' && $component->getAttribute('RECURRENCE-ID')) {
                                     $uid = $component->getAttribute('UID');
                                     if ($uid == $components[$key]->getAttribute('UID')) {
                                         $this->_handlevEvent($k, $components, $mime_part);
                                     }
                                 }
                             } catch (Horde_Icalendar_Exception $e) {
                             }
                         }
                         break;
                     case 'vFreebusy':
                         // Import into Kronolith.
                         if ($registry->hasMethod('calendar/import_vfreebusy')) {
                             try {
                                 $registry->call('calendar/import_vfreebusy', array($components[$key]));
                                 $notification->push(_("The user's free/busy information was sucessfully stored."), 'horde.success');
                                 $result = true;
                             } catch (Horde_Exception $e) {
                                 $notification->push(sprintf(_("There was an error importing user's free/busy information: %s"), $e->getMessage()), 'horde.error');
                             }
                         } else {
                             $notification->push(_("This action is not supported."), 'horde.warning');
                         }
                         break;
                     case 'vTodo':
                         // Import into Nag.
                         if ($registry->hasMethod('tasks/import')) {
                             try {
                                 $guid = $registry->call('tasks/import', array($components[$key], $mime_part->getType()));
                                 $url = Horde::url($registry->link('tasks/show', array('uid' => $guid)));
                                 $notification->push(_("The task has been added to your tasklist.") . '&nbsp;' . Horde::link($url, _("View task"), null, '_blank') . Horde_Themes_Image::tag('mime/icalendar.png', array('alt' => _("View task"))) . '</a>', 'horde.success', array('content.raw'));
                                 $result = true;
                             } catch (Horde_Exception $e) {
                                 $notification->push(sprintf(_("There was an error importing the task: %s"), $e->getMessage()), 'horde.error');
                             }
                         } else {
                             $notification->push(_("This action is not supported."), 'horde.warning');
                         }
                         break;
                     case 'vJournal':
                     default:
                         $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 if ($action == 'import') {
                     break;
                 }
                 // Fall-through for 'accept-import'
             // Fall-through for 'accept-import'
             case 'accept':
             case 'deny':
             case 'tentative':
                 // vEvent request.
                 if (isset($components[$key]) && $components[$key]->getType() == 'vEvent') {
                     $vEvent = $components[$key];
                     $resource = new Horde_Itip_Resource_Identity($injector->getInstance('IMP_Identity'), $vEvent->getAttribute('ATTENDEE'), $vars->identity);
                     switch ($action) {
                         case 'accept':
                         case 'accept-import':
                             $type = new Horde_Itip_Response_Type_Accept($resource);
                             break;
                         case 'deny':
                             $type = new Horde_Itip_Response_Type_Decline($resource);
                             break;
                         case 'tentative':
                             $type = new Horde_Itip_Response_Type_Tentative($resource);
                             break;
                     }
                     try {
                         // Send the reply.
                         Horde_Itip::factory($vEvent, $resource)->sendMultiPartResponse($type, new Horde_Core_Itip_Response_Options_Horde('UTF-8', array()), $injector->getInstance('IMP_Mail'));
                         $notification->push(_("Reply Sent."), 'horde.success');
                         $result = true;
                     } catch (Horde_Itip_Exception $e) {
                         $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("This action is not supported."), 'horde.warning');
                 }
                 break;
             case 'send':
             case 'reply':
             case 'reply2m':
                 // vfreebusy request.
                 if (isset($components[$key]) && $components[$key]->getType() == 'vFreebusy') {
                     $vFb = $components[$key];
                     // Get the organizer details.
                     try {
                         $organizer = parse_url($vFb->getAttribute('ORGANIZER'));
                     } catch (Horde_Icalendar_Exception $e) {
                         break;
                     }
                     $organizerEmail = $organizer['path'];
                     $organizer = $vFb->getAttribute('ORGANIZER', true);
                     $organizerFullEmail = new Horde_Mail_Rfc822_Address($organizerEmail);
                     if (isset($organizer['cn'])) {
                         $organizerFullEmail->personal = $organizer['cn'];
                     }
                     if ($action == 'reply2m') {
                         $startStamp = time();
                         $endStamp = $startStamp + 60 * 24 * 3600;
                     } else {
                         try {
                             $startStamp = $vFb->getAttribute('DTSTART');
                         } catch (Horde_Icalendar_Exception $e) {
                             $startStamp = time();
                         }
                         try {
                             $endStamp = $vFb->getAttribute('DTEND');
                         } catch (Horde_Icalendar_Exception $e) {
                         }
                         if (!$endStamp) {
                             try {
                                 $duration = $vFb->getAttribute('DURATION');
                                 $endStamp = $startStamp + $duration;
                             } catch (Horde_Icalendar_Exception $e) {
                                 $endStamp = $startStamp + 60 * 24 * 3600;
                             }
                         }
                     }
                     $vfb_reply = $registry->call('calendar/getFreeBusy', array($startStamp, $endStamp));
                     // Find out who we are and update status.
                     $identity = $injector->getInstance('IMP_Identity');
                     $email = $identity->getFromAddress();
                     // Build the reply.
                     $msg_headers = new Horde_Mime_Headers();
                     $vCal = new Horde_Icalendar();
                     $vCal->setAttribute('PRODID', '-//The Horde Project//' . $msg_headers->getUserAgent() . '//EN');
                     $vCal->setAttribute('METHOD', 'REPLY');
                     $vCal->addComponent($vfb_reply);
                     $message = _("Attached is a reply to a calendar request you sent.");
                     $body = new Horde_Mime_Part();
                     $body->setType('text/plain');
                     $body->setCharset('UTF-8');
                     $body->setContents(Horde_String::wrap($message, 76));
                     $ics = new Horde_Mime_Part();
                     $ics->setType('text/calendar');
                     $ics->setCharset('UTF-8');
                     $ics->setContents($vCal->exportvCalendar());
                     $ics->setName('icalendar.ics');
                     $ics->setContentTypeParameter('METHOD', 'REPLY');
                     $mime = new Horde_Mime_Part();
                     $mime->addPart($body);
                     $mime->addPart($ics);
                     // Build the reply headers.
                     $msg_headers->addReceivedHeader(array('dns' => $injector->getInstance('Net_DNS2_Resolver'), 'server' => $conf['server']['name']));
                     $msg_headers->addMessageIdHeader();
                     $msg_headers->addHeader('Date', date('r'));
                     $msg_headers->addHeader('From', $email);
                     $msg_headers->addHeader('To', $organizerFullEmail);
                     $identity->setDefault($vars->identity);
                     $replyto = $identity->getValue('replyto_addr');
                     if (!empty($replyto) && !$email->match($replyto)) {
                         $msg_headers->addHeader('Reply-To', $replyto);
                     }
                     $msg_headers->addHeader('Subject', _("Free/Busy Request Response"));
                     // Send the reply.
                     try {
                         $mime->send($organizerEmail, $msg_headers, $injector->getInstance('IMP_Mail'));
                         $notification->push(_("Reply Sent."), 'horde.success');
                         $result = true;
                     } catch (Exception $e) {
                         $notification->push(sprintf(_("Error sending reply: %s."), $e->getMessage()), 'horde.error');
                     }
                 } else {
                     $notification->push(_("Invalid Action selected for this component."), 'horde.warning');
                 }
                 break;
             case 'nosup':
                 // vFreebusy request.
             // vFreebusy request.
             default:
                 $notification->push(_("This action is not supported."), 'horde.warning');
                 break;
         }
     }
     return $result;
 }
Example #21
0
 /**
  * Parse the output from imap_fetchstructure() into a MIME Part object.
  *
  * @param object $data  Data from imap_fetchstructure().
  *
  * @return Horde_Mime_Part  A MIME Part object.
  */
 protected function _parseStructure($data)
 {
     $ob = new Horde_Mime_Part();
     $ob->setType($this->_mimeTypes[$data->type] . '/' . ($data->ifsubtype ? strtolower($data->subtype) : Horde_Mime_Part::UNKNOWN));
     // Optional for multipart-parts, required for all others
     if ($data->ifparameters) {
         $params = array();
         foreach ($data->parameters as $val) {
             $params[$val->attribute] = $val->value;
         }
         $params = Horde_Mime::decodeParam('content-type', $params);
         foreach ($params['params'] as $key => $val) {
             $ob->setContentTypeParameter($key, $val);
         }
     }
     // Optional entries. 'location' and 'language' not supported
     if ($data->ifdisposition) {
         $ob->setDisposition($data->disposition);
         if ($data->ifdparameters) {
             $dparams = array();
             foreach ($data->dparameters as $val) {
                 $dparams[$val->attribute] = $val->value;
             }
             $dparams = Horde_Mime::decodeParam('content-disposition', $dparams);
             foreach ($dparams['params'] as $key => $val) {
                 $ob->setDispositionParameter($key, $val);
             }
         }
     }
     if ($ob->getPrimaryType() == 'multipart') {
         // multipart/* specific entries
         foreach ($data->parts as $val) {
             $ob->addPart($this->_parseStructure($val));
         }
     } else {
         // Required options
         if ($data->ifid) {
             $ob->setContentId($data->id);
         }
         if ($data->ifdescription) {
             $ob->setDescription(Horde_Mime::decode($data->description));
         }
         $ob->setTransferEncoding($this->_mimeEncodings[$data->encoding]);
         $ob->setBytes($data->bytes);
         if ($ob->getType() == 'message/rfc822') {
             $ob->addPart($this->_parseStructure(reset($data->parts)));
         }
     }
     return $ob;
 }