/** * Constructor. * * @param string $from The email address of the original sender. * @param Horde_Mime_Headers $h The headers object for the message. */ public function __construct($from, Horde_Mime_Headers $h) { global $prefs; $addressList = $nameList = array(); /* First we'll get a comma separated list of email addresses * and a comma separated list of personal names out of $from * (there just might be more than one of each). */ $addr_list = IMP::parseAddressList($from); foreach ($addr_list as $addr) { if (!is_null($addr->mailbox)) { $addressList[] = $addr->bare_address; } if (!is_null($addr->personal)) { $nameList[] = $addr->personal; } elseif (!is_null($addr->mailbox)) { $nameList[] = $addr->mailbox; } } /* Define the macros. */ if (is_array($message_id = $h->getValue('message-id'))) { $message_id = reset($message_id); } if (!($subject = $h->getValue('subject'))) { $subject = _("[No Subject]"); } $udate = strtotime($h->getValue('date')); $match = array('/%n/' => "\n", '/%%/' => '%', '/%f/' => $from, '/%a/' => implode(', ', $addressList), '/%p/' => implode(', ', $nameList), '/%r/' => $h->getValue('date'), '/%d/' => strftime("%a, %d %b %Y", $udate), '/%x/' => strftime("%x", $udate), '/%c/' => strftime("%c", $udate), '/%m/' => $message_id, '/%s/' => $subject); $this->_text = preg_replace(array_keys($match), array_values($match), $prefs->getValue('attrib_text')); }
/** * Constructor. * * @param string|Horde_Mail_Rfc822_Object $from The email address of the * original sender. * @param Horde_Mime_Headers $h The headers object for * the message. * @param string $attrib Use this for the * attribution config * instead of the default * prefs version. */ public function __construct($from, Horde_Mime_Headers $h, $attrib = null) { global $prefs; $this->_text = preg_replace_callback('/\\%./', function ($matches) use($from, $h) { switch ($matches[0]) { case '%n': /* New line. */ return "\n"; case '%%': /* Percent character. */ return '%'; case '%f': /* Name and email address of original sender. */ if ($from) { $from = new Horde_Mail_Rfc822_Address($from); return $from->writeAddress(array('noquote' => true)); } return _("Unknown Sender"); case '%a': /* Senders email address(es). */ /* Senders email address(es). */ case '%p': /* Senders name(s). */ $out = array(); foreach (IMP::parseAddressList($from) as $addr) { if ($matches[0] == '%a') { if (!is_null($addr->mailbox)) { $out[] = $addr->bare_address; } } else { $out[] = $addr->label; } } return count($out) ? implode(', ', $out) : _("Unknown Sender"); case '%r': /* RFC 822 date and time. */ return $h->getValue('date'); case '%d': /* Date as ddd, dd mmm yyyy. */ return strftime("%a, %d %b %Y", strtotime($h->getValue('date'))); case '%c': /* Date and time in locale's default. */ /* Date and time in locale's default. */ case '%x': /* Date in locale's default. */ return strftime($matches[0], strtotime($h->getValue('date'))); case '%m': /* Message-ID. */ return is_array($message_id = $h->getValue('message-id')) ? reset($message_id) : $message_id; case '%s': /* Message subject. */ return strlen($subject = $h->getValue('subject')) ? $subject : _("[No Subject]"); default: return ''; } }, is_null($attrib) ? $prefs->getValue('attrib_text') : $attrib); }
/** * Determines the priority of the message based on the headers. * * @param Horde_Mime_Headers $header The headers object. * * @return string 'high', 'low', or 'normal'. */ public function getPriority($header) { if (($xpriority = $header->getValue('x-priority')) && preg_match('/\\s*(\\d+)\\s*/', $xpriority, $matches)) { if (in_array($matches[1], array(1, 2))) { return 'high'; } elseif (in_array($matches[1], array(4, 5))) { return 'low'; } } elseif (($importance = $header->getValue('importance')) && preg_match('/:\\s*(\\w+)\\s*/', $importance, $matches)) { if (strcasecmp($matches[1], 'high') === 0) { return 'high'; } elseif (strcasecmp($matches[1], 'low') === 0) { return 'low'; } } return 'normal'; }
/** * @param Horde_Mime_Headers $data */ public function match($data) { if (!($ctype = $data->getValue('content-type', Horde_Mime_Headers::VALUE_BASE))) { return false; } @(list($primary, $sub) = explode('/', $ctype, 2)); return $primary == 'multipart' && !in_array($sub, array('alternative', 'encrypt', 'related', 'signed')); }
/** */ public function __isset($name) { switch ($name) { case 'reply_to': $name = 'reply-to'; // Fall-through // Fall-through case 'sender': if ($this->_data->getValue($name) !== null) { return true; } $name = 'from'; break; } return $this->_data->getValue($name) !== null; }
public function testUndisclosedHeaderParsing() { $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('To', 'undisclosed-recipients'); $this->assertEquals('', $hdrs->getValue('To')); $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('To', 'undisclosed-recipients:'); $this->assertEquals('', $hdrs->getValue('To')); $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('To', 'undisclosed-recipients:;'); $this->assertEquals('', $hdrs->getValue('To')); }
/** * Try to determine the MIME part that carries an object matching based on the message headers. * * @param Horde_Mime_Part $structure A structural representation of the mime message. * @param Horde_Mime_Headers $headers The message headers. * * @return string|boolean The MIME ID of the message part carrying an object matching the message headers or false if such a part was not identified within the message. */ public static function matchMimePartToHeaderType(Horde_Mime_Part $structure, Horde_Mime_Headers $headers) { $mime_type = $headers->getValue('X-Kolab-Type'); if ($mime_type === null) { return false; } return array(array_search($mime_type, $structure->contentTypeMap()), self::getObjectTypeFromMimeType($mime_type)); }
/** * @param Horde_Mime_Headers $data */ public function match($data) { return $data->getValue('list-post') !== null; }
/** * Sends this message. * * @param string $email The address list to send to. * @param Horde_Mime_Headers $headers The Horde_Mime_Headers object * holding this message's headers. * @param Horde_Mail_Transport $mailer A Horde_Mail_Transport object. * @param array $opts Additional options: * - encode: (integer) The encoding to use. A mask of self::ENCODE_* * values. * DEFAULT: Auto-determined based on transport driver. * * @throws Horde_Mime_Exception * @throws InvalidArgumentException */ public function send($email, $headers, Horde_Mail_Transport $mailer, array $opts = array()) { $old_basepart = $this->_basepart; $this->_basepart = true; /* Does the SMTP backend support 8BITMIME (RFC 1652)? */ $canonical = true; $encode = self::ENCODE_7BIT; if (isset($opts['encode'])) { /* Always allow 7bit encoding. */ $encode |= $opts['encode']; } elseif ($mailer instanceof Horde_Mail_Transport_Smtp) { try { $smtp_ext = $mailer->getSMTPObject()->getServiceExtensions(); if (isset($smtp_ext['8BITMIME'])) { $encode |= self::ENCODE_8BIT; } } catch (Horde_Mail_Exception $e) { } $canonical = false; } elseif ($mailer instanceof Horde_Mail_Transport_Smtphorde) { try { if ($mailer->getSMTPObject()->data_8bit) { $encode |= self::ENCODE_8BIT; } } catch (Horde_Mail_Exception $e) { } $canonical = false; } $msg = $this->toString(array('canonical' => $canonical, 'encode' => $encode, 'headers' => false, 'stream' => true)); /* Add MIME Headers if they don't already exist. */ if (!$headers->getValue('MIME-Version')) { $headers = $this->addMimeHeaders(array('encode' => $encode, 'headers' => $headers)); } if (!empty($this->_temp['toString'])) { $headers->replaceHeader('Content-Transfer-Encoding', $this->_temp['toString']); switch ($this->_temp['toString']) { case '8bit': if ($mailer instanceof Horde_Mail_Transport_Smtp) { $mailer->addServiceExtensionParameter('BODY', '8BITMIME'); } elseif ($mailer instanceof Horde_Mail_Transport_Smtphorde) { $mailer->send8bit = true; } break; } } $this->_basepart = $old_basepart; $rfc822 = new Horde_Mail_Rfc822(); try { $mailer->send($rfc822->parseAddressList($email)->writeAddress(array('encode' => $this->getHeaderCharset(), 'idn' => true)), $headers->toArray(array('canonical' => $canonical, 'charset' => $this->getHeaderCharset())), $msg); } catch (Horde_Mail_Exception $e) { throw new Horde_Mime_Exception($e); } }
/** * @param Horde_Mime_Headers $data */ public function match($data) { return $data->getValue('content-type', Horde_Mime_Headers::VALUE_BASE) == 'multipart/signed'; }
/** * 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); }
/** * Sends this message. * * @param string $email The address list to send to. * @param Horde_Mime_Headers $headers The Horde_Mime_Headers object * holding this message's headers. * @param Horde_Mail_Transport $mailer A Horde_Mail_Transport object. * @param array $opts Additional options: * - encode: (integer) The encoding to use. A mask of self::ENCODE_* * values. * DEFAULT: Auto-determined based on transport driver. * * @throws Horde_Mime_Exception * @throws InvalidArgumentException */ public function send($email, $headers, Horde_Mail_Transport $mailer, array $opts = array()) { $old_basepart = $this->_basepart; $this->_basepart = true; /* Does the SMTP backend support 8BITMIME (RFC 1652) or * BINARYMIME (RFC 3030) extensions? Requires Net_SMTP version * 1.3+. */ $encode = self::ENCODE_7BIT; if (isset($opts['encode'])) { /* Always allow 7bit encoding. */ $encode |= $opts['encode']; } else { if ($mailer instanceof Horde_Mail_Transport_Smtp) { try { $smtp_ext = $mailer->getSMTPObject()->getServiceExtensions(); if (isset($smtp_ext['8BITMIME'])) { $encode |= self::ENCODE_8BIT; } if (isset($smtp_ext['BINARYMIME'])) { $encode |= self::ENCODE_BINARY; } } catch (Horde_Mail_Exception $e) { } } } $msg = $this->toString(array('canonical' => true, 'encode' => $encode, 'headers' => false, 'stream' => true)); /* Make sure the message has a trailing newline. */ fseek($msg, -1, SEEK_END); switch (fgetc($msg)) { case "\r": if (fgetc($msg) != "\n") { fputs($msg, "\n"); } break; default: fputs($msg, "\r\n"); break; } rewind($msg); /* Add MIME Headers if they don't already exist. */ if (!$headers->getValue('MIME-Version')) { $headers = $this->addMimeHeaders(array('encode' => $encode, 'headers' => $headers)); } if (!empty($this->_temp['toString'])) { $headers->replaceHeader('Content-Transfer-Encoding', $this->_temp['toString']); switch ($this->_temp['toString']) { case 'binary': $mailer->addServiceExtensionParameter('BODY', 'BINARYMIME'); break; case '8bit': $mailer->addServiceExtensionParameter('BODY', '8BITMIME'); break; } } $this->_basepart = $old_basepart; $rfc822 = new Horde_Mail_Rfc822(); try { $mailer->send($rfc822->parseAddressList($email)->writeAddress(array('encode' => $this->getHeaderCharset(), 'idn' => true)), $headers->toArray(array('canonical' => true, 'charset' => $this->getHeaderCharset())), $msg); } catch (Horde_Mail_Exception $e) { throw new Horde_Mime_Exception($e); } }
/** * Determine the header information to display in the forward/reply. * * @param Horde_Mime_Headers $h The headers object for the message. * * @return string The header information for the original message. */ protected function _getMsgHeaders($h) { $tmp = array(); if ($ob = $h->getValue('date')) { $tmp[_("Date")] = $ob; } if ($ob = strval($h->getOb('from'))) { $tmp[_("From")] = $ob; } if ($ob = strval($h->getOb('reply-to'))) { $tmp[_("Reply-To")] = $ob; } if ($ob = $h->getValue('subject')) { $tmp[_("Subject")] = $ob; } if ($ob = strval($h->getOb('to'))) { $tmp[_("To")] = $ob; } if ($ob = strval($h->getOb('cc'))) { $tmp[_("Cc")] = $ob; } $text = ''; if (!empty($tmp)) { $max = max(array_map(array('Horde_String', 'length'), array_keys($tmp))) + 2; foreach ($tmp as $key => $val) { $text .= Horde_String::pad($key . ': ', $max, ' ', STR_PAD_LEFT) . $val . "\n"; } } return $text; }
/** * Get the value for a given header. * * @param Horde_Mime_Headers $ob The headers object. * @param string $header The header. * * @return string The header value. */ protected function _getHeaderValue($ob, $header) { return $ob->getValue($header); }
/** * @param Horde_Mime_Headers $data */ public function match($data) { $ctype = $data->getValue('content-type', Horde_Mime_Headers::VALUE_BASE); return $ctype == 'application/pkcs7-mime' || $ctype == 'multipart/encrypted'; }
public function testBug14381() { $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('Date', 'Sat, 22 May 2016 01:41:04 0000'); $this->assertEquals($hdrs->getValue('Date'), 'Sat, 22 May 2016 01:41:04 +0000'); $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader('Date', 'Sat, 22 May 2016 01:41:04 +0000'); $this->assertEquals($hdrs->getValue('Date'), 'Sat, 22 May 2016 01:41:04 +0000'); }
/** * Returns e-mail information for a mailing list. * * @param Horde_Mime_Headers $headers A Horde_Mime_Headers object. * * @return array An array with 2 elements: 'exists' and 'reply_list'. */ public function getListInformation($headers) { $ret = array('exists' => false, 'reply_list' => null); if ($headers->listHeadersExist()) { $ret['exists'] = true; /* See if the List-Post header provides an e-mail address for the * list. */ if ($val = $headers->getValue('list-post')) { foreach ($GLOBALS['injector']->getInstance('Horde_ListHeaders')->parse('list-post', $val) as $val2) { if ($val2 instanceof Horde_ListHeaders_NoPost) { break; } elseif (stripos($val2->url, 'mailto:') === 0) { $ret['reply_list'] = substr($val2->url, 7); break; } } } } return $ret; }
/** * 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; }
/** * @dataProvider undisclosedHeaderParsingProvider */ public function testUndisclosedHeaderParsing($header, $value) { $hdrs = new Horde_Mime_Headers(); $hdrs->addHeader($header, $value); /* @deprecated */ $this->assertEquals('', $hdrs->getValue($header)); $this->assertEquals('', $hdrs[$header]->value); }