Changeset 0917356 in github


Ignore:
Timestamp:
Jan 20, 2010 4:26:47 AM (3 years ago)
Author:
alecpl <alec@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
Children:
ae9d583
Parents:
a7dba854
Message:
  • Fix incompatybility with suhosin.executor.disable_emodifier (#1486321)
  • Update Mail_Mime package
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    rd6584f7 r0917356  
    22=========================== 
    33 
     4- Fix incompatybility with suhosin.executor.disable_emodifier (#1486321) 
    45- Use PLAIN auth when CRAM fails and imap_auth_type='check' (#1486371) 
    56- Fix removal of <title> tag from HTML messages (#1486432) 
  • program/include/rcube_mail_mime.php

    r638fb8a r0917356  
    9696   
    9797  /** 
    98    * Creates a new mimePart object, using multipart/mixed as 
    99    * the initial content-type and returns it during the 
    100    * build process. 
    101    * 
    102    * @return object  The multipart/mixed mimePart object 
    103    * @access private 
    104    */ 
    105   function &_addMixedPart() 
    106   { 
    107     $params['content_type'] = $this->_headers['Content-Type'] ? $this->_headers['Content-Type'] : 'multipart/mixed'; 
    108     $ret = new Mail_mimePart('', $params); 
    109     return $ret; 
    110   } 
    111    
    112    
    113   /** 
    11498   * Encodes a header as per RFC2047 
    11599   * 
  • program/lib/Mail/mime.php

    rf7f9346 r0917356  
    4646 * @author    Cipriano Groenendal <cipri@php.net> 
    4747 * @author    Sean Coates <sean@php.net> 
     48 * @author    Aleksander Machniak <alec@php.net> 
    4849 * @copyright 2003-2006 PEAR <pear-group@php.net> 
    4950 * @license   http://www.opensource.org/licenses/bsd-license.php BSD License 
     
    143144 
    144145    /** 
     146     * Headers for the mail 
     147     * 
     148     * @var array 
     149     * @access private 
     150     */ 
     151    var $_headers = array(); 
     152 
     153    /** 
    145154     * Build parameters 
    146155     * 
     
    148157     * @access private 
    149158     */ 
    150     var $_build_params = array(); 
    151  
    152     /** 
    153      * Headers for the mail 
    154      * 
    155      * @var array 
    156      * @access private 
    157      */ 
    158     var $_headers = array(); 
    159  
    160     /** 
    161      * End Of Line sequence (for serialize) 
    162      * 
    163      * @var string 
    164      * @access private 
    165      */ 
    166     var $_eol; 
    167  
    168  
    169     /** 
    170      * Constructor function. 
    171      * 
    172      * @param string $crlf what type of linebreak to use. 
    173      *                     Defaults to "\r\n" 
     159    var $_build_params = array( 
     160        // What encoding to use for the headers 
     161        // Options: quoted-printable or base64 
     162        'head_encoding' => 'quoted-printable', 
     163        // What encoding to use for plain text 
     164        // Options: 7bit, 8bit, base64, or quoted-printable 
     165        'text_encoding' => 'quoted-printable', 
     166        // What encoding to use for html 
     167        // Options: 7bit, 8bit, base64, or quoted-printable 
     168        'html_encoding' => 'quoted-printable', 
     169        // The character set to use for html 
     170        'html_charset'  => 'ISO-8859-1', 
     171        // The character set to use for text 
     172        'text_charset'  => 'ISO-8859-1', 
     173        // The character set to use for headers 
     174        'head_charset'  => 'ISO-8859-1', 
     175        // End-of-line sequence 
     176        'eol'           => "\r\n", 
     177        // Delay attachment files IO until building the message 
     178        'delay_file_io' => false 
     179    ); 
     180 
     181    /** 
     182     * Constructor function 
     183     * 
     184     * @param mixed $params Build parameters that change the way the email 
     185     *                      is built. Should be an associative array. 
     186     *                      See $_build_params. 
    174187     * 
    175188     * @return void 
    176      * 
    177      * @access public 
    178      */ 
    179     function Mail_mime($crlf = "\r\n") 
    180     { 
    181         $this->_setEOL($crlf); 
    182         $this->_build_params = array( 
    183                                      'head_encoding' => 'quoted-printable', 
    184                                      'text_encoding' => '7bit', 
    185                                      'html_encoding' => 'quoted-printable', 
    186                                      '7bit_wrap'     => 998, 
    187                                      'html_charset'  => 'ISO-8859-1', 
    188                                      'text_charset'  => 'ISO-8859-1', 
    189                                      'head_charset'  => 'ISO-8859-1' 
    190                                     ); 
    191     } 
    192  
    193     /** 
    194      * wakeup function called by unserialize. It re-sets the EOL constant 
    195      * 
    196      * @access private 
     189     * @access public 
     190     */ 
     191    function Mail_mime($params = array()) 
     192    { 
     193        // Backward-compatible EOL setting 
     194        if (is_string($params)) { 
     195            $this->_build_params['eol'] = $params; 
     196        } else if (defined('MAIL_MIME_CRLF') && !isset($params['eol'])) { 
     197            $this->_build_params['eol'] = MAIL_MIME_CRLF; 
     198        } 
     199 
     200        // Update build parameters 
     201        if (!empty($params) && is_array($params)) { 
     202            while (list($key, $value) = each($params)) { 
     203                $this->_build_params[$key] = $value; 
     204            } 
     205        } 
     206    } 
     207 
     208    /** 
     209     * Set build parameter value 
     210     * 
     211     * @param string $name  Parameter name 
     212     * @param string $value Parameter value 
     213     * 
    197214     * @return void 
    198      */ 
    199     function __wakeup() 
    200     { 
    201         $this->_setEOL($this->_eol); 
    202     } 
    203  
     215     * @access public 
     216     * @since 1.6.0 
     217     */ 
     218    function setParam($name, $value) 
     219    { 
     220        $this->_build_params[$name] = $value; 
     221    } 
     222 
     223    /** 
     224     * Get build parameter value 
     225     * 
     226     * @param string $name Parameter name 
     227     * 
     228     * @return mixed Parameter value 
     229     * @access public 
     230     * @since 1.6.0 
     231     */ 
     232    function getParam($name) 
     233    { 
     234        return isset($this->_build_params[$name]) ? $this->_build_params[$name] : null; 
     235    } 
    204236 
    205237    /** 
     
    210242     * 
    211243     * @param string $data   Either a string or 
    212      *                        the file name with the contents 
     244     *                       the file name with the contents 
    213245     * @param bool   $isfile If true the first param should be treated 
    214      *                        as a file name, else as a string (default) 
     246     *                       as a file name, else as a string (default) 
    215247     * @param bool   $append If true the text or file is appended to 
    216      *                        the existing body, else the old body is 
    217      *                        overwritten 
    218      * 
    219      * @return mixed   true on success or PEAR_Error object 
     248     *                       the existing body, else the old body is 
     249     *                       overwritten 
     250     * 
     251     * @return mixed         True on success or PEAR_Error object 
    220252     * @access public 
    221253     */ 
     
    243275 
    244276    /** 
     277     * Get message text body 
     278     * 
     279     * @return string Text body 
     280     * @access public 
     281     * @since 1.6.0 
     282     */ 
     283    function getTXTBody() 
     284    { 
     285        return $this->_txtbody; 
     286    } 
     287 
     288    /** 
    245289     * Adds a html part to the mail. 
    246290     * 
    247      * @param string $data   either a string or the file name with the 
    248      *                        contents 
    249      * @param bool   $isfile a flag that determines whether $data is a 
    250      *                        filename, or a string(false, default) 
    251      * 
    252      * @return bool    true on success 
     291     * @param string $data   Either a string or the file name with the 
     292     *                       contents 
     293     * @param bool   $isfile A flag that determines whether $data is a 
     294     *                       filename, or a string(false, default) 
     295     * 
     296     * @return bool          True on success 
    253297     * @access public 
    254298     */ 
     
    269313 
    270314    /** 
     315     * Get message HTML body 
     316     * 
     317     * @return string HTML body 
     318     * @access public 
     319     * @since 1.6.0 
     320     */ 
     321    function getHTMLBody() 
     322    { 
     323        return $this->_htmlbody; 
     324    } 
     325 
     326    /** 
    271327     * Adds an image to the list of embedded images. 
    272328     * 
    273      * @param string $file   the image file name OR image data itself 
    274      * @param string $c_type the content type 
    275      * @param string $name   the filename of the image. 
    276      *                        Only used if $file is the image data. 
    277      * @param bool   $isfile whether $file is a filename or not. 
    278      *                        Defaults to true 
    279      * 
    280      * @return bool          true on success 
    281      * @access public 
    282      */ 
    283     function addHTMLImage($file, $c_type='application/octet-stream', 
    284                           $name = '', $isfile = true) 
    285     { 
    286         $filedata = ($isfile === true) ? $this->_file2str($file) 
    287                                            : $file; 
    288         if ($isfile === true) { 
    289             $filename = ($name == '' ? $file : $name); 
    290         } else { 
     329     * @param string $file       The image file name OR image data itself 
     330     * @param string $c_type     The content type 
     331     * @param string $name       The filename of the image. 
     332     *                           Only used if $file is the image data. 
     333     * @param bool   $isfile     Whether $file is a filename or not. 
     334     *                           Defaults to true 
     335     * @param string $content_id Desired Content-ID of MIME part 
     336     *                           Defaults to generated unique ID 
     337     * 
     338     * @return bool          True on success 
     339     * @access public 
     340     */ 
     341    function addHTMLImage($file, 
     342        $c_type='application/octet-stream', 
     343        $name = '', 
     344        $isfile = true, 
     345        $content_id = null 
     346    ) { 
     347        $bodyfile = null; 
     348 
     349        if ($isfile) { 
     350            // Don't load file into memory 
     351            if ($this->_build_params['delay_file_io']) { 
     352                $filedata = null; 
     353                $bodyfile = $file; 
     354            } else { 
     355                if (PEAR::isError($filedata = $this->_file2str($file))) { 
     356                    return $filedata; 
     357                } 
     358            } 
     359            $filename = ($name ? $name : $file); 
     360        } else { 
     361            $filedata = $file; 
    291362            $filename = $name; 
    292363        } 
    293         if (PEAR::isError($filedata)) { 
    294             return $filedata; 
    295         } 
     364 
     365        if (!$content_id) { 
     366            $content_id = md5(uniqid(time())); 
     367        } 
     368 
    296369        $this->_html_images[] = array( 
    297                                       'body'   => $filedata, 
    298                                       'name'   => $filename, 
    299                                       'c_type' => $c_type, 
    300                                       'cid'    => md5(uniqid(time())) 
    301                                      ); 
     370            'body'      => $filedata, 
     371            'body_file' => $bodyfile, 
     372            'name'      => $filename, 
     373            'c_type'    => $c_type, 
     374            'cid'       => $content_id 
     375        ); 
     376 
    302377        return true; 
    303378    } 
     
    307382     * 
    308383     * @param string $file        The file name of the file to attach 
    309      *                             OR the file contents itself 
     384     *                            OR the file contents itself 
    310385     * @param string $c_type      The content type 
    311386     * @param string $name        The filename of the attachment 
    312      *                             Only use if $file is the contents 
     387     *                            Only use if $file is the contents 
    313388     * @param bool   $isfile      Whether $file is a filename or not 
    314      *                             Defaults to true 
     389     *                            Defaults to true 
    315390     * @param string $encoding    The type of encoding to use. 
    316      *                             Defaults to base64. 
    317      *                             Possible values: 7bit, 8bit, base64,  
    318      *                             or quoted-printable. 
     391     *                            Defaults to base64. 
     392     *                            Possible values: 7bit, 8bit, base64,  
     393     *                            or quoted-printable. 
    319394     * @param string $disposition The content-disposition of this file 
    320      *                             Defaults to attachment. 
    321      *                             Possible values: attachment, inline. 
     395     *                            Defaults to attachment. 
     396     *                            Possible values: attachment, inline. 
    322397     * @param string $charset     The character set used in the filename 
    323      *                             of this attachment. 
     398     *                            of this attachment. 
    324399     * @param string $language    The language of the attachment 
    325400     * @param string $location    The RFC 2557.4 location of the attachment 
    326      * @param string $n_encoding      Use RFC 2047 for attachment name (Content-Type) encoding 
    327      * @param string $f_encoding      Use RFC 2047 for attachment filename (Content-Disposition) encoding 
    328      * 
    329      * @return mixed true on success or PEAR_Error object 
     401     * @param string $n_encoding  Encoding for attachment name (Content-Type) 
     402     *                            By default filenames are encoded using RFC2231 method 
     403     *                            Here you can set RFC2047 encoding (quoted-printable 
     404     *                            or base64) instead 
     405     * @param string $f_encoding  Encoding for attachment filename (Content-Disposition) 
     406     *                            See $n_encoding description 
     407     * 
     408     * @return mixed              True on success or PEAR_Error object 
    330409     * @access public 
    331410     */ 
    332411    function addAttachment($file, 
    333                            $c_type      = 'application/octet-stream', 
    334                            $name        = '', 
    335                            $isfile      = true, 
    336                            $encoding    = 'base64', 
    337                            $disposition = 'attachment', 
    338                            $charset     = '', 
    339                            $language    = '', 
    340                            $location    = '', 
    341                            $n_encoding  = NULL, 
    342                            $f_encoding  = NULL) 
    343     { 
    344         $filedata = ($isfile === true) ? $this->_file2str($file) : $file; 
    345  
    346         if (PEAR::isError($filedata)) { 
    347             return $filedata; 
    348         } 
    349  
    350         if ($isfile === true) { 
     412        $c_type      = 'application/octet-stream', 
     413        $name        = '', 
     414        $isfile      = true, 
     415        $encoding    = 'base64', 
     416        $disposition = 'attachment', 
     417        $charset     = '', 
     418        $language    = '', 
     419        $location    = '', 
     420        $n_encoding  = null, 
     421        $f_encoding  = null 
     422    ) { 
     423        $bodyfile = null; 
     424 
     425        if ($isfile) { 
     426            // Don't load file into memory 
     427            if ($this->_build_params['delay_file_io']) { 
     428                $filedata = null; 
     429                $bodyfile = $file; 
     430            } else { 
     431                if (PEAR::isError($filedata = $this->_file2str($file))) { 
     432                    return $filedata; 
     433                } 
     434            } 
    351435            // Force the name the user supplied, otherwise use $file 
    352             $filename = (strlen($name)) ? $name : $file; 
    353         } else { 
     436            $filename = ($name ? $name : $file); 
     437        } else { 
     438            $filedata = $file; 
    354439            $filename = $name; 
    355440        } 
     441 
    356442        if (!strlen($filename)) { 
    357443            $msg = "The supplied filename for the attachment can't be empty"; 
     
    362448 
    363449        $this->_parts[] = array( 
    364                                 'body'        => $filedata, 
    365                                 'name'        => $filename, 
    366                                 'c_type'      => $c_type, 
    367                                 'encoding'    => $encoding, 
    368                                 'charset'     => $charset, 
    369                                 'language'    => $language, 
    370                                 'location'    => $location, 
    371                                 'disposition' => $disposition, 
    372                                 'name-encoding'     => $n_encoding, 
    373                                 'filename-encoding' => $f_encoding 
    374                                ); 
     450            'body'        => $filedata, 
     451            'body_file'   => $bodyfile, 
     452            'name'        => $filename, 
     453            'c_type'      => $c_type, 
     454            'encoding'    => $encoding, 
     455            'charset'     => $charset, 
     456            'language'    => $language, 
     457            'location'    => $location, 
     458            'disposition' => $disposition, 
     459            'name_encoding'     => $n_encoding, 
     460            'filename_encoding' => $f_encoding 
     461        ); 
     462 
    375463        return true; 
    376464    } 
     
    379467     * Get the contents of the given file name as string 
    380468     * 
    381      * @param string $file_name path of file to process 
    382      * 
    383      * @return string  contents of $file_name 
     469     * @param string $file_name Path of file to process 
     470     * 
     471     * @return string           Contents of $file_name 
    384472     * @access private 
    385473     */ 
    386474    function &_file2str($file_name) 
    387475    { 
    388         //Check state of file and raise an error properly 
     476        // Check state of file and raise an error properly 
    389477        if (!file_exists($file_name)) { 
    390478            $err = PEAR::raiseError('File not found: ' . $file_name); 
     
    400488        } 
    401489 
    402         //Temporarily reset magic_quotes_runtime and read file contents 
     490        // Temporarily reset magic_quotes_runtime and read file contents 
    403491        if ($magic_quote_setting = get_magic_quotes_runtime()) { 
    404             set_magic_quotes_runtime(0); 
     492            @ini_set('magic_quotes_runtime', 0); 
    405493        } 
    406494        $cont = file_get_contents($file_name); 
    407495        if ($magic_quote_setting) { 
    408             set_magic_quotes_runtime($magic_quote_setting); 
     496            @ini_set('magic_quotes_runtime', $magic_quote_setting); 
    409497        } 
    410498 
     
    417505     * 
    418506     * @param mixed  &$obj The object to add the part to, or 
    419      *                      null if a new object is to be created. 
     507     *                     null if a new object is to be created. 
    420508     * @param string $text The text to add. 
    421509     * 
    422      * @return object  The text mimePart object 
     510     * @return object      The text mimePart object 
    423511     * @access private 
    424512     */ 
     
    428516        $params['encoding']     = $this->_build_params['text_encoding']; 
    429517        $params['charset']      = $this->_build_params['text_charset']; 
     518        $params['eol']          = $this->_build_params['eol']; 
     519 
    430520        if (is_object($obj)) { 
    431521            $ret = $obj->addSubpart($text, $params); 
     
    442532     * 
    443533     * @param mixed &$obj The object to add the part to, or 
    444      *                     null if a new object is to be created. 
    445      * 
    446      * @return object The html mimePart object 
     534     *                    null if a new object is to be created. 
     535     * 
     536     * @return object     The html mimePart object 
    447537     * @access private 
    448538     */ 
     
    452542        $params['encoding']     = $this->_build_params['html_encoding']; 
    453543        $params['charset']      = $this->_build_params['html_charset']; 
     544        $params['eol']          = $this->_build_params['eol']; 
     545 
    454546        if (is_object($obj)) { 
    455547            $ret = $obj->addSubpart($this->_htmlbody, $params); 
     
    473565        $params                 = array(); 
    474566        $params['content_type'] = 'multipart/mixed'; 
    475  
    476         //Create empty multipart/mixed Mail_mimePart object to return 
     567        $params['eol']          = $this->_build_params['eol']; 
     568 
     569        // Create empty multipart/mixed Mail_mimePart object to return 
    477570        $ret = new Mail_mimePart('', $params); 
    478571        return $ret; 
     
    485578     * 
    486579     * @param mixed &$obj The object to add the part to, or 
    487      *                     null if a new object is to be created. 
    488      * 
    489      * @return object  The multipart/mixed mimePart object 
     580     *                    null if a new object is to be created. 
     581     * 
     582     * @return object     The multipart/mixed mimePart object 
    490583     * @access private 
    491584     */ 
     
    493586    { 
    494587        $params['content_type'] = 'multipart/alternative'; 
     588        $params['eol']          = $this->_build_params['eol']; 
     589 
    495590        if (is_object($obj)) { 
    496591            return $obj->addSubpart('', $params); 
     
    507602     * 
    508603     * @param mixed &$obj The object to add the part to, or 
    509      *                     null if a new object is to be created 
    510      * 
    511      * @return object  The multipart/mixed mimePart object 
     604     *                    null if a new object is to be created 
     605     * 
     606     * @return object     The multipart/mixed mimePart object 
    512607     * @access private 
    513608     */ 
     
    515610    { 
    516611        $params['content_type'] = 'multipart/related'; 
     612        $params['eol']          = $this->_build_params['eol']; 
     613 
    517614        if (is_object($obj)) { 
    518615            return $obj->addSubpart('', $params); 
     
    530627     * @param array  $value The image information 
    531628     * 
    532      * @return object  The image mimePart object 
     629     * @return object       The image mimePart object 
    533630     * @access private 
    534631     */ 
     
    540637        $params['dfilename']    = $value['name']; 
    541638        $params['cid']          = $value['cid']; 
    542  
    543         if (!empty($value['name-encoding'])) { 
    544             $params['name-encoding'] = $value['name-encoding']; 
    545         } 
    546         if (!empty($value['filename-encoding'])) { 
    547             $params['filename-encoding'] = $value['filename-encoding']; 
     639        $params['body_file']    = $value['body_file']; 
     640        $params['eol']          = $this->_build_params['eol']; 
     641 
     642        if (!empty($value['name_encoding'])) { 
     643            $params['name_encoding'] = $value['name_encoding']; 
     644        } 
     645        if (!empty($value['filename_encoding'])) { 
     646            $params['filename_encoding'] = $value['filename_encoding']; 
    548647        } 
    549648 
    550649        $ret = $obj->addSubpart($value['body'], $params); 
    551650        return $ret; 
    552  
    553651    } 
    554652 
     
    560658     * @param array  $value The attachment information 
    561659     * 
    562      * @return object  The image mimePart object 
     660     * @return object       The image mimePart object 
    563661     * @access private 
    564662     */ 
    565663    function &_addAttachmentPart(&$obj, $value) 
    566664    { 
    567         $params['dfilename'] = $value['name']; 
    568         $params['encoding']  = $value['encoding']; 
     665        $params['eol']          = $this->_build_params['eol']; 
     666        $params['dfilename']    = $value['name']; 
     667        $params['encoding']     = $value['encoding']; 
     668        $params['content_type'] = $value['c_type']; 
     669        $params['body_file']    = $value['body_file']; 
     670        $params['disposition']  = isset($value['disposition']) ?  
     671                                  $value['disposition'] : 'attachment'; 
    569672        if ($value['charset']) { 
    570673            $params['charset'] = $value['charset']; 
     
    576679            $params['location'] = $value['location']; 
    577680        } 
    578         if ($value['name-encoding']) { 
    579             $params['name-encoding'] = $value['name-encoding']; 
    580         } 
    581         if ($value['filename-encoding']) { 
    582             $params['filename-encoding'] = $value['filename-encoding']; 
    583         } 
    584         $params['content_type'] = $value['c_type']; 
    585         $params['disposition']  = isset($value['disposition']) ?  
    586                                   $value['disposition'] : 'attachment'; 
     681        if (!empty($value['name_encoding'])) { 
     682            $params['name_encoding'] = $value['name_encoding']; 
     683        } 
     684        if (!empty($value['filename_encoding'])) { 
     685            $params['filename_encoding'] = $value['filename_encoding']; 
     686        } 
     687 
    587688        $ret = $obj->addSubpart($value['body'], $params); 
    588689        return $ret; 
     
    594695     * with Mail_Mime is created. This means that, 
    595696     * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF  
    596      * using the $xtra_headers parameter! 
     697     * using the $headers parameter! 
    597698     *  
    598      * @param string $separation   The separation etween these two parts. 
    599      * @param array  $build_params The Build parameters passed to the 
    600      *                             &get() function. See &get for more info. 
    601      * @param array  $xtra_headers The extra headers that should be passed 
    602      *                             to the &headers() function. 
    603      *                             See that function for more info. 
    604      * @param bool   $overwrite    Overwrite the existing headers with new. 
    605      * 
    606      * @return string The complete e-mail. 
    607      * @access public 
    608      */ 
    609     function getMessage( 
    610                         $separation   = null, 
    611                         $build_params = null, 
    612                         $xtra_headers = null, 
    613                         $overwrite    = false 
    614                        ) 
    615     { 
     699     * @param string $separation The separation between these two parts. 
     700     * @param array  $params     The Build parameters passed to the 
     701     *                           &get() function. See &get for more info. 
     702     * @param array  $headers    The extra headers that should be passed 
     703     *                           to the &headers() function. 
     704     *                           See that function for more info. 
     705     * @param bool   $overwrite  Overwrite the existing headers with new. 
     706     * 
     707     * @return mixed The complete e-mail or PEAR error object 
     708     * @access public 
     709     */ 
     710    function getMessage($separation = null, $params = null, $headers = null, 
     711        $overwrite = false 
     712    ) { 
    616713        if ($separation === null) { 
    617             $separation = MAIL_MIME_CRLF; 
    618         } 
    619         $body = $this->get($build_params); 
    620         $head = $this->txtHeaders($xtra_headers, $overwrite); 
     714            $separation = $this->_build_params['eol']; 
     715        } 
     716 
     717        $body = $this->get($params); 
     718 
     719        if (PEAR::isError($body)) { 
     720            return $body; 
     721        } 
     722 
     723        $head = $this->txtHeaders($headers, $overwrite); 
    621724        $mail = $head . $separation . $body; 
    622725        return $mail; 
    623726    } 
    624727 
     728    /** 
     729     * Writes (appends) the complete e-mail into file. 
     730     *  
     731     * @param string $filename  Output file location 
     732     * @param array  $params    The Build parameters passed to the 
     733     *                          &get() function. See &get for more info. 
     734     * @param array  $headers   The extra headers that should be passed 
     735     *                          to the &headers() function. 
     736     *                          See that function for more info. 
     737     * @param bool   $overwrite Overwrite the existing headers with new. 
     738     * 
     739     * @return mixed True or PEAR error object 
     740     * @access public 
     741     */ 
     742    function saveMessage($filename, $params = null, $headers = null, $overwrite = false) 
     743    { 
     744        // Check state of file and raise an error properly 
     745        if (file_exists($filename) && !is_writable($filename)) { 
     746            $err = PEAR::raiseError('File is not writable: ' . $filename); 
     747            return $err; 
     748        } 
     749 
     750        // Temporarily reset magic_quotes_runtime and read file contents 
     751        if ($magic_quote_setting = get_magic_quotes_runtime()) { 
     752            @ini_set('magic_quotes_runtime', 0); 
     753        } 
     754 
     755        if (!($fh = fopen($filename, 'ab'))) { 
     756            $err = PEAR::raiseError('Unable to open file: ' . $filename); 
     757            return $err; 
     758        } 
     759 
     760        // Write message headers into file (skipping Content-* headers) 
     761        $head = $this->txtHeaders($headers, $overwrite, true); 
     762        if (fwrite($fh, $head) === false) { 
     763            $err = PEAR::raiseError('Error writing to file: ' . $filename); 
     764            return $err; 
     765        } 
     766 
     767        fclose($fh); 
     768 
     769        if ($magic_quote_setting) { 
     770            @ini_set('magic_quotes_runtime', $magic_quote_setting); 
     771        } 
     772 
     773        // Write the rest of the message into file 
     774        $res = $this->get($params, $filename); 
     775 
     776        return $res ? $res : true; 
     777    } 
    625778 
    626779    /** 
     
    628781     * returns the mime content. 
    629782     * 
    630      * @param array $build_params Build parameters that change the way the email 
    631      *                             is built. Should be associative. Can contain: 
    632      *                head_encoding  -  What encoding to use for the headers.  
    633      *                                  Options: quoted-printable or base64 
    634      *                                  Default is quoted-printable 
    635      *                text_encoding  -  What encoding to use for plain text 
    636      *                                  Options: 7bit, 8bit, 
    637      *                                  base64, or quoted-printable 
    638      *                                  Default is 7bit 
    639      *                html_encoding  -  What encoding to use for html 
    640      *                                  Options: 7bit, 8bit, 
    641      *                                  base64, or quoted-printable 
    642      *                                  Default is quoted-printable 
    643      *                7bit_wrap      -  Number of characters before text is 
    644      *                                  wrapped in 7bit encoding 
    645      *                                  Default is 998 
    646      *                html_charset   -  The character set to use for html. 
    647      *                                  Default is iso-8859-1 
    648      *                text_charset   -  The character set to use for text. 
    649      *                                  Default is iso-8859-1 
    650      *                head_charset   -  The character set to use for headers. 
    651      *                                  Default is iso-8859-1 
    652      * 
    653      * @return string The mime content 
    654      * @access public 
    655      */ 
    656     function &get($build_params = null) 
    657     { 
    658         if (isset($build_params)) { 
    659             while (list($key, $value) = each($build_params)) { 
     783     * @param array    $params   Build parameters that change the way the email 
     784     *                           is built. Should be associative. See $_build_params. 
     785     * @param resource $filename Output file where to save the message instead of 
     786     *                           returning it 
     787     * 
     788     * @return mixed The MIME message content string, null or PEAR error object 
     789     * @access public 
     790     */ 
     791    function &get($params = null, $filename = null) 
     792    { 
     793        if (isset($params)) { 
     794            while (list($key, $value) = each($params)) { 
    660795                $this->_build_params[$key] = $value; 
    661796            } 
    662797        } 
    663798 
    664         if (isset($this->_headers['From'])){ 
    665             //Bug #11381: Illegal characters in domain ID 
    666             if (preg_match("|(@[0-9a-zA-Z\-\.]+)|", $this->_headers['From'], $matches)){ 
     799        if (isset($this->_headers['From'])) { 
     800            // Bug #11381: Illegal characters in domain ID 
     801            if (preg_match("|(@[0-9a-zA-Z\-\.]+)|", $this->_headers['From'], $matches)) { 
    667802                $domainID = $matches[1]; 
    668             }else{ 
     803            } else { 
    669804                $domainID = "@localhost"; 
    670805            } 
    671             foreach($this->_html_images as $i => $img){ 
    672                 $this->_html_images[$i]['cid'] = $this->_html_images[$i]['cid'] . $domainID; 
    673             } 
    674         } 
    675  
    676         if (count($this->_html_images) AND isset($this->_htmlbody)) { 
     806            foreach ($this->_html_images as $i => $img) { 
     807                $this->_html_images[$i]['cid'] 
     808                    = $this->_html_images[$i]['cid'] . $domainID; 
     809            } 
     810        } 
     811 
     812        if (count($this->_html_images) && isset($this->_htmlbody)) { 
    677813            foreach ($this->_html_images as $key => $value) { 
    678814                $regex   = array(); 
     
    687823 
    688824                $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody); 
    689                 $this->_html_images[$key]['name'] = 
    690                     $this->_basename($this->_html_images[$key]['name']); 
     825                $this->_html_images[$key]['name'] 
     826                    = $this->_basename($this->_html_images[$key]['name']); 
    691827            } 
    692828        } 
     
    696832        $html_images = count($this->_html_images)           ? true : false; 
    697833        $html        = strlen($this->_htmlbody)             ? true : false; 
    698         $text        = (!$html AND strlen($this->_txtbody)) ? true : false; 
     834        $text        = (!$html && strlen($this->_txtbody)) ? true : false; 
    699835 
    700836        switch (true) { 
    701         case $text AND !$attachments: 
     837        case $text && !$attachments: 
    702838            $message =& $this->_addTextPart($null, $this->_txtbody); 
    703839            break; 
    704840 
    705         case !$text AND !$html AND $attachments: 
     841        case !$text && !$html && $attachments: 
    706842            $message =& $this->_addMixedPart(); 
    707843            for ($i = 0; $i < count($this->_parts); $i++) { 
     
    710846            break; 
    711847 
    712         case $text AND $attachments: 
     848        case $text && $attachments: 
    713849            $message =& $this->_addMixedPart(); 
    714850            $this->_addTextPart($message, $this->_txtbody); 
     
    718854            break; 
    719855 
    720         case $html AND !$attachments AND !$html_images: 
     856        case $html && !$attachments && !$html_images: 
    721857            if (isset($this->_txtbody)) { 
    722858                $message =& $this->_addAlternativePart($null); 
     
    728864            break; 
    729865 
    730         case $html AND !$attachments AND $html_images: 
     866        case $html && !$attachments && $html_images: 
     867            // * Content-Type: multipart/alternative; 
     868            //    * text 
     869            //    * Content-Type: multipart/related; 
     870            //       * html 
     871            //       * image... 
     872            if (isset($this->_txtbody)) { 
     873                $message =& $this->_addAlternativePart($null); 
     874                $this->_addTextPart($message, $this->_txtbody); 
     875 
     876                $ht =& $this->_addRelatedPart($message); 
     877                $this->_addHtmlPart($ht); 
     878                for ($i = 0; $i < count($this->_html_images); $i++) { 
     879                    $this->_addHtmlImagePart($ht, $this->_html_images[$i]); 
     880                } 
     881            } else { 
     882                // * Content-Type: multipart/related; 
     883                //    * html 
     884                //    * image... 
     885                $message =& $this->_addRelatedPart($null); 
     886                $this->_addHtmlPart($message); 
     887                for ($i = 0; $i < count($this->_html_images); $i++) { 
     888                    $this->_addHtmlImagePart($message, $this->_html_images[$i]); 
     889                } 
     890            } 
     891            /* 
     892            // #13444, #9725: the code below was a non-RFC compliant hack 
     893            // * Content-Type: multipart/related; 
     894            //    * Content-Type: multipart/alternative; 
     895            //        * text 
     896            //        * html 
     897            //    * image... 
    731898            $message =& $this->_addRelatedPart($null); 
    732899            if (isset($this->_txtbody)) { 
     
    740907                $this->_addHtmlImagePart($message, $this->_html_images[$i]); 
    741908            } 
     909            */ 
    742910            break; 
    743911 
    744         case $html AND $attachments AND !$html_images: 
     912        case $html && $attachments && !$html_images: 
    745913            $message =& $this->_addMixedPart(); 
    746914            if (isset($this->_txtbody)) { 
     
    756924            break; 
    757925 
    758         case $html AND $attachments AND $html_images: 
     926        case $html && $attachments && $html_images: 
    759927            $message =& $this->_addMixedPart(); 
    760928            if (isset($this->_txtbody)) { 
     
    776944        } 
    777945 
    778         if (isset($message)) { 
    779             $output = $message->encode(); 
    780  
    781             $this->_headers = array_merge($this->_headers, 
    782                                           $output['headers']); 
     946        if (!isset($message)) { 
     947            $ret = null; 
     948            return $ret; 
     949        } 
     950         
     951        // Use saved boundary 
     952        if (!empty($this->_build_params['boundary'])) { 
     953            $boundary = $this->_build_params['boundary']; 
     954        } else { 
     955            $boundary = null; 
     956        } 
     957 
     958        // Write output to file 
     959        if ($filename) { 
     960            // Append mimePart message headers and body into file 
     961            if (PEAR::isError($headers = $message->encodeToFile($filename, $boundary))) { 
     962                return $headers; 
     963            } 
     964            $this->_headers = array_merge($this->_headers, $headers); 
     965            $ret = null; 
     966            return $ret; 
     967        } else { 
     968            if (PEAR::isError($output = $message->encode($boundary))) { 
     969                return $output; 
     970            } 
     971            $this->_headers = array_merge($this->_headers, $output['headers']); 
    783972            $body = $output['body']; 
    784973            return $body; 
    785  
    786         } else { 
    787             $ret = false; 
    788             return $ret; 
    789974        } 
    790975    } 
     
    795980     * $array['header-name'] = 'header-value'; 
    796981     * 
    797      * @param array $xtra_headers Assoc array with any extra headers. 
    798      *                             Optional. 
     982     * @param array $xtra_headers Assoc array with any extra headers (optional) 
    799983     * @param bool  $overwrite    Overwrite already existing headers. 
     984     * @param bool  $skip_content Don't return content headers: Content-Type 
     985     *                            Content-Disposition and Content-Transfer-Encoding 
    800986     *  
    801      * @return array Assoc array with the mime headers 
    802      * @access public 
    803      */ 
    804     function &headers($xtra_headers = null, $overwrite = false) 
    805     { 
    806         // Content-Type header should already be present, 
    807         // So just add mime version header 
     987     * @return array              Assoc array with the mime headers 
     988     * @access public 
     989     */ 
     990    function &headers($xtra_headers = null, $overwrite = false, $skip_content = false) 
     991    { 
     992        // Add mime version header 
    808993        $headers['MIME-Version'] = '1.0'; 
    809         if (isset($xtra_headers)) { 
     994 
     995        // Content-Type and Content-Transfer-Encoding headers should already 
     996        // be present if get() was called, but we'll re-set them to make sure 
     997        // we got them when called before get() or something in the message 
     998        // has been changed after get() [#14780] 
     999        if (!$skip_content) { 
     1000            $headers += $this->_contentHeaders(); 
     1001        } 
     1002 
     1003        if (!empty($xtra_headers)) { 
    8101004            $headers = array_merge($headers, $xtra_headers); 
    8111005        } 
     1006 
    8121007        if ($overwrite) { 
    8131008            $this->_headers = array_merge($this->_headers, $headers); 
     
    8161011        } 
    8171012 
    818         $encodedHeaders = $this->_encodeHeaders($this->_headers); 
     1013        $headers = $this->_headers; 
     1014 
     1015        if ($skip_content) { 
     1016            unset($headers['Content-Type']); 
     1017            unset($headers['Content-Transfer-Encoding']); 
     1018            unset($headers['Content-Disposition']); 
     1019        } 
     1020 
     1021        $encodedHeaders = $this->_encodeHeaders($headers); 
    8191022        return $encodedHeaders; 
    8201023    } 
     
    8241027     * (usefull if you want to use the PHP mail() function) 
    8251028     * 
    826      * @param array $xtra_headers Assoc array with any extra headers. 
    827      *                             Optional. 
     1029     * @param array $xtra_headers Assoc array with any extra headers (optional) 
    8281030     * @param bool  $overwrite    Overwrite the existing heaers with new. 
    829      * 
    830      * @return string  Plain text headers 
    831      * @access public 
    832      */ 
    833     function txtHeaders($xtra_headers = null, $overwrite = false) 
    834     { 
    835         $headers = $this->headers($xtra_headers, $overwrite); 
     1031     * @param bool  $skip_content Don't return content headers: Content-Type 
     1032     *                            and Content-Transfer-Encoding 
     1033     * 
     1034     * @return string             Plain text headers 
     1035     * @access public 
     1036     */ 
     1037    function txtHeaders($xtra_headers = null, $overwrite = false, $skip_content = false) 
     1038    { 
     1039        $headers = $this->headers($xtra_headers, $overwrite, $skip_content); 
     1040 
     1041        // Place Received: headers at the beginning of the message 
     1042        // Spam detectors often flag messages with it after the Subject: as spam 
     1043        if (isset($headers['Received'])) { 
     1044            $received = $headers['Received']; 
     1045            unset($headers['Received']); 
     1046            $headers = array('Received' => $received) + $headers; 
     1047        } 
    8361048 
    8371049        $ret = ''; 
     1050        $eol = $this->_build_params['eol']; 
     1051 
    8381052        foreach ($headers as $key => $val) { 
    839             $ret .= "$key: $val" . MAIL_MIME_CRLF; 
    840         } 
     1053            if (is_array($val)) { 
     1054                foreach ($val as $value) { 
     1055                    $ret .= "$key: $value" . $eol; 
     1056                } 
     1057            } else { 
     1058                $ret .= "$key: $val" . $eol; 
     1059            } 
     1060        } 
     1061 
    8411062        return $ret; 
    8421063    } 
     
    9051126 
    9061127    /** 
    907      * Since the PHP send function requires you to specifiy  
     1128     * Since the PHP send function requires you to specify 
    9081129     * recipients (To: header) separately from the other 
    9091130     * headers, the To: header is not properly encoded. 
     
    9141135     * @param string $recipients A comma-delimited list of recipients 
    9151136     * 
    916      * @return string Encoded data 
     1137     * @return string            Encoded data 
    9171138     * @access public 
    9181139     */ 
     
    9251146 
    9261147    /** 
    927      * Encodes a header as per RFC2047 
     1148     * Encodes headers as per RFC2047 
    9281149     * 
    9291150     * @param array $input  The header data to encode 
    9301151     * @param array $params Extra build parameters 
    9311152     * 
    932      * @return array Encoded data 
     1153     * @return array        Encoded data 
    9331154     * @access private 
    9341155     */ 
     
    9391160            $build_params[$key] = $value; 
    9401161        } 
    941         //$hdr_name: Name of the heaer 
    942         //$hdr_value: Full line of header value. 
    943         //$atoms: The $hdr_value split into atoms* 
    944         //$atom: A single atom to encode.* 
    945         //$hdr_value_out: The recombined $hdr_val-atoms, or the encoded string. 
    946         //Note: Atom as specified here is not exactly the same as an RFC822 atom, 
    947         //as $atom's may contain just a single space. 
    948  
    949         $useIconv = true; 
    950         if (isset($build_params['ignore-iconv'])) { 
    951             $useIconv = !$build_params['ignore-iconv']; 
    952         } 
     1162 
    9531163        foreach ($input as $hdr_name => $hdr_value) { 
    954             /* 
    955             $parts = preg_split('/([ ])/', $hdr_value, -1, PREG_SPLIT_DELIM_CAPTURE); 
    956             $atoms = array(); 
    957             foreach ($parts as $part){ 
    958                 $atom .= $part; 
    959                 $quoteMatch = preg_match_all('|"|', $atom, $matches) % 2; 
    960                 if (!$quoteMatch){ 
    961                     $atoms[] = $atom; 
    962                     $atom = null; 
     1164            if (is_array($hdr_value)) { 
     1165                foreach ($hdr_value as $idx => $value) { 
     1166                    $input[$hdr_name][$idx] = $this->encodeHeader( 
     1167                        $hdr_name, $value, 
     1168                        $build_params['head_charset'], $build_params['head_encoding'] 
     1169                    ); 
    9631170                } 
    964             } 
    965             if ($atom){ 
    966                 $atoms[] = $atom; 
    967             } 
    968             foreach ($atoms as $atom){ 
    969             */ 
    970             if (preg_match('#([\x80-\xFF]){1}#', $hdr_value)) { 
    971                 if (function_exists('iconv_mime_encode') && $useIconv) { 
    972                     $imePrefs = array(); 
    973                     if ($build_params['head_encoding'] == 'base64') { 
    974                         $imePrefs['scheme'] = 'B'; 
     1171            } else { 
     1172                $input[$hdr_name] = $this->encodeHeader( 
     1173                    $hdr_name, $hdr_value, 
     1174                    $build_params['head_charset'], $build_params['head_encoding'] 
     1175                ); 
     1176            } 
     1177        } 
     1178 
     1179        return $input; 
     1180    } 
     1181 
     1182    /** 
     1183     * Encodes a header as per RFC2047 
     1184     * 
     1185     * @param string $name     The header name 
     1186     * @param string $value    The header data to encode 
     1187     * @param string $charset  Character set name 
     1188     * @param string $encoding Encoding name (base64 or quoted-printable) 
     1189     * 
     1190     * @return string          Encoded header data (without a name) 
     1191     * @access public 
     1192     * @since 1.5.3 
     1193     */ 
     1194    function encodeHeader($name, $value, $charset, $encoding) 
     1195    { 
     1196        // Structured headers 
     1197        $comma_headers = array( 
     1198            'from', 'to', 'cc', 'bcc', 'sender', 'reply-to', 
     1199            'resent-from', 'resent-to', 'resent-cc', 'resent-bcc', 
     1200            'resent-sender', 'resent-reply-to', 
     1201        ); 
     1202        $other_headers = array( 
     1203            'references', 'in-reply-to', 'message-id', 'resent-message-id', 
     1204        ); 
     1205 
     1206        $name = strtolower($name); 
     1207        $eol = $this->_build_params['eol']; 
     1208 
     1209        if (in_array($name, $comma_headers)) { 
     1210            $separator = ','; 
     1211        } else if (in_array($name, $other_headers)) { 
     1212            $separator = ' '; 
     1213        } 
     1214 
     1215        if (!$charset) { 
     1216            $charset = 'ISO-8859-1'; 
     1217        } 
     1218 
     1219        // Structured header (make sure addr-spec inside is not encoded) 
     1220        if (!empty($separator)) { 
     1221            $parts = $this->_explodeQuotedString($separator, $value); 
     1222            $value = ''; 
     1223 
     1224            foreach ($parts as $part) { 
     1225                $part = preg_replace('/\r?\n[\s\t]*/', $eol . ' ', $part); 
     1226                $part = trim($part); 
     1227 
     1228                if (!$part) { 
     1229                    continue; 
     1230                } 
     1231                if ($value) { 
     1232                    $value .= $separator==',' ? $separator.' ' : ' '; 
     1233                } else { 
     1234                    $value = $name . ': '; 
     1235                } 
     1236 
     1237                // let's find phrase (name) and/or addr-spec 
     1238                if (preg_match('/^<\S+@\S+>$/', $part)) { 
     1239                    $value .= $part; 
     1240                } else if (preg_match('/^\S+@\S+$/', $part)) { 
     1241                    // address without brackets and without name 
     1242                    $value .= $part; 
     1243                } else if (preg_match('/<*\S+@\S+>*$/', $part, $matches)) { 
     1244                    // address with name (handle name) 
     1245                    $address = $matches[0]; 
     1246                    $word = str_replace($address, '', $part); 
     1247                    $word = trim($word); 
     1248                    // check if phrase requires quoting 
     1249                    if ($word) { 
     1250                        // non-ASCII: require encoding 
     1251                        if (preg_match('#([\x80-\xFF]){1}#', $word)) { 
     1252                            if ($word[0] == '"' && $word[strlen($word)-1] == '"') { 
     1253                                // de-quote quoted-string, encoding changes 
     1254                                // string to atom 
     1255                                $search = array("\\\"", "\\\\"); 
     1256                                $replace = array("\"", "\\"); 
     1257                                $word = str_replace($search, $replace, $word); 
     1258                                $word = substr($word, 1, -1); 
     1259                            } 
     1260                            // find length of last line 
     1261                            if (($pos = strrpos($value, $eol)) !== false) { 
     1262                                $last_len = strlen($value) - $pos; 
     1263                            } else { 
     1264                                $last_len = strlen($value); 
     1265                            } 
     1266                            $word = $this->_encodeString( 
     1267                                $word, $charset, $encoding, $last_len 
     1268                            ); 
     1269                        } else if (($word[0] != '"' || $word[strlen($word)-1] != '"') 
     1270                            && preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $word) 
     1271                        ) { 
     1272                            // ASCII: quote string if needed 
     1273                            $word = '"'.addcslashes($word, '\\"').'"'; 
     1274                        } 
     1275                    } 
     1276                    $value .= $word.' '.$address; 
     1277                } else { 
     1278                    // addr-spec not found, don't encode (?) 
     1279                    $value .= $part; 
     1280                } 
     1281 
     1282                // RFC2822 recommends 78 characters limit, use 76 from RFC2047 
     1283                $value = wordwrap($value, 76, $eol . ' '); 
     1284            } 
     1285 
     1286            $value = preg_replace('/^'.$name.': /', '', $value); 
     1287 
     1288        } else { 
     1289            // Unstructured header 
     1290            // non-ASCII: require encoding 
     1291            if (preg_match('#([\x80-\xFF]){1}#', $value)) { 
     1292                if ($value[0] == '"' && $value[strlen($value)-1] == '"') { 
     1293                    // de-quote quoted-string, encoding changes 
     1294                    // string to atom 
     1295                    $search = array("\\\"", "\\\\"); 
     1296                    $replace = array("\"", "\\"); 
     1297                    $value = str_replace($search, $replace, $value); 
     1298                    $value = substr($value, 1, -1); 
     1299                } 
     1300                $value = $this->_encodeString( 
     1301                    $value, $charset, $encoding, strlen($name) + 2 
     1302                ); 
     1303            } else if (strlen($name.': '.$value) > 78) { 
     1304                // ASCII: check if header line isn't too long and use folding 
     1305                $value = preg_replace('/\r?\n[\s\t]*/', $eol . ' ', $value); 
     1306                $tmp = wordwrap($name.': '.$value, 78, $eol . ' '); 
     1307                $value = preg_replace('/^'.$name.':\s*/', '', $tmp); 
     1308                // hard limit 998 (RFC2822) 
     1309                $value = wordwrap($value, 998, $eol . ' ', true); 
     1310            } 
     1311        } 
     1312 
     1313        return $value; 
     1314    } 
     1315 
     1316    /** 
     1317     * Encodes a header value as per RFC2047 
     1318     * 
     1319     * @param string $value      The header data to encode 
     1320     * @param string $charset    Character set name 
     1321     * @param string $encoding   Encoding name (base64 or quoted-printable) 
     1322     * @param int    $prefix_len Prefix length 
     1323     * 
     1324     * @return string            Encoded header data 
     1325     * @access private 
     1326     */ 
     1327    function _encodeString($value, $charset, $encoding, $prefix_len=0) 
     1328    { 
     1329        if ($encoding == 'base64') { 
     1330            // Base64 encode the entire string 
     1331            $value = base64_encode($value); 
     1332 
     1333            // Generate the header using the specified params and dynamicly  
     1334            // determine the maximum length of such strings. 
     1335            // 75 is the value specified in the RFC. 
     1336            $prefix = '=?' . $charset . '?B?'; 
     1337            $suffix = '?='; 
     1338            $maxLength = 75 - strlen($prefix . $suffix) - 2; 
     1339            $maxLength1stLine = $maxLength - $prefix_len; 
     1340 
     1341            // We can cut base4 every 4 characters, so the real max 
     1342            // we can get must be rounded down. 
     1343            $maxLength = $maxLength - ($maxLength % 4); 
     1344            $maxLength1stLine = $maxLength1stLine - ($maxLength1stLine % 4); 
     1345 
     1346            $cutpoint = $maxLength1stLine; 
     1347            $value_out = $value; 
     1348            $output = ''; 
     1349            while ($value_out) { 
     1350                // Split translated string at every $maxLength 
     1351                $part = substr($value_out, 0, $cutpoint); 
     1352                $value_out = substr($value_out, $cutpoint); 
     1353                $cutpoint = $maxLength; 
     1354                // RFC 2047 specifies that any split header should 
     1355                // be seperated by a CRLF SPACE.  
     1356                if ($output) { 
     1357                    $output .= $this->_build_params['eol'] . ' '; 
     1358                } 
     1359                $output .= $prefix . $part . $suffix; 
     1360            } 
     1361            $value = $output; 
     1362        } else { 
     1363            // quoted-printable encoding has been selected 
     1364            $value = Mail_mimePart::encodeQP($value); 
     1365 
     1366            // Generate the header using the specified params and dynamicly  
     1367            // determine the maximum length of such strings. 
     1368            // 75 is the value specified in the RFC. 
     1369            $prefix = '=?' . $charset . '?Q?'; 
     1370            $suffix = '?='; 
     1371            $maxLength = 75 - strlen($prefix . $suffix) - 3; 
     1372            $maxLength1stLine = $maxLength - $prefix_len; 
     1373            $maxLength = $maxLength - 1; 
     1374 
     1375            // This regexp will break QP-encoded text at every $maxLength 
     1376            // but will not break any encoded letters. 
     1377            $reg1st = "|(.{0,$maxLength1stLine}[^\=][^\=])|"; 
     1378            $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|"; 
     1379 
     1380            $value_out = $value; 
     1381            $realMax = $maxLength1stLine + strlen($prefix . $suffix); 
     1382            if (strlen($value_out) >= $realMax) { 
     1383                // Begin with the regexp for the first line. 
     1384                $reg = $reg1st; 
     1385                $output = ''; 
     1386                while ($value_out) { 
     1387                    // Split translated string at every $maxLength 
     1388                    // But make sure not to break any translated chars. 
     1389                    $found = preg_match($reg, $value_out, $matches); 
     1390 
     1391                    // After this first line, we need to use a different 
     1392                    // regexp for the first line. 
     1393                    $reg = $reg2nd; 
     1394 
     1395                    // Save the found part and encapsulate it in the 
     1396                    // prefix & suffix. Then remove the part from the 
     1397                    // $value_out variable. 
     1398                    if ($found) { 
     1399                        $part = $matches[0]; 
     1400                        $len = strlen($matches[0]); 
     1401                        $value_out = substr($value_out, $len); 
    9751402                    } else { 
    976                         $imePrefs['scheme'] = 'Q'; 
     1403                        $part = $value_out; 
     1404                        $value_out = ""; 
    9771405                    } 
    978                     $imePrefs['input-charset']  = $build_params['head_charset']; 
    979                     $imePrefs['output-charset'] = $build_params['head_charset']; 
    980                     $imePrefs['line-length'] = 74; 
    981                     $imePrefs['line-break-chars'] = "\r\n"; //Specified in RFC2047 
    982  
    983                     $hdr_value = iconv_mime_encode($hdr_name, $hdr_value, $imePrefs); 
    984                     $hdr_value = preg_replace("#^{$hdr_name}\:\ #", "", $hdr_value); 
    985                 } elseif ($build_params['head_encoding'] == 'base64') { 
    986                     //Base64 encoding has been selected. 
    987                     //Base64 encode the entire string 
    988                     $hdr_value = base64_encode($hdr_value); 
    989  
    990                     //Generate the header using the specified params and dynamicly  
    991                     //determine the maximum length of such strings. 
    992                     //75 is the value specified in the RFC. The first -2 is there so  
    993                     //the later regexp doesn't break any of the translated chars. 
    994                     //The -2 on the first line-regexp is to compensate for the ": " 
    995                     //between the header-name and the header value 
    996                     $prefix = '=?' . $build_params['head_charset'] . '?B?'; 
    997                     $suffix = '?='; 
    998                     $maxLength = 75 - strlen($prefix . $suffix) - 2; 
    999                     $maxLength1stLine = $maxLength - strlen($hdr_name) - 2; 
    1000  
    1001                     //We can cut base4 every 4 characters, so the real max 
    1002                     //we can get must be rounded down. 
    1003                     $maxLength = $maxLength - ($maxLength % 4); 
    1004                     $maxLength1stLine = $maxLength1stLine - ($maxLength1stLine % 4); 
    1005  
    1006                     $cutpoint = $maxLength1stLine; 
    1007                     $hdr_value_out = $hdr_value; 
    1008                     $output = ""; 
    1009                     while ($hdr_value_out) { 
    1010                         //Split translated string at every $maxLength 
    1011                         $part = substr($hdr_value_out, 0, $cutpoint); 
    1012                         $hdr_value_out = substr($hdr_value_out, $cutpoint); 
    1013                         $cutpoint = $maxLength; 
    1014                         //RFC 2047 specifies that any split header should 
    1015                         //be seperated by a CRLF SPACE.  
    1016                         if ($output) { 
    1017                             $output .= "\r\n "; 
    1018                         } 
    1019                         $output .= $prefix . $part . $suffix; 
     1406 
     1407                    // RFC 2047 specifies that any split header should  
     1408                    // be seperated by a CRLF SPACE 
     1409                    if ($output) { 
     1410                        $output .= $this->_build_params['eol'] . ' '; 
    10201411                    } 
    1021                     $hdr_value = $output; 
    1022                 } else { 
    1023                     //quoted-printable encoding has been selected 
    1024  
    1025                     //Fix for Bug #10298, Ota Mares <om@viazenetti.de> 
    1026                     //Check if there is a double quote at beginning or end of 
    1027                     //the string to prevent that an open or closing quote gets  
    1028                     //ignored because it is encapsuled by an encoding pre/suffix. 
    1029                     //Remove the double quote and set the specific prefix or  
    1030                     //suffix variable so that we can concat the encoded string and 
    1031                     //the double quotes back together to get the intended string. 
    1032                     $quotePrefix = $quoteSuffix = ''; 
    1033                     if ($hdr_value{0} == '"') { 
    1034                         $hdr_value = substr($hdr_value, 1); 
    1035                         $quotePrefix = '"'; 
    1036                     } 
    1037                     if ($hdr_value{strlen($hdr_value)-1} == '"') { 
    1038                         $hdr_value = substr($hdr_value, 0, -1); 
    1039                         $quoteSuffix = '"'; 
    1040                     } 
    1041  
    1042                     //Generate the header using the specified params and dynamicly  
    1043                     //determine the maximum length of such strings. 
    1044                     //75 is the value specified in the RFC. The -2 is there so  
    1045                     //the later regexp doesn't break any of the translated chars. 
    1046                     //The -2 on the first line-regexp is to compensate for the ": " 
    1047                     //between the header-name and the header value 
    1048                     $prefix = '=?' . $build_params['head_charset'] . '?Q?'; 
    1049                     $suffix = '?='; 
    1050                     $maxLength = 75 - strlen($prefix . $suffix) - 2 - 1; 
    1051                     $maxLength1stLine = $maxLength - strlen($hdr_name) - 2; 
    1052                     $maxLength = $maxLength - 1; 
    1053  
    1054                     //Replace all special characters used by the encoder. 
    1055                     $search  = array('=',   '_',   '?',   ' '); 
    1056                     $replace = array('=3D', '=5F', '=3F', '_'); 
    1057                     $hdr_value = str_replace($search, $replace, $hdr_value); 
    1058  
    1059                     //Replace all extended characters (\x80-xFF) with their 
    1060                     //ASCII values. 
    1061                     $hdr_value = preg_replace('#([\x80-\xFF])#e', 
    1062                         '"=" . strtoupper(dechex(ord("\1")))', 
    1063                         $hdr_value); 
    1064  
    1065                     //This regexp will break QP-encoded text at every $maxLength 
    1066                     //but will not break any encoded letters. 
    1067                     $reg1st = "|(.{0,$maxLength1stLine}[^\=][^\=])|"; 
    1068                     $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|"; 
    1069                     //Fix for Bug #10298, Ota Mares <om@viazenetti.de> 
    1070                     //Concat the double quotes and encoded string together 
    1071                     $hdr_value = $quotePrefix . $hdr_value . $quoteSuffix; 
    1072  
    1073                     $hdr_value_out = $hdr_value; 
    1074                     $realMax = $maxLength1stLine + strlen($prefix . $suffix); 
    1075                     if (strlen($hdr_value_out) >= $realMax) { 
    1076                         //Begin with the regexp for the first line. 
    1077                         $reg = $reg1st; 
    1078                         $output = ""; 
    1079                         while ($hdr_value_out) { 
    1080                             //Split translated string at every $maxLength 
    1081                             //But make sure not to break any translated chars. 
    1082                             $found = preg_match($reg, $hdr_value_out, $matches); 
    1083  
    1084                             //After this first line, we need to use a different 
    1085                             //regexp for the first line. 
    1086                             $reg = $reg2nd; 
    1087  
    1088                             //Save the found part and encapsulate it in the 
    1089                             //prefix & suffix. Then remove the part from the 
    1090                             //$hdr_value_out variable. 
    1091                             if ($found) { 
    1092                                 $part = $matches[0]; 
    1093                                 $len = strlen($matches[0]); 
    1094                                 $hdr_value_out = substr($hdr_value_out, $len); 
    1095                             } else { 
    1096                                 $part = $hdr_value_out; 
    1097                                 $hdr_value_out = ""; 
    1098                             } 
    1099  
    1100                             //RFC 2047 specifies that any split header should  
    1101                             //be seperated by a CRLF SPACE 
    1102                             if ($output) { 
    1103                                 $output .= "\r\n "; 
    1104                             } 
    1105                             $output .= $prefix . $part . $suffix; 
    1106                         } 
    1107                         $hdr_value_out = $output; 
    1108                     } else { 
    1109                         $hdr_value_out = $prefix . $hdr_value_out . $suffix; 
    1110                     } 
    1111                     $hdr_value = $hdr_value_out; 
     1412                    $output .= $prefix . $part . $suffix; 
    11121413                } 
    1113             } 
    1114             $input[$hdr_name] = $hdr_value; 
    1115         } 
    1116         return $input; 
    1117     } 
    1118  
    1119     /** 
    1120      * Set the object's end-of-line and define the constant if applicable. 
    1121      * 
    1122      * @param string $eol End Of Line sequence 
    1123      * 
    1124      * @return void 
    1125      * @access private 
    1126      */ 
    1127     function _setEOL($eol) 
    1128     { 
    1129         $this->_eol = $eol; 
    1130         if (!defined('MAIL_MIME_CRLF')) { 
    1131             define('MAIL_MIME_CRLF', $this->_eol, true); 
    1132         } 
     1414                $value_out = $output; 
     1415            } else { 
     1416                $value_out = $prefix . $value_out . $suffix; 
     1417            } 
     1418            $value = $value_out; 
     1419        } 
     1420 
     1421        return $value; 
     1422    } 
     1423 
     1424    /** 
     1425     * Explode quoted string 
     1426     * 
     1427     * @param string $delimiter Delimiter expression string for preg_match() 
     1428     * @param string $string    Input string 
     1429     * 
     1430     * @return array            String tokens array 
     1431     * @access private 
     1432     */ 
     1433    function _explodeQuotedString($delimiter, $string) 
     1434    { 
     1435        $result = array(); 
     1436        $strlen = strlen($string); 
     1437 
     1438        for ($q=$p=$i=0; $i < $strlen; $i++) { 
     1439            if ($string[$i] == "\"" 
     1440                && (empty($string[$i-1]) || $string[$i-1] != "\\") 
     1441            ) { 
     1442                $q = $q ? false : true; 
     1443            } else if (!$q && preg_match("/$delimiter/", $string[$i])) { 
     1444                $result[] = substr($string, $p, $i - $p); 
     1445                $p = $i + 1; 
     1446            } 
     1447        } 
     1448 
     1449        $result[] = substr($string, $p); 
     1450        return $result; 
    11331451    } 
    11341452 
     
    11361454     * Get file's basename (locale independent)  
    11371455     * 
    1138      * @param string Filename 
    1139      * 
    1140      * @return string Basename 
     1456     * @param string $filename Filename 
     1457     * 
     1458     * @return string          Basename 
    11411459     * @access private 
    11421460     */ 
     
    11441462    { 
    11451463        // basename() is not unicode safe and locale dependent 
    1146         if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) 
     1464        if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) { 
    11471465            return preg_replace('/^.*[\\\\\\/]/', '', $filename); 
    1148         else 
     1466        } else { 
    11491467            return preg_replace('/^.*[\/]/', '', $filename); 
     1468        } 
     1469    } 
     1470 
     1471    /** 
     1472     * Get Content-Type and Content-Transfer-Encoding headers of the message 
     1473     * 
     1474     * @return array Headers array 
     1475     * @access private 
     1476     */ 
     1477    function _contentHeaders() 
     1478    { 
     1479        $attachments = count($this->_parts)                 ? true : false; 
     1480        $html_images = count($this->_html_images)           ? true : false; 
     1481        $html        = strlen($this->_htmlbody)             ? true : false; 
     1482        $text        = (!$html && strlen($this->_txtbody))  ? true : false; 
     1483        $headers     = array(); 
     1484 
     1485        // See get() 
     1486        switch (true) { 
     1487        case $text && !$attachments: 
     1488            $headers['Content-Type'] = 'text/plain'; 
     1489            break; 
     1490 
     1491        case !$text && !$html && $attachments: 
     1492        case $text && $attachments: 
     1493        case $html && $attachments && !$html_images: 
     1494        case $html && $attachments && $html_images: 
     1495            $headers['Content-Type'] = 'multipart/mixed'; 
     1496            break; 
     1497 
     1498        case $html && !$attachments && !$html_images && isset($this->_txtbody): 
     1499        case $html && !$attachments && $html_images && isset($this->_txtbody): 
     1500            $headers['Content-Type'] = 'multipart/alternative'; 
     1501            break; 
     1502 
     1503        case $html && !$attachments && !$html_images && !isset($this->_txtbody): 
     1504            $headers['Content-Type'] = 'text/html'; 
     1505            break; 
     1506 
     1507        case $html && !$attachments && $html_images && !isset($this->_txtbody): 
     1508            $headers['Content-Type'] = 'multipart/related'; 
     1509            break; 
     1510 
     1511        default: 
     1512            return $headers; 
     1513        } 
     1514 
     1515        $eol = !empty($this->_build_params['eol']) 
     1516            ? $this->_build_params['eol'] : "\r\n"; 
     1517 
     1518        if ($headers['Content-Type'] == 'text/plain') { 
     1519            // single-part message: add charset and encoding 
     1520            $headers['Content-Type'] 
     1521                .= ";$eol charset=" . $this->_build_params['text_charset']; 
     1522            $headers['Content-Transfer-Encoding'] 
     1523                = $this->_build_params['text_encoding']; 
     1524        } else if ($headers['Content-Type'] == 'text/html') { 
     1525            // single-part message: add charset and encoding 
     1526            $headers['Content-Type'] 
     1527                .= ";$eol charset=" . $this->_build_params['html_charset']; 
     1528            $headers['Content-Transfer-Encoding'] 
     1529                = $this->_build_params['html_encoding']; 
     1530        } else { 
     1531            // multipart message: add charset and boundary 
     1532            if (!empty($this->_build_params['boundary'])) { 
     1533                $boundary = $this->_build_params['boundary']; 
     1534            } else if (!empty($this->_headers['Content-Type']) 
     1535                && preg_match('/boundary="([^"]+)"/', $this->_headers['Content-Type'], $m) 
     1536            ) { 
     1537                $boundary = $m[1]; 
     1538            } else { 
     1539                $boundary = '=_' . md5(rand() . microtime()); 
     1540            } 
     1541 
     1542            $this->_build_params['boundary'] = $boundary; 
     1543            $headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; 
     1544        } 
     1545 
     1546        return $headers; 
    11501547    } 
    11511548 
  • program/lib/Mail/mimePart.php

    rf7f9346 r0917356  
    4141 * THE POSSIBILITY OF SUCH DAMAGE. 
    4242 * 
    43  * @category   Mail 
    44  * @package    Mail_Mime 
    45  * @author     Richard Heyes  <richard@phpguru.org> 
    46  * @author     Cipriano Groenendal <cipri@php.net> 
    47  * @author     Sean Coates <sean@php.net> 
    48  * @copyright  2003-2006 PEAR <pear-group@php.net> 
    49  * @license    http://www.opensource.org/licenses/bsd-license.php BSD License 
    50  * @version    CVS: $Id$ 
    51  * @link       http://pear.php.net/package/Mail_mime 
     43 * @category  Mail 
     44 * @package   Mail_Mime 
     45 * @author    Richard Heyes  <richard@phpguru.org> 
     46 * @author    Cipriano Groenendal <cipri@php.net> 
     47 * @author    Sean Coates <sean@php.net> 
     48 * @author    Aleksander Machniak <alec@php.net> 
     49 * @copyright 2003-2006 PEAR <pear-group@php.net> 
     50 * @license   http://www.opensource.org/licenses/bsd-license.php BSD License 
     51 * @version   CVS: $Id$ 
     52 * @link      http://pear.php.net/package/Mail_mime 
    5253 */ 
    5354 
     
    6263 * This class however allows full control over the email. 
    6364 * 
    64  * @category   Mail 
    65  * @package    Mail_Mime 
    66  * @author     Richard Heyes  <richard@phpguru.org> 
    67  * @author     Cipriano Groenendal <cipri@php.net> 
    68  * @author     Sean Coates <sean@php.net> 
    69  * @copyright  2003-2006 PEAR <pear-group@php.net> 
    70  * @license    http://www.opensource.org/licenses/bsd-license.php BSD License 
    71  * @version    Release: @package_version@ 
    72  * @link       http://pear.php.net/package/Mail_mime 
     65 * @category  Mail 
     66 * @package   Mail_Mime 
     67 * @author    Richard Heyes  <richard@phpguru.org> 
     68 * @author    Cipriano Groenendal <cipri@php.net> 
     69 * @author    Sean Coates <sean@php.net> 
     70 * @author    Aleksander Machniak <alec@php.net> 
     71 * @copyright 2003-2006 PEAR <pear-group@php.net> 
     72 * @license   http://www.opensource.org/licenses/bsd-license.php BSD License 
     73 * @version   Release: @package_version@ 
     74 * @link      http://pear.php.net/package/Mail_mime 
    7375 */ 
    74 class Mail_mimePart { 
    75  
    76    /** 
     76class Mail_mimePart 
     77{ 
     78    /** 
    7779    * The encoding type of this part 
    7880    * 
     
    8284    var $_encoding; 
    8385 
    84    /** 
     86    /** 
    8587    * An array of subparts 
    8688    * 
     
    9092    var $_subparts; 
    9193 
    92    /** 
     94    /** 
    9395    * The output of this part after being built 
    9496    * 
     
    98100    var $_encoded; 
    99101 
    100    /** 
     102    /** 
    101103    * Headers for this part 
    102104    * 
     
    106108    var $_headers; 
    107109 
    108    /** 
     110    /** 
    109111    * The body of this part (not encoded) 
    110112    * 
     
    115117 
    116118    /** 
    117      * Constructor. 
    118      * 
    119      * Sets up the object. 
    120      * 
    121      * @param $body   - The body of the mime part if any. 
    122      * @param $params - An associative array of parameters: 
    123      *                  content_type - The content type for this part eg multipart/mixed 
    124      *                  encoding     - The encoding to use, 7bit, 8bit, base64, or quoted-printable 
    125      *                  cid          - Content ID to apply 
    126      *                  disposition  - Content disposition, inline or attachment 
    127      *                  dfilename    - Optional filename parameter for content disposition 
    128      *                  description  - Content description 
    129      *                  charset      - Character set to use 
    130      * @access public 
    131      */ 
     119    * The location of file with body of this part (not encoded) 
     120    * 
     121    * @var string 
     122    * @access private 
     123    */ 
     124    var $_body_file; 
     125 
     126    /** 
     127    * The end-of-line sequence 
     128    * 
     129    * @var string 
     130    * @access private 
     131    */ 
     132    var $_eol = "\r\n"; 
     133 
     134    /** 
     135    * Constructor. 
     136    * 
     137    * Sets up the object. 
     138    * 
     139    * @param string $body   The body of the mime part if any. 
     140    * @param array  $params An associative array of optional parameters: 
     141    *     content_type      - The content type for this part eg multipart/mixed 
     142    *     encoding          - The encoding to use, 7bit, 8bit, 
     143    *                         base64, or quoted-printable 
     144    *     cid               - Content ID to apply 
     145    *     disposition       - Content disposition, inline or attachment 
     146    *     dfilename         - Filename parameter for content disposition 
     147    *     description       - Content description 
     148    *     charset           - Character set to use 
     149    *     name_encoding     - Encoding for attachment name (Content-Type) 
     150    *                         By default filenames are encoded using RFC2231 
     151    *                         Here you can set RFC2047 encoding (quoted-printable 
     152    *                         or base64) instead 
     153    *     filename_encoding - Encoding for attachment filename (Content-Disposition) 
     154    *                         See 'name_encoding' 
     155    *     eol               - End of line sequence. Default: "\r\n" 
     156    *     body_file         - Location of file with part's body (instead of $body) 
     157    * 
     158    * @access public 
     159    */ 
    132160    function Mail_mimePart($body = '', $params = array()) 
    133161    { 
    134         if (!defined('MAIL_MIMEPART_CRLF')) { 
    135             define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE); 
    136         } 
    137  
    138         $contentType = array(); 
    139         $contentDisp = array(); 
     162        if (!empty($params['eol'])) { 
     163            $this->_eol = $params['eol']; 
     164        } else if (defined('MAIL_MIMEPART_CRLF')) { // backward-copat. 
     165            $this->_eol = MAIL_MIMEPART_CRLF; 
     166        } 
     167 
     168        $c_type = array(); 
     169        $c_disp = array(); 
    140170        foreach ($params as $key => $value) { 
    141171            switch ($key) { 
    142                 case 'content_type': 
    143                     $contentType['type'] = $value; 
    144                     //$headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); 
    145                     break; 
    146  
    147                 case 'encoding': 
    148                     $this->_encoding = $value; 
    149                     $headers['Content-Transfer-Encoding'] = $value; 
    150                     break; 
    151  
    152                 case 'cid': 
    153                     $headers['Content-ID'] = '<' . $value . '>'; 
    154                     break; 
    155  
    156                 case 'disposition': 
    157                     $contentDisp['disp'] = $value; 
    158                     break; 
    159  
    160                 case 'dfilename': 
    161                     $contentDisp['filename'] = $value; 
    162                     $contentType['name'] = $value; 
    163                     break; 
    164  
    165                 case 'description': 
    166                     $headers['Content-Description'] = $value; 
    167                     break; 
    168  
    169                 case 'charset': 
    170                     $contentType['charset'] = $value; 
    171                     $contentDisp['charset'] = $value; 
    172                     break; 
    173  
    174                 case 'language': 
    175                     $contentType['language'] = $value; 
    176                     $contentDisp['language'] = $value; 
    177                     break; 
    178  
    179                 case 'location': 
    180                     $headers['Content-Location'] = $value; 
    181                     break; 
    182  
    183             } 
    184         } 
    185  
    186         if (isset($contentType['type'])) { 
    187             $headers['Content-Type'] = $contentType['type']; 
    188         if (isset($contentType['charset'])) { 
    189                 $headers['Content-Type'] .= "; charset={$contentType['charset']}"; 
    190             } 
    191             if (isset($contentType['name'])) { 
    192                 $headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF; 
    193                 $headers['Content-Type'] .= 
    194                     $this->_buildHeaderParam('name', $contentType['name'], 
    195                         isset($contentType['charset']) ? $contentType['charset'] : 'US-ASCII', 
    196                         isset($contentType['language']) ? $contentType['language'] : NULL, 
    197                         isset($params['name-encoding']) ?  $params['name-encoding'] : NULL); 
    198             } 
    199         } 
    200  
    201  
    202         if (isset($contentDisp['disp'])) { 
    203             $headers['Content-Disposition'] = $contentDisp['disp']; 
    204             if (isset($contentDisp['filename'])) { 
    205                 $headers['Content-Disposition'] .= ';' . MAIL_MIMEPART_CRLF; 
    206                 $headers['Content-Disposition'] .= 
    207                     $this->_buildHeaderParam('filename', $contentDisp['filename'], 
    208                         isset($contentDisp['charset']) ? $contentDisp['charset'] : 'US-ASCII', 
    209                         isset($contentDisp['language']) ? $contentDisp['language'] : NULL, 
    210                         isset($params['filename-encoding']) ? $params['filename-encoding'] : NULL); 
     172            case 'content_type': 
     173                $c_type['type'] = $value; 
     174                break; 
     175 
     176            case 'encoding': 
     177                $this->_encoding = $value; 
     178                $headers['Content-Transfer-Encoding'] = $value; 
     179                break; 
     180 
     181            case 'cid': 
     182                $headers['Content-ID'] = '<' . $value . '>'; 
     183                break; 
     184 
     185            case 'disposition': 
     186                $c_disp['disp'] = $value; 
     187                break; 
     188 
     189            case 'dfilename': 
     190                $c_disp['filename'] = $value; 
     191                $c_type['name'] = $value; 
     192                break; 
     193 
     194            case 'description': 
     195                $headers['Content-Description'] = $value; 
     196                break; 
     197 
     198            case 'charset': 
     199                $c_type['charset'] = $value; 
     200                $c_disp['charset'] = $value; 
     201                break; 
     202 
     203            case 'language': 
     204                $c_type['language'] = $value; 
     205                $c_disp['language'] = $value; 
     206                break; 
     207 
     208            case 'location': 
     209                $headers['Content-Location'] = $value; 
     210                break; 
     211 
     212            case 'body_file': 
     213                $this->_body_file = $value; 
     214                break; 
     215            } 
     216        } 
     217 
     218        // Content-Type 
     219        if (isset($c_type['type'])) { 
     220            $headers['Content-Type'] = $c_type['type']; 
     221            if (isset($c_type['name'])) { 
     222                $headers['Content-Type'] .= ';' . $this->_eol; 
     223                $headers['Content-Type'] .= $this->_buildHeaderParam( 
     224                    'name', $c_type['name'],  
     225                    isset($c_type['charset']) ? $c_type['charset'] : 'US-ASCII',  
     226                    isset($c_type['language']) ? $c_type['language'] : null, 
     227                    isset($params['name_encoding']) ?  $params['name_encoding'] : null 
     228                ); 
     229            } 
     230            if (isset($c_type['charset'])) { 
     231                $headers['Content-Type'] 
     232                    .= ';' . $this->_eol . " charset={$c_type['charset']}"; 
     233            } 
     234        } 
     235 
     236        // Content-Disposition 
     237        if (isset($c_disp['disp'])) { 
     238            $headers['Content-Disposition'] = $c_disp['disp']; 
     239            if (isset($c_disp['filename'])) { 
     240                $headers['Content-Disposition'] .= ';' . $this->_eol; 
     241                $headers['Content-Disposition'] .= $this->_buildHeaderParam( 
     242                    'filename', $c_disp['filename'],  
     243                    isset($c_disp['charset']) ? $c_disp['charset'] : 'US-ASCII',  
     244                    isset($c_disp['language']) ? $c_disp['language'] : null, 
     245                    isset($params['filename_encoding']) ?  $params['filename_encoding'] : null 
     246                ); 
    211247            } 
    212248        } 
     
    217253        } 
    218254 
    219         //Default encoding 
     255        // Default encoding 
    220256        if (!isset($this->_encoding)) { 
    221257            $this->_encoding = '7bit'; 
     
    229265 
    230266    /** 
    231      * encode() 
    232      * 
    233267     * Encodes and returns the email. Also stores 
    234268     * it in the encoded member variable 
    235269     * 
     270     * @param string $boundary Pre-defined boundary string 
     271     * 
    236272     * @return An associative array containing two elements, 
    237273     *         body and headers. The headers element is itself 
    238      *         an indexed array. 
     274     *         an indexed array. On error returns PEAR error object. 
    239275     * @access public 
    240276     */ 
    241     function encode() 
     277    function encode($boundary=null) 
    242278    { 
    243279        $encoded =& $this->_encoded; 
    244280 
    245281        if (count($this->_subparts)) { 
    246             $boundary = '=_' . md5(rand() . microtime()); 
    247             $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; 
    248  
    249             // Add body parts to $subparts 
     282            $boundary = $boundary ? $boundary : '=_' . md5(rand() . microtime()); 
     283            $eol = $this->_eol; 
     284 
     285            $this->_headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; 
     286 
     287            $encoded['body'] = '';  
     288 
    250289            for ($i = 0; $i < count($this->_subparts); $i++) { 
    251                 $headers = array(); 
     290                $encoded['body'] .= '--' . $boundary . $eol; 
    252291                $tmp = $this->_subparts[$i]->encode(); 
     292                if (PEAR::isError($tmp)) { 
     293                    return $tmp; 
     294                } 
    253295                foreach ($tmp['headers'] as $key => $value) { 
    254                     $headers[] = $key . ': ' . $value; 
    255                 } 
    256                 $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'] . MAIL_MIMEPART_CRLF; 
    257             } 
    258  
    259             $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .  
    260                         implode('--' . $boundary . MAIL_MIMEPART_CRLF , $subparts) . 
    261                         '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; 
    262  
     296                    $encoded['body'] .= $key . ': ' . $value . $eol; 
     297                } 
     298                $encoded['body'] .= $eol . $tmp['body'] . $eol; 
     299            } 
     300 
     301            $encoded['body'] .= '--' . $boundary . '--' . $eol; 
     302 
     303        } else if ($this->_body) { 
     304            $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding); 
     305        } else if ($this->_body_file) { 
     306            // Temporarily reset magic_quotes_runtime for file reads and writes 
     307            if ($magic_quote_setting = get_magic_quotes_runtime()) { 
     308                @ini_set('magic_quotes_runtime', 0); 
     309            } 
     310            $body = $this->_getEncodedDataFromFile($this->_body_file, $this->_encoding); 
     311            if ($magic_quote_setting) { 
     312                @ini_set('magic_quotes_runtime', $magic_quote_setting); 
     313            } 
     314 
     315            if (PEAR::isError($body)) { 
     316                return $body; 
     317            } 
     318            $encoded['body'] = $body; 
    263319        } else { 
    264             $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding); 
     320            $encoded['body'] = ''; 
    265321        } 
    266322 
     
    272328 
    273329    /** 
    274      * &addSubPart() 
    275      * 
     330     * Encodes and saves the email into file. File must exist. 
     331     * Data will be appended to the file. 
     332     * 
     333     * @param string $filename Output file location 
     334     * @param string $boundary Pre-defined boundary string 
     335     * 
     336     * @return array An associative array containing message headers 
     337     *               or PEAR error object 
     338     * @access public 
     339     * @since 1.6.0 
     340     */ 
     341    function encodeToFile($filename, $boundary=null) 
     342    { 
     343        if (file_exists($filename) && !is_writable($filename)) { 
     344            $err = PEAR::raiseError('File is not writeable: ' . $filename); 
     345            return $err; 
     346        } 
     347 
     348        if (!($fh = fopen($filename, 'ab'))) { 
     349            $err = PEAR::raiseError('Unable to open file: ' . $filename); 
     350            return $err; 
     351        } 
     352 
     353        // Temporarily reset magic_quotes_runtime for file reads and writes 
     354        if ($magic_quote_setting = get_magic_quotes_runtime()) { 
     355            @ini_set('magic_quotes_runtime', 0); 
     356        } 
     357 
     358        $res = $this->_encodePartToFile($fh, $boundary); 
     359 
     360        fclose($fh); 
     361 
     362        if ($magic_quote_setting) { 
     363            @ini_set('magic_quotes_runtime', $magic_quote_setting); 
     364        } 
     365 
     366        return PEAR::isError($res) ? $res : $this->_headers; 
     367    } 
     368 
     369    /** 
     370     * Encodes given email part into file 
     371     * 
     372     * @param string $fh       Output file handle 
     373     * @param string $boundary Pre-defined boundary string 
     374     * 
     375     * @return array True on sucess or PEAR error object 
     376     * @access private 
     377     */ 
     378    function _encodePartToFile($fh, $boundary=null) 
     379    { 
     380        $eol = $this->_eol; 
     381 
     382        if (count($this->_subparts)) { 
     383            $boundary = $boundary ? $boundary : '=_' . md5(rand() . microtime()); 
     384            $this->_headers['Content-Type'] .= ";$eol boundary=\"$boundary\""; 
     385        } 
     386 
     387        foreach ($this->_headers as $key => $value) { 
     388            fwrite($fh, $key . ': ' . $value . $eol); 
     389        } 
     390 
     391        if (count($this->_subparts)) { 
     392            for ($i = 0; $i < count($this->_subparts); $i++) { 
     393                fwrite($fh, $eol . '--' . $boundary . $eol); 
     394                $res = $this->_subparts[$i]->_encodePartToFile($fh); 
     395                if (PEAR::isError($res)) { 
     396                    return $res; 
     397                } 
     398            } 
     399 
     400            fwrite($fh, $eol . '--' . $boundary . '--' . $eol); 
     401 
     402        } else if ($this->_body) { 
     403            fwrite($fh, $eol . $this->_getEncodedData($this->_body, $this->_encoding)); 
     404        } else if ($this->_body_file) { 
     405            fwrite($fh, $eol); 
     406            $res = $this->_getEncodedDataFromFile( 
     407                $this->_body_file, $this->_encoding, $fh 
     408            ); 
     409            if (PEAR::isError($res)) { 
     410                return $res; 
     411            } 
     412        } 
     413 
     414        return true; 
     415    } 
     416 
     417    /** 
    276418     * Adds a subpart to current mime part and returns 
    277419     * a reference to it 
    278420     * 
    279      * @param $body   The body of the subpart, if any. 
    280      * @param $params The parameters for the subpart, same 
    281      *                as the $params argument for constructor. 
    282      * @return A reference to the part you just added. It is 
    283      *         crucial if using multipart/* in your subparts that 
    284      *         you use =& in your script when calling this function, 
    285      *         otherwise you will not be able to add further subparts. 
     421     * @param string $body   The body of the subpart, if any. 
     422     * @param array  $params The parameters for the subpart, same 
     423     *                       as the $params argument for constructor. 
     424     * 
     425     * @return Mail_mimePart A reference to the part you just added. It is 
     426     *                       crucial if using multipart/* in your subparts that 
     427     *                       you use =& in your script when calling this function, 
     428     *                       otherwise you will not be able to add further subparts. 
    286429     * @access public 
    287430     */ 
     
    293436 
    294437    /** 
    295      * _getEncodedData() 
    296      * 
    297438     * Returns encoded data based upon encoding passed to it 
    298439     * 
    299      * @param $data     The data to encode. 
    300      * @param $encoding The encoding type to use, 7bit, base64, 
    301      *                  or quoted-printable. 
     440     * @param string $data     The data to encode. 
     441     * @param string $encoding The encoding type to use, 7bit, base64, 
     442     *                         or quoted-printable. 
     443     * 
     444     * @return string 
    302445     * @access private 
    303446     */ 
     
    305448    { 
    306449        switch ($encoding) { 
    307             case '8bit': 
    308             case '7bit': 
    309                 return $data; 
    310                 break; 
    311  
    312             case 'quoted-printable': 
    313                 return $this->_quotedPrintableEncode($data); 
    314                 break; 
    315  
    316             case 'base64': 
    317                 return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF)); 
    318                 break; 
    319  
    320             default: 
    321                 return $data; 
    322         } 
    323     } 
    324  
    325     /** 
    326      * quotedPrintableEncode() 
    327      * 
     450        case 'quoted-printable': 
     451            return $this->_quotedPrintableEncode($data); 
     452            break; 
     453 
     454        case 'base64': 
     455            return rtrim(chunk_split(base64_encode($data), 76, $this->_eol)); 
     456            break; 
     457 
     458        case '8bit': 
     459        case '7bit': 
     460        default: 
     461            return $data; 
     462        } 
     463    } 
     464 
     465    /** 
     466     * Returns encoded data based upon encoding passed to it 
     467     * 
     468     * @param string   $filename Data file location 
     469     * @param string   $encoding The encoding type to use, 7bit, base64, 
     470     *                           or quoted-printable. 
     471     * @param resource $fh       Output file handle. If set, data will be 
     472     *                           stored into it instead of returning it 
     473     * 
     474     * @return string Encoded data or PEAR error object 
     475     * @access private 
     476     */ 
     477    function _getEncodedDataFromFile($filename, $encoding, $fh=null) 
     478    { 
     479        if (!is_readable($filename)) { 
     480            $err = PEAR::raiseError('Unable to read file: ' . $filename); 
     481            return $err; 
     482        } 
     483 
     484        if (!($fd = fopen($filename, 'rb'))) { 
     485            $err = PEAR::raiseError('Could not open file: ' . $filename); 
     486            return $err; 
     487        } 
     488 
     489        $data = ''; 
     490 
     491        switch ($encoding) { 
     492        case 'quoted-printable': 
     493            while (!feof($fd)) { 
     494                $buffer = $this->_quotedPrintableEncode(fgets($fd)); 
     495                if ($fh) { 
     496                    fwrite($fh, $buffer); 
     497                } else { 
     498                    $data .= $buffer; 
     499                } 
     500            } 
     501            break; 
     502 
     503        case 'base64': 
     504            while (!feof($fd)) { 
     505                // Should read in a multiple of 57 bytes so that 
     506                // the output is 76 bytes per line. Don't use big chunks 
     507                // because base64 encoding is memory expensive 
     508                $buffer = fread($fd, 57 * 9198); // ca. 0.5 MB 
     509                $buffer = base64_encode($buffer); 
     510                $buffer = chunk_split($buffer, 76, $this->_eol); 
     511                if (feof($fd)) { 
     512                    $buffer = rtrim($buffer); 
     513                } 
     514 
     515                if ($fh) { 
     516                    fwrite($fh, $buffer); 
     517                } else { 
     518                    $data .= $buffer; 
     519                } 
     520            } 
     521            break; 
     522 
     523        case '8bit': 
     524        case '7bit': 
     525        default: 
     526            while (!feof($fd)) { 
     527                $buffer = fread($fd, 1048576); // 1 MB 
     528                if ($fh) { 
     529                    fwrite($fh, $buffer); 
     530                } else { 
     531                    $data .= $buffer; 
     532                } 
     533            } 
     534        } 
     535 
     536        fclose($fd); 
     537 
     538        if (!$fh) { 
     539            return $data; 
     540        } 
     541    } 
     542 
     543    /** 
    328544     * Encodes data to quoted-printable standard. 
    329545     * 
    330      * @param $input    The data to encode 
    331      * @param $line_max Optional max line length. Should 
    332      *                  not be more than 76 chars 
     546     * @param string $input    The data to encode 
     547     * @param int    $line_max Optional max line length. Should 
     548     *                         not be more than 76 chars 
     549     * 
     550     * @return string Encoded data 
    333551     * 
    334552     * @access private 
     
    336554    function _quotedPrintableEncode($input , $line_max = 76) 
    337555    { 
     556        $eol = $this->_eol; 
     557        /* 
     558        // imap_8bit() is extremely fast, but doesn't handle properly some characters 
     559        if (function_exists('imap_8bit') && $line_max == 76) { 
     560            $input = preg_replace('/\r?\n/', "\r\n", $input); 
     561            $input = imap_8bit($input); 
     562            if ($eol != "\r\n") { 
     563                $input = str_replace("\r\n", $eol, $input); 
     564            } 
     565            return $input; 
     566        } 
     567        */ 
    338568        $lines  = preg_split("/\r?\n/", $input); 
    339         $eol    = MAIL_MIMEPART_CRLF; 
    340569        $escape = '='; 
    341570        $output = ''; 
    342571 
    343         while (list(, $line) = each($lines)) { 
    344  
    345             $line    = preg_split('||', $line, -1, PREG_SPLIT_NO_EMPTY); 
    346             $linlen     = count($line); 
     572        while (list($idx, $line) = each($lines)) { 
    347573            $newline = ''; 
    348  
    349             for ($i = 0; $i < $linlen; $i++) { 
     574            $i = 0; 
     575 
     576            while (isset($line[$i])) { 
    350577                $char = $line[$i]; 
    351578                $dec  = ord($char); 
    352  
    353                 if (($dec == 32) AND ($i == ($linlen - 1))) {    // convert space at eol only 
     579                $i++; 
     580 
     581                if (($dec == 32) && (!isset($line[$i]))) { 
     582                    // convert space at eol only 
    354583                    $char = '=20'; 
    355  
    356                 } elseif (($dec == 9) AND ($i == ($linlen - 1))) {  // convert tab at eol only 
    357                     $char = '=09'; 
    358                 } elseif ($dec == 9) { 
    359                     ; // Do nothing if a tab. 
    360                 } elseif (($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { 
    361                     $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); 
    362                 } elseif (($dec == 46) AND (($newline == '') || ((strlen($newline) + strlen("=2E")) >= $line_max))) { 
    363                     //Bug #9722: convert full-stop at bol, 
    364                     //some Windows servers need this, won't break anything (cipri) 
    365                     //Bug #11731: full-stop at bol also needs to be encoded 
    366                     //if this line would push us over the line_max limit. 
     584                } elseif ($dec == 9 && isset($line[$i])) { 
     585                    ; // Do nothing if a TAB is not on eol 
     586                } elseif (($dec == 61) || ($dec < 32) || ($dec > 126)) { 
     587                    $char = $escape . sprintf('%02X', $dec); 
     588                } elseif (($dec == 46) && (($newline == '') 
     589                    || ((strlen($newline) + strlen("=2E")) >= $line_max)) 
     590                ) { 
     591                    // Bug #9722: convert full-stop at bol, 
     592                    // some Windows servers need this, won't break anything (cipri) 
     593                    // Bug #11731: full-stop at bol also needs to be encoded 
     594                    // if this line would push us over the line_max limit. 
    367595                    $char = '=2E'; 
    368596                } 
    369597 
    370                 //Note, when changing this line, also change the ($dec == 46) 
    371                 //check line, as it mimics this line due to Bug #11731 
    372                 if ((strlen($newline) + strlen($char)) >= $line_max) {        // MAIL_MIMEPART_CRLF is not counted 
    373                     $output  .= $newline . $escape . $eol;                    // soft line break; " =\r\n" is okay 
     598                // Note, when changing this line, also change the ($dec == 46) 
     599                // check line, as it mimics this line due to Bug #11731 
     600                // EOL is not counted 
     601                if ((strlen($newline) + strlen($char)) >= $line_max) { 
     602                    // soft line break; " =\r\n" is okay 
     603                    $output  .= $newline . $escape . $eol; 
    374604                    $newline  = ''; 
    375605                } 
     
    377607            } // end of for 
    378608            $output .= $newline . $eol; 
    379         } 
    380         $output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf 
     609            unset($lines[$idx]); 
     610        } 
     611        // Don't want last crlf 
     612        $output = substr($output, 0, -1 * strlen($eol)); 
    381613        return $output; 
    382614    } 
    383615 
    384616    /** 
    385      * _buildHeaderParam() 
    386      * 
    387617     * Encodes the paramater of a header. 
    388618     * 
    389      * @param $name         The name of the header-parameter 
    390      * @param $value        The value of the paramter 
    391      * @param $charset      The characterset of $value 
    392      * @param $language     The language used in $value 
    393      * @param $paramEnc     Parameter encoding type 
    394      * @param $maxLength    The maximum length of a line. Defauls to 78 
     619     * @param string $name      The name of the header-parameter 
     620     * @param string $value     The value of the paramter 
     621     * @param string $charset   The characterset of $value 
     622     * @param string $language  The language used in $value 
     623     * @param string $encoding  Parameter encoding. If not set, parameter value 
     624     *                          is encoded according to RFC2231 
     625     * @param int    $maxLength The maximum length of a line. Defauls to 75 
     626     * 
     627     * @return string 
    395628     * 
    396629     * @access private 
    397630     */ 
    398     function _buildHeaderParam($name, $value, $charset=NULL, $language=NULL, $paramEnc=NULL, $maxLength=78) 
    399     { 
    400         // RFC 2045:  
     631    function _buildHeaderParam($name, $value, $charset=null, $language=null, 
     632        $encoding=null, $maxLength=75 
     633    ) { 
     634        // RFC 2045: 
    401635        // value needs encoding if contains non-ASCII chars or is longer than 78 chars 
    402         if (!preg_match('#[^\x20-\x7E]#', $value)) { // ASCII 
    403             // token 
    404             if (!preg_match('#([^\x21,\x23-\x27,\x2A,\x2B,\x2D,\x2E,\x30-\x39,\x41-\x5A,\x5E-\x7E])#', $value)) { 
    405                 if (strlen($name) + strlen($value) + 3 <= $maxLength) 
    406                     return " {$name}={$value};"; 
    407             } else { // quoted-string 
     636        if (!preg_match('#[^\x20-\x7E]#', $value)) { 
     637            $token_regexp = '#([^\x21,\x23-\x27,\x2A,\x2B,\x2D' 
     638                . ',\x2E,\x30-\x39,\x41-\x5A,\x5E-\x7E])#'; 
     639            if (!preg_match($token_regexp, $value)) { 
     640                // token 
     641                if (strlen($name) + strlen($value) + 3 <= $maxLength) { 
     642                    return " {$name}={$value}"; 
     643                } 
     644            } else { 
     645                // quoted-string 
    408646                $quoted = addcslashes($value, '\\"'); 
    409                 if (strlen($name) + strlen($quoted) + 5 <= $maxLength) 
    410                     return " {$name}=\"{$quoted}\";"; 
     647                if (strlen($name) + strlen($quoted) + 5 <= $maxLength) { 
     648                    return " {$name}=\"{$quoted}\""; 
     649                } 
    411650            } 
    412651        } 
    413652 
    414653        // RFC2047: use quoted-printable/base64 encoding 
    415         if ($paramEnc == 'quoted-printable' || $paramEnc == 'base64') 
    416             return $this->_buildRFC2047Param($name, $value, $charset, $paramEnc); 
     654        if ($encoding == 'quoted-printable' || $encoding == 'base64') { 
     655            return $this->_buildRFC2047Param($name, $value, $charset, $encoding); 
     656        } 
    417657 
    418658        // RFC2231: 
    419         $encValue = preg_replace( 
    420             '#([^\x21,\x23,\x24,\x26,\x2B,\x2D,\x2E,\x30-\x39,\x41-\x5A,\x5E-\x7E])#e', 
    421             '"%" . strtoupper(dechex(ord("\1")))', 
    422             $value); 
     659        $encValue = preg_replace_callback( 
     660            '/([^\x21,\x23,\x24,\x26,\x2B,\x2D,\x2E,\x30-\x39,\x41-\x5A,\x5E-\x7E])/', 
     661            array($this, '_encodeReplaceCallback'), $value 
     662        ); 
    423663        $value = "$charset'$language'$encValue"; 
    424664 
    425         $header = " {$name}*={$value};"; 
     665        $header = " {$name}*={$value}"; 
    426666        if (strlen($header) <= $maxLength) { 
    427667            return $header; 
     
    446686            $headCount++; 
    447687        } 
    448         $headers = implode(';' . MAIL_MIMEPART_CRLF, $headers) . ';'; 
     688 
     689        $headers = implode(';' . $this->_eol, $headers); 
    449690        return $headers; 
    450691    } 
    451692 
    452693    /** 
    453      * Encodes header parameter as per RFC2047 if needed (values too long will be truncated) 
    454      * 
    455      * @param string $name  The parameter name 
    456      * @param string $value  The parameter value 
    457      * @param string $charset  The parameter charset 
     694     * Encodes header parameter as per RFC2047 if needed 
     695     * 
     696     * @param string $name      The parameter name 
     697     * @param string $value     The parameter value 
     698     * @param string $charset   The parameter charset 
    458699     * @param string $encoding  Encoding type (quoted-printable or base64) 
    459      * @param int $maxLength  Encoded parameter max length (75 is the value specified in the RFC) 
     700     * @param int    $maxLength Encoded parameter max length. Default: 76 
    460701     * 
    461702     * @return string Parameter line 
    462703     * @access private 
    463704     */ 
    464     function _buildRFC2047Param($name, $value, $charset, $encoding='quoted-printable', $maxLength=75) 
    465     { 
     705    function _buildRFC2047Param($name, $value, $charset, 
     706        $encoding='quoted-printable', $maxLength=76 
     707    ) { 
    466708        // WARNING: RFC 2047 says: "An 'encoded-word' MUST NOT be used in 
    467         // parameter of a MIME Content-Type or Content-Disposition field" 
     709        // parameter of a MIME Content-Type or Content-Disposition field", 
    468710        // but... it's supported by many clients/servers 
    469  
    470         if ($encoding == 'base64') 
    471         { 
     711        $quoted = ''; 
     712 
     713        if ($encoding == 'base64') { 
    472714            $value = base64_encode($value); 
    473715            $prefix = '=?' . $charset . '?B?'; 
    474716            $suffix = '?='; 
    475             $quoted = ''; 
    476  
    477             $add_len = strlen($prefix . $suffix) + strlen($name) + 6; // 2 x SPACE, 2 x '"', '=', ';' 
     717 
     718            // 2 x SPACE, 2 x '"', '=', ';' 
     719            $add_len = strlen($prefix . $suffix) + strlen($name) + 6; 
    478720            $len = $add_len + strlen($value); 
    479721 
     
    484726                $value = substr($value, $real_len); 
    485727 
    486                 $quoted .= $prefix . $_quote . $suffix . MAIL_MIMEPART_CRLF . ' '; 
     728                $quoted .= $prefix . $_quote . $suffix . $this->_eol . ' '; 
    487729                $add_len = strlen($prefix . $suffix) + 4; // 2 x SPACE, '"', ';' 
    488730                $len = strlen($value) + $add_len; 
     
    490732            $quoted .= $prefix . $value . $suffix; 
    491733 
    492         } 
    493         else // quoted-printable 
    494         { 
    495             // Replace all special characters used by the encoder. 
    496             $search  = array('=',   '_',   '?',   ' '); 
    497             $replace = array('=3D', '=5F', '=3F', '_'); 
    498             $value = str_replace($search, $replace, $value); 
    499  
    500             // Replace all extended characters (\x80-xFF) with their 
    501             // ASCII values. 
    502             $value = preg_replace('/([\x80-\xFF])/e', 
    503                 '"=" . strtoupper(dechex(ord("\1")))', $value); 
    504  
     734        } else { 
     735            // quoted-printable 
     736            $value = $this->encodeQP($value); 
    505737            $prefix = '=?' . $charset . '?Q?'; 
    506738            $suffix = '?='; 
    507739 
    508             $add_len = strlen($prefix . $suffix) + strlen($name) + 6; // 2 x SPACE, 2 x '"', '=', ';' 
     740            // 2 x SPACE, 2 x '"', '=', ';' 
     741            $add_len = strlen($prefix . $suffix) + strlen($name) + 6; 
    509742            $len = $add_len + strlen($value); 
    510743 
    511744            while ($len > $maxLength) { 
    512745                $length = $maxLength - $add_len; 
    513                 // not break any encoded letters 
    514                 if(preg_match("/^(.{0,$length}[^\=][^\=])/", $value, $matches)) 
     746                // don't break any encoded letters 
     747                if (preg_match("/^(.{0,$length}[^\=][^\=])/", $value, $matches)) { 
    515748                    $_quote = $matches[1]; 
    516  
    517                 $quoted .= $prefix . $_quote . $suffix . MAIL_MIMEPART_CRLF . ' '; 
     749                } 
     750 
     751                $quoted .= $prefix . $_quote . $suffix . $this->_eol . ' '; 
    518752                $value = substr($value, strlen($_quote)); 
    519753                $add_len = strlen($prefix . $suffix) + 4; // 2 x SPACE, '"', ';' 
     
    524758        } 
    525759 
    526         return " {$name}=\"{$quoted}\"; "; 
     760        return " {$name}=\"{$quoted}\""; 
     761    } 
     762 
     763    /** 
     764     * Callback function to replace extended characters (\x80-xFF) with their 
     765     * ASCII values (RFC2231) 
     766     * 
     767     * @param array $matches Preg_replace's matches array 
     768     * 
     769     * @return string        Encoded character string 
     770     * @access private 
     771     */ 
     772    function _encodeReplaceCallback($matches) 
     773    { 
     774        return sprintf('%%%02X', ord($matches[1])); 
     775    } 
     776 
     777    /** 
     778     * Encodes the given string using quoted-printable 
     779     * 
     780     * @param string $str String to encode 
     781     * 
     782     * @return string     Encoded string 
     783     * @access public 
     784     * @since 1.6.0 
     785     */ 
     786    function encodeQP($str) 
     787    { 
     788        // Replace all special characters used by the encoder 
     789        $search  = array('=',   '_',   '?',   ' '); 
     790        $replace = array('=3D', '=5F', '=3F', '_'); 
     791        $str = str_replace($search, $replace, $str); 
     792 
     793        // Replace all extended characters (\x80-xFF) with their 
     794        // ASCII values. 
     795        return preg_replace_callback( 
     796            '/([\x80-\xFF])/', array('Mail_mimePart', '_qpReplaceCallback'), $str 
     797        ); 
     798    } 
     799 
     800    /** 
     801     * Callback function to replace extended characters (\x80-xFF) with their 
     802     * ASCII values (RFC2047: quoted-printable) 
     803     * 
     804     * @param array $matches Preg_replace's matches array 
     805     * 
     806     * @return string        Encoded character string 
     807     * @access private 
     808     */ 
     809    function _qpReplaceCallback($matches) 
     810    { 
     811        return sprintf('=%02X', ord($matches[1])); 
    527812    } 
    528813 
Note: See TracChangeset for help on using the changeset viewer.