Thomas
2013-10-14 566747af00ae413c942a7c6702e24c044af36f17
commit | author | age
4e17e6 1 <?php
ab6f80 2 /**
T 3  * The Mail_Mime class is used to create MIME E-mail messages
4  *
5  * The Mail_Mime class provides an OO interface to create MIME
6  * enabled email messages. This way you can create emails that
7  * contain plain-text bodies, HTML bodies, attachments, inline
8  * images and specific headers.
9  *
10  * Compatible with PHP versions 4 and 5
11  *
12  * LICENSE: This LICENSE is in the BSD license style.
13  * Copyright (c) 2002-2003, Richard Heyes <richard@phpguru.org>
14  * Copyright (c) 2003-2006, PEAR <pear-group@php.net>
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or
18  * without modification, are permitted provided that the following
19  * conditions are met:
20  *
21  * - Redistributions of source code must retain the above copyright
22  *   notice, this list of conditions and the following disclaimer.
23  * - Redistributions in binary form must reproduce the above copyright
24  *   notice, this list of conditions and the following disclaimer in the
25  *   documentation and/or other materials provided with the distribution.
26  * - Neither the name of the authors, nor the names of its contributors 
27  *   may be used to endorse or promote products derived from this 
28  *   software without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
31  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
34  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
35  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
36  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
37  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
38  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
39  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
40  * THE POSSIBILITY OF SUCH DAMAGE.
41  *
ee289d 42  * @category  Mail
A 43  * @package   Mail_Mime
44  * @author    Richard Heyes  <richard@phpguru.org>
45  * @author    Tomas V.V. Cox <cox@idecnet.com>
46  * @author    Cipriano Groenendal <cipri@php.net>
47  * @author    Sean Coates <sean@php.net>
091735 48  * @author    Aleksander Machniak <alec@php.net>
ee289d 49  * @copyright 2003-2006 PEAR <pear-group@php.net>
A 50  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
4c8bec 51  * @version   CVS: $Id$
ee289d 52  * @link      http://pear.php.net/package/Mail_mime
A 53  *
54  *            This class is based on HTML Mime Mail class from
55  *            Richard Heyes <richard@phpguru.org> which was based also
56  *            in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it>
57  *            and Sascha Schumann <sascha@schumann.cx>
ab6f80 58  */
4e17e6 59
T 60
61 /**
ab6f80 62  * require PEAR
4e17e6 63  *
ab6f80 64  * This package depends on PEAR to raise errors.
T 65  */
ee289d 66 require_once 'PEAR.php';
ab6f80 67
T 68 /**
69  * require Mail_mimePart
4e17e6 70  *
ab6f80 71  * Mail_mimePart contains the code required to
T 72  * create all the different parts a mail can
73  * consist of.
74  */
ee289d 75 require_once 'Mail/mimePart.php';
ab6f80 76
T 77
78 /**
79  * The Mail_Mime class provides an OO interface to create MIME
80  * enabled email messages. This way you can create emails that
81  * contain plain-text bodies, HTML bodies, attachments, inline
82  * images and specific headers.
83  *
ee289d 84  * @category  Mail
A 85  * @package   Mail_Mime
86  * @author    Richard Heyes  <richard@phpguru.org>
87  * @author    Tomas V.V. Cox <cox@idecnet.com>
88  * @author    Cipriano Groenendal <cipri@php.net>
89  * @author    Sean Coates <sean@php.net>
90  * @copyright 2003-2006 PEAR <pear-group@php.net>
91  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
4c8bec 92  * @version   Release: @package_version@
ee289d 93  * @link      http://pear.php.net/package/Mail_mime
4e17e6 94  */
T 95 class Mail_mime
96 {
97     /**
98      * Contains the plain text part of the email
ab6f80 99      *
4e17e6 100      * @var string
ab6f80 101      * @access private
4e17e6 102      */
T 103     var $_txtbody;
ab6f80 104
4e17e6 105     /**
T 106      * Contains the html part of the email
ab6f80 107      *
4e17e6 108      * @var string
ab6f80 109      * @access private
4e17e6 110      */
T 111     var $_htmlbody;
ab6f80 112
4e17e6 113     /**
T 114      * list of the attached images
ab6f80 115      *
4e17e6 116      * @var array
ab6f80 117      * @access private
4e17e6 118      */
T 119     var $_html_images = array();
ab6f80 120
4e17e6 121     /**
T 122      * list of the attachements
ab6f80 123      *
4e17e6 124      * @var array
ab6f80 125      * @access private
4e17e6 126      */
T 127     var $_parts = array();
ab6f80 128
4e17e6 129     /**
T 130      * Headers for the mail
ab6f80 131      *
4e17e6 132      * @var array
ab6f80 133      * @access private
4e17e6 134      */
T 135     var $_headers = array();
ab6f80 136
4e17e6 137     /**
091735 138      * Build parameters
ab6f80 139      *
091735 140      * @var array
ab6f80 141      * @access private
4e17e6 142      */
091735 143     var $_build_params = array(
A 144         // What encoding to use for the headers
145         // Options: quoted-printable or base64
146         'head_encoding' => 'quoted-printable',
147         // What encoding to use for plain text
148         // Options: 7bit, 8bit, base64, or quoted-printable
149         'text_encoding' => 'quoted-printable',
150         // What encoding to use for html
151         // Options: 7bit, 8bit, base64, or quoted-printable
152         'html_encoding' => 'quoted-printable',
153         // The character set to use for html
154         'html_charset'  => 'ISO-8859-1',
155         // The character set to use for text
156         'text_charset'  => 'ISO-8859-1',
157         // The character set to use for headers
158         'head_charset'  => 'ISO-8859-1',
159         // End-of-line sequence
160         'eol'           => "\r\n",
161         // Delay attachment files IO until building the message
162         'delay_file_io' => false
163     );
4e17e6 164
T 165     /**
091735 166      * Constructor function
ab6f80 167      *
091735 168      * @param mixed $params Build parameters that change the way the email
A 169      *                      is built. Should be an associative array.
170      *                      See $_build_params.
ee289d 171      *
ab6f80 172      * @return void
4e17e6 173      * @access public
T 174      */
091735 175     function Mail_mime($params = array())
4e17e6 176     {
091735 177         // Backward-compatible EOL setting
A 178         if (is_string($params)) {
179             $this->_build_params['eol'] = $params;
180         } else if (defined('MAIL_MIME_CRLF') && !isset($params['eol'])) {
181             $this->_build_params['eol'] = MAIL_MIME_CRLF;
182         }
183
184         // Update build parameters
185         if (!empty($params) && is_array($params)) {
186             while (list($key, $value) = each($params)) {
187                 $this->_build_params[$key] = $value;
188             }
189         }
4e17e6 190     }
T 191
192     /**
091735 193      * Set build parameter value
4e17e6 194      *
091735 195      * @param string $name  Parameter name
A 196      * @param string $value Parameter value
197      *
ee289d 198      * @return void
091735 199      * @access public
A 200      * @since 1.6.0
4e17e6 201      */
091735 202     function setParam($name, $value)
4e17e6 203     {
091735 204         $this->_build_params[$name] = $value;
4e17e6 205     }
T 206
091735 207     /**
A 208      * Get build parameter value
209      *
210      * @param string $name Parameter name
211      *
212      * @return mixed Parameter value
213      * @access public
214      * @since 1.6.0
215      */
216     function getParam($name)
217     {
218         return isset($this->_build_params[$name]) ? $this->_build_params[$name] : null;
219     }
ab6f80 220
4e17e6 221     /**
T 222      * Accessor function to set the body text. Body text is used if
223      * it's not an html mail being sent or else is used to fill the
224      * text/plain part that emails clients who don't support
225      * html should show.
226      *
ee289d 227      * @param string $data   Either a string or
091735 228      *                       the file name with the contents
ee289d 229      * @param bool   $isfile If true the first param should be treated
091735 230      *                       as a file name, else as a string (default)
ee289d 231      * @param bool   $append If true the text or file is appended to
091735 232      *                       the existing body, else the old body is
A 233      *                       overwritten
ee289d 234      *
091735 235      * @return mixed         True on success or PEAR_Error object
4e17e6 236      * @access public
T 237      */
238     function setTXTBody($data, $isfile = false, $append = false)
239     {
240         if (!$isfile) {
241             if (!$append) {
242                 $this->_txtbody = $data;
243             } else {
244                 $this->_txtbody .= $data;
245             }
246         } else {
247             $cont = $this->_file2str($data);
4fb36e 248             if ($this->_isError($cont)) {
4e17e6 249                 return $cont;
T 250             }
251             if (!$append) {
252                 $this->_txtbody = $cont;
253             } else {
254                 $this->_txtbody .= $cont;
255             }
256         }
4c8bec 257
4e17e6 258         return true;
T 259     }
260
261     /**
091735 262      * Get message text body
A 263      *
264      * @return string Text body
265      * @access public
266      * @since 1.6.0
267      */
268     function getTXTBody()
269     {
270         return $this->_txtbody;
271     }
272
273     /**
ab6f80 274      * Adds a html part to the mail.
4e17e6 275      *
091735 276      * @param string $data   Either a string or the file name with the
A 277      *                       contents
278      * @param bool   $isfile A flag that determines whether $data is a
279      *                       filename, or a string(false, default)
ee289d 280      *
091735 281      * @return bool          True on success
4e17e6 282      * @access public
T 283      */
284     function setHTMLBody($data, $isfile = false)
285     {
286         if (!$isfile) {
287             $this->_htmlbody = $data;
288         } else {
289             $cont = $this->_file2str($data);
4fb36e 290             if ($this->_isError($cont)) {
4e17e6 291                 return $cont;
T 292             }
293             $this->_htmlbody = $cont;
294         }
295
296         return true;
297     }
298
299     /**
091735 300      * Get message HTML body
A 301      *
302      * @return string HTML body
303      * @access public
304      * @since 1.6.0
305      */
306     function getHTMLBody()
307     {
308         return $this->_htmlbody;
309     }
310
311     /**
4e17e6 312      * Adds an image to the list of embedded images.
T 313      *
091735 314      * @param string $file       The image file name OR image data itself
A 315      * @param string $c_type     The content type
316      * @param string $name       The filename of the image.
317      *                           Only used if $file is the image data.
318      * @param bool   $isfile     Whether $file is a filename or not.
319      *                           Defaults to true
320      * @param string $content_id Desired Content-ID of MIME part
321      *                           Defaults to generated unique ID
ee289d 322      *
091735 323      * @return bool          True on success
4e17e6 324      * @access public
T 325      */
091735 326     function addHTMLImage($file,
A 327         $c_type='application/octet-stream',
328         $name = '',
329         $isfile = true,
330         $content_id = null
331     ) {
332         $bodyfile = null;
333
334         if ($isfile) {
335             // Don't load file into memory
336             if ($this->_build_params['delay_file_io']) {
337                 $filedata = null;
338                 $bodyfile = $file;
339             } else {
4fb36e 340                 if ($this->_isError($filedata = $this->_file2str($file))) {
091735 341                     return $filedata;
A 342                 }
343             }
344             $filename = ($name ? $name : $file);
4e17e6 345         } else {
091735 346             $filedata = $file;
856110 347             $filename = $name;
4e17e6 348         }
091735 349
A 350         if (!$content_id) {
4c8bec 351             $content_id = preg_replace('/[^0-9a-zA-Z]/', '', uniqid(time(), true));
4e17e6 352         }
091735 353
4e17e6 354         $this->_html_images[] = array(
091735 355             'body'      => $filedata,
A 356             'body_file' => $bodyfile,
357             'name'      => $filename,
358             'c_type'    => $c_type,
359             'cid'       => $content_id
360         );
361
4e17e6 362         return true;
T 363     }
364
365     /**
366      * Adds a file to the list of attachments.
367      *
ee289d 368      * @param string $file        The file name of the file to attach
53604a 369      *                            or the file contents itself
ee289d 370      * @param string $c_type      The content type
A 371      * @param string $name        The filename of the attachment
091735 372      *                            Only use if $file is the contents
53604a 373      * @param bool   $isfile      Whether $file is a filename or not. Defaults to true
A 374      * @param string $encoding    The type of encoding to use. Defaults to base64.
375      *                            Possible values: 7bit, 8bit, base64 or quoted-printable.
ee289d 376      * @param string $disposition The content-disposition of this file
091735 377      *                            Defaults to attachment.
A 378      *                            Possible values: attachment, inline.
53604a 379      * @param string $charset     The character set of attachment's content.
ee289d 380      * @param string $language    The language of the attachment
A 381      * @param string $location    The RFC 2557.4 location of the attachment
53604a 382      * @param string $n_encoding  Encoding of the attachment's name in Content-Type
091735 383      *                            By default filenames are encoded using RFC2231 method
A 384      *                            Here you can set RFC2047 encoding (quoted-printable
385      *                            or base64) instead
53604a 386      * @param string $f_encoding  Encoding of the attachment's filename
A 387      *                            in Content-Disposition header.
be5133 388      * @param string $description Content-Description header
53604a 389      * @param string $h_charset   The character set of the headers e.g. filename
A 390      *                            If not specified, $charset will be used
ba1fb0 391      * @param array  $add_headers Additional part headers. Array keys can be in form
AM 392      *                            of <header_name>:<parameter_name>
ee289d 393      *
091735 394      * @return mixed              True on success or PEAR_Error object
4e17e6 395      * @access public
T 396      */
ee289d 397     function addAttachment($file,
091735 398         $c_type      = 'application/octet-stream',
A 399         $name        = '',
400         $isfile      = true,
401         $encoding    = 'base64',
402         $disposition = 'attachment',
403         $charset     = '',
404         $language    = '',
405         $location    = '',
406         $n_encoding  = null,
be5133 407         $f_encoding  = null,
53604a 408         $description = '',
9843dc 409         $h_charset   = null,
AM 410         $add_headers = array()
091735 411     ) {
A 412         $bodyfile = null;
f7f934 413
091735 414         if ($isfile) {
A 415             // Don't load file into memory
416             if ($this->_build_params['delay_file_io']) {
417                 $filedata = null;
418                 $bodyfile = $file;
419             } else {
4fb36e 420                 if ($this->_isError($filedata = $this->_file2str($file))) {
091735 421                     return $filedata;
A 422                 }
423             }
4e17e6 424             // Force the name the user supplied, otherwise use $file
4fb36e 425             $filename = ($name ? $name : $this->_basename($file));
4e17e6 426         } else {
091735 427             $filedata = $file;
4e17e6 428             $filename = $name;
T 429         }
091735 430
ee289d 431         if (!strlen($filename)) {
A 432             $msg = "The supplied filename for the attachment can't be empty";
4c8bec 433             return $this->_raiseError($msg);
4e17e6 434         }
T 435
436         $this->_parts[] = array(
091735 437             'body'        => $filedata,
A 438             'body_file'   => $bodyfile,
439             'name'        => $filename,
440             'c_type'      => $c_type,
441             'charset'     => $charset,
53604a 442             'encoding'    => $encoding,
091735 443             'language'    => $language,
A 444             'location'    => $location,
445             'disposition' => $disposition,
be5133 446             'description' => $description,
9843dc 447             'add_headers' => $add_headers,
091735 448             'name_encoding'     => $n_encoding,
53604a 449             'filename_encoding' => $f_encoding,
A 450             'headers_charset'   => $h_charset,
091735 451         );
A 452
4e17e6 453         return true;
T 454     }
455
456     /**
457      * Get the contents of the given file name as string
458      *
091735 459      * @param string $file_name Path of file to process
ee289d 460      *
091735 461      * @return string           Contents of $file_name
4e17e6 462      * @access private
T 463      */
4fb36e 464     function _file2str($file_name)
4e17e6 465     {
091735 466         // Check state of file and raise an error properly
ee289d 467         if (!file_exists($file_name)) {
4c8bec 468             return $this->_raiseError('File not found: ' . $file_name);
ee289d 469         }
A 470         if (!is_file($file_name)) {
4c8bec 471             return $this->_raiseError('Not a regular file: ' . $file_name);
ee289d 472         }
4e17e6 473         if (!is_readable($file_name)) {
4c8bec 474             return $this->_raiseError('File is not readable: ' . $file_name);
4e17e6 475         }
f7f934 476
091735 477         // Temporarily reset magic_quotes_runtime and read file contents
ee289d 478         if ($magic_quote_setting = get_magic_quotes_runtime()) {
091735 479             @ini_set('magic_quotes_runtime', 0);
4e17e6 480         }
f7f934 481         $cont = file_get_contents($file_name);
ee289d 482         if ($magic_quote_setting) {
091735 483             @ini_set('magic_quotes_runtime', $magic_quote_setting);
15fee7 484         }
f7f934 485
4e17e6 486         return $cont;
T 487     }
488
489     /**
490      * Adds a text subpart to the mimePart object and
491      * returns it during the build process.
492      *
ee289d 493      * @param mixed  &$obj The object to add the part to, or
091735 494      *                     null if a new object is to be created.
ee289d 495      * @param string $text The text to add.
A 496      *
091735 497      * @return object      The text mimePart object
4e17e6 498      * @access private
T 499      */
4c8bec 500     function &_addTextPart(&$obj = null, $text = '')
4e17e6 501     {
T 502         $params['content_type'] = 'text/plain';
503         $params['encoding']     = $this->_build_params['text_encoding'];
504         $params['charset']      = $this->_build_params['text_charset'];
091735 505         $params['eol']          = $this->_build_params['eol'];
A 506
4e17e6 507         if (is_object($obj)) {
856110 508             $ret = $obj->addSubpart($text, $params);
4e17e6 509         } else {
856110 510             $ret = new Mail_mimePart($text, $params);
4e17e6 511         }
4c8bec 512
AM 513         return $ret;
4e17e6 514     }
T 515
516     /**
517      * Adds a html subpart to the mimePart object and
518      * returns it during the build process.
519      *
ee289d 520      * @param mixed &$obj The object to add the part to, or
091735 521      *                    null if a new object is to be created.
ee289d 522      *
091735 523      * @return object     The html mimePart object
4e17e6 524      * @access private
T 525      */
4c8bec 526     function &_addHtmlPart(&$obj = null)
4e17e6 527     {
T 528         $params['content_type'] = 'text/html';
529         $params['encoding']     = $this->_build_params['html_encoding'];
530         $params['charset']      = $this->_build_params['html_charset'];
091735 531         $params['eol']          = $this->_build_params['eol'];
A 532
4e17e6 533         if (is_object($obj)) {
856110 534             $ret = $obj->addSubpart($this->_htmlbody, $params);
4e17e6 535         } else {
856110 536             $ret = new Mail_mimePart($this->_htmlbody, $params);
4e17e6 537         }
4c8bec 538
AM 539         return $ret;
4e17e6 540     }
T 541
542     /**
543      * Creates a new mimePart object, using multipart/mixed as
544      * the initial content-type and returns it during the
545      * build process.
546      *
ee289d 547      * @return object The multipart/mixed mimePart object
4e17e6 548      * @access private
T 549      */
4c8bec 550     function &_addMixedPart()
4e17e6 551     {
T 552         $params['content_type'] = 'multipart/mixed';
091735 553         $params['eol']          = $this->_build_params['eol'];
f7f934 554
091735 555         // Create empty multipart/mixed Mail_mimePart object to return
856110 556         $ret = new Mail_mimePart('', $params);
S 557         return $ret;
4e17e6 558     }
T 559
560     /**
561      * Adds a multipart/alternative part to a mimePart
562      * object (or creates one), and returns it during
563      * the build process.
564      *
ee289d 565      * @param mixed &$obj The object to add the part to, or
091735 566      *                    null if a new object is to be created.
ee289d 567      *
091735 568      * @return object     The multipart/mixed mimePart object
4e17e6 569      * @access private
T 570      */
4c8bec 571     function &_addAlternativePart(&$obj = null)
4e17e6 572     {
T 573         $params['content_type'] = 'multipart/alternative';
091735 574         $params['eol']          = $this->_build_params['eol'];
A 575
4e17e6 576         if (is_object($obj)) {
4c8bec 577             $ret = $obj->addSubpart('', $params);
4e17e6 578         } else {
856110 579             $ret = new Mail_mimePart('', $params);
4e17e6 580         }
4c8bec 581
AM 582         return $ret;
4e17e6 583     }
T 584
585     /**
586      * Adds a multipart/related part to a mimePart
587      * object (or creates one), and returns it during
588      * the build process.
589      *
ee289d 590      * @param mixed &$obj The object to add the part to, or
091735 591      *                    null if a new object is to be created
ee289d 592      *
091735 593      * @return object     The multipart/mixed mimePart object
4e17e6 594      * @access private
T 595      */
4c8bec 596     function &_addRelatedPart(&$obj = null)
4e17e6 597     {
T 598         $params['content_type'] = 'multipart/related';
091735 599         $params['eol']          = $this->_build_params['eol'];
A 600
4e17e6 601         if (is_object($obj)) {
4c8bec 602             $ret = $obj->addSubpart('', $params);
4e17e6 603         } else {
856110 604             $ret = new Mail_mimePart('', $params);
4e17e6 605         }
4c8bec 606
AM 607         return $ret;
4e17e6 608     }
T 609
610     /**
611      * Adds an html image subpart to a mimePart object
612      * and returns it during the build process.
613      *
ee289d 614      * @param object &$obj  The mimePart to add the image to
A 615      * @param array  $value The image information
616      *
091735 617      * @return object       The image mimePart object
4e17e6 618      * @access private
T 619      */
4c8bec 620     function &_addHtmlImagePart(&$obj, $value)
4e17e6 621     {
ee289d 622         $params['content_type'] = $value['c_type'];
4e17e6 623         $params['encoding']     = 'base64';
T 624         $params['disposition']  = 'inline';
53604a 625         $params['filename']     = $value['name'];
4e17e6 626         $params['cid']          = $value['cid'];
091735 627         $params['body_file']    = $value['body_file'];
A 628         $params['eol']          = $this->_build_params['eol'];
f7f934 629
091735 630         if (!empty($value['name_encoding'])) {
A 631             $params['name_encoding'] = $value['name_encoding'];
f7f934 632         }
091735 633         if (!empty($value['filename_encoding'])) {
A 634             $params['filename_encoding'] = $value['filename_encoding'];
f7f934 635         }
A 636
856110 637         $ret = $obj->addSubpart($value['body'], $params);
S 638         return $ret;
4e17e6 639     }
T 640
641     /**
642      * Adds an attachment subpart to a mimePart object
643      * and returns it during the build process.
644      *
ee289d 645      * @param object &$obj  The mimePart to add the image to
A 646      * @param array  $value The attachment information
647      *
091735 648      * @return object       The image mimePart object
4e17e6 649      * @access private
T 650      */
4c8bec 651     function &_addAttachmentPart(&$obj, $value)
4e17e6 652     {
091735 653         $params['eol']          = $this->_build_params['eol'];
53604a 654         $params['filename']     = $value['name'];
091735 655         $params['encoding']     = $value['encoding'];
A 656         $params['content_type'] = $value['c_type'];
657         $params['body_file']    = $value['body_file'];
658         $params['disposition']  = isset($value['disposition']) ? 
659                                   $value['disposition'] : 'attachment';
53604a 660
A 661         // content charset
662         if (!empty($value['charset'])) {
a8435b 663             $params['charset'] = $value['charset'];
S 664         }
53604a 665         // headers charset (filename, description)
A 666         if (!empty($value['headers_charset'])) {
667             $params['headers_charset'] = $value['headers_charset'];
668         }
669         if (!empty($value['language'])) {
ee289d 670             $params['language'] = $value['language'];
A 671         }
53604a 672         if (!empty($value['location'])) {
ee289d 673             $params['location'] = $value['location'];
A 674         }
091735 675         if (!empty($value['name_encoding'])) {
A 676             $params['name_encoding'] = $value['name_encoding'];
f7f934 677         }
091735 678         if (!empty($value['filename_encoding'])) {
A 679             $params['filename_encoding'] = $value['filename_encoding'];
f7f934 680         }
be5133 681         if (!empty($value['description'])) {
A 682             $params['description'] = $value['description'];
9843dc 683         }
AM 684         if (is_array($value['add_headers'])) {
685             $params['headers'] = $value['add_headers'];
be5133 686         }
091735 687
856110 688         $ret = $obj->addSubpart($value['body'], $params);
S 689         return $ret;
4e17e6 690     }
856110 691
S 692     /**
693      * Returns the complete e-mail, ready to send using an alternative
694      * mail delivery method. Note that only the mailpart that is made
695      * with Mail_Mime is created. This means that,
696      * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF 
091735 697      * using the $headers parameter!
856110 698      * 
091735 699      * @param string $separation The separation between these two parts.
A 700      * @param array  $params     The Build parameters passed to the
4c8bec 701      *                           get() function. See get() for more info.
091735 702      * @param array  $headers    The extra headers that should be passed
4c8bec 703      *                           to the headers() method.
091735 704      *                           See that function for more info.
A 705      * @param bool   $overwrite  Overwrite the existing headers with new.
ee289d 706      *
091735 707      * @return mixed The complete e-mail or PEAR error object
856110 708      * @access public
S 709      */
091735 710     function getMessage($separation = null, $params = null, $headers = null,
A 711         $overwrite = false
712     ) {
ee289d 713         if ($separation === null) {
091735 714             $separation = $this->_build_params['eol'];
856110 715         }
091735 716
A 717         $body = $this->get($params);
718
4fb36e 719         if ($this->_isError($body)) {
091735 720             return $body;
A 721         }
722
4c8bec 723         return $this->txtHeaders($headers, $overwrite) . $separation . $body;
856110 724     }
S 725
091735 726     /**
90fe6c 727      * Returns the complete e-mail body, ready to send using an alternative
A 728      * mail delivery method.
729      * 
730      * @param array $params The Build parameters passed to the
4c8bec 731      *                      get() method. See get() for more info.
90fe6c 732      *
A 733      * @return mixed The e-mail body or PEAR error object
734      * @access public
735      * @since 1.6.0
736      */
737     function getMessageBody($params = null)
738     {
739         return $this->get($params, null, true);
740     }
741
742     /**
091735 743      * Writes (appends) the complete e-mail into file.
A 744      * 
745      * @param string $filename  Output file location
746      * @param array  $params    The Build parameters passed to the
4c8bec 747      *                          get() method. See get() for more info.
091735 748      * @param array  $headers   The extra headers that should be passed
4c8bec 749      *                          to the headers() function.
091735 750      *                          See that function for more info.
A 751      * @param bool   $overwrite Overwrite the existing headers with new.
752      *
753      * @return mixed True or PEAR error object
754      * @access public
90fe6c 755      * @since 1.6.0
091735 756      */
A 757     function saveMessage($filename, $params = null, $headers = null, $overwrite = false)
758     {
759         // Check state of file and raise an error properly
760         if (file_exists($filename) && !is_writable($filename)) {
4c8bec 761             return $this->_raiseError('File is not writable: ' . $filename);
091735 762         }
A 763
764         // Temporarily reset magic_quotes_runtime and read file contents
765         if ($magic_quote_setting = get_magic_quotes_runtime()) {
766             @ini_set('magic_quotes_runtime', 0);
767         }
768
769         if (!($fh = fopen($filename, 'ab'))) {
4c8bec 770             return $this->_raiseError('Unable to open file: ' . $filename);
091735 771         }
A 772
773         // Write message headers into file (skipping Content-* headers)
774         $head = $this->txtHeaders($headers, $overwrite, true);
775         if (fwrite($fh, $head) === false) {
4c8bec 776             return $this->_raiseError('Error writing to file: ' . $filename);
091735 777         }
A 778
779         fclose($fh);
780
781         if ($magic_quote_setting) {
782             @ini_set('magic_quotes_runtime', $magic_quote_setting);
783         }
784
785         // Write the rest of the message into file
786         $res = $this->get($params, $filename);
787
788         return $res ? $res : true;
789     }
4e17e6 790
T 791     /**
90fe6c 792      * Writes (appends) the complete e-mail body into file.
4c8bec 793      *
90fe6c 794      * @param string $filename Output file location
A 795      * @param array  $params   The Build parameters passed to the
4c8bec 796      *                         get() method. See get() for more info.
90fe6c 797      *
A 798      * @return mixed True or PEAR error object
799      * @access public
800      * @since 1.6.0
801      */
802     function saveMessageBody($filename, $params = null)
803     {
804         // Check state of file and raise an error properly
805         if (file_exists($filename) && !is_writable($filename)) {
4c8bec 806             return $this->_raiseError('File is not writable: ' . $filename);
90fe6c 807         }
A 808
809         // Temporarily reset magic_quotes_runtime and read file contents
810         if ($magic_quote_setting = get_magic_quotes_runtime()) {
811             @ini_set('magic_quotes_runtime', 0);
812         }
813
814         if (!($fh = fopen($filename, 'ab'))) {
4c8bec 815             return $this->_raiseError('Unable to open file: ' . $filename);
90fe6c 816         }
A 817
818         // Write the rest of the message into file
819         $res = $this->get($params, $filename, true);
820
821         return $res ? $res : true;
822     }
823
824     /**
4e17e6 825      * Builds the multipart message from the list ($this->_parts) and
T 826      * returns the mime content.
827      *
90fe6c 828      * @param array    $params    Build parameters that change the way the email
A 829      *                            is built. Should be associative. See $_build_params.
830      * @param resource $filename  Output file where to save the message instead of
831      *                            returning it
832      * @param boolean  $skip_head True if you want to return/save only the message
833      *                            without headers
ee289d 834      *
091735 835      * @return mixed The MIME message content string, null or PEAR error object
4e17e6 836      * @access public
T 837      */
4c8bec 838     function get($params = null, $filename = null, $skip_head = false)
4e17e6 839     {
091735 840         if (isset($params)) {
A 841             while (list($key, $value) = each($params)) {
4e17e6 842                 $this->_build_params[$key] = $value;
T 843             }
844         }
f7f934 845
091735 846         if (isset($this->_headers['From'])) {
A 847             // Bug #11381: Illegal characters in domain ID
8fc810 848             if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $this->_headers['From'], $matches)) {
ee289d 849                 $domainID = $matches[1];
091735 850             } else {
8fc810 851                 $domainID = '@localhost';
ee289d 852             }
091735 853             foreach ($this->_html_images as $i => $img) {
8fc810 854                 $cid = $this->_html_images[$i]['cid']; 
141eb8 855                 if (!preg_match('#'.preg_quote($domainID).'$#', $cid)) {
S 856                     $this->_html_images[$i]['cid'] = $cid . $domainID;
857                 }
ee289d 858             }
A 859         }
f7f934 860
091735 861         if (count($this->_html_images) && isset($this->_htmlbody)) {
856110 862             foreach ($this->_html_images as $key => $value) {
ee289d 863                 $regex   = array();
856110 864                 $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' .
S 865                             preg_quote($value['name'], '#') . '\3#';
866                 $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' .
867                             preg_quote($value['name'], '#') . '\1\s*\)#';
ee289d 868
A 869                 $rep   = array();
856110 870                 $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3';
ee289d 871                 $rep[] = 'url(\1cid:' . $value['cid'] . '\1)';
A 872
873                 $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody);
091735 874                 $this->_html_images[$key]['name']
A 875                     = $this->_basename($this->_html_images[$key]['name']);
4e17e6 876             }
T 877         }
878
be5133 879         $this->_checkParams();
A 880
4e17e6 881         $null        = null;
ee289d 882         $attachments = count($this->_parts)                 ? true : false;
A 883         $html_images = count($this->_html_images)           ? true : false;
884         $html        = strlen($this->_htmlbody)             ? true : false;
be5133 885         $text        = (!$html && strlen($this->_txtbody))  ? true : false;
4e17e6 886
T 887         switch (true) {
091735 888         case $text && !$attachments:
4e17e6 889             $message =& $this->_addTextPart($null, $this->_txtbody);
T 890             break;
891
091735 892         case !$text && !$html && $attachments:
4e17e6 893             $message =& $this->_addMixedPart();
T 894             for ($i = 0; $i < count($this->_parts); $i++) {
895                 $this->_addAttachmentPart($message, $this->_parts[$i]);
896             }
897             break;
898
091735 899         case $text && $attachments:
4e17e6 900             $message =& $this->_addMixedPart();
T 901             $this->_addTextPart($message, $this->_txtbody);
902             for ($i = 0; $i < count($this->_parts); $i++) {
903                 $this->_addAttachmentPart($message, $this->_parts[$i]);
904             }
905             break;
906
091735 907         case $html && !$attachments && !$html_images:
4e17e6 908             if (isset($this->_txtbody)) {
T 909                 $message =& $this->_addAlternativePart($null);
910                 $this->_addTextPart($message, $this->_txtbody);
911                 $this->_addHtmlPart($message);
912             } else {
913                 $message =& $this->_addHtmlPart($null);
914             }
915             break;
916
091735 917         case $html && !$attachments && $html_images:
A 918             // * Content-Type: multipart/alternative;
919             //    * text
920             //    * Content-Type: multipart/related;
921             //       * html
922             //       * image...
923             if (isset($this->_txtbody)) {
924                 $message =& $this->_addAlternativePart($null);
925                 $this->_addTextPart($message, $this->_txtbody);
926
927                 $ht =& $this->_addRelatedPart($message);
928                 $this->_addHtmlPart($ht);
929                 for ($i = 0; $i < count($this->_html_images); $i++) {
930                     $this->_addHtmlImagePart($ht, $this->_html_images[$i]);
931                 }
932             } else {
933                 // * Content-Type: multipart/related;
934                 //    * html
935                 //    * image...
936                 $message =& $this->_addRelatedPart($null);
937                 $this->_addHtmlPart($message);
938                 for ($i = 0; $i < count($this->_html_images); $i++) {
939                     $this->_addHtmlImagePart($message, $this->_html_images[$i]);
940                 }
941             }
942             /*
943             // #13444, #9725: the code below was a non-RFC compliant hack
944             // * Content-Type: multipart/related;
945             //    * Content-Type: multipart/alternative;
946             //        * text
947             //        * html
948             //    * image...
ee289d 949             $message =& $this->_addRelatedPart($null);
4e17e6 950             if (isset($this->_txtbody)) {
ee289d 951                 $alt =& $this->_addAlternativePart($message);
A 952                 $this->_addTextPart($alt, $this->_txtbody);
953                 $this->_addHtmlPart($alt);
4e17e6 954             } else {
ee289d 955                 $this->_addHtmlPart($message);
4e17e6 956             }
T 957             for ($i = 0; $i < count($this->_html_images); $i++) {
ee289d 958                 $this->_addHtmlImagePart($message, $this->_html_images[$i]);
4e17e6 959             }
091735 960             */
4e17e6 961             break;
T 962
091735 963         case $html && $attachments && !$html_images:
4e17e6 964             $message =& $this->_addMixedPart();
T 965             if (isset($this->_txtbody)) {
966                 $alt =& $this->_addAlternativePart($message);
967                 $this->_addTextPart($alt, $this->_txtbody);
968                 $this->_addHtmlPart($alt);
969             } else {
970                 $this->_addHtmlPart($message);
971             }
972             for ($i = 0; $i < count($this->_parts); $i++) {
973                 $this->_addAttachmentPart($message, $this->_parts[$i]);
974             }
975             break;
976
091735 977         case $html && $attachments && $html_images:
4e17e6 978             $message =& $this->_addMixedPart();
T 979             if (isset($this->_txtbody)) {
980                 $alt =& $this->_addAlternativePart($message);
981                 $this->_addTextPart($alt, $this->_txtbody);
982                 $rel =& $this->_addRelatedPart($alt);
983             } else {
984                 $rel =& $this->_addRelatedPart($message);
985             }
986             $this->_addHtmlPart($rel);
987             for ($i = 0; $i < count($this->_html_images); $i++) {
988                 $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
989             }
990             for ($i = 0; $i < count($this->_parts); $i++) {
991                 $this->_addAttachmentPart($message, $this->_parts[$i]);
992             }
993             break;
994
995         }
996
091735 997         if (!isset($message)) {
4c8bec 998             return null;
091735 999         }
8fc810 1000
091735 1001         // Use saved boundary
A 1002         if (!empty($this->_build_params['boundary'])) {
1003             $boundary = $this->_build_params['boundary'];
1004         } else {
1005             $boundary = null;
1006         }
f7f934 1007
091735 1008         // Write output to file
A 1009         if ($filename) {
1010             // Append mimePart message headers and body into file
90fe6c 1011             $headers = $message->encodeToFile($filename, $boundary, $skip_head);
4fb36e 1012             if ($this->_isError($headers)) {
091735 1013                 return $headers;
A 1014             }
1015             $this->_headers = array_merge($this->_headers, $headers);
4c8bec 1016             return null;
091735 1017         } else {
90fe6c 1018             $output = $message->encode($boundary, $skip_head);
4fb36e 1019             if ($this->_isError($output)) {
091735 1020                 return $output;
A 1021             }
1022             $this->_headers = array_merge($this->_headers, $output['headers']);
4c8bec 1023             return $output['body'];
4e17e6 1024         }
T 1025     }
1026
1027     /**
1028      * Returns an array with the headers needed to prepend to the email
1029      * (MIME-Version and Content-Type). Format of argument is:
1030      * $array['header-name'] = 'header-value';
1031      *
091735 1032      * @param array $xtra_headers Assoc array with any extra headers (optional)
6b0113 1033      *                            (Don't set Content-Type for multipart messages here!)
ee289d 1034      * @param bool  $overwrite    Overwrite already existing headers.
e62346 1035      * @param bool  $skip_content Don't return content headers: Content-Type,
091735 1036      *                            Content-Disposition and Content-Transfer-Encoding
ee289d 1037      * 
091735 1038      * @return array              Assoc array with the mime headers
4e17e6 1039      * @access public
T 1040      */
4c8bec 1041     function headers($xtra_headers = null, $overwrite = false, $skip_content = false)
4e17e6 1042     {
091735 1043         // Add mime version header
4e17e6 1044         $headers['MIME-Version'] = '1.0';
091735 1045
A 1046         // Content-Type and Content-Transfer-Encoding headers should already
1047         // be present if get() was called, but we'll re-set them to make sure
1048         // we got them when called before get() or something in the message
1049         // has been changed after get() [#14780]
1050         if (!$skip_content) {
1051             $headers += $this->_contentHeaders();
1052         }
1053
1054         if (!empty($xtra_headers)) {
4e17e6 1055             $headers = array_merge($headers, $xtra_headers);
T 1056         }
091735 1057
ee289d 1058         if ($overwrite) {
856110 1059             $this->_headers = array_merge($this->_headers, $headers);
ee289d 1060         } else {
856110 1061             $this->_headers = array_merge($headers, $this->_headers);
S 1062         }
4e17e6 1063
091735 1064         $headers = $this->_headers;
A 1065
1066         if ($skip_content) {
1067             unset($headers['Content-Type']);
1068             unset($headers['Content-Transfer-Encoding']);
1069             unset($headers['Content-Disposition']);
6b0113 1070         } else if (!empty($this->_build_params['ctype'])) {
A 1071             $headers['Content-Type'] = $this->_build_params['ctype'];
091735 1072         }
A 1073
1074         $encodedHeaders = $this->_encodeHeaders($headers);
856110 1075         return $encodedHeaders;
4e17e6 1076     }
T 1077
1078     /**
1079      * Get the text version of the headers
4fb36e 1080      * (usefull if you want to use the PHP mail() function)
4e17e6 1081      *
091735 1082      * @param array $xtra_headers Assoc array with any extra headers (optional)
6b0113 1083      *                            (Don't set Content-Type for multipart messages here!)
e62346 1084      * @param bool  $overwrite    Overwrite the existing headers with new.
A 1085      * @param bool  $skip_content Don't return content headers: Content-Type,
1086      *                            Content-Disposition and Content-Transfer-Encoding
ee289d 1087      *
091735 1088      * @return string             Plain text headers
4e17e6 1089      * @access public
T 1090      */
091735 1091     function txtHeaders($xtra_headers = null, $overwrite = false, $skip_content = false)
4e17e6 1092     {
091735 1093         $headers = $this->headers($xtra_headers, $overwrite, $skip_content);
A 1094
1095         // Place Received: headers at the beginning of the message
1096         // Spam detectors often flag messages with it after the Subject: as spam
1097         if (isset($headers['Received'])) {
1098             $received = $headers['Received'];
1099             unset($headers['Received']);
1100             $headers = array('Received' => $received) + $headers;
1101         }
f7f934 1102
4e17e6 1103         $ret = '';
091735 1104         $eol = $this->_build_params['eol'];
A 1105
4e17e6 1106         foreach ($headers as $key => $val) {
091735 1107             if (is_array($val)) {
A 1108                 foreach ($val as $value) {
1109                     $ret .= "$key: $value" . $eol;
1110                 }
1111             } else {
1112                 $ret .= "$key: $val" . $eol;
1113             }
4e17e6 1114         }
091735 1115
4e17e6 1116         return $ret;
T 1117     }
1118
1119     /**
6b0113 1120      * Sets message Content-Type header.
A 1121      * Use it to build messages with various content-types e.g. miltipart/raport
1122      * not supported by _contentHeaders() function.
1123      *
1124      * @param string $type   Type name
1125      * @param array  $params Hash array of header parameters
1126      *
1127      * @return void
1128      * @access public
1129      * @since 1.7.0
1130      */
1131     function setContentType($type, $params = array())
1132     {
1133         $header = $type;
1134
1135         $eol = !empty($this->_build_params['eol'])
1136             ? $this->_build_params['eol'] : "\r\n";
1137
1138         // add parameters
fe3a1d 1139         $token_regexp = '#([^\x21\x23-\x27\x2A\x2B\x2D'
A 1140             . '\x2E\x30-\x39\x41-\x5A\x5E-\x7E])#';
6b0113 1141         if (is_array($params)) {
A 1142             foreach ($params as $name => $value) {
1143                 if ($name == 'boundary') {
1144                     $this->_build_params['boundary'] = $value;
1145                 }
1146                 if (!preg_match($token_regexp, $value)) {
1147                     $header .= ";$eol $name=$value";
1148                 } else {
1149                     $value = addcslashes($value, '\\"');
1150                     $header .= ";$eol $name=\"$value\"";
1151                 }
1152             }
1153         }
1154
1155         // add required boundary parameter if not defined
1156         if (preg_match('/^multipart\//i', $type)) {
1157             if (empty($this->_build_params['boundary'])) {
8fc810 1158                 $this->_build_params['boundary'] = '=_' . md5(rand() . microtime());
6b0113 1159             }
A 1160
1161             $header .= ";$eol boundary=\"".$this->_build_params['boundary']."\"";
1162         }
1163
1164         $this->_build_params['ctype'] = $header;
1165     }
1166
1167     /**
4e17e6 1168      * Sets the Subject header
T 1169      *
ee289d 1170      * @param string $subject String to set the subject to.
A 1171      *
1172      * @return void
1173      * @access public
4e17e6 1174      */
T 1175     function setSubject($subject)
1176     {
1177         $this->_headers['Subject'] = $subject;
1178     }
1179
1180     /**
1181      * Set an email to the From (the sender) header
1182      *
ee289d 1183      * @param string $email The email address to use
A 1184      *
1185      * @return void
4e17e6 1186      * @access public
T 1187      */
1188     function setFrom($email)
1189     {
1190         $this->_headers['From'] = $email;
1191     }
1192
1193     /**
8fc810 1194      * Add an email to the To header
A 1195      * (multiple calls to this method are allowed)
1196      *
1197      * @param string $email The email direction to add
1198      *
1199      * @return void
1200      * @access public
1201      */
1202     function addTo($email)
1203     {
1204         if (isset($this->_headers['To'])) {
1205             $this->_headers['To'] .= ", $email";
1206         } else {
1207             $this->_headers['To'] = $email;
1208         }
1209     }
1210
1211     /**
4e17e6 1212      * Add an email to the Cc (carbon copy) header
T 1213      * (multiple calls to this method are allowed)
1214      *
ee289d 1215      * @param string $email The email direction to add
A 1216      *
1217      * @return void
4e17e6 1218      * @access public
T 1219      */
1220     function addCc($email)
1221     {
1222         if (isset($this->_headers['Cc'])) {
1223             $this->_headers['Cc'] .= ", $email";
1224         } else {
1225             $this->_headers['Cc'] = $email;
1226         }
1227     }
1228
1229     /**
1230      * Add an email to the Bcc (blank carbon copy) header
1231      * (multiple calls to this method are allowed)
1232      *
ee289d 1233      * @param string $email The email direction to add
A 1234      *
1235      * @return void
4e17e6 1236      * @access public
T 1237      */
1238     function addBcc($email)
1239     {
1240         if (isset($this->_headers['Bcc'])) {
1241             $this->_headers['Bcc'] .= ", $email";
1242         } else {
1243             $this->_headers['Bcc'] = $email;
1244         }
1245     }
1246
1247     /**
091735 1248      * Since the PHP send function requires you to specify
a8435b 1249      * recipients (To: header) separately from the other
S 1250      * headers, the To: header is not properly encoded.
1251      * To fix this, you can use this public method to 
1252      * encode your recipients before sending to the send
1253      * function
1254      *
ee289d 1255      * @param string $recipients A comma-delimited list of recipients
A 1256      *
091735 1257      * @return string            Encoded data
a8435b 1258      * @access public
S 1259      */
1260     function encodeRecipients($recipients)
1261     {
1262         $input = array("To" => $recipients);
1263         $retval = $this->_encodeHeaders($input);
1264         return $retval["To"] ;
1265     }
1266
1267     /**
091735 1268      * Encodes headers as per RFC2047
856110 1269      *
ee289d 1270      * @param array $input  The header data to encode
A 1271      * @param array $params Extra build parameters
1272      *
091735 1273      * @return array        Encoded data
856110 1274      * @access private
S 1275      */
ab6f80 1276     function _encodeHeaders($input, $params = array())
4e17e6 1277     {
ab6f80 1278         $build_params = $this->_build_params;
T 1279         while (list($key, $value) = each($params)) {
1280             $build_params[$key] = $value;
1281         }
f7f934 1282
4e17e6 1283         foreach ($input as $hdr_name => $hdr_value) {
091735 1284             if (is_array($hdr_value)) {
A 1285                 foreach ($hdr_value as $idx => $value) {
1286                     $input[$hdr_name][$idx] = $this->encodeHeader(
1287                         $hdr_name, $value,
1288                         $build_params['head_charset'], $build_params['head_encoding']
1289                     );
ab6f80 1290                 }
091735 1291             } else {
A 1292                 $input[$hdr_name] = $this->encodeHeader(
1293                     $hdr_name, $hdr_value,
1294                     $build_params['head_charset'], $build_params['head_encoding']
1295                 );
ee289d 1296             }
A 1297         }
091735 1298
4e17e6 1299         return $input;
T 1300     }
bb5ddf 1301
4e17e6 1302     /**
091735 1303      * Encodes a header as per RFC2047
4e17e6 1304      *
091735 1305      * @param string $name     The header name
A 1306      * @param string $value    The header data to encode
1307      * @param string $charset  Character set name
1308      * @param string $encoding Encoding name (base64 or quoted-printable)
ee289d 1309      *
091735 1310      * @return string          Encoded header data (without a name)
A 1311      * @access public
1312      * @since 1.5.3
1313      */
1314     function encodeHeader($name, $value, $charset, $encoding)
1315     {
9843dc 1316         $mime_part = new Mail_mimePart;
AM 1317         return $mime_part->encodeHeader(
be5133 1318             $name, $value, $charset, $encoding, $this->_build_params['eol']
091735 1319         );
4e17e6 1320     }
T 1321
09f19e 1322     /**
A 1323      * Get file's basename (locale independent) 
1324      *
091735 1325      * @param string $filename Filename
09f19e 1326      *
091735 1327      * @return string          Basename
09f19e 1328      * @access private
A 1329      */
1330     function _basename($filename)
1331     {
f7f934 1332         // basename() is not unicode safe and locale dependent
091735 1333         if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) {
f7f934 1334             return preg_replace('/^.*[\\\\\\/]/', '', $filename);
091735 1335         } else {
f7f934 1336             return preg_replace('/^.*[\/]/', '', $filename);
091735 1337         }
A 1338     }
1339
1340     /**
1341      * Get Content-Type and Content-Transfer-Encoding headers of the message
1342      *
1343      * @return array Headers array
1344      * @access private
1345      */
1346     function _contentHeaders()
1347     {
1348         $attachments = count($this->_parts)                 ? true : false;
1349         $html_images = count($this->_html_images)           ? true : false;
1350         $html        = strlen($this->_htmlbody)             ? true : false;
1351         $text        = (!$html && strlen($this->_txtbody))  ? true : false;
1352         $headers     = array();
1353
1354         // See get()
1355         switch (true) {
1356         case $text && !$attachments:
1357             $headers['Content-Type'] = 'text/plain';
1358             break;
1359
1360         case !$text && !$html && $attachments:
1361         case $text && $attachments:
1362         case $html && $attachments && !$html_images:
1363         case $html && $attachments && $html_images:
1364             $headers['Content-Type'] = 'multipart/mixed';
1365             break;
1366
1367         case $html && !$attachments && !$html_images && isset($this->_txtbody):
1368         case $html && !$attachments && $html_images && isset($this->_txtbody):
1369             $headers['Content-Type'] = 'multipart/alternative';
1370             break;
1371
1372         case $html && !$attachments && !$html_images && !isset($this->_txtbody):
1373             $headers['Content-Type'] = 'text/html';
1374             break;
1375
1376         case $html && !$attachments && $html_images && !isset($this->_txtbody):
1377             $headers['Content-Type'] = 'multipart/related';
1378             break;
1379
1380         default:
1381             return $headers;
1382         }
1383
be5133 1384         $this->_checkParams();
A 1385
091735 1386         $eol = !empty($this->_build_params['eol'])
A 1387             ? $this->_build_params['eol'] : "\r\n";
1388
1389         if ($headers['Content-Type'] == 'text/plain') {
1390             // single-part message: add charset and encoding
53604a 1391             $charset = 'charset=' . $this->_build_params['text_charset'];
A 1392             // place charset parameter in the same line, if possible
1393             // 26 = strlen("Content-Type: text/plain; ")
091735 1394             $headers['Content-Type']
53604a 1395                 .= (strlen($charset) + 26 <= 76) ? "; $charset" : ";$eol $charset";
091735 1396             $headers['Content-Transfer-Encoding']
A 1397                 = $this->_build_params['text_encoding'];
1398         } else if ($headers['Content-Type'] == 'text/html') {
1399             // single-part message: add charset and encoding
53604a 1400             $charset = 'charset=' . $this->_build_params['html_charset'];
A 1401             // place charset parameter in the same line, if possible
091735 1402             $headers['Content-Type']
53604a 1403                 .= (strlen($charset) + 25 <= 76) ? "; $charset" : ";$eol $charset";
091735 1404             $headers['Content-Transfer-Encoding']
A 1405                 = $this->_build_params['html_encoding'];
1406         } else {
53604a 1407             // multipart message: and boundary
091735 1408             if (!empty($this->_build_params['boundary'])) {
A 1409                 $boundary = $this->_build_params['boundary'];
1410             } else if (!empty($this->_headers['Content-Type'])
1411                 && preg_match('/boundary="([^"]+)"/', $this->_headers['Content-Type'], $m)
1412             ) {
1413                 $boundary = $m[1];
1414             } else {
1415                 $boundary = '=_' . md5(rand() . microtime());
1416             }
1417
1418             $this->_build_params['boundary'] = $boundary;
1419             $headers['Content-Type'] .= ";$eol boundary=\"$boundary\"";
1420         }
1421
1422         return $headers;
09f19e 1423     }
4e17e6 1424
be5133 1425     /**
A 1426      * Validate and set build parameters
1427      *
1428      * @return void
1429      * @access private
1430      */
1431     function _checkParams()
1432     {
1433         $encodings = array('7bit', '8bit', 'base64', 'quoted-printable');
1434
1435         $this->_build_params['text_encoding']
1436             = strtolower($this->_build_params['text_encoding']);
1437         $this->_build_params['html_encoding']
1438             = strtolower($this->_build_params['html_encoding']);
1439
1440         if (!in_array($this->_build_params['text_encoding'], $encodings)) {
1441             $this->_build_params['text_encoding'] = '7bit';
1442         }
1443         if (!in_array($this->_build_params['html_encoding'], $encodings)) {
1444             $this->_build_params['html_encoding'] = '7bit';
1445         }
1446
1447         // text body
1448         if ($this->_build_params['text_encoding'] == '7bit'
1449             && !preg_match('/ascii/i', $this->_build_params['text_charset'])
1450             && preg_match('/[^\x00-\x7F]/', $this->_txtbody)
1451         ) {
1452             $this->_build_params['text_encoding'] = 'quoted-printable';
1453         }
1454         // html body
1455         if ($this->_build_params['html_encoding'] == '7bit'
1456             && !preg_match('/ascii/i', $this->_build_params['html_charset'])
1457             && preg_match('/[^\x00-\x7F]/', $this->_htmlbody)
1458         ) {
1459             $this->_build_params['html_encoding'] = 'quoted-printable';
1460         }
1461     }
1462
4fb36e 1463     /**
4c8bec 1464      * PEAR::isError implementation
4fb36e 1465      *
TB 1466      * @param mixed $data Object
1467      *
1468      * @return bool True if object is an instance of PEAR_Error
1469      * @access private
1470      */
1471     function _isError($data)
1472     {
1473         // PEAR::isError() is not PHP 5.4 compatible (see Bug #19473)
1474         if (is_object($data) && is_a($data, 'PEAR_Error')) {
1475             return true;
1476         }
1477
1478         return false;
1479     }
1480
4c8bec 1481     /**
AM 1482      * PEAR::raiseError implementation
1483      *
1484      * @param $message A text error message
1485      *
1486      * @return PEAR_Error Instance of PEAR_Error
1487      * @access private
1488      */
1489     function _raiseError($message)
1490     {
1491         // PEAR::raiseError() is not PHP 5.4 compatible
1492         return new PEAR_Error($message);
1493     }
1494
4e17e6 1495 } // End of class