Changeset 1530 in subversion
- Timestamp:
- Jun 13, 2008 3:42:15 PM (5 years ago)
- Location:
- trunk/roundcubemail
- Files:
-
- 3 edited
-
CHANGELOG (modified) (1 diff)
-
program/lib/Mail/mime.php (modified) (40 diffs)
-
program/lib/Mail/mimePart.php (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/roundcubemail/CHANGELOG
r1525 r1530 5 5 ---------- 6 6 - Added option to display images in messages from known senders (#1484601) 7 - Updated PEAR::Mail_Mime 7 8 8 9 2008/06/12 (alec) -
trunk/roundcubemail/program/lib/Mail/mime.php
r514 r1530 40 40 * THE POSSIBILITY OF SUCH DAMAGE. 41 41 * 42 * @category Mail 43 * @package Mail_Mime 44 * @author Richard Heyes <richard@phpguru.org> 45 * @author Tomas V.V. Cox <cox@idecnet.com> 46 * @author Cipriano Groenendal <cipri@php.net> 47 * @author Sean Coates <sean@php.net> 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 52 * @notes This class is based on HTML Mime Mail class from 53 * Richard Heyes <richard@phpguru.org> which was based also 54 * in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> 55 * and Sascha Schumann <sascha@schumann.cx> 42 * @category Mail 43 * @package Mail_Mime 44 * @author Richard Heyes <richard@phpguru.org> 45 * @author Tomas V.V. Cox <cox@idecnet.com> 46 * @author Cipriano Groenendal <cipri@php.net> 47 * @author Sean Coates <sean@php.net> 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 52 * 53 * This class is based on HTML Mime Mail class from 54 * Richard Heyes <richard@phpguru.org> which was based also 55 * in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> 56 * and Sascha Schumann <sascha@schumann.cx> 56 57 */ 57 58 … … 62 63 * This package depends on PEAR to raise errors. 63 64 */ 64 require_once ('PEAR.php');65 require_once 'PEAR.php'; 65 66 66 67 /** … … 71 72 * consist of. 72 73 */ 73 require_once ('Mail/mimePart.php');74 require_once 'Mail/mimePart.php'; 74 75 75 76 … … 80 81 * images and specific headers. 81 82 * 82 * @category 83 * @package Mail_Mime84 * @author Richard Heyes <richard@phpguru.org>85 * @author Tomas V.V. Cox <cox@idecnet.com>86 * @author Cipriano Groenendal <cipri@php.net>87 * @author Sean Coates <sean@php.net>88 * @copyright 2003-2006 PEAR <pear-group@php.net>89 * @license http://www.opensource.org/licenses/bsd-license.php BSD License90 * @version Release: @package_version@91 * @link http://pear.php.net/package/Mail_mime83 * @category Mail 84 * @package Mail_Mime 85 * @author Richard Heyes <richard@phpguru.org> 86 * @author Tomas V.V. Cox <cox@idecnet.com> 87 * @author Cipriano Groenendal <cipri@php.net> 88 * @author Sean Coates <sean@php.net> 89 * @copyright 2003-2006 PEAR <pear-group@php.net> 90 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 91 * @version Release: @package_version@ 92 * @link http://pear.php.net/package/Mail_mime 92 93 */ 93 94 class Mail_mime … … 169 170 * Constructor function. 170 171 * 171 * @param string $crlf what type of linebreak to use. 172 * Defaults to "\r\n" 172 * @param string $crlf what type of linebreak to use. 173 * Defaults to "\r\n" 174 * 173 175 * @return void 174 176 * … … 193 195 * 194 196 * @access private 197 * @return void 195 198 */ 196 199 function __wakeup() … … 206 209 * html should show. 207 210 * 208 * @param string $data Either a string or 209 * the file name with the contents 210 * @param bool $isfile If true the first param should be treated 211 * as a file name, else as a string (default) 212 * @param bool $append If true the text or file is appended to 213 * the existing body, else the old body is 214 * overwritten 211 * @param string $data Either a string or 212 * the file name with the contents 213 * @param bool $isfile If true the first param should be treated 214 * as a file name, else as a string (default) 215 * @param bool $append If true the text or file is appended to 216 * the existing body, else the old body is 217 * overwritten 218 * 215 219 * @return mixed true on success or PEAR_Error object 216 220 * @access public … … 241 245 * Adds a html part to the mail. 242 246 * 243 * @param string $data either a string or the file name with the 244 * contents 245 * @param bool $isfile a flag that determines whether $data is a 246 * filename, or a string(false, default) 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 * 247 252 * @return bool true on success 248 253 * @access public … … 266 271 * Adds an image to the list of embedded images. 267 272 * 268 * @param string $file the image file name OR image data itself 269 * @param string $c_type the content type 270 * @param string $name the filename of the image. 271 * Only use if $file is the image data. 272 * @param bool $isfile whether $file is a filename or not. 273 * Defaults to true 274 * @return bool true on success 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 275 281 * @access public 276 282 */ … … 300 306 * Adds a file to the list of attachments. 301 307 * 302 * @param string $file The file name of the file to attach 303 * OR the file contents itself 304 * @param string $c_type The content type 305 * @param string $name The filename of the attachment 306 * Only use if $file is the contents 307 * @param bool $isfile Whether $file is a filename or not 308 * Defaults to true 309 * @param string $encoding The type of encoding to use. 310 * Defaults to base64. 311 * Possible values: 7bit, 8bit, base64, 312 * or quoted-printable. 313 * @param string $disposition The content-disposition of this file 314 * Defaults to attachment. 315 * Possible values: attachment, inline. 316 * @param string $charset The character set used in the filename 317 * of this attachment. 308 * @param string $file The file name of the file to attach 309 * OR the file contents itself 310 * @param string $c_type The content type 311 * @param string $name The filename of the attachment 312 * Only use if $file is the contents 313 * @param bool $isfile Whether $file is a filename or not 314 * Defaults to true 315 * @param string $encoding The type of encoding to use. 316 * Defaults to base64. 317 * Possible values: 7bit, 8bit, base64, 318 * or quoted-printable. 319 * @param string $disposition The content-disposition of this file 320 * Defaults to attachment. 321 * Possible values: attachment, inline. 322 * @param string $charset The character set used in the filename 323 * of this attachment. 324 * @param string $language The language of the attachment 325 * @param string $location The RFC 2557.4 location of the attachment 326 * 318 327 * @return mixed true on success or PEAR_Error object 319 328 * @access public 320 329 */ 321 function addAttachment($file, $c_type = 'application/octet-stream', 322 $name = '', $isfile = true, 323 $encoding = 'base64', 324 $disposition = 'attachment', $charset = '') 330 function addAttachment($file, 331 $c_type = 'application/octet-stream', 332 $name = '', 333 $isfile = true, 334 $encoding = 'base64', 335 $disposition = 'attachment', 336 $charset = '', 337 $language = '', 338 $location = '') 325 339 { 326 340 $filedata = ($isfile === true) ? $this->_file2str($file) … … 328 342 if ($isfile === true) { 329 343 // Force the name the user supplied, otherwise use $file 330 $filename = ( !empty($name)) ? $name : $file;344 $filename = (strlen($name)) ? $name : $file; 331 345 } else { 332 346 $filename = $name; 333 347 } 334 if (empty($filename)) { 335 $err = PEAR::raiseError( 336 "The supplied filename for the attachment can't be empty" 337 ); 338 return $err; 348 if (!strlen($filename)) { 349 $msg = "The supplied filename for the attachment can't be empty"; 350 $err = PEAR::raiseError($msg); 351 return $err; 339 352 } 340 353 $filename = basename($filename); … … 349 362 'encoding' => $encoding, 350 363 'charset' => $charset, 364 'language' => $language, 365 'location' => $location, 351 366 'disposition' => $disposition 352 367 ); … … 357 372 * Get the contents of the given file name as string 358 373 * 359 * @param string $file_name path of file to process 374 * @param string $file_name path of file to process 375 * 360 376 * @return string contents of $file_name 361 377 * @access private … … 363 379 function &_file2str($file_name) 364 380 { 381 //Check state of file and raise an error properly 382 if (!file_exists($file_name)) { 383 $err = PEAR::raiseError('File not found: ' . $file_name); 384 return $err; 385 } 386 if (!is_file($file_name)) { 387 $err = PEAR::raiseError('Not a regular file: ' . $file_name); 388 return $err; 389 } 365 390 if (!is_readable($file_name)) { 366 $err = PEAR::raiseError('File is not readable ' . $file_name);391 $err = PEAR::raiseError('File is not readable: ' . $file_name); 367 392 return $err; 368 393 } 369 if (!$fd = fopen($file_name, 'rb')) { 370 $err = PEAR::raiseError('Could not open ' . $file_name); 371 return $err; 372 } 373 $filesize = filesize($file_name); 374 if ($filesize == 0){ 375 $cont = ""; 376 }else{ 377 if ($magic_quote_setting = get_magic_quotes_runtime()){ 378 set_magic_quotes_runtime(0); 379 } 380 $cont = fread($fd, $filesize); 381 if ($magic_quote_setting){ 382 set_magic_quotes_runtime($magic_quote_setting); 383 } 384 } 385 fclose($fd); 394 395 //Temporarily reset magic_quotes_runtime and read file contents 396 if ($magic_quote_setting = get_magic_quotes_runtime()) { 397 set_magic_quotes_runtime(0); 398 } 399 $cont = file_get_contents($file_name); 400 if ($magic_quote_setting) { 401 set_magic_quotes_runtime($magic_quote_setting); 402 } 403 386 404 return $cont; 387 405 } … … 391 409 * returns it during the build process. 392 410 * 393 * @param mixed The object to add the part to, or 394 * null if a new object is to be created. 395 * @param string The text to add. 411 * @param mixed &$obj The object to add the part to, or 412 * null if a new object is to be created. 413 * @param string $text The text to add. 414 * 396 415 * @return object The text mimePart object 397 416 * @access private … … 415 434 * returns it during the build process. 416 435 * 417 * @param mixed The object to add the part to, or 418 * null if a new object is to be created. 419 * @return object The html mimePart object 436 * @param mixed &$obj The object to add the part to, or 437 * null if a new object is to be created. 438 * 439 * @return object The html mimePart object 420 440 * @access private 421 441 */ … … 439 459 * build process. 440 460 * 441 * @return object The multipart/mixed mimePart object461 * @return object The multipart/mixed mimePart object 442 462 * @access private 443 463 */ 444 464 function &_addMixedPart() 445 465 { 466 $params = array(); 446 467 $params['content_type'] = 'multipart/mixed'; 468 469 //Create empty multipart/mixed Mail_mimePart object to return 447 470 $ret = new Mail_mimePart('', $params); 448 471 return $ret; … … 454 477 * the build process. 455 478 * 456 * @param mixed The object to add the part to, or 457 * null if a new object is to be created. 479 * @param mixed &$obj The object to add the part to, or 480 * null if a new object is to be created. 481 * 458 482 * @return object The multipart/mixed mimePart object 459 483 * @access private … … 475 499 * the build process. 476 500 * 477 * @param mixed The object to add the part to, or 478 * null if a new object is to be created 501 * @param mixed &$obj The object to add the part to, or 502 * null if a new object is to be created 503 * 479 504 * @return object The multipart/mixed mimePart object 480 505 * @access private … … 495 520 * and returns it during the build process. 496 521 * 497 * @param object The mimePart to add the image to 498 * @param array The image information 522 * @param object &$obj The mimePart to add the image to 523 * @param array $value The image information 524 * 499 525 * @return object The image mimePart object 500 526 * @access private … … 502 528 function &_addHtmlImagePart(&$obj, $value) 503 529 { 504 $params['content_type'] = $value['c_type'] . '; ' . 505 'name="' . $value['name'] . '"'; 530 $params['content_type'] = $value['c_type']; 506 531 $params['encoding'] = 'base64'; 507 532 $params['disposition'] = 'inline'; 508 533 $params['dfilename'] = $value['name']; 509 534 $params['cid'] = $value['cid']; 535 510 536 $ret = $obj->addSubpart($value['body'], $params); 511 537 return $ret; 512 538 513 539 } 514 540 … … 517 543 * and returns it during the build process. 518 544 * 519 * @param object The mimePart to add the image to 520 * @param array The attachment information 545 * @param object &$obj The mimePart to add the image to 546 * @param array $value The attachment information 547 * 521 548 * @return object The image mimePart object 522 549 * @access private … … 524 551 function &_addAttachmentPart(&$obj, $value) 525 552 { 526 $params['dfilename'] = $value['name']; 527 $params['encoding'] = $value['encoding']; 528 if ($value['disposition'] != "inline") { 529 $fname = array("fname" => $value['name']); 530 $fname_enc = $this->_encodeHeaders($fname, array('head_charset' => $value['charset'] ? $value['charset'] : 'iso-8859-1')); 531 $params['dfilename'] = $fname_enc['fname']; 532 } 553 $params['dfilename'] = $value['name']; 554 $params['encoding'] = $value['encoding']; 533 555 if ($value['charset']) { 534 556 $params['charset'] = $value['charset']; 535 557 } 536 $params['content_type'] = $value['c_type'] . '; ' . 537 'name="' . $params['dfilename'] . '"'; 558 if ($value['language']) { 559 $params['language'] = $value['language']; 560 } 561 if ($value['location']) { 562 $params['location'] = $value['location']; 563 } 564 $params['content_type'] = $value['c_type']; 538 565 $params['disposition'] = isset($value['disposition']) ? 539 566 $value['disposition'] : 'attachment'; … … 549 576 * using the $xtra_headers parameter! 550 577 * 551 * @param string $separation The separation etween these two parts. 552 * @param array $build_params The Build parameters passed to the 553 * &get() function. See &get for more info. 554 * @param array $xtra_headers The extra headers that should be passed 555 * to the &headers() function. 556 * See that function for more info. 557 * @param bool $overwrite Overwrite the existing headers with new. 578 * @param string $separation The separation etween these two parts. 579 * @param array $build_params The Build parameters passed to the 580 * &get() function. See &get for more info. 581 * @param array $xtra_headers The extra headers that should be passed 582 * to the &headers() function. 583 * See that function for more info. 584 * @param bool $overwrite Overwrite the existing headers with new. 585 * 558 586 * @return string The complete e-mail. 559 587 * @access public 560 588 */ 561 function getMessage($separation = null, $build_params = null, $xtra_headers = null, $overwrite = false) 562 { 563 if ($separation === null) 564 { 589 function getMessage( 590 $separation = null, 591 $build_params = null, 592 $xtra_headers = null, 593 $overwrite = false 594 ) 595 { 596 if ($separation === null) { 565 597 $separation = MAIL_MIME_CRLF; 566 598 } … … 576 608 * returns the mime content. 577 609 * 578 * @param arrayBuild parameters that change the way the email579 * is built. Should be associative. Can contain:610 * @param array $build_params Build parameters that change the way the email 611 * is built. Should be associative. Can contain: 580 612 * head_encoding - What encoding to use for the headers. 581 613 * Options: quoted-printable or base64 582 614 * Default is quoted-printable 583 615 * text_encoding - What encoding to use for plain text 584 * Options: 7bit, 8bit, base64, or quoted-printable 616 * Options: 7bit, 8bit, 617 * base64, or quoted-printable 585 618 * Default is 7bit 586 619 * html_encoding - What encoding to use for html 587 * Options: 7bit, 8bit, base64, or quoted-printable 620 * Options: 7bit, 8bit, 621 * base64, or quoted-printable 588 622 * Default is quoted-printable 589 623 * 7bit_wrap - Number of characters before text is … … 596 630 * head_charset - The character set to use for headers. 597 631 * Default is iso-8859-1 632 * 598 633 * @return string The mime content 599 634 * @access public … … 606 641 } 607 642 } 608 609 if (!empty($this->_html_images) AND isset($this->_htmlbody)) { 643 644 if (isset($this->_headers['From'])){ 645 //Bug #11381: Illegal characters in domain ID 646 if (preg_match("|(@[0-9a-zA-Z\-\.]+)|", $this->_headers['From'], $matches)){ 647 $domainID = $matches[1]; 648 }else{ 649 $domainID = "@localhost"; 650 } 651 foreach($this->_html_images as $i => $img){ 652 $this->_html_images[$i]['cid'] = $this->_html_images[$i]['cid'] . $domainID; 653 } 654 } 655 656 if (count($this->_html_images) AND isset($this->_htmlbody)) { 610 657 foreach ($this->_html_images as $key => $value) { 611 $regex = array();658 $regex = array(); 612 659 $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' . 613 660 preg_quote($value['name'], '#') . '\3#'; 614 661 $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' . 615 662 preg_quote($value['name'], '#') . '\1\s*\)#'; 616 $rep = array(); 663 664 $rep = array(); 617 665 $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3'; 618 $rep[] = 'url(\1cid:' . $value['cid'] . '\ 2)';619 $this->_htmlbody = preg_replace($regex, $rep, 620 $this->_htmlbody621 );622 $this->_html_images[$key]['name'] =basename($this->_html_images[$key]['name']);666 $rep[] = 'url(\1cid:' . $value['cid'] . '\1)'; 667 668 $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody); 669 $this->_html_images[$key]['name'] = 670 basename($this->_html_images[$key]['name']); 623 671 } 624 672 } 625 673 626 674 $null = null; 627 $attachments = !empty($this->_parts)? true : false;628 $html_images = !empty($this->_html_images)? true : false;629 $html = !empty($this->_htmlbody) ? true : false;630 $text = (!$html AND !empty($this->_txtbody)) ? true : false;675 $attachments = count($this->_parts) ? true : false; 676 $html_images = count($this->_html_images) ? true : false; 677 $html = strlen($this->_htmlbody) ? true : false; 678 $text = (!$html AND strlen($this->_txtbody)) ? true : false; 631 679 632 680 switch (true) { … … 661 709 662 710 case $html AND !$attachments AND $html_images: 711 $message =& $this->_addRelatedPart($null); 663 712 if (isset($this->_txtbody)) { 664 $ message =& $this->_addAlternativePart($null);665 $this->_addTextPart($ message, $this->_txtbody);666 $ related =& $this->_addRelatedPart($message);713 $alt =& $this->_addAlternativePart($message); 714 $this->_addTextPart($alt, $this->_txtbody); 715 $this->_addHtmlPart($alt); 667 716 } else { 668 $message =& $this->_addRelatedPart($null); 669 $related =& $message; 670 } 671 $this->_addHtmlPart($related); 717 $this->_addHtmlPart($message); 718 } 672 719 for ($i = 0; $i < count($this->_html_images); $i++) { 673 $this->_addHtmlImagePart($ related, $this->_html_images[$i]);720 $this->_addHtmlImagePart($message, $this->_html_images[$i]); 674 721 } 675 722 break; … … 711 758 if (isset($message)) { 712 759 $output = $message->encode(); 760 713 761 $this->_headers = array_merge($this->_headers, 714 762 $output['headers']); … … 727 775 * $array['header-name'] = 'header-value'; 728 776 * 729 * @param array $xtra_headers Assoc array with any extra headers.777 * @param array $xtra_headers Assoc array with any extra headers. 730 778 * Optional. 731 * @param bool $overwrite Overwrite already existing headers. 779 * @param bool $overwrite Overwrite already existing headers. 780 * 732 781 * @return array Assoc array with the mime headers 733 782 * @access public … … 741 790 $headers = array_merge($headers, $xtra_headers); 742 791 } 743 if ($overwrite) {792 if ($overwrite) { 744 793 $this->_headers = array_merge($this->_headers, $headers); 745 } else{794 } else { 746 795 $this->_headers = array_merge($headers, $this->_headers); 747 796 } … … 755 804 * (usefull if you want to use the PHP mail() function) 756 805 * 757 * @param array $xtra_headers Assoc array with any extra headers. 758 * Optional. 759 * @param bool $overwrite Overwrite the existing heaers with new. 806 * @param array $xtra_headers Assoc array with any extra headers. 807 * Optional. 808 * @param bool $overwrite Overwrite the existing heaers with new. 809 * 760 810 * @return string Plain text headers 761 811 * @access public … … 764 814 { 765 815 $headers = $this->headers($xtra_headers, $overwrite); 816 766 817 $ret = ''; 767 818 foreach ($headers as $key => $val) { … … 774 825 * Sets the Subject header 775 826 * 776 * @param string $subject String to set the subject to 777 * access public 827 * @param string $subject String to set the subject to. 828 * 829 * @return void 830 * @access public 778 831 */ 779 832 function setSubject($subject) … … 785 838 * Set an email to the From (the sender) header 786 839 * 787 * @param string $email The email direction to add 840 * @param string $email The email address to use 841 * 842 * @return void 788 843 * @access public 789 844 */ … … 797 852 * (multiple calls to this method are allowed) 798 853 * 799 * @param string $email The email direction to add 854 * @param string $email The email direction to add 855 * 856 * @return void 800 857 * @access public 801 858 */ … … 813 870 * (multiple calls to this method are allowed) 814 871 * 815 * @param string $email The email direction to add 872 * @param string $email The email direction to add 873 * 874 * @return void 816 875 * @access public 817 876 */ … … 833 892 * function 834 893 * 835 * @param string $recipients A comma-delimited list of recipients 894 * @param string $recipients A comma-delimited list of recipients 895 * 836 896 * @return string Encoded data 837 897 * @access public … … 847 907 * Encodes a header as per RFC2047 848 908 * 849 * @param array $input The header data to encode 850 * @param array $params Extra build parameters 909 * @param array $input The header data to encode 910 * @param array $params Extra build parameters 911 * 851 912 * @return array Encoded data 852 913 * @access private … … 859 920 $build_params[$key] = $value; 860 921 } 861 922 //$hdr_name: Name of the heaer 923 //$hdr_value: Full line of header value. 924 //$atoms: The $hdr_value split into atoms* 925 //$atom: A single atom to encode.* 926 //$hdr_value_out: The recombined $hdr_val-atoms, or the encoded string. 927 //Note: Atom as specified here is not exactly the same as an RFC822 atom, 928 //as $atom's may contain just a single space. 929 930 $useIconv = true; 931 if (isset($build_params['ignore-iconv'])) { 932 $useIconv = !$build_params['ignore-iconv']; 933 } 862 934 foreach ($input as $hdr_name => $hdr_value) { 863 $hdr_vals = preg_split("|(\s)|", $hdr_value, -1, PREG_SPLIT_DELIM_CAPTURE); 864 $hdr_value_out=""; 865 $previous = ""; 866 foreach ($hdr_vals as $hdr_val){ 867 if (!trim($hdr_val)){ 868 //whitespace needs to be handled with another string, or it 869 //won't show between encoded strings. Prepend this to the next item. 870 $previous .= $hdr_val; 871 continue; 872 }else{ 873 $hdr_val = $previous . $hdr_val; 874 $previous = ""; 935 /* 936 $parts = preg_split('/([ ])/', $hdr_value, -1, PREG_SPLIT_DELIM_CAPTURE); 937 $atoms = array(); 938 foreach ($parts as $part){ 939 $atom .= $part; 940 $quoteMatch = preg_match_all('|"|', $atom, $matches) % 2; 941 if (!$quoteMatch){ 942 $atoms[] = $atom; 943 $atom = null; 875 944 } 876 if (function_exists('iconv_mime_encode') && preg_match('#[\x80-\xFF]{1}#', $hdr_val)){ 877 $imePref = array(); 878 if ($build_params['head_encoding'] == 'base64'){ 945 } 946 if ($atom){ 947 $atoms[] = $atom; 948 } 949 foreach ($atoms as $atom){ 950 */ 951 if (preg_match('#([\x80-\xFF]){1}#', $hdr_value)) { 952 if (function_exists('iconv_mime_encode') && $useIconv) { 953 $imePrefs = array(); 954 if ($build_params['head_encoding'] == 'base64') { 879 955 $imePrefs['scheme'] = 'B'; 880 } else{956 } else { 881 957 $imePrefs['scheme'] = 'Q'; 882 958 } 883 959 $imePrefs['input-charset'] = $build_params['head_charset']; 884 960 $imePrefs['output-charset'] = $build_params['head_charset']; 885 $hdr_val = iconv_mime_encode($hdr_name, $hdr_val, $imePrefs); 886 $hdr_val = preg_replace("#^{$hdr_name}\:\ #", "", $hdr_val); 887 }elseif (preg_match('#[\x80-\xFF]{1}#', $hdr_val)){ 888 //This header contains non ASCII chars and should be encoded. 889 switch ($build_params['head_encoding']) { 890 case 'base64': 891 //Base64 encoding has been selected. 892 893 //Generate the header using the specified params and dynamicly 894 //determine the maximum length of such strings. 895 //75 is the value specified in the RFC. The first -2 is there so 896 //the later regexp doesn't break any of the translated chars. 897 //The -2 on the first line-regexp is to compensate for the ": " 898 //between the header-name and the header value 899 $prefix = '=?' . $build_params['head_charset'] . '?B?'; 900 $suffix = '?='; 901 $maxLength = 75 - strlen($prefix . $suffix) - 2; 902 $maxLength1stLine = $maxLength - strlen($hdr_name) - 2; 903 904 //Base64 encode the entire string 905 $hdr_val = base64_encode($hdr_val); 906 907 //This regexp will break base64-encoded text at every 908 //$maxLength but will not break any encoded letters. 909 $reg1st = "|.{0,$maxLength1stLine}[^\=][^\=]|"; 910 $reg2nd = "|.{0,$maxLength}[^\=][^\=]|"; 911 break; 912 case 'quoted-printable': 913 default: 914 //quoted-printable encoding has been selected 915 916 //Generate the header using the specified params and dynamicly 917 //determine the maximum length of such strings. 918 //75 is the value specified in the RFC. The -2 is there so 919 //the later regexp doesn't break any of the translated chars. 920 //The -2 on the first line-regexp is to compensate for the ": " 921 //between the header-name and the header value 922 $prefix = '=?' . $build_params['head_charset'] . '?Q?'; 923 $suffix = '?='; 924 $maxLength = 75 - strlen($prefix . $suffix) - 2; 925 $maxLength1stLine = $maxLength - strlen($hdr_name) - 2; 926 927 //Replace all special characters used by the encoder. 928 $search = array("=", "_", "?", " "); 929 $replace = array("=3D", "=5F", "=3F", "_"); 930 $hdr_val = str_replace($search, $replace, $hdr_val); 931 932 //Replace all extended characters (\x80-xFF) with their 933 //ASCII values. 934 $hdr_val = preg_replace( 935 '#([\x80-\xFF])#e', 936 '"=" . strtoupper(dechex(ord("\1")))', 937 $hdr_val 938 ); 939 //This regexp will break QP-encoded text at every $maxLength 940 //but will not break any encoded letters. 941 $reg1st = "|(.{0,$maxLength1stLine})[^\=]|"; 942 $reg2nd = "|(.{0,$maxLength})[^\=]|"; 943 break; 944 } 945 //Begin with the regexp for the first line. 946 $reg = $reg1st; 947 //Prevent lins that are just way to short; 948 if ($maxLength1stLine >1){ 949 $reg = $reg2nd; 950 } 961 $imePrefs['line-length'] = 74; 962 $imePrefs['line-break-chars'] = "\r\n"; //Specified in RFC2047 963 964 $hdr_value = iconv_mime_encode($hdr_name, $hdr_value, $imePrefs); 965 $hdr_value = preg_replace("#^{$hdr_name}\:\ #", "", $hdr_value); 966 } elseif ($build_params['head_encoding'] == 'base64') { 967 //Base64 encoding has been selected. 968 //Base64 encode the entire string 969 $hdr_value = base64_encode($hdr_value); 970 971 //Generate the header using the specified params and dynamicly 972 //determine the maximum length of such strings. 973 //75 is the value specified in the RFC. The first -2 is there so 974 //the later regexp doesn't break any of the translated chars. 975 //The -2 on the first line-regexp is to compensate for the ": " 976 //between the header-name and the header value 977 $prefix = '=?' . $build_params['head_charset'] . '?B?'; 978 $suffix = '?='; 979 $maxLength = 75 - strlen($prefix . $suffix) - 2; 980 $maxLength1stLine = $maxLength - strlen($hdr_name) - 2; 981 982 //We can cut base4 every 4 characters, so the real max 983 //we can get must be rounded down. 984 $maxLength = $maxLength - ($maxLength % 4); 985 $maxLength1stLine = $maxLength1stLine - ($maxLength1stLine % 4); 986 987 $cutpoint = $maxLength1stLine; 988 $hdr_value_out = $hdr_value; 951 989 $output = ""; 952 while ($hdr_val ) {990 while ($hdr_value_out) { 953 991 //Split translated string at every $maxLength 954 //But make sure not to break any translated chars. 955 $found = preg_match($reg, $hdr_val, $matches); 956 957 //After this first line, we need to use a different 958 //regexp for the first line. 959 $reg = $reg2nd; 960 961 //Save the found part and encapsulate it in the 962 //prefix & suffix. Then remove the part from the 963 //$hdr_val variable. 964 if ($found){ 965 $part = $matches[0]; 966 $hdr_val = substr($hdr_val, strlen($matches[0])); 967 }else{ 968 $part = $hdr_val; 969 $hdr_val = ""; 970 } 971 972 //RFC 2047 specifies that any split header should be seperated 973 //by a CRLF SPACE. 974 if ($output){ 992 $part = substr($hdr_value_out, 0, $cutpoint); 993 $hdr_value_out = substr($hdr_value_out, $cutpoint); 994 $cutpoint = $maxLength; 995 //RFC 2047 specifies that any split header should 996 //be seperated by a CRLF SPACE. 997 if ($output) { 975 998 $output .= "\r\n "; 976 999 } 977 1000 $output .= $prefix . $part . $suffix; 978 1001 } 979 $hdr_val = $output; 1002 $hdr_value = $output; 1003 } else { 1004 //quoted-printable encoding has been selected 1005 1006 //Fix for Bug #10298, Ota Mares <om@viazenetti.de> 1007 //Check if there is a double quote at beginning or end of 1008 //the string to prevent that an open or closing quote gets 1009 //ignored because it is encapsuled by an encoding pre/suffix. 1010 //Remove the double quote and set the specific prefix or 1011 //suffix variable so that we can concat the encoded string and 1012 //the double quotes back together to get the intended string. 1013 $quotePrefix = $quoteSuffix = ''; 1014 if ($hdr_value{0} == '"') { 1015 $hdr_value = substr($hdr_value, 1); 1016 $quotePrefix = '"'; 1017 } 1018 if ($hdr_value{strlen($hdr_value)-1} == '"') { 1019 $hdr_value = substr($hdr_value, 0, -1); 1020 $quoteSuffix = '"'; 1021 } 1022 1023 //Generate the header using the specified params and dynamicly 1024 //determine the maximum length of such strings. 1025 //75 is the value specified in the RFC. The -2 is there so 1026 //the later regexp doesn't break any of the translated chars. 1027 //The -2 on the first line-regexp is to compensate for the ": " 1028 //between the header-name and the header value 1029 $prefix = '=?' . $build_params['head_charset'] . '?Q?'; 1030 $suffix = '?='; 1031 $maxLength = 75 - strlen($prefix . $suffix) - 2 - 1; 1032 $maxLength1stLine = $maxLength - strlen($hdr_name) - 2; 1033 $maxLength = $maxLength - 1; 1034 1035 //Replace all special characters used by the encoder. 1036 $search = array('=', '_', '?', ' '); 1037 $replace = array('=3D', '=5F', '=3F', '_'); 1038 $hdr_value = str_replace($search, $replace, $hdr_value); 1039 1040 //Replace all extended characters (\x80-xFF) with their 1041 //ASCII values. 1042 $hdr_value = preg_replace('#([\x80-\xFF])#e', 1043 '"=" . strtoupper(dechex(ord("\1")))', 1044 $hdr_value); 1045 1046 //This regexp will break QP-encoded text at every $maxLength 1047 //but will not break any encoded letters. 1048 $reg1st = "|(.{0,$maxLength1stLine}[^\=][^\=])|"; 1049 $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|"; 1050 //Fix for Bug #10298, Ota Mares <om@viazenetti.de> 1051 //Concat the double quotes and encoded string together 1052 $hdr_value = $quotePrefix . $hdr_value . $quoteSuffix; 1053 1054 1055 $hdr_value_out = $hdr_value; 1056 $realMax = $maxLength1stLine + strlen($prefix . $suffix); 1057 if (strlen($hdr_value_out) >= $realMax) { 1058 //Begin with the regexp for the first line. 1059 $reg = $reg1st; 1060 $output = ""; 1061 while ($hdr_value_out) { 1062 //Split translated string at every $maxLength 1063 //But make sure not to break any translated chars. 1064 $found = preg_match($reg, $hdr_value_out, $matches); 1065 1066 //After this first line, we need to use a different 1067 //regexp for the first line. 1068 $reg = $reg2nd; 1069 1070 //Save the found part and encapsulate it in the 1071 //prefix & suffix. Then remove the part from the 1072 //$hdr_value_out variable. 1073 if ($found) { 1074 $part = $matches[0]; 1075 $len = strlen($matches[0]); 1076 $hdr_value_out = substr($hdr_value_out, $len); 1077 } else { 1078 $part = $hdr_value_out; 1079 $hdr_value_out = ""; 1080 } 1081 1082 //RFC 2047 specifies that any split header should 1083 //be seperated by a CRLF SPACE 1084 if ($output) { 1085 $output .= "\r\n "; 1086 } 1087 $output .= $prefix . $part . $suffix; 1088 } 1089 $hdr_value_out = $output; 1090 } else { 1091 $hdr_value_out = $prefix . $hdr_value_out . $suffix; 1092 } 1093 $hdr_value = $hdr_value_out; 980 1094 } 981 $hdr_value_out .= $hdr_val; 982 } 983 $input[$hdr_name] = $hdr_value_out; 984 } 985 1095 } 1096 $input[$hdr_name] = $hdr_value; 1097 } 986 1098 return $input; 987 1099 } 988 1100 989 1101 /** 990 * Set the object's end-of-line and define the constant if applicable 1102 * Set the object's end-of-line and define the constant if applicable. 991 1103 * 992 1104 * @param string $eol End Of Line sequence 1105 * 1106 * @return void 993 1107 * @access private 994 1108 */ -
trunk/roundcubemail/program/lib/Mail/mimePart.php
r1323 r1530 136 136 } 137 137 138 $contentType = array(); 139 $contentDisp = array(); 138 140 foreach ($params as $key => $value) { 139 141 switch ($key) { 140 142 case 'content_type': 141 $headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); 143 $contentType['type'] = $value; 144 //$headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : ''); 142 145 break; 143 146 … … 152 155 153 156 case 'disposition': 154 $ headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');157 $contentDisp['disp'] = $value; 155 158 break; 156 159 157 160 case 'dfilename': 158 if (isset($headers['Content-Disposition'])) { 159 $headers['Content-Disposition'] .= '; filename="' . $value . '"'; 160 } else { 161 $dfilename = $value; 162 } 161 $contentDisp['filename'] = $value; 162 $contentType['name'] = $value; 163 163 break; 164 164 … … 168 168 169 169 case 'charset': 170 if (isset($headers['Content-Type'])) { 171 $headers['Content-Type'] .= '; charset="' . $value . '"'; 172 } else { 173 $charset = $value; 174 } 175 break; 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 176 183 } 177 184 } 178 185 if (isset($contentType['type'])) { 186 $headers['Content-Type'] = $contentType['type']; 187 if (isset($contentType['name'])) { 188 $headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF; 189 $headers['Content-Type'] .= $this->_buildHeaderParam('name', $contentType['name'], 190 isset($contentType['charset']) ? $contentType['charset'] : 'US-ASCII', 191 isset($contentType['language']) ? $contentType['language'] : NULL); 192 } elseif (isset($contentType['charset'])) { 193 $headers['Content-Type'] .= "; charset=\"{$contentType['charset']}\""; 194 } 195 } 196 197 198 if (isset($contentDisp['disp'])) { 199 $headers['Content-Disposition'] = $contentDisp['disp']; 200 if (isset($contentDisp['filename'])) { 201 $headers['Content-Disposition'] .= ';' . MAIL_MIMEPART_CRLF; 202 $headers['Content-Disposition'] .= $this->_buildHeaderParam('filename', $contentDisp['filename'], 203 isset($contentDisp['charset']) ? $contentDisp['charset'] : 'US-ASCII', 204 isset($contentDisp['language']) ? $contentDisp['language'] : NULL); 205 } 206 } 207 208 209 210 179 211 // Default content-type 180 212 if (!isset($headers['Content-Type'])) { … … 208 240 $encoded =& $this->_encoded; 209 241 210 if (!empty($this->_subparts)) { 211 // http://pear.php.net/bugs/bug.php?id=13032 212 // srand((double)microtime()*1000000); 242 if (count($this->_subparts)) { 243 srand((double)microtime()*1000000); 213 244 $boundary = '=_' . md5(rand() . microtime()); 214 245 $this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"'; … … 221 252 $headers[] = $key . ': ' . $value; 222 253 } 223 $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'] ;254 $subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'] . MAIL_MIMEPART_CRLF; 224 255 } 225 256 226 $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . 227 implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .228 '--' . $boundary.'--' . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF;257 $encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF . 258 rtrim(implode('--' . $boundary . MAIL_MIMEPART_CRLF , $subparts), MAIL_MIMEPART_CRLF) . MAIL_MIMEPART_CRLF . 259 '--' . $boundary.'--' . MAIL_MIMEPART_CRLF; 229 260 230 261 } else { 231 $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF;262 $encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding); 232 263 } 233 264 … … 308 339 $output = ''; 309 340 310 while (list(, $line) = each($lines)){341 while (list(, $line) = each($lines)) { 311 342 312 343 $line = preg_split('||', $line, -1, PREG_SPLIT_NO_EMPTY); … … 318 349 $dec = ord($char); 319 350 320 if (($dec == 32) AND ($i == ($linlen - 1))) { // convert space at eol only351 if (($dec == 32) AND ($i == ($linlen - 1))) { // convert space at eol only 321 352 $char = '=20'; 322 353 323 } elseif (($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only354 } elseif (($dec == 9) AND ($i == ($linlen - 1))) { // convert tab at eol only 324 355 $char = '=09'; 325 } elseif ($dec == 9) {356 } elseif ($dec == 9) { 326 357 ; // Do nothing if a tab. 327 } elseif (($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {358 } elseif (($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) { 328 359 $char = $escape . strtoupper(sprintf('%02s', dechex($dec))); 360 } elseif (($dec == 46) AND (($newline == '') || ((strlen($newline) + strlen("=2E")) >= $line_max))) { 361 //Bug #9722: convert full-stop at bol, 362 //some Windows servers need this, won't break anything (cipri) 363 //Bug #11731: full-stop at bol also needs to be encoded 364 //if this line would push us over the line_max limit. 365 $char = '=2E'; 329 366 } 330 367 368 //Note, when changing this line, also change the ($dec == 46) 369 //check line, as it mimics this line due to Bug #11731 331 370 if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted 332 371 $output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay … … 340 379 return $output; 341 380 } 381 382 /** 383 * _buildHeaderParam() 384 * 385 * Encodes the paramater of a header. 386 * 387 * @param $name The name of the header-parameter 388 * @param $value The value of the paramter 389 * @param $charset The characterset of $value 390 * @param $language The language used in $value 391 * @param $maxLength The maximum length of a line. Defauls to 75 392 * 393 * @access private 394 */ 395 function _buildHeaderParam($name, $value, $charset=NULL, $language=NULL, $maxLength=75) 396 { 397 //If we find chars to encode, or if charset or language 398 //is not any of the defaults, we need to encode the value. 399 $shouldEncode = 0; 400 $secondAsterisk = ''; 401 if (preg_match('#([\x80-\xFF]){1}#', $value)) { 402 $shouldEncode = 1; 403 } elseif ($charset && (strtolower($charset) != 'us-ascii')) { 404 $shouldEncode = 1; 405 } elseif ($language && ($language != 'en' && $language != 'en-us')) { 406 $shouldEncode = 1; 407 } 408 if ($shouldEncode) { 409 $search = array('%', ' ', "\t"); 410 $replace = array('%25', '%20', '%09'); 411 $encValue = str_replace($search, $replace, $value); 412 $encValue = preg_replace('#([\x80-\xFF])#e', '"%" . strtoupper(dechex(ord("\1")))', $encValue); 413 $value = "$charset'$language'$encValue"; 414 $secondAsterisk = '*'; 415 } 416 $header = " {$name}{$secondAsterisk}=\"{$value}\"; "; 417 if (strlen($header) <= $maxLength) { 418 return $header; 419 } 420 421 $preLength = strlen(" {$name}*0{$secondAsterisk}=\""); 422 $sufLength = strlen("\";"); 423 $maxLength = MAX(16, $maxLength - $preLength - $sufLength - 2); 424 $maxLengthReg = "|(.{0,$maxLength}[^\%][^\%])|"; 425 426 $headers = array(); 427 $headCount = 0; 428 while ($value) { 429 $matches = array(); 430 $found = preg_match($maxLengthReg, $value, $matches); 431 if ($found) { 432 $headers[] = " {$name}*{$headCount}{$secondAsterisk}=\"{$matches[0]}\""; 433 $value = substr($value, strlen($matches[0])); 434 } else { 435 $headers[] = " {$name}*{$headCount}{$secondAsterisk}=\"{$value}\""; 436 $value = ""; 437 } 438 $headCount++; 439 } 440 $headers = implode(MAIL_MIMEPART_CRLF, $headers) . ';'; 441 return $headers; 442 } 342 443 } // End of class
Note: See TracChangeset
for help on using the changeset viewer.
