From 3e5579b4d69f63f1057771b336189c688680d346 Mon Sep 17 00:00:00 2001 From: Bermi Date: Fri, 25 Jul 2008 23:50:21 +0000 Subject: [PATCH] Updating PEAR Mail, Net and Auth git-svn-id: http://svn.akelos.org/trunk@974 a2fa5c27-f921-0410-a72c-bf682d381be0 --- vendor/pear/Auth/SASL.php | 5 +- vendor/pear/Auth/SASL/DigestMD5.php | 26 +- vendor/pear/Auth/SASL/Plain.php | 2 +- vendor/pear/Mail.php | 24 +- vendor/pear/Mail/RFC822.php | 39 +- vendor/pear/Mail/mail.php | 45 ++- vendor/pear/Mail/mimePart.php | 703 ++++++++++++++++++------------------ vendor/pear/Mail/mock.php | 119 ++++++ vendor/pear/Mail/sendmail.php | 85 +++-- vendor/pear/Mail/smtp.php | 274 +++++++++++--- vendor/pear/Mail/smtpmx.php | 478 ++++++++++++++++++++++++ vendor/pear/Net/SMTP.php | 376 ++++++++++++------- vendor/pear/Net/Socket.php | 40 +- 13 files changed, 1596 insertions(+), 620 deletions(-) create mode 100644 vendor/pear/Mail/mock.php create mode 100644 vendor/pear/Mail/smtpmx.php diff --git a/vendor/pear/Auth/SASL.php b/vendor/pear/Auth/SASL.php index d0c0b77..45a3f71 100644 --- a/vendor/pear/Auth/SASL.php +++ b/vendor/pear/Auth/SASL.php @@ -32,7 +32,7 @@ // | Author: Richard Heyes | // +-----------------------------------------------------------------------+ // -// $Id: SASL.php,v 1.4 2003/02/21 16:07:17 mj Exp $ +// $Id: SASL.php,v 1.5 2006/03/22 05:20:11 amistry Exp $ /** * Client implementation of various SASL mechanisms @@ -91,7 +91,8 @@ class Auth_SASL } require_once($filename); - return new $classname(); + $obj = new $classname(); + return $obj; } } diff --git a/vendor/pear/Auth/SASL/DigestMD5.php b/vendor/pear/Auth/SASL/DigestMD5.php index 01f9778..4534e50 100644 --- a/vendor/pear/Auth/SASL/DigestMD5.php +++ b/vendor/pear/Auth/SASL/DigestMD5.php @@ -32,7 +32,7 @@ // | Author: Richard Heyes | // +-----------------------------------------------------------------------+ // -// $Id: DigestMD5.php,v 1.6 2003/02/21 16:07:17 mj Exp $ +// $Id: DigestMD5.php,v 1.8 2006/03/22 05:20:11 amistry Exp $ /** * Implmentation of DIGEST-MD5 SASL mechanism @@ -74,7 +74,12 @@ class Auth_SASL_DigestMD5 extends Auth_SASL_Common $digest_uri = sprintf('%s/%s', $service, $hostname); $response_value = $this->_getResponseValue($authcid, $pass, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $authzid); - return sprintf('username="%s",realm="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc="00000001",qop=auth,digest-uri="%s",response=%s,%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']); + if ($challenge['realm']) { + return sprintf('username="%s",realm="%s"' . $authzid_string . +',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['realm'], $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']); + } else { + return sprintf('username="%s"' . $authzid_string . ',nonce="%s",cnonce="%s",nc=00000001,qop=auth,digest-uri="%s",response=%s,maxbuf=%d', $authcid, $challenge['nonce'], $cnonce, $digest_uri, $response_value, $challenge['maxbuf']); + } } else { return PEAR::raiseError('Invalid digest challenge'); } @@ -125,20 +130,19 @@ class Auth_SASL_DigestMD5 extends Auth_SASL_Common */ // Realm if (empty($tokens['realm'])) { - $uname = posix_uname(); - $tokens['realm'] = $uname['nodename']; + $tokens['realm'] = ""; } - + // Maxbuf if (empty($tokens['maxbuf'])) { $tokens['maxbuf'] = 65536; } - + // Required: nonce, algorithm if (empty($tokens['nonce']) OR empty($tokens['algorithm'])) { return array(); } - + return $tokens; } @@ -174,11 +178,11 @@ class Auth_SASL_DigestMD5 extends Auth_SASL_Common */ function _getCnonce() { - if (file_exists('/dev/urandom')) { - return base64_encode(fread(fopen('/dev/urandom', 'r'), 32)); + if (file_exists('/dev/urandom') && $fd = @fopen('/dev/urandom', 'r')) { + return base64_encode(fread($fd, 32)); - } elseif (file_exists('/dev/random')) { - return base64_encode(fread(fopen('/dev/random', 'r'), 32)); + } elseif (file_exists('/dev/random') && $fd = @fopen('/dev/random', 'r')) { + return base64_encode(fread($fd, 32)); } else { $str = ''; diff --git a/vendor/pear/Auth/SASL/Plain.php b/vendor/pear/Auth/SASL/Plain.php index 9c9527e..e4662ff 100644 --- a/vendor/pear/Auth/SASL/Plain.php +++ b/vendor/pear/Auth/SASL/Plain.php @@ -32,7 +32,7 @@ // | Author: Richard Heyes | // +-----------------------------------------------------------------------+ // -// $Id: Plain.php,v 1.5 2003/02/21 16:07:17 mj Exp $ +// $Id: Plain.php,v 1.6 2003/09/11 18:53:56 mbretter Exp $ /** * Implmentation of PLAIN SASL mechanism diff --git a/vendor/pear/Mail.php b/vendor/pear/Mail.php index 6f75ef2..5142186 100644 --- a/vendor/pear/Mail.php +++ b/vendor/pear/Mail.php @@ -16,7 +16,7 @@ // | Author: Chuck Hagenbuch | // +----------------------------------------------------------------------+ // -// $Id: Mail.php,v 1.17 2006/09/15 03:41:18 jon Exp $ +// $Id: Mail.php,v 1.20 2007/10/06 17:00:00 chagenbu Exp $ require_once 'PEAR.php'; @@ -26,7 +26,7 @@ require_once 'PEAR.php'; * useful in multiple mailer backends. * * @access public - * @version $Revision: 1.17 $ + * @version $Revision: 1.20 $ * @package Mail */ class Mail @@ -82,12 +82,20 @@ class Mail * @return mixed Returns true on success, or a PEAR_Error * containing a descriptive error message on * failure. + * * @access public * @deprecated use Mail_mail::send instead */ function send($recipients, $headers, $body) { - $this->_sanitizeHeaders($headers); + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } // if we're passed an array of recipients, implode it. if (is_array($recipients)) { @@ -103,10 +111,9 @@ class Mail } // flatten the headers out. - list(,$text_headers) = Mail::prepareHeaders($headers); + list(, $text_headers) = Mail::prepareHeaders($headers); return mail($recipients, $subject, $body, $text_headers); - } /** @@ -151,9 +158,9 @@ class Mail foreach ($headers as $key => $value) { if (strcasecmp($key, 'From') === 0) { include_once 'Mail/RFC822.php'; - $parser = &new Mail_RFC822(); + $parser = new Mail_RFC822(); $addresses = $parser->parseAddressList($value, 'localhost', false); - if (PEAR::isError($addresses)) { + if (is_a($addresses, 'PEAR_Error')) { return $addresses; } @@ -161,7 +168,6 @@ class Mail // Reject envelope From: addresses with spaces. if (strstr($from, ' ')) { - die('Aquiii'); return false; } @@ -222,7 +228,7 @@ class Mail $addresses = Mail_RFC822::parseAddressList($recipients, 'localhost', false); // If parseAddressList() returned a PEAR_Error object, just return it. - if (PEAR::isError($addresses)) { + if (is_a($addresses, 'PEAR_Error')) { return $addresses; } diff --git a/vendor/pear/Mail/RFC822.php b/vendor/pear/Mail/RFC822.php index 47e84f8..8714df2 100644 --- a/vendor/pear/Mail/RFC822.php +++ b/vendor/pear/Mail/RFC822.php @@ -52,7 +52,7 @@ * * @author Richard Heyes * @author Chuck Hagenbuch - * @version $Revision: 1.21 $ + * @version $Revision: 1.24 $ * @license BSD * @package Mail */ @@ -342,22 +342,39 @@ class Mail_RFC822 { } /** - * Checks if a string has an unclosed quotes or not. + * Checks if a string has unclosed quotes or not. * * @access private - * @param string $string The string to check. - * @return boolean True if there are unclosed quotes inside the string, false otherwise. + * @param string $string The string to check. + * @return boolean True if there are unclosed quotes inside the string, + * false otherwise. */ function _hasUnclosedQuotes($string) { - $string = explode('"', $string); - $string_cnt = count($string); + $string = trim($string); + $iMax = strlen($string); + $in_quote = false; + $i = $slashes = 0; + + for (; $i < $iMax; ++$i) { + switch ($string[$i]) { + case '\\': + ++$slashes; + break; + + case '"': + if ($slashes % 2 == 0) { + $in_quote = !$in_quote; + } + // Fall through to default action below. - for ($i = 0; $i < (count($string) - 1); $i++) - if (substr($string[$i], -1) == '\\') - $string_cnt--; + default: + $slashes = 0; + break; + } + } - return ($string_cnt % 2 === 0); + return $in_quote; } /** @@ -912,7 +929,7 @@ class Mail_RFC822 { */ function isValidInetAddress($data, $strict = false) { - $regex = $strict ? '/^([.0-9a-z_-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,4})$/i'; + $regex = $strict ? '/^([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i' : '/^([*+!.&#$|\'\\%\/0-9a-z^_`{}=?~:-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})$/i'; if (preg_match($regex, trim($data), $matches)) { return array($matches[1], $matches[2]); } else { diff --git a/vendor/pear/Mail/mail.php b/vendor/pear/Mail/mail.php index 9135fa2..b13d695 100644 --- a/vendor/pear/Mail/mail.php +++ b/vendor/pear/Mail/mail.php @@ -16,12 +16,12 @@ // | Author: Chuck Hagenbuch | // +----------------------------------------------------------------------+ // -// $Id: mail.php,v 1.13 2004/09/09 02:08:55 jon Exp $ +// $Id: mail.php,v 1.20 2007/10/06 17:00:00 chagenbu Exp $ /** * internal PHP-mail() implementation of the PEAR Mail:: interface. * @package Mail - * @version $Revision: 1.13 $ + * @version $Revision: 1.20 $ */ class Mail_mail extends Mail { @@ -41,9 +41,9 @@ class Mail_mail extends Mail { */ function Mail_mail($params = null) { - /* The other mail implementations accept parameters as arrays. - * In the interest of being consistent, explode an array into - * a string of parameter arguments. */ + // The other mail implementations accept parameters as arrays. + // In the interest of being consistent, explode an array into + // a string of parameter arguments. if (is_array($params)) { $this->_params = join(' ', $params); } else { @@ -54,10 +54,14 @@ class Mail_mail extends Mail { * line arguments, we can't guarantee the use of the standard * "\r\n" separator. Instead, we use the system's native line * separator. */ - $this->sep = (strstr(PHP_OS, 'WIN')) ? "\r\n" : "\n"; + if (defined('PHP_EOL')) { + $this->sep = PHP_EOL; + } else { + $this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n"; + } } - /** + /** * Implements Mail_mail::send() function using php's built-in mail() * command. * @@ -85,6 +89,15 @@ class Mail_mail extends Mail { */ function send($recipients, $headers, $body) { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + // If we're passed an array of recipients, implode it. if (is_array($recipients)) { $recipients = implode(', ', $recipients); @@ -98,17 +111,19 @@ class Mail_mail extends Mail { unset($headers['Subject']); } + // Also remove the To: header. The mail() function will add its own + // To: header based on the contents of $recipients. + unset($headers['To']); + // Flatten the headers out. $headerElements = $this->prepareHeaders($headers); - if (PEAR::isError($headerElements)) { + if (is_a($headerElements, 'PEAR_Error')) { return $headerElements; } list(, $text_headers) = $headerElements; - /* - * We only use mail()'s optional fifth parameter if the additional - * parameters have been provided and we're not running in safe mode. - */ + // We only use mail()'s optional fifth parameter if the additional + // parameters have been provided and we're not running in safe mode. if (empty($this->_params) || ini_get('safe_mode')) { $result = mail($recipients, $subject, $body, $text_headers); } else { @@ -116,10 +131,8 @@ class Mail_mail extends Mail { $this->_params); } - /* - * If the mail() function returned failure, we need to create a - * PEAR_Error object and return it instead of the boolean result. - */ + // If the mail() function returned failure, we need to create a + // PEAR_Error object and return it instead of the boolean result. if ($result === false) { $result = PEAR::raiseError('mail() returned failure'); } diff --git a/vendor/pear/Mail/mimePart.php b/vendor/pear/Mail/mimePart.php index 6edb2ef..208081a 100644 --- a/vendor/pear/Mail/mimePart.php +++ b/vendor/pear/Mail/mimePart.php @@ -1,351 +1,352 @@ - | -// +-----------------------------------------------------------------------+ - -/** -* -* Raw mime encoding class -* -* What is it? -* This class enables you to manipulate and build -* a mime email from the ground up. -* -* Why use this instead of mime.php? -* mime.php is a userfriendly api to this class for -* people who aren't interested in the internals of -* mime mail. This class however allows full control -* over the email. -* -* Eg. -* -* // Since multipart/mixed has no real body, (the body is -* // the subpart), we set the body argument to blank. -* -* $params['content_type'] = 'multipart/mixed'; -* $email = new Mail_mimePart('', $params); -* -* // Here we add a text part to the multipart we have -* // already. Assume $body contains plain text. -* -* $params['content_type'] = 'text/plain'; -* $params['encoding'] = '7bit'; -* $text = $email->addSubPart($body, $params); -* -* // Now add an attachment. Assume $attach is -* the contents of the attachment -* -* $params['content_type'] = 'application/zip'; -* $params['encoding'] = 'base64'; -* $params['disposition'] = 'attachment'; -* $params['dfilename'] = 'example.zip'; -* $attach =& $email->addSubPart($body, $params); -* -* // Now build the email. Note that the encode -* // function returns an associative array containing two -* // elements, body and headers. You will need to add extra -* // headers, (eg. Mime-Version) before sending. -* -* $email = $message->encode(); -* $email['headers'][] = 'Mime-Version: 1.0'; -* -* -* Further examples are available at http://www.phpguru.org -* -* TODO: -* - Set encode() to return the $obj->encoded if encode() -* has already been run. Unless a flag is passed to specifically -* re-build the message. -* -* @author Richard Heyes -* @version $Revision: 1.13 $ -* @package Mail -*/ - -class Mail_mimePart { - - /** - * The encoding type of this part - * @var string - */ - var $_encoding; - - /** - * An array of subparts - * @var array - */ - var $_subparts; - - /** - * The output of this part after being built - * @var string - */ - var $_encoded; - - /** - * Headers for this part - * @var array - */ - var $_headers; - - /** - * The body of this part (not encoded) - * @var string - */ - var $_body; - - /** - * Constructor. - * - * Sets up the object. - * - * @param $body - The body of the mime part if any. - * @param $params - An associative array of parameters: - * content_type - The content type for this part eg multipart/mixed - * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable - * cid - Content ID to apply - * disposition - Content disposition, inline or attachment - * dfilename - Optional filename parameter for content disposition - * description - Content description - * charset - Character set to use - * @access public - */ - function Mail_mimePart($body = '', $params = array()) - { - if (!defined('MAIL_MIMEPART_CRLF')) { - define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); - } - - foreach ($params as $key => $value) { - switch ($key) { - case 'content_type': - $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); - break; - - case 'encoding': - $this->_encoding = $value; - $headers['Content-Transfer-Encoding'] = $value; - break; - - case 'cid': - $headers['Content-ID'] = '<' . $value . '>'; - break; - - case 'disposition': - $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : ''); - break; - - case 'dfilename': - if (isset($headers['Content-Disposition'])) { - $headers['Content-Disposition'] .= '; filename="' . $value . '"'; - } else { - $dfilename = $value; - } - break; - - case 'description': - $headers['Content-Description'] = $value; - break; - - case 'charset': - if (isset($headers['Content-Type'])) { - $headers['Content-Type'] .= '; charset="' . $value . '"'; - } else { - $charset = $value; - } - break; - } - } - - // Default content-type - if (!isset($headers['Content-Type'])) { - $headers['Content-Type'] = 'text/plain'; - } - - //Default encoding - if (!isset($this->_encoding)) { - $this->_encoding = '7bit'; - } - - // Assign stuff to member variables - $this->_encoded = array(); - $this->_headers = $headers; - $this->_body = $body; - } - - /** - * encode() - * - * Encodes and returns the email. Also stores - * it in the encoded member variable - * - * @return An associative array containing two elements, - * body and headers. The headers element is itself - * an indexed array. - * @access public - */ - function encode() - { - $encoded =& $this->_encoded; - - if (!empty($this->_subparts)) { - srand((double)microtime()*1000000); - $boundary = '=_' . md5(rand() . microtime()); - $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; - - // Add body parts to $subparts - for ($i = 0; $i < count($this->_subparts); $i++) { - $headers = array(); - $tmp = $this->_subparts[$i]->encode(); - foreach ($tmp['headers'] as $key => $value) { - $headers[] = $key . ': ' . $value; - } - $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; - } - - $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . - implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . - '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; - - } else { - $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; - } - - // Add headers to $encoded - $encoded['headers'] =& $this->_headers; - - return $encoded; - } - - /** - * &addSubPart() - * - * Adds a subpart to current mime part and returns - * a reference to it - * - * @param $body The body of the subpart, if any. - * @param $params The parameters for the subpart, same - * as the $params argument for constructor. - * @return A reference to the part you just added. It is - * crucial if using multipart/* in your subparts that - * you use =& in your script when calling this function, - * otherwise you will not be able to add further subparts. - * @access public - */ - function &addSubPart($body, $params) - { - $this->_subparts[] = new Mail_mimePart($body, $params); - return $this->_subparts[count($this->_subparts) - 1]; - } - - /** - * _getEncodedData() - * - * Returns encoded data based upon encoding passed to it - * - * @param $data The data to encode. - * @param $encoding The encoding type to use, 7bit, base64, - * or quoted-printable. - * @access private - */ - function _getEncodedData($data, $encoding) - { - switch ($encoding) { - case '8bit': - case '7bit': - return $data; - break; - - case 'quoted-printable': - return $this->_quotedPrintableEncode($data); - break; - - case 'base64': - return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); - break; - - default: - return $data; - } - } - - /** - * quoteadPrintableEncode() - * - * Encodes data to quoted-printable standard. - * - * @param $input The data to encode - * @param $line_max Optional max line length. Should - * not be more than 76 chars - * - * @access private - */ - function _quotedPrintableEncode($input , $line_max = 76) - { - $lines = preg_split("/\r?\n/", $input); - $eol = MAIL_MIMEPART_CRLF; - $escape = '='; - $output = ''; - - while(list(, $line) = each($lines)){ - - $linlen = strlen($line); - $newline = ''; - - for ($i = 0; $i < $linlen; $i++) { - $char = substr($line, $i, 1); - $dec = ord($char); - - if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only - $char = '=20'; - - } elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only - $char = '=09'; - } elseif($dec == 9) { - ; // Do nothing if a tab. - } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { - $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); - } - - if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted - $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay - $newline = ''; - } - $newline .= $char; - } // end of for - $output .= $newline . $eol; - } - $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf - return $output; - } -} // End of class -?> + | +// +-----------------------------------------------------------------------+ + +/** +* +* Raw mime encoding class +* +* What is it? +* This class enables you to manipulate and build +* a mime email from the ground up. +* +* Why use this instead of mime.php? +* mime.php is a userfriendly api to this class for +* people who aren't interested in the internals of +* mime mail. This class however allows full control +* over the email. +* +* Eg. +* +* // Since multipart/mixed has no real body, (the body is +* // the subpart), we set the body argument to blank. +* +* $params['content_type'] = 'multipart/mixed'; +* $email = new Mail_mimePart('', $params); +* +* // Here we add a text part to the multipart we have +* // already. Assume $body contains plain text. +* +* $params['content_type'] = 'text/plain'; +* $params['encoding'] = '7bit'; +* $text = $email->addSubPart($body, $params); +* +* // Now add an attachment. Assume $attach is +* the contents of the attachment +* +* $params['content_type'] = 'application/zip'; +* $params['encoding'] = 'base64'; +* $params['disposition'] = 'attachment'; +* $params['dfilename'] = 'example.zip'; +* $attach =& $email->addSubPart($body, $params); +* +* // Now build the email. Note that the encode +* // function returns an associative array containing two +* // elements, body and headers. You will need to add extra +* // headers, (eg. Mime-Version) before sending. +* +* $email = $message->encode(); +* $email['headers'][] = 'Mime-Version: 1.0'; +* +* +* Further examples are available at http://www.phpguru.org +* +* TODO: +* - Set encode() to return the $obj->encoded if encode() +* has already been run. Unless a flag is passed to specifically +* re-build the message. +* +* @author Richard Heyes +* @version $Revision: 1.13 $ +* @package Mail +*/ + +class Mail_mimePart { + + /** + * The encoding type of this part + * @var string + */ + var $_encoding; + + /** + * An array of subparts + * @var array + */ + var $_subparts; + + /** + * The output of this part after being built + * @var string + */ + var $_encoded; + + /** + * Headers for this part + * @var array + */ + var $_headers; + + /** + * The body of this part (not encoded) + * @var string + */ + var $_body; + + /** + * Constructor. + * + * Sets up the object. + * + * @param $body - The body of the mime part if any. + * @param $params - An associative array of parameters: + * content_type - The content type for this part eg multipart/mixed + * encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable + * cid - Content ID to apply + * disposition - Content disposition, inline or attachment + * dfilename - Optional filename parameter for content disposition + * description - Content description + * charset - Character set to use + * @access public + */ + function Mail_mimePart($body = '', $params = array()) + { + if (!defined('MAIL_MIMEPART_CRLF')) { + define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); + } + + foreach ($params as $key => $value) { + switch ($key) { + case 'content_type': + $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); + break; + + case 'encoding': + $this->_encoding = $value; + $headers['Content-Transfer-Encoding'] = $value; + break; + + case 'cid': + $headers['Content-ID'] = '<' . $value . '>'; + break; + + case 'disposition': + $headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : ''); + break; + + case 'dfilename': + if (isset($headers['Content-Disposition'])) { + $headers['Content-Disposition'] .= '; filename="' . $value . '"'; + } else { + $dfilename = $value; + } + break; + + case 'description': + $headers['Content-Description'] = $value; + break; + + case 'charset': + if (isset($headers['Content-Type'])) { + $headers['Content-Type'] .= '; charset="' . $value . '"'; + } else { + $charset = $value; + } + break; + } + } + + // Default content-type + if (!isset($headers['Content-Type'])) { + $headers['Content-Type'] = 'text/plain'; + } + + //Default encoding + if (!isset($this->_encoding)) { + $this->_encoding = '7bit'; + } + + + // Assign stuff to member variables + $this->_encoded = array(); + $this->_headers = $headers; + $this->_body = $body; + } + + /** + * encode() + * + * Encodes and returns the email. Also stores + * it in the encoded member variable + * + * @return An associative array containing two elements, + * body and headers. The headers element is itself + * an indexed array. + * @access public + */ + function encode() + { + $encoded =& $this->_encoded; + + if (!empty($this->_subparts)) { + srand((double)microtime()*1000000); + $boundary = '=_' . md5(rand() . microtime()); + $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; + + // Add body parts to $subparts + for ($i = 0; $i < count($this->_subparts); $i++) { + $headers = array(); + $tmp = $this->_subparts[$i]->encode(); + foreach ($tmp['headers'] as $key => $value) { + $headers[] = $key . ': ' . $value; + } + $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body']; + } + + $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . + implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) . + '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; + + } else { + $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF; + } + + // Add headers to $encoded + $encoded['headers'] =& $this->_headers; + + return $encoded; + } + + /** + * &addSubPart() + * + * Adds a subpart to current mime part and returns + * a reference to it + * + * @param $body The body of the subpart, if any. + * @param $params The parameters for the subpart, same + * as the $params argument for constructor. + * @return A reference to the part you just added. It is + * crucial if using multipart/* in your subparts that + * you use =& in your script when calling this function, + * otherwise you will not be able to add further subparts. + * @access public + */ + function &addSubPart($body, $params) + { + $this->_subparts[] = new Mail_mimePart($body, $params); + return $this->_subparts[count($this->_subparts) - 1]; + } + + /** + * _getEncodedData() + * + * Returns encoded data based upon encoding passed to it + * + * @param $data The data to encode. + * @param $encoding The encoding type to use, 7bit, base64, + * or quoted-printable. + * @access private + */ + function _getEncodedData($data, $encoding) + { + switch ($encoding) { + case '8bit': + case '7bit': + return $data; + break; + + case 'quoted-printable': + return $this->_quotedPrintableEncode($data); + break; + + case 'base64': + return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); + break; + + default: + return $data; + } + } + + /** + * quoteadPrintableEncode() + * + * Encodes data to quoted-printable standard. + * + * @param $input The data to encode + * @param $line_max Optional max line length. Should + * not be more than 76 chars + * + * @access private + */ + function _quotedPrintableEncode($input , $line_max = 76) + { + $lines = preg_split("/\r?\n/", $input); + $eol = MAIL_MIMEPART_CRLF; + $escape = '='; + $output = ''; + + while(list(, $line) = each($lines)){ + + $linlen = strlen($line); + $newline = ''; + + for ($i = 0; $i < $linlen; $i++) { + $char = substr($line, $i, 1); + $dec = ord($char); + + if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only + $char = '=20'; + + } elseif(($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only + $char = '=09'; + } elseif($dec == 9) { + ; // Do nothing if a tab. + } elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { + $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); + } + + if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted + $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay + $newline = ''; + } + $newline .= $char; + } // end of for + $output .= $newline . $eol; + } + $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf + return $output; + } +} // End of class +?> diff --git a/vendor/pear/Mail/mock.php b/vendor/pear/Mail/mock.php new file mode 100644 index 0000000..971dae6 --- /dev/null +++ b/vendor/pear/Mail/mock.php @@ -0,0 +1,119 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: mock.php,v 1.1 2007/12/08 17:57:54 chagenbu Exp $ +// + +/** + * Mock implementation of the PEAR Mail:: interface for testing. + * @access public + * @package Mail + * @version $Revision: 1.1 $ + */ +class Mail_mock extends Mail { + + /** + * Array of messages that have been sent with the mock. + * + * @var array + * @access public + */ + var $sentMessages = array(); + + /** + * Callback before sending mail. + * + * @var callback + */ + var $_preSendCallback; + + /** + * Callback after sending mai. + * + * @var callback + */ + var $_postSendCallback; + + /** + * Constructor. + * + * Instantiates a new Mail_mock:: object based on the parameters + * passed in. It looks for the following parameters, both optional: + * preSendCallback Called before an email would be sent. + * postSendCallback Called after an email would have been sent. + * + * @param array Hash containing any parameters. + * @access public + */ + function Mail_mock($params) + { + if (isset($params['preSendCallback']) && + is_callable($params['preSendCallback'])) { + $this->_preSendCallback = $params['preSendCallback']; + } + + if (isset($params['postSendCallback']) && + is_callable($params['postSendCallback'])) { + $this->_postSendCallback = $params['postSendCallback']; + } + } + + /** + * Implements Mail_mock::send() function. Silently discards all + * mail. + * + * @param mixed $recipients Either a comma-seperated list of recipients + * (RFC822 compliant), or an array of recipients, + * each RFC822 valid. This may contain recipients not + * specified in the headers, for Bcc:, resending + * messages, etc. + * + * @param array $headers The array of headers to send with the mail, in an + * associative array, where the array key is the + * header name (ie, 'Subject'), and the array value + * is the header value (ie, 'test'). The header + * produced from those values would be 'Subject: + * test'. + * + * @param string $body The full text of the message body, including any + * Mime parts, etc. + * + * @return mixed Returns true on success, or a PEAR_Error + * containing a descriptive error message on + * failure. + * @access public + */ + function send($recipients, $headers, $body) + { + if ($this->_preSendCallback) { + call_user_func_array($this->_preSendCallback, + array(&$this, $recipients, $headers, $body)); + } + + $entry = array('recipients' => $recipients, 'headers' => $headers, 'body' => $body); + $this->sentMessages[] = $entry; + + if ($this->_postSendCallback) { + call_user_func_array($this->_postSendCallback, + array(&$this, $recipients, $headers, $body)); + } + + return true; + } + +} diff --git a/vendor/pear/Mail/sendmail.php b/vendor/pear/Mail/sendmail.php index 39a43c2..cd248e6 100644 --- a/vendor/pear/Mail/sendmail.php +++ b/vendor/pear/Mail/sendmail.php @@ -20,25 +20,25 @@ * Sendmail implementation of the PEAR Mail:: interface. * @access public * @package Mail - * @version $Revision: 1.10 $ + * @version $Revision: 1.19 $ */ class Mail_sendmail extends Mail { - /** + /** * The location of the sendmail or sendmail wrapper binary on the * filesystem. * @var string */ var $sendmail_path = '/usr/sbin/sendmail'; - /** + /** * Any extra command-line parameters to pass to the sendmail or * sendmail wrapper binary. * @var string */ - var $sendmail_args = ''; + var $sendmail_args = '-i'; - /** + /** * Constructor. * * Instantiates a new Mail_sendmail:: object based on the parameters @@ -58,18 +58,26 @@ class Mail_sendmail extends Mail { */ function Mail_sendmail($params) { - if (isset($params['sendmail_path'])) $this->sendmail_path = $params['sendmail_path']; - if (isset($params['sendmail_args'])) $this->sendmail_args = $params['sendmail_args']; + if (isset($params['sendmail_path'])) { + $this->sendmail_path = $params['sendmail_path']; + } + if (isset($params['sendmail_args'])) { + $this->sendmail_args = $params['sendmail_args']; + } /* * Because we need to pass message headers to the sendmail program on * the commandline, we can't guarantee the use of the standard "\r\n" * separator. Instead, we use the system's native line separator. */ - $this->sep = (strstr(PHP_OS, 'WIN')) ? "\r\n" : "\n"; + if (defined('PHP_EOL')) { + $this->sep = PHP_EOL; + } else { + $this->sep = (strpos(PHP_OS, 'WIN') === false) ? "\n" : "\r\n"; + } } - /** + /** * Implements Mail::send() function using the sendmail * command-line binary. * @@ -96,42 +104,59 @@ class Mail_sendmail extends Mail { */ function send($recipients, $headers, $body) { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + $recipients = $this->parseRecipients($recipients); - if (PEAR::isError($recipients)) { + if (is_a($recipients, 'PEAR_Error')) { return $recipients; } $recipients = escapeShellCmd(implode(' ', $recipients)); $headerElements = $this->prepareHeaders($headers); - if (PEAR::isError($headerElements)) { + if (is_a($headerElements, 'PEAR_Error')) { return $headerElements; } list($from, $text_headers) = $headerElements; + /* Since few MTAs are going to allow this header to be forged + * unless it's in the MAIL FROM: exchange, we'll use + * Return-Path instead of From: if it's set. */ + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + if (!isset($from)) { return PEAR::raiseError('No from address given.'); - } elseif (strstr($from, ' ') || - strstr($from, ';') || - strstr($from, '&') || - strstr($from, '`')) { + } elseif (strpos($from, ' ') !== false || + strpos($from, ';') !== false || + strpos($from, '&') !== false || + strpos($from, '`') !== false) { return PEAR::raiseError('From address specified with dangerous characters.'); } - $result = 0; - if (@is_file($this->sendmail_path)) { - $from = escapeShellCmd($from); - $mail = popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w'); - fputs($mail, $text_headers); - fputs($mail, $this->sep); // newline to end the headers section - fputs($mail, $body); - $result = pclose($mail); - if (version_compare(phpversion(), '4.2.3') == -1) { - // With older php versions, we need to shift the - // pclose result to get the exit code. - $result = $result >> 8 & 0xFF; - } - } else { - return PEAR::raiseError('sendmail [' . $this->sendmail_path . '] is not a valid file'); + $from = escapeShellCmd($from); + $mail = @popen($this->sendmail_path . (!empty($this->sendmail_args) ? ' ' . $this->sendmail_args : '') . " -f$from -- $recipients", 'w'); + if (!$mail) { + return PEAR::raiseError('Failed to open sendmail [' . $this->sendmail_path . '] for execution.'); + } + + // Write the headers following by two newlines: one to end the headers + // section and a second to separate the headers block from the body. + fputs($mail, $text_headers . $this->sep . $this->sep); + + fputs($mail, $body); + $result = pclose($mail); + if (version_compare(phpversion(), '4.2.3') == -1) { + // With older php versions, we need to shift the pclose + // result to get the exit code. + $result = $result >> 8 & 0xFF; } if ($result != 0) { diff --git a/vendor/pear/Mail/smtp.php b/vendor/pear/Mail/smtp.php index 40686a6..baf3a96 100644 --- a/vendor/pear/Mail/smtp.php +++ b/vendor/pear/Mail/smtp.php @@ -17,16 +17,51 @@ // | Jon Parise | // +----------------------------------------------------------------------+ +/** Error: Failed to create a Net_SMTP object */ +define('PEAR_MAIL_SMTP_ERROR_CREATE', 10000); + +/** Error: Failed to connect to SMTP server */ +define('PEAR_MAIL_SMTP_ERROR_CONNECT', 10001); + +/** Error: SMTP authentication failure */ +define('PEAR_MAIL_SMTP_ERROR_AUTH', 10002); + +/** Error: No From: address has been provided */ +define('PEAR_MAIL_SMTP_ERROR_FROM', 10003); + +/** Error: Failed to set sender */ +define('PEAR_MAIL_SMTP_ERROR_SENDER', 10004); + +/** Error: Failed to add recipient */ +define('PEAR_MAIL_SMTP_ERROR_RECIPIENT', 10005); + +/** Error: Failed to send data */ +define('PEAR_MAIL_SMTP_ERROR_DATA', 10006); + /** - * SMTP implementation of the PEAR Mail:: interface. Requires the PEAR - * Net_SMTP:: class. + * SMTP implementation of the PEAR Mail interface. Requires the Net_SMTP class. * @access public * @package Mail - * @version $Revision: 1.20 $ + * @version $Revision: 1.33 $ */ class Mail_smtp extends Mail { /** + * SMTP connection object. + * + * @var object + * @access private + */ + var $_smtp = null; + + /** + * The list of service extension parameters to pass to the Net_SMTP + * mailFrom() command. + * @var array + */ + var $_extparams = array(); + + /** * The SMTP host to connect to. * @var string */ @@ -79,19 +114,27 @@ class Mail_smtp extends Mail { var $timeout = null; /** - * Whether to use VERP or not. If not a boolean, the string value - * will be used as the VERP separators. + * Turn on Net_SMTP debugging? * - * @var mixed boolean or string + * @var boolean $debug */ - var $verp = false; + var $debug = false; /** - * Turn on Net_SMTP debugging? + * Indicates whether or not the SMTP connection should persist over + * multiple calls to the send() method. * - * @var boolean $debug + * @var boolean */ - var $debug = false; + var $persist = false; + + /** + * Use SMTP command pipelining (specified in RFC 2920) if the SMTP server + * supports it. This speeds up delivery over high-latency connections. By + * default, use the default value supplied by Net_SMTP. + * @var bool + */ + var $pipelining; /** * Constructor. @@ -106,7 +149,10 @@ class Mail_smtp extends Mail { * localhost The local hostname / domain. Defaults to localhost. * timeout The SMTP connection timeout. Defaults to none. * verp Whether to use VERP or not. Defaults to false. + * DEPRECATED as of 1.2.0 (use setMailParams()). * debug Activate SMTP debug mode? Defaults to false. + * persist Should the SMTP connection persist? + * pipelining Use SMTP command pipelining * * If a parameter is present in the $params array, it replaces the * default. @@ -124,8 +170,25 @@ class Mail_smtp extends Mail { if (isset($params['password'])) $this->password = $params['password']; if (isset($params['localhost'])) $this->localhost = $params['localhost']; if (isset($params['timeout'])) $this->timeout = $params['timeout']; - if (isset($params['verp'])) $this->verp = $params['verp']; - if (isset($params['debug'])) $this->debug = (boolean)$params['debug']; + if (isset($params['debug'])) $this->debug = (bool)$params['debug']; + if (isset($params['persist'])) $this->persist = (bool)$params['persist']; + if (isset($params['pipelining'])) $this->pipelining = (bool)$params['pipelining']; + + // Deprecated options + if (isset($params['verp'])) { + $this->addServiceExtensionParameter('XVERP', is_bool($params['verp']) ? null : $params['verp']); + } + + register_shutdown_function(array(&$this, '_Mail_smtp')); + } + + /** + * Destructor implementation to ensure that we disconnect from any + * potentially-alive persistent SMTP connections. + */ + function _Mail_smtp() + { + $this->disconnect(); } /** @@ -145,7 +208,7 @@ class Mail_smtp extends Mail { * test'. * * @param string $body The full text of the message body, including any - * Mime parts, etc. + * MIME parts, etc. * * @return mixed Returns true on success, or a PEAR_Error * containing a descriptive error message on @@ -154,35 +217,24 @@ class Mail_smtp extends Mail { */ function send($recipients, $headers, $body) { - include_once 'Net/SMTP.php'; - - if (!($smtp = &new Net_SMTP($this->host, $this->port, $this->localhost))) { - return PEAR::raiseError('unable to instantiate Net_SMTP object'); - } - - if ($this->debug) { - $smtp->setDebug(true); + /* If we don't already have an SMTP object, create one. */ + $result = &$this->getSMTPObject(); + if (PEAR::isError($result)) { + return $result; } - if (PEAR::isError($smtp->connect($this->timeout))) { - return PEAR::raiseError('unable to connect to smtp server ' . - $this->host . ':' . $this->port); + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); } - if ($this->auth) { - $method = is_string($this->auth) ? $this->auth : ''; - - if (PEAR::isError($smtp->auth($this->username, $this->password, - $method))) { - return PEAR::raiseError('unable to authenticate to smtp server'); - } - } + $this->_sanitizeHeaders($headers); $headerElements = $this->prepareHeaders($headers); - if (PEAR::isError($headerElements)) { + if (is_a($headerElements, 'PEAR_Error')) { + $this->_smtp->rset(); return $headerElements; } - list($from, $text_headers) = $headerElements; + list($from, $textHeaders) = $headerElements; /* Since few MTAs are going to allow this header to be forged * unless it's in the MAIL FROM: exchange, we'll use @@ -192,32 +244,164 @@ class Mail_smtp extends Mail { } if (!isset($from)) { - return PEAR::raiseError('No from address given'); + $this->_smtp->rset(); + return PEAR::raiseError('No From: address has been provided', + PEAR_MAIL_SMTP_ERROR_FROM); } - $args['verp'] = $this->verp; - if (PEAR::isError($smtp->mailFrom($from, $args))) { - return PEAR::raiseError('unable to set sender to [' . $from . ']'); + $params = null; + if (!empty($this->_extparams)) { + foreach ($this->_extparams as $key => $val) { + $params .= ' ' . $key . (is_null($val) ? '' : '=' . $val); + } + } + if (PEAR::isError($res = $this->_smtp->mailFrom($from, ltrim($params)))) { + $error = $this->_error("Failed to set sender: $from", $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_SENDER); } $recipients = $this->parseRecipients($recipients); - if (PEAR::isError($recipients)) { + if (is_a($recipients, 'PEAR_Error')) { + $this->_smtp->rset(); return $recipients; } foreach ($recipients as $recipient) { - if (PEAR::isError($res = $smtp->rcptTo($recipient))) { - return PEAR::raiseError('unable to add recipient [' . - $recipient . ']: ' . $res->getMessage()); + $res = $this->_smtp->rcptTo($recipient); + if (is_a($res, 'PEAR_Error')) { + $error = $this->_error("Failed to add recipient: $recipient", $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_RECIPIENT); } } - if (PEAR::isError($smtp->data($text_headers . "\r\n" . $body))) { - return PEAR::raiseError('unable to send data'); + /* Send the message's headers and the body as SMTP data. */ + $res = $this->_smtp->data($textHeaders . "\r\n\r\n" . $body); + if (is_a($res, 'PEAR_Error')) { + $error = $this->_error('Failed to send data', $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_DATA); + } + + /* If persistent connections are disabled, destroy our SMTP object. */ + if ($this->persist === false) { + $this->disconnect(); } - $smtp->disconnect(); return true; } + /** + * Connect to the SMTP server by instantiating a Net_SMTP object. + * + * @return mixed Returns a reference to the Net_SMTP object on success, or + * a PEAR_Error containing a descriptive error message on + * failure. + * + * @since 1.2.0 + * @access public + */ + function &getSMTPObject() + { + if (is_object($this->_smtp) !== false) { + return $this->_smtp; + } + + include_once 'Net/SMTP.php'; + $this->_smtp = &new Net_SMTP($this->host, + $this->port, + $this->localhost); + + /* If we still don't have an SMTP object at this point, fail. */ + if (is_object($this->_smtp) === false) { + return PEAR::raiseError('Failed to create a Net_SMTP object', + PEAR_MAIL_SMTP_ERROR_CREATE); + } + + /* Configure the SMTP connection. */ + if ($this->debug) { + $this->_smtp->setDebug(true); + } + + /* Attempt to connect to the configured SMTP server. */ + if (PEAR::isError($res = $this->_smtp->connect($this->timeout))) { + $error = $this->_error('Failed to connect to ' . + $this->host . ':' . $this->port, + $res); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_CONNECT); + } + + /* Attempt to authenticate if authentication has been enabled. */ + if ($this->auth) { + $method = is_string($this->auth) ? $this->auth : ''; + + if (PEAR::isError($res = $this->_smtp->auth($this->username, + $this->password, + $method))) { + $error = $this->_error("$method authentication failure", + $res); + $this->_smtp->rset(); + return PEAR::raiseError($error, PEAR_MAIL_SMTP_ERROR_AUTH); + } + } + + return $this->_smtp; + } + + /** + * Add parameter associated with a SMTP service extension. + * + * @param string Extension keyword. + * @param string Any value the keyword needs. + * + * @since 1.2.0 + * @access public + */ + function addServiceExtensionParameter($keyword, $value = null) + { + $this->_extparams[$keyword] = $value; + } + + /** + * Disconnect and destroy the current SMTP connection. + * + * @return boolean True if the SMTP connection no longer exists. + * + * @since 1.1.9 + * @access public + */ + function disconnect() + { + /* If we have an SMTP object, disconnect and destroy it. */ + if (is_object($this->_smtp) && $this->_smtp->disconnect()) { + $this->_smtp = null; + } + + /* We are disconnected if we no longer have an SMTP object. */ + return ($this->_smtp === null); + } + + /** + * Build a standardized string describing the current SMTP error. + * + * @param string $text Custom string describing the error context. + * @param object $error Reference to the current PEAR_Error object. + * + * @return string A string describing the current SMTP error. + * + * @since 1.1.7 + * @access private + */ + function _error($text, &$error) + { + /* Split the SMTP response into a code and a response string. */ + list($code, $response) = $this->_smtp->getResponse(); + + /* Build our standardized error string. */ + return $text + . ' [SMTP: ' . $error->getMessage() + . " (code: $code, response: $response)]"; + } + } diff --git a/vendor/pear/Mail/smtpmx.php b/vendor/pear/Mail/smtpmx.php new file mode 100644 index 0000000..9d2dccf --- /dev/null +++ b/vendor/pear/Mail/smtpmx.php @@ -0,0 +1,478 @@ + + * @copyright 1997-2005 The PHP Group + * @license http://www.php.net/license/3_0.txt PHP License 3.0 + * @version CVS: $Id: smtpmx.php,v 1.2 2007/10/06 17:00:00 chagenbu Exp $ + * @see Mail + */ + +require_once 'Net/SMTP.php'; + +/** + * SMTP MX implementation of the PEAR Mail interface. Requires the Net_SMTP class. + * + * + * @access public + * @author gERD Schaufelberger + * @package Mail + * @version $Revision: 1.2 $ + */ +class Mail_smtpmx extends Mail { + + /** + * SMTP connection object. + * + * @var object + * @access private + */ + var $_smtp = null; + + /** + * The port the SMTP server is on. + * @var integer + * @see getservicebyname() + */ + var $port = 25; + + /** + * Hostname or domain that will be sent to the remote SMTP server in the + * HELO / EHLO message. + * + * @var string + * @see posix_uname() + */ + var $mailname = 'localhost'; + + /** + * SMTP connection timeout value. NULL indicates no timeout. + * + * @var integer + */ + var $timeout = 10; + + /** + * use either PEAR:Net_DNS or getmxrr + * + * @var boolean + */ + var $withNetDns = true; + + /** + * PEAR:Net_DNS_Resolver + * + * @var object + */ + var $resolver; + + /** + * Whether to use VERP or not. If not a boolean, the string value + * will be used as the VERP separators. + * + * @var mixed boolean or string + */ + var $verp = false; + + /** + * Whether to use VRFY or not. + * + * @var boolean $vrfy + */ + var $vrfy = false; + + /** + * Switch to test mode - don't send emails for real + * + * @var boolean $debug + */ + var $test = false; + + /** + * Turn on Net_SMTP debugging? + * + * @var boolean $peardebug + */ + var $debug = false; + + /** + * internal error codes + * + * translate internal error identifier to PEAR-Error codes and human + * readable messages. + * + * @var boolean $debug + * @todo as I need unique error-codes to identify what exactly went wrond + * I did not use intergers as it should be. Instead I added a "namespace" + * for each code. This avoids conflicts with error codes from different + * classes. How can I use unique error codes and stay conform with PEAR? + */ + var $errorCode = array( + 'not_connected' => array( + 'code' => 1, + 'msg' => 'Could not connect to any mail server ({HOST}) at port {PORT} to send mail to {RCPT}.' + ), + 'failed_vrfy_rcpt' => array( + 'code' => 2, + 'msg' => 'Recipient "{RCPT}" could not be veryfied.' + ), + 'failed_set_from' => array( + 'code' => 3, + 'msg' => 'Failed to set sender: {FROM}.' + ), + 'failed_set_rcpt' => array( + 'code' => 4, + 'msg' => 'Failed to set recipient: {RCPT}.' + ), + 'failed_send_data' => array( + 'code' => 5, + 'msg' => 'Failed to send mail to: {RCPT}.' + ), + 'no_from' => array( + 'code' => 5, + 'msg' => 'No from address has be provided.' + ), + 'send_data' => array( + 'code' => 7, + 'msg' => 'Failed to create Net_SMTP object.' + ), + 'no_mx' => array( + 'code' => 8, + 'msg' => 'No MX-record for {RCPT} found.' + ), + 'no_resolver' => array( + 'code' => 9, + 'msg' => 'Could not start resolver! Install PEAR:Net_DNS or switch off "netdns"' + ), + 'failed_rset' => array( + 'code' => 10, + 'msg' => 'RSET command failed, SMTP-connection corrupt.' + ), + ); + + /** + * Constructor. + * + * Instantiates a new Mail_smtp:: object based on the parameters + * passed in. It looks for the following parameters: + * mailname The name of the local mail system (a valid hostname which matches the reverse lookup) + * port smtp-port - the default comes from getservicebyname() and should work fine + * timeout The SMTP connection timeout. Defaults to 30 seconds. + * vrfy Whether to use VRFY or not. Defaults to false. + * verp Whether to use VERP or not. Defaults to false. + * test Activate test mode? Defaults to false. + * debug Activate SMTP and Net_DNS debug mode? Defaults to false. + * netdns whether to use PEAR:Net_DNS or the PHP build in function getmxrr, default is true + * + * If a parameter is present in the $params array, it replaces the + * default. + * + * @access public + * @param array Hash containing any parameters different from the + * defaults. + * @see _Mail_smtpmx() + */ + function __construct($params) + { + if (isset($params['mailname'])) { + $this->mailname = $params['mailname']; + } else { + // try to find a valid mailname + if (function_exists('posix_uname')) { + $uname = posix_uname(); + $this->mailname = $uname['nodename']; + } + } + + // port number + if (isset($params['port'])) { + $this->_port = $params['port']; + } else { + $this->_port = getservbyname('smtp', 'tcp'); + } + + if (isset($params['timeout'])) $this->timeout = $params['timeout']; + if (isset($params['verp'])) $this->verp = $params['verp']; + if (isset($params['test'])) $this->test = $params['test']; + if (isset($params['peardebug'])) $this->test = $params['peardebug']; + if (isset($params['netdns'])) $this->withNetDns = $params['netdns']; + } + + /** + * Constructor wrapper for PHP4 + * + * @access public + * @param array Hash containing any parameters different from the defaults + * @see __construct() + */ + function Mail_smtpmx($params) + { + $this->__construct($params); + register_shutdown_function(array(&$this, '__destruct')); + } + + /** + * Destructor implementation to ensure that we disconnect from any + * potentially-alive persistent SMTP connections. + */ + function __destruct() + { + if (is_object($this->_smtp)) { + $this->_smtp->disconnect(); + $this->_smtp = null; + } + } + + /** + * Implements Mail::send() function using SMTP direct delivery + * + * @access public + * @param mixed $recipients in RFC822 style or array + * @param array $headers The array of headers to send with the mail. + * @param string $body The full text of the message body, + * @return mixed Returns true on success, or a PEAR_Error + */ + function send($recipients, $headers, $body) + { + if (!is_array($headers)) { + return PEAR::raiseError('$headers must be an array'); + } + + $result = $this->_sanitizeHeaders($headers); + if (is_a($result, 'PEAR_Error')) { + return $result; + } + + // Prepare headers + $headerElements = $this->prepareHeaders($headers); + if (is_a($headerElements, 'PEAR_Error')) { + return $headerElements; + } + list($from, $textHeaders) = $headerElements; + + // use 'Return-Path' if possible + if (!empty($headers['Return-Path'])) { + $from = $headers['Return-Path']; + } + if (!isset($from)) { + return $this->_raiseError('no_from'); + } + + // Prepare recipients + $recipients = $this->parseRecipients($recipients); + if (is_a($recipients, 'PEAR_Error')) { + return $recipients; + } + + foreach ($recipients as $rcpt) { + list($user, $host) = explode('@', $rcpt); + + $mx = $this->_getMx($host); + if (is_a($mx, 'PEAR_Error')) { + return $mx; + } + + if (empty($mx)) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('no_mx', $info); + } + + $connected = false; + foreach ($mx as $mserver => $mpriority) { + $this->_smtp = new Net_SMTP($mserver, $this->port, $this->mailname); + + // configure the SMTP connection. + if ($this->debug) { + $this->_smtp->setDebug(true); + } + + // attempt to connect to the configured SMTP server. + $res = $this->_smtp->connect($this->timeout); + if (is_a($res, 'PEAR_Error')) { + $this->_smtp = null; + continue; + } + + // connection established + if ($res) { + $connected = true; + break; + } + } + + if (!$connected) { + $info = array( + 'host' => implode(', ', array_keys($mx)), + 'port' => $this->port, + 'rcpt' => $rcpt, + ); + return $this->_raiseError('not_connected', $info); + } + + // Verify recipient + if ($this->vrfy) { + $res = $this->_smtp->vrfy($rcpt); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_vrfy_rcpt', $info); + } + } + + // mail from: + $args['verp'] = $this->verp; + $res = $this->_smtp->mailFrom($from, $args); + if (is_a($res, 'PEAR_Error')) { + $info = array('from' => $from); + return $this->_raiseError('failed_set_from', $info); + } + + // rcpt to: + $res = $this->_smtp->rcptTo($rcpt); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_set_rcpt', $info); + } + + // Don't send anything in test mode + if ($this->test) { + $result = $this->_smtp->rset(); + $res = $this->_smtp->rset(); + if (is_a($res, 'PEAR_Error')) { + return $this->_raiseError('failed_rset'); + } + + $this->_smtp->disconnect(); + $this->_smtp = null; + return true; + } + + // Send data + $res = $this->_smtp->data("$textHeaders\r\n$body"); + if (is_a($res, 'PEAR_Error')) { + $info = array('rcpt' => $rcpt); + return $this->_raiseError('failed_send_data', $info); + } + + $this->_smtp->disconnect(); + $this->_smtp = null; + } + + return true; + } + + /** + * Recieve mx rexords for a spciefied host + * + * The MX records + * + * @access private + * @param string $host mail host + * @return mixed sorted + */ + function _getMx($host) + { + $mx = array(); + + if ($this->withNetDns) { + $res = $this->_loadNetDns(); + if (is_a($res, 'PEAR_Error')) { + return $res; + } + + $response = $this->resolver->query($host, 'MX'); + if (!$response) { + return false; + } + + foreach ($response->answer as $rr) { + if ($rr->type == 'MX') { + $mx[$rr->exchange] = $rr->preference; + } + } + } else { + $mxHost = array(); + $mxWeight = array(); + + if (!getmxrr($host, $mxHost, $mxWeight)) { + return false; + } + for ($i = 0; $i < count($mxHost); ++$i) { + $mx[$mxHost[$i]] = $mxWeight[$i]; + } + } + + asort($mx); + return $mx; + } + + /** + * initialize PEAR:Net_DNS_Resolver + * + * @access private + * @return boolean true on success + */ + function _loadNetDns() + { + if (is_object($this->resolver)) { + return true; + } + + if (!include_once 'Net/DNS.php') { + return $this->_raiseError('no_resolver'); + } + + $this->resolver = new Net_DNS_Resolver(); + if ($this->debug) { + $this->resolver->test = 1; + } + + return true; + } + + /** + * raise standardized error + * + * include additional information in error message + * + * @access private + * @param string $id maps error ids to codes and message + * @param array $info optional information in associative array + * @see _errorCode + */ + function _raiseError($id, $info = array()) + { + $code = $this->errorCode[$id]['code']; + $msg = $this->errorCode[$id]['msg']; + + // include info to messages + if (!empty($info)) { + $search = array(); + $replace = array(); + + foreach ($info as $key => $value) { + array_push($search, '{' . strtoupper($key) . '}'); + array_push($replace, $value); + } + + $msg = str_replace($search, $replace, $msg); + } + + return PEAR::raiseError($msg, $code); + } + +} diff --git a/vendor/pear/Net/SMTP.php b/vendor/pear/Net/SMTP.php index 71dcb5e..d632258 100644 --- a/vendor/pear/Net/SMTP.php +++ b/vendor/pear/Net/SMTP.php @@ -17,6 +17,8 @@ // | Jon Parise | // | Damian Alejandro Fernandez Sosa | // +----------------------------------------------------------------------+ +// +// $Id: SMTP.php,v 1.63 2008/06/10 05:39:12 jon Exp $ require_once 'PEAR.php'; require_once 'Net/Socket.php'; @@ -63,6 +65,26 @@ class Net_SMTP var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN'); /** + * Use SMTP command pipelining (specified in RFC 2920) if the SMTP + * server supports it. + * + * When pipeling is enabled, rcptTo(), mailFrom(), sendFrom(), + * somlFrom() and samlFrom() do not wait for a response from the + * SMTP server but return immediately. + * + * @var bool + * @access public + */ + var $pipelining = false; + + /** + * Number of pipelined commands. + * @var int + * @access private + */ + var $_pipelined_commands = 0; + + /** * Should debugging output be enabled? * @var boolean * @access private @@ -101,25 +123,39 @@ class Net_SMTP * Instantiates a new Net_SMTP object, overriding any defaults * with parameters that are passed in. * - * @param string The server to connect to. - * @param int The port to connect to. - * @param string The value to give when sending EHLO or HELO. + * If you have SSL support in PHP, you can connect to a server + * over SSL using an 'ssl://' prefix: + * + * // 465 is a common smtps port. + * $smtp = new Net_SMTP('ssl://mail.host.com', 465); + * $smtp->connect(); + * + * @param string $host The server to connect to. + * @param integer $port The port to connect to. + * @param string $localhost The value to give when sending EHLO or HELO. + * @param boolean $pipeling Use SMTP command pipelining * * @access public * @since 1.0 */ - function Net_SMTP($host = null, $port = null, $localhost = null) + function Net_SMTP($host = null, $port = null, $localhost = null, $pipelining = false) { - if (isset($host)) $this->host = $host; - if (isset($port)) $this->port = $port; - if (isset($localhost)) $this->localhost = $localhost; + if (isset($host)) { + $this->host = $host; + } + if (isset($port)) { + $this->port = $port; + } + if (isset($localhost)) { + $this->localhost = $localhost; + } + $this->pipelining = $pipelining; $this->_socket = new Net_Socket(); - /* - * Include the Auth_SASL package. If the package is not available, - * we disable the authentication methods that depend upon it. - */ + /* Include the Auth_SASL package. If the package is not + * available, we disable the authentication methods that + * depend upon it. */ if ((@include_once 'Auth/SASL.php') === false) { $pos = array_search('DIGEST-MD5', $this->auth_methods); unset($this->auth_methods[$pos]); @@ -158,17 +194,20 @@ class Net_SMTP } if (PEAR::isError($error = $this->_socket->write($data))) { - return new PEAR_Error('Failed to write to socket: ' . - $error->getMessage()); + return PEAR::raiseError('Failed to write to socket: ' . + $error->getMessage()); } return true; } /** - * Send a command to the server with an optional string of arguments. - * A carriage return / linefeed (CRLF) sequence will be appended to each - * command string before it is sent to the SMTP server. + * Send a command to the server with an optional string of + * arguments. A carriage return / linefeed (CRLF) sequence will + * be appended to each command string before it is sent to the + * SMTP server - an error will be thrown if the command string + * already contains any newline characters. Use _send() for + * commands that must contain newlines. * * @param string $command The SMTP command to send to the server. * @param string $args A string of optional arguments to append @@ -182,7 +221,11 @@ class Net_SMTP function _put($command, $args = '') { if (!empty($args)) { - return $this->_send($command . ' ' . $args . "\r\n"); + $command .= ' ' . $args; + } + + if (strcspn($command, "\r\n") !== strlen($command)) { + return PEAR::raiseError('Commands cannot contain newlines'); } return $this->_send($command . "\r\n"); @@ -195,6 +238,9 @@ class Net_SMTP * @param mixed $valid The set of valid response codes. These * may be specified as an array of integer * values or as a single integer value. + * @param bool $later Do not parse the response now, but wait + * until the last command in the pipelined + * command group * * @return mixed True if the server returned a valid response code or * a PEAR_Error object is an error condition is reached. @@ -204,55 +250,58 @@ class Net_SMTP * * @see getResponse */ - function _parseResponse($valid) + function _parseResponse($valid, $later = false) { $this->_code = -1; $this->_arguments = array(); - while ($line = $this->_socket->readLine()) { - if ($this->_debug) { - echo "DEBUG: Recv: $line\n"; - } + if ($later) { + $this->_pipelined_commands++; + return true; + } - /* If we receive an empty line, the connection has been closed. */ - if (empty($line)) { - $this->disconnect(); - return new PEAR_Error("Connection was unexpectedly closed"); - } + for ($i = 0; $i <= $this->_pipelined_commands; $i++) { + while ($line = $this->_socket->readLine()) { + if ($this->_debug) { + echo "DEBUG: Recv: $line\n"; + } + + /* If we receive an empty line, the connection has been closed. */ + if (empty($line)) { + $this->disconnect(); + return PEAR::raiseError('Connection was unexpectedly closed'); + } - /* Read the code and store the rest in the arguments array. */ - $code = substr($line, 0, 3); - $this->_arguments[] = trim(substr($line, 4)); + /* Read the code and store the rest in the arguments array. */ + $code = substr($line, 0, 3); + $this->_arguments[] = trim(substr($line, 4)); - /* Check the syntax of the response code. */ - if (is_numeric($code)) { - $this->_code = (int)$code; - } else { - $this->_code = -1; - break; - } + /* Check the syntax of the response code. */ + if (is_numeric($code)) { + $this->_code = (int)$code; + } else { + $this->_code = -1; + break; + } - /* If this is not a multiline response, we're done. */ - if (substr($line, 3, 1) != '-') { - break; + /* If this is not a multiline response, we're done. */ + if (substr($line, 3, 1) != '-') { + break; + } } } - /* Compare the server's response code with the valid code. */ + $this->_pipelined_commands = 0; + + /* Compare the server's response code with the valid code/codes. */ if (is_int($valid) && ($this->_code === $valid)) { return true; + } elseif (is_array($valid) && in_array($this->_code, $valid, true)) { + return true; } - /* If we were given an array of valid response codes, check each one. */ - if (is_array($valid)) { - foreach ($valid as $valid_code) { - if ($this->_code === $valid_code) { - return true; - } - } - } - - return new PEAR_Error("Invalid response code received from server"); + return PEAR::raiseError('Invalid response code received from server', + $this->_code); } /** @@ -288,8 +337,8 @@ class Net_SMTP $result = $this->_socket->connect($this->host, $this->port, $persistent, $timeout); if (PEAR::isError($result)) { - return new PEAR_Error('Failed to connect socket: ' . - $result->getMessage()); + return PEAR::raiseError('Failed to connect socket: ' . + $result->getMessage()); } if (PEAR::isError($error = $this->_parseResponse(220))) { @@ -319,8 +368,8 @@ class Net_SMTP return $error; } if (PEAR::isError($error = $this->_socket->disconnect())) { - return new PEAR_Error('Failed to disconnect socket: ' . - $error->getMessage()); + return PEAR::raiseError('Failed to disconnect socket: ' . + $error->getMessage()); } return true; @@ -353,7 +402,7 @@ class Net_SMTP return $error; } if (PEAR::isError($this->_parseResponse(250))) { - return new PEAR_Error('HELO was not accepted: ', $this->_code); + return PEAR::raiseError('HELO was not accepted: ', $this->_code); } return true; @@ -366,6 +415,10 @@ class Net_SMTP $this->_esmtp[$verb] = $arguments; } + if (!isset($this->_esmtp['PIPELINING'])) { + $this->pipelining = false; + } + return true; } @@ -389,7 +442,7 @@ class Net_SMTP } } - return new PEAR_Error('No supported authentication methods'); + return PEAR::raiseError('No supported authentication methods'); } /** @@ -408,13 +461,35 @@ class Net_SMTP function auth($uid, $pwd , $method = '') { if (empty($this->_esmtp['AUTH'])) { - return new PEAR_Error('SMTP server does no support authentication'); + if (version_compare(PHP_VERSION, '5.1.0', '>=')) { + if (!isset($this->_esmtp['STARTTLS'])) { + return PEAR::raiseError('SMTP server does not support authentication'); + } + if (PEAR::isError($result = $this->_put('STARTTLS'))) { + return $result; + } + if (PEAR::isError($result = $this->_parseResponse(220))) { + return $result; + } + if (PEAR::isError($result = $this->_socket->enableCrypto(true, STREAM_CRYPTO_METHOD_TLS_CLIENT))) { + return $result; + } elseif ($result !== true) { + return PEAR::raiseError('STARTTLS failed'); + } + + /* Send EHLO again to recieve the AUTH string from the + * SMTP server. */ + $this->_negotiate(); + if (empty($this->_esmtp['AUTH'])) { + return PEAR::raiseError('SMTP server does not support authentication'); + } + } else { + return PEAR::raiseError('SMTP server does not support authentication'); + } } - /* - * If no method has been specified, get the name of the best supported - * method advertised by the SMTP server. - */ + /* If no method has been specified, get the name of the best + * supported method advertised by the SMTP server. */ if (empty($method)) { if (PEAR::isError($method = $this->_getBestAuthMethod())) { /* Return the PEAR_Error object from _getBestAuthMethod(). */ @@ -423,26 +498,30 @@ class Net_SMTP } else { $method = strtoupper($method); if (!in_array($method, $this->auth_methods)) { - return new PEAR_Error("$method is not a supported authentication method"); + return PEAR::raiseError("$method is not a supported authentication method"); } } switch ($method) { - case 'DIGEST-MD5': - $result = $this->_authDigest_MD5($uid, $pwd); - break; - case 'CRAM-MD5': - $result = $this->_authCRAM_MD5($uid, $pwd); - break; - case 'LOGIN': - $result = $this->_authLogin($uid, $pwd); - break; - case 'PLAIN': - $result = $this->_authPlain($uid, $pwd); - break; - default: - $result = new PEAR_Error("$method is not a supported authentication method"); - break; + case 'DIGEST-MD5': + $result = $this->_authDigest_MD5($uid, $pwd); + break; + + case 'CRAM-MD5': + $result = $this->_authCRAM_MD5($uid, $pwd); + break; + + case 'LOGIN': + $result = $this->_authLogin($uid, $pwd); + break; + + case 'PLAIN': + $result = $this->_authPlain($uid, $pwd); + break; + + default: + $result = PEAR::raiseError("$method is not a supported authentication method"); + break; } /* If an error was encountered, return the PEAR_Error object. */ @@ -450,11 +529,6 @@ class Net_SMTP return $result; } - /* RFC-2554 requires us to re-negotiate ESMTP after an AUTH. */ - if (PEAR::isError($error = $this->_negotiate())) { - return $error; - } - return true; } @@ -496,11 +570,10 @@ class Net_SMTP return $error; } - /* - * We don't use the protocol's third step because SMTP doesn't allow - * subsequent authentication, so we just silently ignore it. - */ - if (PEAR::isError($error = $this->_put(' '))) { + /* We don't use the protocol's third step because SMTP doesn't + * allow subsequent authentication, so we just silently ignore + * it. */ + if (PEAR::isError($error = $this->_put(''))) { return $error; } /* 235: Authentication successful */ @@ -561,7 +634,7 @@ class Net_SMTP */ function _authLogin($uid, $pwd) { - if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) { + if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) { return $error; } /* 334: Continue authentication request */ @@ -655,21 +728,58 @@ class Net_SMTP } /** + * Return the list of SMTP service extensions advertised by the server. + * + * @return array The list of SMTP service extensions. + * @access public + * @since 1.3 + */ + function getServiceExtensions() + { + return $this->_esmtp; + } + + /** * Send the MAIL FROM: command. * - * @param string The sender (reverse path) to set. + * @param string $sender The sender (reverse path) to set. + * @param string $params String containing additional MAIL parameters, + * such as the NOTIFY flags defined by RFC 1891 + * or the VERP protocol. + * + * If $params is an array, only the 'verp' option + * is supported. If 'verp' is true, the XVERP + * parameter is appended to the MAIL command. If + * the 'verp' value is a string, the full + * XVERP=value parameter is appended. * * @return mixed Returns a PEAR_Error with an error message on any * kind of failure, or true on success. * @access public * @since 1.0 */ - function mailFrom($sender) + function mailFrom($sender, $params = null) { - if (PEAR::isError($error = $this->_put('MAIL', "FROM:<$sender>"))) { + $args = "FROM:<$sender>"; + + /* Support the deprecated array form of $params. */ + if (is_array($params) && isset($params['verp'])) { + /* XVERP */ + if ($params['verp'] === true) { + $args .= ' XVERP'; + + /* XVERP=something */ + } elseif (trim($params['verp'])) { + $args .= ' XVERP=' . $params['verp']; + } + } elseif (is_string($params)) { + $args .= ' ' . $params; + } + + if (PEAR::isError($error = $this->_put('MAIL', $args))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { return $error; } @@ -679,19 +789,27 @@ class Net_SMTP /** * Send the RCPT TO: command. * - * @param string The recipient (forward path) to add. + * @param string $recipient The recipient (forward path) to add. + * @param string $params String containing additional RCPT parameters, + * such as the NOTIFY flags defined by RFC 1891. * * @return mixed Returns a PEAR_Error with an error message on any * kind of failure, or true on success. + * * @access public * @since 1.0 */ - function rcptTo($recipient) + function rcptTo($recipient, $params = null) { - if (PEAR::isError($error = $this->_put('RCPT', "TO:<$recipient>"))) { + $args = "TO:<$recipient>"; + if (is_string($params)) { + $args .= ' ' . $params; + } + + if (PEAR::isError($error = $this->_put('RCPT', $args))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(array(250, 251)))) { + if (PEAR::isError($error = $this->_parseResponse(array(250, 251), $this->pipelining))) { return $error; } @@ -701,36 +819,32 @@ class Net_SMTP /** * Quote the data so that it meets SMTP standards. * - * This is provided as a separate public function to facilitate easier - * overloading for the cases where it is desirable to customize the - * quoting behavior. + * This is provided as a separate public function to facilitate + * easier overloading for the cases where it is desirable to + * customize the quoting behavior. * - * @param string The message text to quote. The string must be passed - * by reference, and the text will be modified in place. + * @param string $data The message text to quote. The string must be passed + * by reference, and the text will be modified in place. * * @access public * @since 1.2 */ function quotedata(&$data) { - /* - * Change Unix (\n) and Mac (\r) linefeeds into Internet-standard CRLF - * (\r\n) linefeeds. - */ - $data = preg_replace("/([^\r]{1})\n/", "\\1\r\n", $data); - $data = preg_replace("/\n\n/", "\n\r\n", $data); - - /* - * Because a single leading period (.) signifies an end to the data, - * legitimate leading periods need to be "doubled" (e.g. '..'). - */ - $data = preg_replace("/\n\./", "\n..", $data); + /* Change Unix (\n) and Mac (\r) linefeeds into + * Internet-standard CRLF (\r\n) linefeeds. */ + $data = preg_replace(array('/(?_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) { if (strlen($data) >= $this->_esmtp['SIZE']) { $this->disconnect(); - return new PEAR_Error('Message size excedes the server limit'); + return PEAR::raiseError('Message size excedes the server limit'); } } @@ -762,10 +875,10 @@ class Net_SMTP return $error; } - if (PEAR::isError($this->_send($data . "\r\n.\r\n"))) { - return new PEAR_Error('write to socket failed'); + if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) { + return $result; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { return $error; } @@ -787,7 +900,7 @@ class Net_SMTP if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { return $error; } @@ -826,7 +939,7 @@ class Net_SMTP if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { return $error; } @@ -865,7 +978,7 @@ class Net_SMTP if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { return $error; } @@ -902,7 +1015,7 @@ class Net_SMTP if (PEAR::isError($error = $this->_put('RSET'))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(250, $this->pipelining))) { return $error; } @@ -925,7 +1038,7 @@ class Net_SMTP if (PEAR::isError($error = $this->_put('VRFY', $string))) { return $error; } - if (PEAR::isError($error = $this->_parseResponse(250))) { + if (PEAR::isError($error = $this->_parseResponse(array(250, 252)))) { return $error; } @@ -965,6 +1078,5 @@ class Net_SMTP { return true; } -} -?> +} diff --git a/vendor/pear/Net/Socket.php b/vendor/pear/Net/Socket.php index d7a0495..73bb4dd 100644 --- a/vendor/pear/Net/Socket.php +++ b/vendor/pear/Net/Socket.php @@ -17,7 +17,7 @@ // | Chuck Hagenbuch | // +----------------------------------------------------------------------+ // -// $Id: Socket.php,v 1.31 2007/05/04 04:30:29 chagenbu Exp $ +// $Id: Socket.php,v 1.38 2008/02/15 18:24:17 chagenbu Exp $ require_once 'PEAR.php'; @@ -123,6 +123,7 @@ class Net_Socket extends PEAR { $openfunc = $this->persistent ? 'pfsockopen' : 'fsockopen'; $errno = 0; $errstr = ''; + $old_track_errors = @ini_set('track_errors', 1); if ($options && function_exists('stream_context_create')) { if ($this->timeout) { $timeout = $this->timeout; @@ -130,7 +131,15 @@ class Net_Socket extends PEAR { $timeout = 0; } $context = stream_context_create($options); - $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); + + // Since PHP 5 fsockopen doesn't allow context specification + if (function_exists('stream_socket_client')) { + $flags = $this->persistent ? STREAM_CLIENT_PERSISTENT : STREAM_CLIENT_CONNECT; + $addr = $this->addr . ':' . $this->port; + $fp = stream_socket_client($addr, $errno, $errstr, $timeout, $flags, $context); + } else { + $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $timeout, $context); + } } else { if ($this->timeout) { $fp = @$openfunc($this->addr, $this->port, $errno, $errstr, $this->timeout); @@ -140,9 +149,14 @@ class Net_Socket extends PEAR { } if (!$fp) { + if ($errno == 0 && isset($php_errormsg)) { + $errstr = $php_errormsg; + } + @ini_set('track_errors', $old_track_errors); return $this->raiseError($errstr, $errno); } + @ini_set('track_errors', $old_track_errors); $this->fp = $fp; return $this->setBlocking($this->blocking); @@ -152,7 +166,7 @@ class Net_Socket extends PEAR { * Disconnects from the peer, closes the socket. * * @access public - * @return mixed true on success or an error object otherwise + * @return mixed true on success or a PEAR_Error instance otherwise */ function disconnect() { @@ -184,7 +198,7 @@ class Net_Socket extends PEAR { * * @param boolean $mode True for blocking sockets, false for nonblocking. * @access public - * @return mixed true on success or an error object otherwise + * @return mixed true on success or a PEAR_Error instance otherwise */ function setBlocking($mode) { @@ -204,7 +218,7 @@ class Net_Socket extends PEAR { * @param integer $seconds Seconds. * @param integer $microseconds Microseconds. * @access public - * @return mixed true on success or an error object otherwise + * @return mixed true on success or a PEAR_Error instance otherwise */ function setTimeout($seconds, $microseconds) { @@ -229,7 +243,7 @@ class Net_Socket extends PEAR { return $this->raiseError('not connected'); } - $returned = stream_set_write_buffer($this->fp, $code); + $returned = stream_set_write_buffer($this->fp, $size); if ($returned == 0) { return true; } @@ -248,7 +262,7 @@ class Net_Socket extends PEAR { *

* * @access public - * @return mixed Array containing information about existing socket resource or an error object otherwise + * @return mixed Array containing information about existing socket resource or a PEAR_Error instance otherwise */ function getStatus() { @@ -303,7 +317,9 @@ class Net_Socket extends PEAR { * NULL means all at once. * * @access public - * @return mixed true on success or an error object otherwise + * @return mixed If the socket is not connected, returns an instance of PEAR_Error + * If the write succeeds, returns the number of bytes written + * If the write fails, returns false. */ function write($data, $blocksize = null) { @@ -312,7 +328,7 @@ class Net_Socket extends PEAR { } if (is_null($blocksize) && !OS_WINDOWS) { - return fwrite($this->fp, $data); + return @fwrite($this->fp, $data); } else { if (is_null($blocksize)) { $blocksize = 1024; @@ -432,10 +448,10 @@ class Net_Socket extends PEAR { } /** - * Reads an IP Address and returns it in a dot formated string + * Reads an IP Address and returns it in a dot formatted string * * @access public - * @return Dot formated string, or a PEAR_Error if + * @return Dot formatted string, or a PEAR_Error if * not connected. */ function readIPAddress() @@ -445,7 +461,7 @@ class Net_Socket extends PEAR { } $buf = @fread($this->fp, 4); - return sprintf("%s.%s.%s.%s", ord($buf[0]), ord($buf[1]), + return sprintf('%d.%d.%d.%d', ord($buf[0]), ord($buf[1]), ord($buf[2]), ord($buf[3])); } -- 2.11.4.GIT