[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * The Horde_Mime_Mdn:: class implements Message Disposition Notifications as 4 * described by RFC 3798. 5 * 6 * Copyright 2004-2014 Horde LLC (http://www.horde.org/) 7 * 8 * See the enclosed file COPYING for license information (LGPL). If you 9 * did not receive this file, see http://www.horde.org/licenses/lgpl21. 10 * 11 * @author Michael Slusarz <slusarz@horde.org> 12 * @category Horde 13 * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 14 * @package Mime 15 */ 16 class Horde_Mime_Mdn 17 { 18 /* RFC 3798 header for requesting a MDN. */ 19 const MDN_HEADER = 'Disposition-Notification-To'; 20 21 /** 22 * The Horde_Mime_Headers object. 23 * 24 * @var Horde_Mime_Headers 25 */ 26 protected $_headers; 27 28 /** 29 * The text of the original message. 30 * 31 * @var string 32 */ 33 protected $_msgtext = false; 34 35 /** 36 * Constructor. 37 * 38 * @param Horde_Mime_Headers $mime_headers A headers object. 39 */ 40 public function __construct(Horde_Mime_Headers $headers) 41 { 42 $this->_headers = $headers; 43 } 44 45 /** 46 * Returns the address to return the MDN to. 47 * 48 * @return string The address to send the MDN to. Returns null if no 49 * MDN is requested. 50 */ 51 public function getMdnReturnAddr() 52 { 53 /* RFC 3798 [2.1] requires the Disposition-Notification-To header 54 * for an MDN to be created. */ 55 return $this->_headers->getValue(self::MDN_HEADER); 56 } 57 58 /** 59 * Is user input required to send the MDN? 60 * Explicit confirmation is needed in some cases to prevent mail loops 61 * and the use of MDNs for mail bombing. 62 * 63 * @return boolean Is explicit user input required to send the MDN? 64 */ 65 public function userConfirmationNeeded() 66 { 67 $return_path = $this->_headers->getValue('Return-Path'); 68 69 /* RFC 3798 [2.1]: Explicit confirmation is needed if there is no 70 * Return-Path in the header. Also, "if the message contains more 71 * than one Return-Path header, the implementation may [] treat the 72 * situation as a failure of the comparison." */ 73 if (empty($return_path) || is_array($return_path)) { 74 return true; 75 } 76 77 /* RFC 3798 [2.1]: Explicit confirmation is needed if there is more 78 * than one distinct address in the Disposition-Notification-To 79 * header. */ 80 $rfc822 = new Horde_Mail_Rfc822(); 81 $addr_ob = $rfc822->parseAddressList($this->getMdnReturnAddr()); 82 83 switch (count($addr_ob)) { 84 case 0: 85 return false; 86 87 case 1: 88 // No-op 89 break; 90 91 default: 92 return true; 93 } 94 95 /* RFC 3798 [2.1] states that "MDNs SHOULD NOT be sent automatically 96 * if the address in the Disposition-Notification-To header differs 97 * from the address in the Return-Path header." This comparison is 98 * case-sensitive for the mailbox part and case-insensitive for the 99 * host part. */ 100 $ret_ob = new Horde_Mail_Rfc822_Address($return_path); 101 102 return ($ret_ob->valid && 103 ($addr_ob->bare_address == $ret_ob->bare_address)); 104 } 105 106 /** 107 * When generating the MDN, should we return the enitre text of the 108 * original message? The default is no - we only return the headers of 109 * the original message. If the text is passed in via this method, we 110 * will return the entire message. 111 * 112 * @param string $text The text of the original message. 113 */ 114 public function originalMessageText($text) 115 { 116 $this->_msgtext = $text; 117 } 118 119 /** 120 * Generate the MDN according to the specifications listed in RFC 121 * 3798 [3]. 122 * 123 * @param boolean $action Was this MDN type a result of a manual 124 * action on part of the user? 125 * @param boolean $sending Was this MDN sent as a result of a manual 126 * action on part of the user? 127 * @param string $type The type of action performed by the user. 128 * Per RFC 3798 [3.2.6.2] the following types are 129 * valid: 130 * - deleted 131 * - displayed 132 * @param string $name The name of the local server. 133 * @param Mail $mailer A Mail driver. 134 * @param array $opts Additional options: 135 * - charset: (string) Default charset. 136 * DEFAULT: NONE 137 * - from_addr: (string) From address. 138 * DEFAULT: NONE 139 * @param array $mod The list of modifications. Per RFC 3798 140 * [3.2.6.3] the following modifications are 141 * valid: 142 * - error 143 * @param array $err If $mod is 'error', the additional 144 * information to provide. Key is the type of 145 * modification, value is the text. 146 * 147 * @throws Horde_Mime_Exception 148 */ 149 public function generate($action, $sending, $type, $name, $mailer, 150 array $opts = array(), array $mod = array(), 151 array $err = array()) 152 { 153 $opts = array_merge(array( 154 'charset' => null, 155 'from_addr' => null 156 ), $opts); 157 158 $to = $this->getMdnReturnAddr(); 159 $ua = $this->_headers->getUserAgent(); 160 161 $orig_recip = $this->_headers->getValue('Original-Recipient'); 162 if (!empty($orig_recip) && is_array($orig_recip)) { 163 $orig_recip = $orig_recip[0]; 164 } 165 166 $msg_id = $this->_headers->getValue('Message-ID'); 167 168 /* Create the Disposition field now (RFC 3798 [3.2.6]). */ 169 $dispo = 'Disposition: ' . 170 (($action) ? 'manual-action' : 'automatic-action') . 171 '/' . 172 (($sending) ? 'MDN-sent-manually' : 'MDN-sent-automatically') . 173 '; ' . 174 $type; 175 if (!empty($mod)) { 176 $dispo .= '/' . implode(', ', $mod); 177 } 178 179 /* Set up the mail headers. */ 180 $msg_headers = new Horde_Mime_Headers(); 181 $msg_headers->addMessageIdHeader(); 182 $msg_headers->addUserAgentHeader($ua); 183 $msg_headers->addHeader('Date', date('r')); 184 if ($opts['from_addr']) { 185 $msg_headers->addHeader('From', $opts['from_addr']); 186 } 187 $msg_headers->addHeader('To', $this->getMdnReturnAddr()); 188 $msg_headers->addHeader('Subject', Horde_Mime_Translation::t("Disposition Notification")); 189 190 /* MDNs are a subtype of 'multipart/report'. */ 191 $msg = new Horde_Mime_Part(); 192 $msg->setType('multipart/report'); 193 $msg->setContentTypeParameter('report-type', 'disposition-notification'); 194 195 /* The first part is a human readable message. */ 196 $part_one = new Horde_Mime_Part(); 197 $part_one->setType('text/plain'); 198 $part_one->setCharset($opts['charset']); 199 if ($type == 'displayed') { 200 $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')); 201 $flowed = new Horde_Text_Flowed($contents, $opts['charset']); 202 $flowed->setDelSp(true); 203 $part_one->setContentTypeParameter('format', 'flowed'); 204 $part_one->setContentTypeParameter('DelSp', 'Yes'); 205 $part_one->setContents($flowed->toFlowed()); 206 } 207 // TODO: Messages for other notification types. 208 $msg->addPart($part_one); 209 210 /* The second part is a machine-parseable description. */ 211 $part_two = new Horde_Mime_Part(); 212 $part_two->setType('message/disposition-notification'); 213 $part_two_text = array('Reporting-UA: ' . $name . '; ' . $ua . "\n"); 214 if (!empty($orig_recip)) { 215 $part_two_text[] = 'Original-Recipient: rfc822;' . $orig_recip . "\n"; 216 } 217 if ($opts['from_addr']) { 218 $part_two_text[] = 'Final-Recipient: rfc822;' . $opts['from_addr'] . "\n"; 219 } 220 if (!empty($msg_id)) { 221 $part_two_text[] = 'Original-Message-ID: rfc822;' . $msg_id . "\n"; 222 } 223 $part_two_text[] = $dispo . "\n"; 224 if (in_array('error', $mod) && isset($err['error'])) { 225 $part_two_text[] = 'Error: ' . $err['error'] . "\n"; 226 } 227 $part_two->setContents($part_two_text); 228 $msg->addPart($part_two); 229 230 /* The third part is the text of the original message. RFC 3798 [3] 231 * allows us to return only a portion of the entire message - this 232 * is left up to the user. */ 233 $part_three = new Horde_Mime_Part(); 234 $part_three->setType('message/rfc822'); 235 $part_three_text = array($this->_headers->toString()); 236 if (!empty($this->_msgtext)) { 237 $part_three_text[] = $part_three->getEOL() . $this->_msgtext; 238 } 239 $part_three->setContents($part_three_text); 240 $msg->addPart($part_three); 241 242 return $msg->send($to, $msg_headers, $mailer); 243 } 244 245 /** 246 * Add a MDN (read receipt) request headers to the Horde_Mime_Headers:: 247 * object. 248 * 249 * @param string $to The address the receipt should be mailed to. 250 */ 251 public function addMdnRequestHeaders($to) 252 { 253 /* This is the RFC 3798 way of requesting a receipt. */ 254 $this->_headers->addHeader(self::MDN_HEADER, $to); 255 } 256 257 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |