[phpBB Debug] PHP Warning: in file [ROOT]/includes/crs/crs_misc_functions.php on line 37: mime_content_type(): Empty filename or path
[phpBB Debug] PHP Warning: in file [ROOT]/includes/crs/crs_misc_functions.php on line 37: mime_content_type(): Empty filename or path
Zen Cart 源代码 class.phpmailer.php

Zen Cart 源代码 class.phpmailer.php




下载文件

文件名: class.phpmailer.php
文件类型: PHP文件
文件大小: 88.91 KiB
MD5: 847a955153a4ee649a89f063c8e89b44

class.phpmailer.php - 关闭高亮
  1. <?php
  2. /*~ class.phpmailer.php
  3. .---------------------------------------------------------------------------.
  4. |  Software: PHPMailer - PHP email class                                    |
  5. |   Version: 5.2.6                                                          |
  6. |      Site: https://github.com/PHPMailer/PHPMailer/                        |
  7. | ------------------------------------------------------------------------- |
  8. |    Admins: Marcus Bointon                                                 |
  9. |    Admins: Jim Jagielski                                                  |
  10. |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
  11. |          : Marcus Bointon (coolbru) phpmailer@synchromedia.co.uk          |
  12. |          : Jim Jagielski (jimjag) jimjag@gmail.com                        |
  13. |   Founder: Brent R. Matzelle (original founder)                           |
  14. | Copyright (c) 2010-2012, Jim Jagielski. All Rights Reserved.              |
  15. | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
  16. | Copyright (c) 2001-2003, Brent R. Matzelle                                |
  17. | ------------------------------------------------------------------------- |
  18. |   License: Distributed under the Lesser General Public License (LGPL)     |
  19. |            http://www.gnu.org/copyleft/lesser.html                        |
  20. | This program is distributed in the hope that it will be useful - WITHOUT  |
  21. | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
  22. | FITNESS FOR A PARTICULAR PURPOSE.                                         |
  23. '---------------------------------------------------------------------------'
  24. */
  25.  
  26. /**
  27.  * PHPMailer - PHP email creation and transport class
  28.  * NOTE: Requires PHP version 5 or later
  29.  * @package PHPMailer
  30.  * @author Andy Prevost
  31.  * @author Marcus Bointon
  32.  * @author Jim Jagielski
  33.  * @copyright 2010 - 2012 Jim Jagielski
  34.  * @copyright 2004 - 2009 Andy Prevost
  35.  * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
  36.  */
  37.  
  38. if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
  39.  
  40. /**
  41.  * PHP email creation and transport class
  42.  * @package PHPMailer
  43.  */
  44. class PHPMailer {
  45.  
  46.   /////////////////////////////////////////////////
  47.   // PROPERTIES, PUBLIC
  48.   /////////////////////////////////////////////////
  49.  
  50.   /**
  51.    * Email priority (1 = High, 3 = Normal, 5 = low).
  52.    * @var int
  53.    */
  54.   public $Priority          = 3;
  55.  
  56.   /**
  57.    * Sets the CharSet of the message.
  58.    * @var string
  59.    */
  60.   public $CharSet           = 'iso-8859-1';
  61.  
  62.   /**
  63.    * Sets the Content-type of the message.
  64.    * @var string
  65.    */
  66.   public $ContentType       = 'text/plain';
  67.  
  68.   /**
  69.    * Sets the Encoding of the message. Options for this are
  70.    *  "8bit", "7bit", "binary", "base64", and "quoted-printable".
  71.    * @var string
  72.    */
  73.   public $Encoding          = '8bit';
  74.  
  75.   /**
  76.    * Holds the most recent mailer error message.
  77.    * @var string
  78.    */
  79.   public $ErrorInfo         = '';
  80.  
  81.   /**
  82.    * Sets the From email address for the message.
  83.    * @var string
  84.    */
  85.   public $From              = 'root@localhost';
  86.  
  87.   /**
  88.    * Sets the From name of the message.
  89.    * @var string
  90.    */
  91.   public $FromName          = 'Root User';
  92.  
  93.   /**
  94.    * Sets the Sender email (Return-Path) of the message.  If not empty,
  95.    * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  96.    * @var string
  97.    */
  98.   public $Sender            = '';
  99.  
  100.   /**
  101.    * Sets the Return-Path of the message.  If empty, it will
  102.    * be set to either From or Sender.
  103.    * @var string
  104.    */
  105.   public $ReturnPath        = '';
  106.  
  107.   /**
  108.    * Sets the Subject of the message.
  109.    * @var string
  110.    */
  111.   public $Subject           = '';
  112.  
  113.   /**
  114.    * Sets the Body of the message.  This can be either an HTML or text body.
  115.    * If HTML then run IsHTML(true).
  116.    * @var string
  117.    */
  118.   public $Body              = '';
  119.  
  120.   /**
  121.    * Sets the text-only body of the message.  This automatically sets the
  122.    * email to multipart/alternative.  This body can be read by mail
  123.    * clients that do not have HTML email capability such as mutt. Clients
  124.    * that can read HTML will view the normal Body.
  125.    * @var string
  126.    */
  127.   public $AltBody           = '';
  128.  
  129.   /**
  130.    * Stores the complete compiled MIME message body.
  131.    * @var string
  132.    * @access protected
  133.    */
  134.   protected $MIMEBody       = '';
  135.  
  136.   /**
  137.    * Stores the complete compiled MIME message headers.
  138.    * @var string
  139.    * @access protected
  140.    */
  141.   protected $MIMEHeader     = '';
  142.  
  143.   /**
  144.    * Stores the extra header list which CreateHeader() doesn't fold in
  145.    * @var string
  146.    * @access protected
  147.    */
  148.   protected $mailHeader     = '';
  149.  
  150.   /**
  151.    * Sets word wrapping on the body of the message to a given number of
  152.    * characters.
  153.    * @var int
  154.    */
  155.   public $WordWrap          = 0;
  156.  
  157.   /**
  158.    * Method to send mail: ("mail", "sendmail", or "smtp").
  159.    * @var string
  160.    */
  161.   public $Mailer            = 'mail';
  162.  
  163.   /**
  164.    * Sets the path of the sendmail program.
  165.    * @var string
  166.    */
  167.   public $Sendmail          = '/usr/sbin/sendmail';
  168.  
  169.   /**
  170.    * Determine if mail() uses a fully sendmail compatible MTA that
  171.    * supports sendmail's "-oi -f" options
  172.    * @var boolean
  173.    */
  174.   public $UseSendmailOptions    = true;
  175.  
  176.   /**
  177.    * Path to PHPMailer plugins.  Useful if the SMTP class
  178.    * is in a different directory than the PHP include path.
  179.    * @var string
  180.    */
  181.   public $PluginDir         = '';
  182.  
  183.   /**
  184.    * Sets the email address that a reading confirmation will be sent.
  185.    * @var string
  186.    */
  187.   public $ConfirmReadingTo  = '';
  188.  
  189.   /**
  190.    * Sets the hostname to use in Message-Id and Received headers
  191.    * and as default HELO string. If empty, the value returned
  192.    * by SERVER_NAME is used or 'localhost.localdomain'.
  193.    * @var string
  194.    */
  195.   public $Hostname          = '';
  196.  
  197.   /**
  198.    * Sets the message ID to be used in the Message-Id header.
  199.    * If empty, a unique id will be generated.
  200.    * @var string
  201.    */
  202.   public $MessageID         = '';
  203.  
  204.   /**
  205.    * Sets the message Date to be used in the Date header.
  206.    * If empty, the current date will be added.
  207.    * @var string
  208.    */
  209.   public $MessageDate       = '';
  210.  
  211.   /////////////////////////////////////////////////
  212.   // PROPERTIES FOR SMTP
  213.   /////////////////////////////////////////////////
  214.  
  215.   /**
  216.    * Sets the SMTP hosts.
  217.    *
  218.    * All hosts must be separated by a
  219.    * semicolon.  You can also specify a different port
  220.    * for each host by using this format: [hostname:port]
  221.    * (e.g. "smtp1.example.com:25;smtp2.example.com").
  222.    * Hosts will be tried in order.
  223.    * @var string
  224.    */
  225.   public $Host          = 'localhost';
  226.  
  227.   /**
  228.    * Sets the default SMTP server port.
  229.    * @var int
  230.    */
  231.   public $Port          = 25;
  232.  
  233.   /**
  234.    * Sets the SMTP HELO of the message (Default is $Hostname).
  235.    * @var string
  236.    */
  237.   public $Helo          = '';
  238.  
  239.   /**
  240.    * Sets connection prefix. Options are "", "ssl" or "tls"
  241.    * @var string
  242.    */
  243.   public $SMTPSecure    = '';
  244.  
  245.   /**
  246.    * Sets SMTP authentication. Utilizes the Username and Password variables.
  247.    * @var bool
  248.    */
  249.   public $SMTPAuth      = false;
  250.  
  251.   /**
  252.    * Sets SMTP username.
  253.    * @var string
  254.    */
  255.   public $Username      = '';
  256.  
  257.   /**
  258.    * Sets SMTP password.
  259.    * @var string
  260.    */
  261.   public $Password      = '';
  262.  
  263.   /**
  264.    *  Sets SMTP auth type. Options are LOGIN | PLAIN | NTLM | CRAM-MD5 (default LOGIN)
  265.    *  @var string
  266.    */
  267.   public $AuthType      = '';
  268.  
  269.   /**
  270.    *  Sets SMTP realm.
  271.    *  @var string
  272.    */
  273.   public $Realm         = '';
  274.  
  275.   /**
  276.    *  Sets SMTP workstation.
  277.    *  @var string
  278.    */
  279.   public $Workstation   = '';
  280.  
  281.   /**
  282.    * Sets the SMTP server timeout in seconds.
  283.    * This function will not work with the win32 version.
  284.    * @var int
  285.    */
  286.   public $Timeout       = 10;
  287.  
  288.   /**
  289.    * Sets SMTP class debugging on or off.
  290.    * @var bool
  291.    */
  292.   public $SMTPDebug     = false;
  293.  
  294.   /**
  295.    * Sets the function/method to use for debugging output.
  296.    * Right now we only honor "echo" or "error_log"
  297.    * @var string
  298.    */
  299.   public $Debugoutput     = "echo";
  300.  
  301.   /**
  302.    * Prevents the SMTP connection from being closed after each mail
  303.    * sending.  If this is set to true then to close the connection
  304.    * requires an explicit call to SmtpClose().
  305.    * @var bool
  306.    */
  307.   public $SMTPKeepAlive = false;
  308.  
  309.   /**
  310.    * Provides the ability to have the TO field process individual
  311.    * emails, instead of sending to entire TO addresses
  312.    * @var bool
  313.    */
  314.   public $SingleTo      = false;
  315.  
  316.    /**
  317.    * If SingleTo is true, this provides the array to hold the email addresses
  318.    * @var bool
  319.    */
  320.   public $SingleToArray = array();
  321.  
  322.   /**
  323.    * Should we allow sending messages with empty body?
  324.    * @var bool
  325.    */
  326.   public $AllowEmpty = false;
  327.  
  328.     /**
  329.    * Provides the ability to change the generic line ending
  330.    * NOTE: The default remains '\n'. We force CRLF where we KNOW
  331.    *        it must be used via self::CRLF
  332.    * @var string
  333.    */
  334.   public $LE              = "\n";
  335.  
  336.    /**
  337.    * Used with DKIM Signing
  338.    * required parameter if DKIM is enabled
  339.    *
  340.    * domain selector example domainkey
  341.    * @var string
  342.    */
  343.   public $DKIM_selector   = '';
  344.  
  345.   /**
  346.    * Used with DKIM Signing
  347.    * required if DKIM is enabled, in format of email address 'you@yourdomain.com' typically used as the source of the email
  348.    * @var string
  349.    */
  350.   public $DKIM_identity   = '';
  351.  
  352.   /**
  353.    * Used with DKIM Signing
  354.    * optional parameter if your private key requires a passphras
  355.    * @var string
  356.    */
  357.   public $DKIM_passphrase   = '';
  358.  
  359.   /**
  360.    * Used with DKIM Singing
  361.    * required if DKIM is enabled, in format of email address 'domain.com'
  362.    * @var string
  363.    */
  364.   public $DKIM_domain     = '';
  365.  
  366.   /**
  367.    * Used with DKIM Signing
  368.    * required if DKIM is enabled, path to private key file
  369.    * @var string
  370.    */
  371.   public $DKIM_private    = '';
  372.  
  373.   /**
  374.    * Callback Action function name.
  375.    * The function that handles the result of the send email action.
  376.    * It is called out by Send() for each email sent.
  377.    *
  378.    * Value can be:
  379.    * - 'function_name' for function names
  380.    * - 'Class::Method' for static method calls
  381.    * - array($object, 'Method') for calling methods on $object
  382.    * See http://php.net/is_callable manual page for more details.
  383.    *
  384.    * Parameters:
  385.    *   bool    $result        result of the send action
  386.    *   string  $to            email address of the recipient
  387.    *   string  $cc            cc email addresses
  388.    *   string  $bcc           bcc email addresses
  389.    *   string  $subject       the subject
  390.    *   string  $body          the email body
  391.    *   string  $from          email address of sender
  392.    * @var string
  393.    */
  394.   public $action_function = ''; //'callbackAction';
  395.  
  396.   /**
  397.    * Sets the PHPMailer Version number
  398.    * @var string
  399.    */
  400.   public $Version         = '5.2.6';
  401.  
  402.   /**
  403.    * What to use in the X-Mailer header
  404.    * @var string NULL for default, whitespace for None, or actual string to use
  405.    */
  406.   public $XMailer         = '';
  407.  
  408.   /////////////////////////////////////////////////
  409.   // PROPERTIES, PRIVATE AND PROTECTED
  410.   /////////////////////////////////////////////////
  411.  
  412.   /**
  413.    * @var SMTP An instance of the SMTP sender class
  414.    * @access protected
  415.    */
  416.   protected   $smtp           = null;
  417.   /**
  418.    * @var array An array of 'to' addresses
  419.    * @access protected
  420.    */
  421.   protected   $to             = array();
  422.   /**
  423.    * @var array An array of 'cc' addresses
  424.    * @access protected
  425.    */
  426.   protected   $cc             = array();
  427.   /**
  428.    * @var array An array of 'bcc' addresses
  429.    * @access protected
  430.    */
  431.   protected   $bcc            = array();
  432.   /**
  433.    * @var array An array of reply-to name and address
  434.    * @access protected
  435.    */
  436.   protected   $ReplyTo        = array();
  437.   /**
  438.    * @var array An array of all kinds of addresses: to, cc, bcc, replyto
  439.    * @access protected
  440.    */
  441.   protected   $all_recipients = array();
  442.   /**
  443.    * @var array An array of attachments
  444.    * @access protected
  445.    */
  446.   protected   $attachment     = array();
  447.   /**
  448.    * @var array An array of custom headers
  449.    * @access protected
  450.    */
  451.   protected   $CustomHeader   = array();
  452.   /**
  453.    * @var string The message's MIME type
  454.    * @access protected
  455.    */
  456.   protected   $message_type   = '';
  457.   /**
  458.    * @var array An array of MIME boundary strings
  459.    * @access protected
  460.    */
  461.   protected   $boundary       = array();
  462.   /**
  463.    * @var array An array of available languages
  464.    * @access protected
  465.    */
  466.   protected   $language       = array();
  467.   /**
  468.    * @var integer The number of errors encountered
  469.    * @access protected
  470.    */
  471.   protected   $error_count    = 0;
  472.   /**
  473.    * @var string The filename of a DKIM certificate file
  474.    * @access protected
  475.    */
  476.   protected   $sign_cert_file = '';
  477.   /**
  478.    * @var string The filename of a DKIM key file
  479.    * @access protected
  480.    */
  481.   protected   $sign_key_file  = '';
  482.   /**
  483.    * @var string The password of a DKIM key
  484.    * @access protected
  485.    */
  486.   protected   $sign_key_pass  = '';
  487.   /**
  488.    * @var boolean Whether to throw exceptions for errors
  489.    * @access protected
  490.    */
  491.   protected   $exceptions     = false;
  492.  
  493.   /////////////////////////////////////////////////
  494.   // CONSTANTS
  495.   /////////////////////////////////////////////////
  496.  
  497.   const STOP_MESSAGE  = 0; // message only, continue processing
  498.   const STOP_CONTINUE = 1; // message?, likely ok to continue processing
  499.   const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
  500.   const CRLF = "\r\n";     // SMTP RFC specified EOL
  501.  
  502.   /////////////////////////////////////////////////
  503.   // METHODS, VARIABLES
  504.   /////////////////////////////////////////////////
  505.  
  506.   /**
  507.    * Calls actual mail() function, but in a safe_mode aware fashion
  508.    * Also, unless sendmail_path points to sendmail (or something that
  509.    * claims to be sendmail), don't pass params (not a perfect fix,
  510.    * but it will do)
  511.    * @param string $to To
  512.    * @param string $subject Subject
  513.    * @param string $body Message Body
  514.    * @param string $header Additional Header(s)
  515.    * @param string $params Params
  516.    * @access private
  517.    * @return bool
  518.    */
  519.   private function mail_passthru($to, $subject, $body, $header, $params) {
  520.     if ( ini_get('safe_mode') || !($this->UseSendmailOptions) ) {
  521.         $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header);
  522.     } else {
  523.         $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($subject)), $body, $header, $params);
  524.     }
  525.     return $rt;
  526.   }
  527.  
  528.   /**
  529.    * Outputs debugging info via user-defined method
  530.    * @param string $str
  531.    */
  532.   private function edebug($str) {
  533.     if ($this->Debugoutput == "error_log") {
  534.         error_log($str);
  535.     } else {
  536.         echo $str;
  537.     }
  538.   }
  539.  
  540.   /**
  541.    * Constructor
  542.    * @param boolean $exceptions Should we throw external exceptions?
  543.    */
  544.   public function __construct($exceptions = false) {
  545.     $this->exceptions = ($exceptions == true);
  546.   }
  547.  
  548.   /**
  549.    * Destructor
  550.    */
  551.   public function __destruct() {
  552.       if ($this->Mailer == 'smtp') { //Close any open SMTP connection nicely
  553.           $this->SmtpClose();
  554.       }
  555.   }
  556.  
  557.   /**
  558.    * Sets message type to HTML.
  559.    * @param bool $ishtml
  560.    * @return void
  561.    */
  562.   public function IsHTML($ishtml = true) {
  563.     if ($ishtml) {
  564.       $this->ContentType = 'text/html';
  565.     } else {
  566.       $this->ContentType = 'text/plain';
  567.     }
  568.   }
  569.  
  570.   /**
  571.    * Sets Mailer to send message using SMTP.
  572.    * @return void
  573.    */
  574.   public function IsSMTP() {
  575.     $this->Mailer = 'smtp';
  576.   }
  577.  
  578.   /**
  579.    * Sets Mailer to send message using PHP mail() function.
  580.    * @return void
  581.    */
  582.   public function IsMail() {
  583.     $this->Mailer = 'mail';
  584.   }
  585.  
  586.   /**
  587.    * Sets Mailer to send message using the $Sendmail program.
  588.    * @return void
  589.    */
  590.   public function IsSendmail() {
  591.     if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
  592.       $this->Sendmail = '/var/qmail/bin/sendmail';
  593.     }
  594.     $this->Mailer = 'sendmail';
  595.   }
  596.  
  597.   /**
  598.    * Sets Mailer to send message using the qmail MTA.
  599.    * @return void
  600.    */
  601.   public function IsQmail() {
  602.     if (stristr(ini_get('sendmail_path'), 'qmail')) {
  603.       $this->Sendmail = '/var/qmail/bin/sendmail';
  604.     }
  605.     $this->Mailer = 'sendmail';
  606.   }
  607.  
  608.   /////////////////////////////////////////////////
  609.   // METHODS, RECIPIENTS
  610.   /////////////////////////////////////////////////
  611.  
  612.   /**
  613.    * Adds a "To" address.
  614.    * @param string $address
  615.    * @param string $name
  616.    * @return boolean true on success, false if address already used
  617.    */
  618.   public function AddAddress($address, $name = '') {
  619.     return $this->AddAnAddress('to', $address, $name);
  620.   }
  621.  
  622.   /**
  623.    * Adds a "Cc" address.
  624.    * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
  625.    * @param string $address
  626.    * @param string $name
  627.    * @return boolean true on success, false if address already used
  628.    */
  629.   public function AddCC($address, $name = '') {
  630.     return $this->AddAnAddress('cc', $address, $name);
  631.   }
  632.  
  633.   /**
  634.    * Adds a "Bcc" address.
  635.    * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
  636.    * @param string $address
  637.    * @param string $name
  638.    * @return boolean true on success, false if address already used
  639.    */
  640.   public function AddBCC($address, $name = '') {
  641.     return $this->AddAnAddress('bcc', $address, $name);
  642.   }
  643.  
  644.   /**
  645.    * Adds a "Reply-to" address.
  646.    * @param string $address
  647.    * @param string $name
  648.    * @return boolean
  649.    */
  650.   public function AddReplyTo($address, $name = '') {
  651.     return $this->AddAnAddress('Reply-To', $address, $name);
  652.   }
  653.  
  654.   /**
  655.    * Adds an address to one of the recipient arrays
  656.    * Addresses that have been added already return false, but do not throw exceptions
  657.    * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
  658.    * @param string $address The email address to send to
  659.    * @param string $name
  660.    * @throws phpmailerException
  661.    * @return boolean true on success, false if address already used or invalid in some way
  662.    * @access protected
  663.    */
  664.   protected function AddAnAddress($kind, $address, $name = '') {
  665.     if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
  666.       $this->SetError($this->Lang('Invalid recipient array').': '.$kind);
  667.       if ($this->exceptions) {
  668.         throw new phpmailerException('Invalid recipient array: ' . $kind);
  669.       }
  670.       if ($this->SMTPDebug) {
  671.         $this->edebug($this->Lang('Invalid recipient array').': '.$kind);
  672.       }
  673.       return false;
  674.     }
  675.     $address = trim($address);
  676.     $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
  677.     if (!$this->ValidateAddress($address)) {
  678.       $this->SetError($this->Lang('invalid_address').': '. $address);
  679.       if ($this->exceptions) {
  680.         throw new phpmailerException($this->Lang('invalid_address').': '.$address);
  681.       }
  682.       if ($this->SMTPDebug) {
  683.         $this->edebug($this->Lang('invalid_address').': '.$address);
  684.       }
  685.       return false;
  686.     }
  687.     if ($kind != 'Reply-To') {
  688.       if (!isset($this->all_recipients[strtolower($address)])) {
  689.         array_push($this->$kind, array($address, $name));
  690.         $this->all_recipients[strtolower($address)] = true;
  691.         return true;
  692.       }
  693.     } else {
  694.       if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
  695.         $this->ReplyTo[strtolower($address)] = array($address, $name);
  696.       return true;
  697.     }
  698.   }
  699.   return false;
  700. }
  701.  
  702.   /**
  703.    * Set the From and FromName properties
  704.    * @param string $address
  705.    * @param string $name
  706.    * @param int $auto Also set Reply-To and Sender
  707.    * @throws phpmailerException
  708.    * @return boolean
  709.    */
  710.   public function SetFrom($address, $name = '', $auto = 1) {
  711.     $address = trim($address);
  712.     $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
  713.     if (!$this->ValidateAddress($address)) {
  714.       $this->SetError($this->Lang('invalid_address').': '. $address);
  715.       if ($this->exceptions) {
  716.         throw new phpmailerException($this->Lang('invalid_address').': '.$address);
  717.       }
  718.       if ($this->SMTPDebug) {
  719.         $this->edebug($this->Lang('invalid_address').': '.$address);
  720.       }
  721.       return false;
  722.     }
  723.     $this->From = $address;
  724.     $this->FromName = $name;
  725.     if ($auto) {
  726.       if (empty($this->ReplyTo)) {
  727.         $this->AddAnAddress('Reply-To', $address, $name);
  728.       }
  729.       if (empty($this->Sender)) {
  730.         $this->Sender = $address;
  731.       }
  732.     }
  733.     return true;
  734.   }
  735.  
  736.   /**
  737.    * Check that a string looks roughly like an email address should
  738.    * Static so it can be used without instantiation, public so people can overload
  739.    * Conforms to RFC5322: Uses *correct* regex on which FILTER_VALIDATE_EMAIL is
  740.    * based; So why not use FILTER_VALIDATE_EMAIL? Because it was broken to
  741.    * not allow a@b type valid addresses :(
  742.    * @link http://squiloople.com/2009/12/20/email-address-validation/
  743.    * @copyright regex Copyright Michael Rushton 2009-10 | http://squiloople.com/ | Feel free to use and redistribute this code. But please keep this copyright notice.
  744.    * @param string $address The email address to check
  745.    * @return boolean
  746.    * @static
  747.    * @access public
  748.    */
  749.   public static function ValidateAddress($address) {
  750.       if (defined('PCRE_VERSION')) { //Check this instead of extension_loaded so it works when that function is disabled
  751.           if (version_compare(PCRE_VERSION, '8.0') >= 0) {
  752.               return (boolean)preg_match('/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD', $address);
  753.           } else {
  754.               //Fall back to an older regex that doesn't need a recent PCRE
  755.               return (boolean)preg_match('/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD', $address);
  756.           }
  757.       } else {
  758.           //No PCRE! Do something _very_ approximate!
  759.           //Check the address is 3 chars or longer and contains an @ that's not the first or last char
  760.           return (strlen($address) >= 3 and strpos($address, '@') >= 1 and strpos($address, '@') != strlen($address) - 1);
  761.       }
  762.   }
  763.  
  764.   /////////////////////////////////////////////////
  765.   // METHODS, MAIL SENDING
  766.   /////////////////////////////////////////////////
  767.  
  768.   /**
  769.    * Creates message and assigns Mailer. If the message is
  770.    * not sent successfully then it returns false.  Use the ErrorInfo
  771.    * variable to view description of the error.
  772.    * @throws phpmailerException
  773.    * @return bool
  774.    */
  775.   public function Send() {
  776.     try {
  777.       if(!$this->PreSend()) return false;
  778.       return $this->PostSend();
  779.     } catch (phpmailerException $e) {
  780.       $this->mailHeader = '';
  781.       $this->SetError($e->getMessage());
  782.       if ($this->exceptions) {
  783.         throw $e;
  784.       }
  785.       return false;
  786.     }
  787.   }
  788.  
  789.   /**
  790.    * Prep mail by constructing all message entities
  791.    * @throws phpmailerException
  792.    * @return bool
  793.    */
  794.   public function PreSend() {
  795.     try {
  796.       $this->mailHeader = "";
  797.       if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
  798.         throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
  799.       }
  800.  
  801.       // Set whether the message is multipart/alternative
  802.       if(!empty($this->AltBody)) {
  803.         $this->ContentType = 'multipart/alternative';
  804.       }
  805.  
  806.       $this->error_count = 0; // reset errors
  807.       $this->SetMessageType();
  808.       //Refuse to send an empty message unless we are specifically allowing it
  809.       if (!$this->AllowEmpty and empty($this->Body)) {
  810.         throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
  811.       }
  812.  
  813.       $this->MIMEHeader = $this->CreateHeader();
  814.       $this->MIMEBody = $this->CreateBody();
  815.  
  816.       // To capture the complete message when using mail(), create
  817.       // an extra header list which CreateHeader() doesn't fold in
  818.       if ($this->Mailer == 'mail') {
  819.         if (count($this->to) > 0) {
  820.           $this->mailHeader .= $this->AddrAppend("To", $this->to);
  821.         } else {
  822.           $this->mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;");
  823.         }
  824.         $this->mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject))));
  825.       }
  826.  
  827.       // digitally sign with DKIM if enabled
  828.       if (!empty($this->DKIM_domain) && !empty($this->DKIM_private) && !empty($this->DKIM_selector) && !empty($this->DKIM_domain) && file_exists($this->DKIM_private)) {
  829.         $header_dkim = $this->DKIM_Add($this->MIMEHeader . $this->mailHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
  830.         $this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader;
  831.       }
  832.  
  833.       return true;
  834.  
  835.     } catch (phpmailerException $e) {
  836.       $this->SetError($e->getMessage());
  837.       if ($this->exceptions) {
  838.         throw $e;
  839.       }
  840.       return false;
  841.     }
  842.   }
  843.  
  844.   /**
  845.    * Actual Email transport function
  846.    * Send the email via the selected mechanism
  847.    * @throws phpmailerException
  848.    * @return bool
  849.    */
  850.   public function PostSend() {
  851.     try {
  852.       // Choose the mailer and send through it
  853.       switch($this->Mailer) {
  854.         case 'sendmail':
  855.           return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody);
  856.         case 'smtp':
  857.           return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
  858.         case 'mail':
  859.           return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
  860.         default:
  861.           return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
  862.       }
  863.     } catch (phpmailerException $e) {
  864.       $this->SetError($e->getMessage());
  865.       if ($this->exceptions) {
  866.         throw $e;
  867.       }
  868.       if ($this->SMTPDebug) {
  869.         $this->edebug($e->getMessage()."\n");
  870.       }
  871.     }
  872.     return false;
  873.   }
  874.  
  875.   /**
  876.    * Sends mail using the $Sendmail program.
  877.    * @param string $header The message headers
  878.    * @param string $body The message body
  879.    * @throws phpmailerException
  880.    * @access protected
  881.    * @return bool
  882.    */
  883.   protected function SendmailSend($header, $body) {
  884.     if ($this->Sender != '') {
  885.       $sendmail = sprintf("%s -oi -f%s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
  886.     } else {
  887.       $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
  888.     }
  889.     if ($this->SingleTo === true) {
  890.       foreach ($this->SingleToArray as $val) {
  891.         if(!@$mail = popen($sendmail, 'w')) {
  892.           throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  893.         }
  894.         fputs($mail, "To: " . $val . "\n");
  895.         fputs($mail, $header);
  896.         fputs($mail, $body);
  897.         $result = pclose($mail);
  898.         // implement call back function if it exists
  899.         $isSent = ($result == 0) ? 1 : 0;
  900.         $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
  901.         if($result != 0) {
  902.           throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  903.         }
  904.       }
  905.     } else {
  906.       if(!@$mail = popen($sendmail, 'w')) {
  907.         throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  908.       }
  909.       fputs($mail, $header);
  910.       fputs($mail, $body);
  911.       $result = pclose($mail);
  912.       // implement call back function if it exists
  913.       $isSent = ($result == 0) ? 1 : 0;
  914.       $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
  915.       if($result != 0) {
  916.         throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  917.       }
  918.     }
  919.     return true;
  920.   }
  921.  
  922.   /**
  923.    * Sends mail using the PHP mail() function.
  924.    * @param string $header The message headers
  925.    * @param string $body The message body
  926.    * @throws phpmailerException
  927.    * @access protected
  928.    * @return bool
  929.    */
  930.   protected function MailSend($header, $body) {
  931.     $toArr = array();
  932.     foreach($this->to as $t) {
  933.       $toArr[] = $this->AddrFormat($t);
  934.     }
  935.     $to = implode(', ', $toArr);
  936.  
  937.     if (empty($this->Sender)) {
  938.       $params = " ";
  939.     } else {
  940.       $params = sprintf("-f%s", $this->Sender);
  941.     }
  942.     if ($this->Sender != '' and !ini_get('safe_mode')) {
  943.       $old_from = ini_get('sendmail_from');
  944.       ini_set('sendmail_from', $this->Sender);
  945.     }
  946.       $rt = false;
  947.     if ($this->SingleTo === true && count($toArr) > 1) {
  948.       foreach ($toArr as $val) {
  949.         $rt = $this->mail_passthru($val, $this->Subject, $body, $header, $params);
  950.         // implement call back function if it exists
  951.         $isSent = ($rt == 1) ? 1 : 0;
  952.         $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
  953.       }
  954.     } else {
  955.       $rt = $this->mail_passthru($to, $this->Subject, $body, $header, $params);
  956.       // implement call back function if it exists
  957.       $isSent = ($rt == 1) ? 1 : 0;
  958.       $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
  959.     }
  960.     if (isset($old_from)) {
  961.       ini_set('sendmail_from', $old_from);
  962.     }
  963.     if(!$rt) {
  964.       throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
  965.     }
  966.     return true;
  967.   }
  968.  
  969.   /**
  970.    * Sends mail via SMTP using PhpSMTP
  971.    * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
  972.    * @param string $header The message headers
  973.    * @param string $body The message body
  974.    * @throws phpmailerException
  975.    * @uses SMTP
  976.    * @access protected
  977.    * @return bool
  978.    */
  979.   protected function SmtpSend($header, $body) {
  980.     require_once $this->PluginDir . 'class.smtp.php';
  981.     $bad_rcpt = array();
  982.  
  983.     if(!$this->SmtpConnect()) {
  984.       throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
  985.     }
  986.     $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
  987.     if(!$this->smtp->Mail($smtp_from)) {
  988.       $this->SetError($this->Lang('from_failed') . $smtp_from . ' : ' .implode(',', $this->smtp->getError()));
  989.       throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
  990.     }
  991.  
  992.     // Attempt to send attach all recipients
  993.     foreach($this->to as $to) {
  994.       if (!$this->smtp->Recipient($to[0])) {
  995.         $bad_rcpt[] = $to[0];
  996.         // implement call back function if it exists
  997.         $isSent = 0;
  998.         $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
  999.       } else {
  1000.         // implement call back function if it exists
  1001.         $isSent = 1;
  1002.         $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
  1003.       }
  1004.     }
  1005.     foreach($this->cc as $cc) {
  1006.       if (!$this->smtp->Recipient($cc[0])) {
  1007.         $bad_rcpt[] = $cc[0];
  1008.         // implement call back function if it exists
  1009.         $isSent = 0;
  1010.         $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
  1011.       } else {
  1012.         // implement call back function if it exists
  1013.         $isSent = 1;
  1014.         $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
  1015.       }
  1016.     }
  1017.     foreach($this->bcc as $bcc) {
  1018.       if (!$this->smtp->Recipient($bcc[0])) {
  1019.         $bad_rcpt[] = $bcc[0];
  1020.         // implement call back function if it exists
  1021.         $isSent = 0;
  1022.         $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
  1023.       } else {
  1024.         // implement call back function if it exists
  1025.         $isSent = 1;
  1026.         $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
  1027.       }
  1028.     }
  1029.  
  1030.  
  1031.     if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
  1032.       $badaddresses = implode(', ', $bad_rcpt);
  1033.       throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
  1034.     }
  1035.     if(!$this->smtp->Data($header . $body)) {
  1036.       throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
  1037.     }
  1038.     if($this->SMTPKeepAlive == true) {
  1039.       $this->smtp->Reset();
  1040.     } else {
  1041.         $this->smtp->Quit();
  1042.         $this->smtp->Close();
  1043.     }
  1044.     return true;
  1045.   }
  1046.  
  1047.   /**
  1048.    * Initiates a connection to an SMTP server.
  1049.    * Returns false if the operation failed.
  1050.    * @uses SMTP
  1051.    * @access public
  1052.    * @throws phpmailerException
  1053.    * @return bool
  1054.    */
  1055.   public function SmtpConnect() {
  1056.     if(is_null($this->smtp)) {
  1057.       $this->smtp = new SMTP;
  1058.     }
  1059.  
  1060.     $this->smtp->Timeout = $this->Timeout;
  1061.     $this->smtp->do_debug = $this->SMTPDebug;
  1062.     $hosts = explode(';', $this->Host);
  1063.     $index = 0;
  1064.     $connection = $this->smtp->Connected();
  1065.  
  1066.     // Retry while there is no connection
  1067.     try {
  1068.       while($index < count($hosts) && !$connection) {
  1069.         $hostinfo = array();
  1070.         if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
  1071.           $host = $hostinfo[1];
  1072.           $port = $hostinfo[2];
  1073.         } else {
  1074.           $host = $hosts[$index];
  1075.           $port = $this->Port;
  1076.         }
  1077.  
  1078.         $tls = ($this->SMTPSecure == 'tls');
  1079.         $ssl = ($this->SMTPSecure == 'ssl');
  1080.  
  1081.         if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
  1082.  
  1083.           $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
  1084.           $this->smtp->Hello($hello);
  1085.  
  1086.           if ($tls) {
  1087.             if (!$this->smtp->StartTLS()) {
  1088.               throw new phpmailerException($this->Lang('connect_host'));
  1089.             }
  1090.  
  1091.             //We must resend HELO after tls negotiation
  1092.             $this->smtp->Hello($hello);
  1093.           }
  1094.  
  1095.           $connection = true;
  1096.           if ($this->SMTPAuth) {
  1097.             if (!$this->smtp->Authenticate($this->Username, $this->Password, $this->AuthType, $this->Realm, $this->Workstation)) {
  1098.               throw new phpmailerException($this->Lang('authenticate'));
  1099.             }
  1100.           }
  1101.         }
  1102.         $index++;
  1103.         if (!$connection) {
  1104.           throw new phpmailerException($this->Lang('connect_host'));
  1105.         }
  1106.       }
  1107.     } catch (phpmailerException $e) {
  1108.       $this->smtp->Reset();
  1109.       if ($this->exceptions) {
  1110.         throw $e;
  1111.       }
  1112.     }
  1113.     return true;
  1114.   }
  1115.  
  1116.   /**
  1117.    * Closes the active SMTP session if one exists.
  1118.    * @return void
  1119.    */
  1120.   public function SmtpClose() {
  1121.     if ($this->smtp !== null) {
  1122.       if($this->smtp->Connected()) {
  1123.         $this->smtp->Quit();
  1124.         $this->smtp->Close();
  1125.       }
  1126.     }
  1127.   }
  1128.  
  1129.   /**
  1130.    * Sets the language for all class error messages.
  1131.    * Returns false if it cannot load the language file.  The default language is English.
  1132.    * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
  1133.    * @param string $lang_path Path to the language file directory
  1134.    * @return bool
  1135.    * @access public
  1136.    */
  1137.   function SetLanguage($langcode = 'en', $lang_path = 'language/') {
  1138.     //Define full set of translatable strings
  1139.     $PHPMAILER_LANG = array(
  1140.       'authenticate'         => 'SMTP Error: Could not authenticate.',
  1141.       'connect_host'         => 'SMTP Error: Could not connect to SMTP host.',
  1142.       'data_not_accepted'    => 'SMTP Error: Data not accepted.',
  1143.       'empty_message'        => 'Message body empty',
  1144.       'encoding'             => 'Unknown encoding: ',
  1145.       'execute'              => 'Could not execute: ',
  1146.       'file_access'          => 'Could not access file: ',
  1147.       'file_open'            => 'File Error: Could not open file: ',
  1148.       'from_failed'          => 'The following From address failed: ',
  1149.       'instantiate'          => 'Could not instantiate mail function.',
  1150.       'invalid_address'      => 'Invalid address',
  1151.       'mailer_not_supported' => ' mailer is not supported.',
  1152.       'provide_address'      => 'You must provide at least one recipient email address.',
  1153.       'recipients_failed'    => 'SMTP Error: The following recipients failed: ',
  1154.       'signing'              => 'Signing Error: ',
  1155.       'smtp_connect_failed'  => 'SMTP Connect() failed.',
  1156.       'smtp_error'           => 'SMTP server error: ',
  1157.       'variable_set'         => 'Cannot set or reset variable: '
  1158.     );
  1159.     //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
  1160.     $l = true;
  1161.     if ($langcode != 'en') { //There is no English translation file
  1162.       $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
  1163.     }
  1164.     $this->language = $PHPMAILER_LANG;
  1165.     return ($l == true); //Returns false if language not found
  1166.   }
  1167.  
  1168.   /**
  1169.   * Return the current array of language strings
  1170.   * @return array
  1171.   */
  1172.   public function GetTranslations() {
  1173.     return $this->language;
  1174.   }
  1175.  
  1176.   /////////////////////////////////////////////////
  1177.   // METHODS, MESSAGE CREATION
  1178.   /////////////////////////////////////////////////
  1179.  
  1180.   /**
  1181.    * Creates recipient headers.
  1182.    * @access public
  1183.    * @param string $type
  1184.    * @param array $addr
  1185.    * @return string
  1186.    */
  1187.   public function AddrAppend($type, $addr) {
  1188.     $addr_str = $type . ': ';
  1189.     $addresses = array();
  1190.     foreach ($addr as $a) {
  1191.       $addresses[] = $this->AddrFormat($a);
  1192.     }
  1193.     $addr_str .= implode(', ', $addresses);
  1194.     $addr_str .= $this->LE;
  1195.  
  1196.     return $addr_str;
  1197.   }
  1198.  
  1199.   /**
  1200.    * Formats an address correctly.
  1201.    * @access public
  1202.    * @param string $addr
  1203.    * @return string
  1204.    */
  1205.   public function AddrFormat($addr) {
  1206.     if (empty($addr[1])) {
  1207.       return $this->SecureHeader($addr[0]);
  1208.     } else {
  1209.       return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
  1210.     }
  1211.   }
  1212.  
  1213.   /**
  1214.    * Wraps message for use with mailers that do not
  1215.    * automatically perform wrapping and for quoted-printable.
  1216.    * Original written by philippe.
  1217.    * @param string $message The message to wrap
  1218.    * @param integer $length The line length to wrap to
  1219.    * @param boolean $qp_mode Whether to run in Quoted-Printable mode
  1220.    * @access public
  1221.    * @return string
  1222.    */
  1223.   public function WrapText($message, $length, $qp_mode = false) {
  1224.     $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
  1225.     // If utf-8 encoding is used, we will need to make sure we don't
  1226.     // split multibyte characters when we wrap
  1227.     $is_utf8 = (strtolower($this->CharSet) == "utf-8");
  1228.     $lelen = strlen($this->LE);
  1229.     $crlflen = strlen(self::CRLF);
  1230.  
  1231.     $message = $this->FixEOL($message);
  1232.     if (substr($message, -$lelen) == $this->LE) {
  1233.       $message = substr($message, 0, -$lelen);
  1234.     }
  1235.  
  1236.     $line = explode($this->LE, $message);   // Magic. We know FixEOL uses $LE
  1237.     $message = '';
  1238.     for ($i = 0 ;$i < count($line); $i++) {
  1239.       $line_part = explode(' ', $line[$i]);
  1240.       $buf = '';
  1241.       for ($e = 0; $e<count($line_part); $e++) {
  1242.         $word = $line_part[$e];
  1243.         if ($qp_mode and (strlen($word) > $length)) {
  1244.           $space_left = $length - strlen($buf) - $crlflen;
  1245.           if ($e != 0) {
  1246.             if ($space_left > 20) {
  1247.               $len = $space_left;
  1248.               if ($is_utf8) {
  1249.                 $len = $this->UTF8CharBoundary($word, $len);
  1250.               } elseif (substr($word, $len - 1, 1) == "=") {
  1251.                 $len--;
  1252.               } elseif (substr($word, $len - 2, 1) == "=") {
  1253.                 $len -= 2;
  1254.               }
  1255.               $part = substr($word, 0, $len);
  1256.               $word = substr($word, $len);
  1257.               $buf .= ' ' . $part;
  1258.               $message .= $buf . sprintf("=%s", self::CRLF);
  1259.             } else {
  1260.               $message .= $buf . $soft_break;
  1261.             }
  1262.             $buf = '';
  1263.           }
  1264.           while (strlen($word) > 0) {
  1265.             if ($length <= 0) {
  1266.                 break;
  1267.             }
  1268.             $len = $length;
  1269.             if ($is_utf8) {
  1270.               $len = $this->UTF8CharBoundary($word, $len);
  1271.             } elseif (substr($word, $len - 1, 1) == "=") {
  1272.               $len--;
  1273.             } elseif (substr($word, $len - 2, 1) == "=") {
  1274.               $len -= 2;
  1275.             }
  1276.             $part = substr($word, 0, $len);
  1277.             $word = substr($word, $len);
  1278.  
  1279.             if (strlen($word) > 0) {
  1280.               $message .= $part . sprintf("=%s", self::CRLF);
  1281.             } else {
  1282.               $buf = $part;
  1283.             }
  1284.           }
  1285.         } else {
  1286.           $buf_o = $buf;
  1287.           $buf .= ($e == 0) ? $word : (' ' . $word);
  1288.  
  1289.           if (strlen($buf) > $length and $buf_o != '') {
  1290.             $message .= $buf_o . $soft_break;
  1291.             $buf = $word;
  1292.           }
  1293.         }
  1294.       }
  1295.       $message .= $buf . self::CRLF;
  1296.     }
  1297.  
  1298.     return $message;
  1299.   }
  1300.  
  1301.   /**
  1302.    * Finds last character boundary prior to maxLength in a utf-8
  1303.    * quoted (printable) encoded string.
  1304.    * Original written by Colin Brown.
  1305.    * @access public
  1306.    * @param string $encodedText utf-8 QP text
  1307.    * @param int    $maxLength   find last character boundary prior to this length
  1308.    * @return int
  1309.    */
  1310.   public function UTF8CharBoundary($encodedText, $maxLength) {
  1311.     $foundSplitPos = false;
  1312.     $lookBack = 3;
  1313.     while (!$foundSplitPos) {
  1314.       $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
  1315.       $encodedCharPos = strpos($lastChunk, "=");
  1316.       if ($encodedCharPos !== false) {
  1317.         // Found start of encoded character byte within $lookBack block.
  1318.         // Check the encoded byte value (the 2 chars after the '=')
  1319.         $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
  1320.         $dec = hexdec($hex);
  1321.         if ($dec < 128) { // Single byte character.
  1322.           // If the encoded char was found at pos 0, it will fit
  1323.           // otherwise reduce maxLength to start of the encoded char
  1324.           $maxLength = ($encodedCharPos == 0) ? $maxLength :
  1325.           $maxLength - ($lookBack - $encodedCharPos);
  1326.           $foundSplitPos = true;
  1327.         } elseif ($dec >= 192) { // First byte of a multi byte character
  1328.           // Reduce maxLength to split at start of character
  1329.           $maxLength = $maxLength - ($lookBack - $encodedCharPos);
  1330.           $foundSplitPos = true;
  1331.         } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
  1332.           $lookBack += 3;
  1333.         }
  1334.       } else {
  1335.         // No encoded character found
  1336.         $foundSplitPos = true;
  1337.       }
  1338.     }
  1339.     return $maxLength;
  1340.   }
  1341.  
  1342.  
  1343.   /**
  1344.    * Set the body wrapping.
  1345.    * @access public
  1346.    * @return void
  1347.    */
  1348.   public function SetWordWrap() {
  1349.     if($this->WordWrap < 1) {
  1350.       return;
  1351.     }
  1352.  
  1353.     switch($this->message_type) {
  1354.       case 'alt':
  1355.       case 'alt_inline':
  1356.       case 'alt_attach':
  1357.       case 'alt_inline_attach':
  1358.         $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
  1359.         break;
  1360.       default:
  1361.         $this->Body = $this->WrapText($this->Body, $this->WordWrap);
  1362.         break;
  1363.     }
  1364.   }
  1365.  
  1366.   /**
  1367.    * Assembles message header.
  1368.    * @access public
  1369.    * @return string The assembled header
  1370.    */
  1371.   public function CreateHeader() {
  1372.     $result = '';
  1373.  
  1374.     // Set the boundaries
  1375.     $uniq_id = md5(uniqid(time()));
  1376.     $this->boundary[1] = 'b1_' . $uniq_id;
  1377.     $this->boundary[2] = 'b2_' . $uniq_id;
  1378.     $this->boundary[3] = 'b3_' . $uniq_id;
  1379.  
  1380.     if ($this->MessageDate == '') {
  1381.       $result .= $this->HeaderLine('Date', self::RFCDate());
  1382.     } else {
  1383.       $result .= $this->HeaderLine('Date', $this->MessageDate);
  1384.     }
  1385.  
  1386.     if ($this->ReturnPath) {
  1387.       $result .= $this->HeaderLine('Return-Path', '<'.trim($this->ReturnPath).'>');
  1388.     } elseif ($this->Sender == '') {
  1389.       $result .= $this->HeaderLine('Return-Path', '<'.trim($this->From).'>');
  1390.     } else {
  1391.       $result .= $this->HeaderLine('Return-Path', '<'.trim($this->Sender).'>');
  1392.     }
  1393.  
  1394.     // To be created automatically by mail()
  1395.     if($this->Mailer != 'mail') {
  1396.       if ($this->SingleTo === true) {
  1397.         foreach($this->to as $t) {
  1398.           $this->SingleToArray[] = $this->AddrFormat($t);
  1399.         }
  1400.       } else {
  1401.         if(count($this->to) > 0) {
  1402.           $result .= $this->AddrAppend('To', $this->to);
  1403.         } elseif (count($this->cc) == 0) {
  1404.           $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
  1405.         }
  1406.       }
  1407.     }
  1408.  
  1409.     $from = array();
  1410.     $from[0][0] = trim($this->From);
  1411.     $from[0][1] = $this->FromName;
  1412.     $result .= $this->AddrAppend('From', $from);
  1413.  
  1414.     // sendmail and mail() extract Cc from the header before sending
  1415.     if(count($this->cc) > 0) {
  1416.       $result .= $this->AddrAppend('Cc', $this->cc);
  1417.     }
  1418.  
  1419.     // sendmail and mail() extract Bcc from the header before sending
  1420.     if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
  1421.       $result .= $this->AddrAppend('Bcc', $this->bcc);
  1422.     }
  1423.  
  1424.     if(count($this->ReplyTo) > 0) {
  1425.       $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
  1426.     }
  1427.  
  1428.     // mail() sets the subject itself
  1429.     if($this->Mailer != 'mail') {
  1430.       $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
  1431.     }
  1432.  
  1433.     if($this->MessageID != '') {
  1434.       $result .= $this->HeaderLine('Message-ID', $this->MessageID);
  1435.     } else {
  1436.       $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
  1437.    }
  1438.    $result .= $this->HeaderLine('X-Priority', $this->Priority);
  1439.    if ($this->XMailer == '') {
  1440.        $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (https://github.com/PHPMailer/PHPMailer/)');
  1441.    } else {
  1442.      $myXmailer = trim($this->XMailer);
  1443.      if ($myXmailer) {
  1444.        $result .= $this->HeaderLine('X-Mailer', $myXmailer);
  1445.      }
  1446.    }
  1447.  
  1448.    if($this->ConfirmReadingTo != '') {
  1449.      $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
  1450.    }
  1451.  
  1452.    // Add custom headers
  1453.    for($index = 0; $index < count($this->CustomHeader); $index++) {
  1454.      $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
  1455.    }
  1456.    if (!$this->sign_key_file) {
  1457.      $result .= $this->HeaderLine('MIME-Version', '1.0');
  1458.      $result .= $this->GetMailMIME();
  1459.    }
  1460.  
  1461.    return $result;
  1462.  }
  1463.  
  1464.  /**
  1465.   * Returns the message MIME.
  1466.   * @access public
  1467.   * @return string
  1468.   */
  1469.  public function GetMailMIME() {
  1470.    $result = '';
  1471.    switch($this->message_type) {
  1472.      case 'inline':
  1473.        $result .= $this->HeaderLine('Content-Type', 'multipart/related;');
  1474.        $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
  1475.         break;
  1476.       case 'attach':
  1477.       case 'inline_attach':
  1478.       case 'alt_attach':
  1479.       case 'alt_inline_attach':
  1480.         $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
  1481.         $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
  1482.         break;
  1483.       case 'alt':
  1484.       case 'alt_inline':
  1485.         $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
  1486.         $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
  1487.         break;
  1488.       default:
  1489.         // Catches case 'plain': and case '':
  1490.         $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
  1491.         $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset='.$this->CharSet);
  1492.         break;
  1493.     }
  1494.  
  1495.     if($this->Mailer != 'mail') {
  1496.       $result .= $this->LE;
  1497.     }
  1498.  
  1499.     return $result;
  1500.   }
  1501.  
  1502.   /**
  1503.    * Returns the MIME message (headers and body). Only really valid post PreSend().
  1504.    * @access public
  1505.    * @return string
  1506.    */
  1507.   public function GetSentMIMEMessage() {
  1508.     return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
  1509.   }
  1510.  
  1511.  
  1512.   /**
  1513.    * Assembles the message body.  Returns an empty string on failure.
  1514.    * @access public
  1515.    * @throws phpmailerException
  1516.    * @return string The assembled message body
  1517.    */
  1518.   public function CreateBody() {
  1519.     $body = '';
  1520.  
  1521.     if ($this->sign_key_file) {
  1522.       $body .= $this->GetMailMIME().$this->LE;
  1523.     }
  1524.  
  1525.     $this->SetWordWrap();
  1526.  
  1527.     switch($this->message_type) {
  1528.       case 'inline':
  1529.         $body .= $this->GetBoundary($this->boundary[1], '', '', '');
  1530.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1531.         $body .= $this->LE.$this->LE;
  1532.         $body .= $this->AttachAll('inline', $this->boundary[1]);
  1533.         break;
  1534.       case 'attach':
  1535.         $body .= $this->GetBoundary($this->boundary[1], '', '', '');
  1536.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1537.         $body .= $this->LE.$this->LE;
  1538.         $body .= $this->AttachAll('attachment', $this->boundary[1]);
  1539.         break;
  1540.       case 'inline_attach':
  1541.         $body .= $this->TextLine('--' . $this->boundary[1]);
  1542.         $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
  1543.         $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
  1544.         $body .= $this->LE;
  1545.         $body .= $this->GetBoundary($this->boundary[2], '', '', '');
  1546.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1547.         $body .= $this->LE.$this->LE;
  1548.         $body .= $this->AttachAll('inline', $this->boundary[2]);
  1549.         $body .= $this->LE;
  1550.         $body .= $this->AttachAll('attachment', $this->boundary[1]);
  1551.         break;
  1552.       case 'alt':
  1553.         $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
  1554.         $body .= $this->EncodeString($this->AltBody, $this->Encoding);
  1555.         $body .= $this->LE.$this->LE;
  1556.         $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
  1557.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1558.         $body .= $this->LE.$this->LE;
  1559.         $body .= $this->EndBoundary($this->boundary[1]);
  1560.         break;
  1561.       case 'alt_inline':
  1562.         $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
  1563.         $body .= $this->EncodeString($this->AltBody, $this->Encoding);
  1564.         $body .= $this->LE.$this->LE;
  1565.         $body .= $this->TextLine('--' . $this->boundary[1]);
  1566.         $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
  1567.         $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
  1568.         $body .= $this->LE;
  1569.         $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
  1570.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1571.         $body .= $this->LE.$this->LE;
  1572.         $body .= $this->AttachAll('inline', $this->boundary[2]);
  1573.         $body .= $this->LE;
  1574.         $body .= $this->EndBoundary($this->boundary[1]);
  1575.         break;
  1576.       case 'alt_attach':
  1577.         $body .= $this->TextLine('--' . $this->boundary[1]);
  1578.         $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
  1579.         $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
  1580.         $body .= $this->LE;
  1581.         $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
  1582.         $body .= $this->EncodeString($this->AltBody, $this->Encoding);
  1583.         $body .= $this->LE.$this->LE;
  1584.         $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
  1585.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1586.         $body .= $this->LE.$this->LE;
  1587.         $body .= $this->EndBoundary($this->boundary[2]);
  1588.         $body .= $this->LE;
  1589.         $body .= $this->AttachAll('attachment', $this->boundary[1]);
  1590.         break;
  1591.       case 'alt_inline_attach':
  1592.         $body .= $this->TextLine('--' . $this->boundary[1]);
  1593.         $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
  1594.         $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
  1595.         $body .= $this->LE;
  1596.         $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
  1597.         $body .= $this->EncodeString($this->AltBody, $this->Encoding);
  1598.         $body .= $this->LE.$this->LE;
  1599.         $body .= $this->TextLine('--' . $this->boundary[2]);
  1600.         $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
  1601.         $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3] . '"');
  1602.         $body .= $this->LE;
  1603.         $body .= $this->GetBoundary($this->boundary[3], '', 'text/html', '');
  1604.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1605.         $body .= $this->LE.$this->LE;
  1606.         $body .= $this->AttachAll('inline', $this->boundary[3]);
  1607.         $body .= $this->LE;
  1608.         $body .= $this->EndBoundary($this->boundary[2]);
  1609.         $body .= $this->LE;
  1610.         $body .= $this->AttachAll('attachment', $this->boundary[1]);
  1611.         break;
  1612.       default:
  1613.         // catch case 'plain' and case ''
  1614.         $body .= $this->EncodeString($this->Body, $this->Encoding);
  1615.         break;
  1616.     }
  1617.  
  1618.     if ($this->IsError()) {
  1619.       $body = '';
  1620.     } elseif ($this->sign_key_file) {
  1621.       try {
  1622.         if (!defined('PKCS7_TEXT')) {
  1623.             throw new phpmailerException($this->Lang('signing').' OpenSSL extension missing.');
  1624.         }
  1625.         $file = tempnam(sys_get_temp_dir(), 'mail');
  1626.         file_put_contents($file, $body); //TODO check this worked
  1627.         $signed = tempnam(sys_get_temp_dir(), 'signed');
  1628.         if (@openssl_pkcs7_sign($file, $signed, 'file://'.realpath($this->sign_cert_file), array('file://'.realpath($this->sign_key_file), $this->sign_key_pass), null)) {
  1629.           @unlink($file);
  1630.           $body = file_get_contents($signed);
  1631.           @unlink($signed);
  1632.         } else {
  1633.           @unlink($file);
  1634.           @unlink($signed);
  1635.           throw new phpmailerException($this->Lang('signing').openssl_error_string());
  1636.         }
  1637.       } catch (phpmailerException $e) {
  1638.         $body = '';
  1639.         if ($this->exceptions) {
  1640.           throw $e;
  1641.         }
  1642.       }
  1643.     }
  1644.     return $body;
  1645.   }
  1646.  
  1647.   /**
  1648.    * Returns the start of a message boundary.
  1649.    * @access protected
  1650.    * @param string $boundary
  1651.    * @param string $charSet
  1652.    * @param string $contentType
  1653.    * @param string $encoding
  1654.    * @return string
  1655.    */
  1656.   protected function GetBoundary($boundary, $charSet, $contentType, $encoding) {
  1657.     $result = '';
  1658.     if($charSet == '') {
  1659.       $charSet = $this->CharSet;
  1660.     }
  1661.     if($contentType == '') {
  1662.       $contentType = $this->ContentType;
  1663.     }
  1664.     if($encoding == '') {
  1665.       $encoding = $this->Encoding;
  1666.     }
  1667.     $result .= $this->TextLine('--' . $boundary);
  1668.     $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet);
  1669.     $result .= $this->LE;
  1670.     $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
  1671.     $result .= $this->LE;
  1672.  
  1673.     return $result;
  1674.   }
  1675.  
  1676.   /**
  1677.    * Returns the end of a message boundary.
  1678.    * @access protected
  1679.    * @param string $boundary
  1680.    * @return string
  1681.    */
  1682.   protected function EndBoundary($boundary) {
  1683.     return $this->LE . '--' . $boundary . '--' . $this->LE;
  1684.   }
  1685.  
  1686.   /**
  1687.    * Sets the message type.
  1688.    * @access protected
  1689.    * @return void
  1690.    */
  1691.   protected function SetMessageType() {
  1692.     $this->message_type = array();
  1693.     if($this->AlternativeExists()) $this->message_type[] = "alt";
  1694.     if($this->InlineImageExists()) $this->message_type[] = "inline";
  1695.     if($this->AttachmentExists()) $this->message_type[] = "attach";
  1696.     $this->message_type = implode("_", $this->message_type);
  1697.     if($this->message_type == "") $this->message_type = "plain";
  1698.   }
  1699.  
  1700.   /**
  1701.    * Returns a formatted header line.
  1702.    * @access public
  1703.    * @param string $name
  1704.    * @param string $value
  1705.    * @return string
  1706.    */
  1707.   public function HeaderLine($name, $value) {
  1708.     return $name . ': ' . $value . $this->LE;
  1709.   }
  1710.  
  1711.   /**
  1712.    * Returns a formatted mail line.
  1713.    * @access public
  1714.    * @param string $value
  1715.    * @return string
  1716.    */
  1717.   public function TextLine($value) {
  1718.     return $value . $this->LE;
  1719.   }
  1720.  
  1721.   /////////////////////////////////////////////////
  1722.   // CLASS METHODS, ATTACHMENTS
  1723.   /////////////////////////////////////////////////
  1724.  
  1725.   /**
  1726.    * Adds an attachment from a path on the filesystem.
  1727.    * Returns false if the file could not be found
  1728.    * or accessed.
  1729.    * @param string $path Path to the attachment.
  1730.    * @param string $name Overrides the attachment name.
  1731.    * @param string $encoding File encoding (see $Encoding).
  1732.    * @param string $type File extension (MIME) type.
  1733.    * @throws phpmailerException
  1734.    * @return bool
  1735.    */
  1736.   public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
  1737.     try {
  1738.       if ( !@is_file($path) ) {
  1739.         throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
  1740.       }
  1741.       $filename = basename($path);
  1742.       if ( $name == '' ) {
  1743.         $name = $filename;
  1744.       }
  1745.  
  1746.       $this->attachment[] = array(
  1747.         0 => $path,
  1748.         1 => $filename,
  1749.         2 => $name,
  1750.         3 => $encoding,
  1751.         4 => $type,
  1752.         5 => false,  // isStringAttachment
  1753.         6 => 'attachment',
  1754.         7 => 0
  1755.       );
  1756.  
  1757.     } catch (phpmailerException $e) {
  1758.       $this->SetError($e->getMessage());
  1759.       if ($this->exceptions) {
  1760.         throw $e;
  1761.       }
  1762.       if ($this->SMTPDebug) {
  1763.         $this->edebug($e->getMessage()."\n");
  1764.       }
  1765.       if ( $e->getCode() == self::STOP_CRITICAL ) {
  1766.         return false;
  1767.       }
  1768.     }
  1769.     return true;
  1770.   }
  1771.  
  1772.   /**
  1773.   * Return the current array of attachments
  1774.   * @return array
  1775.   */
  1776.   public function GetAttachments() {
  1777.     return $this->attachment;
  1778.   }
  1779.  
  1780.   /**
  1781.    * Attaches all fs, string, and binary attachments to the message.
  1782.    * Returns an empty string on failure.
  1783.    * @access protected
  1784.    * @param string $disposition_type
  1785.    * @param string $boundary
  1786.    * @return string
  1787.    */
  1788.   protected function AttachAll($disposition_type, $boundary) {
  1789.     // Return text of body
  1790.     $mime = array();
  1791.     $cidUniq = array();
  1792.     $incl = array();
  1793.  
  1794.     // Add all attachments
  1795.     foreach ($this->attachment as $attachment) {
  1796.       // CHECK IF IT IS A VALID DISPOSITION_FILTER
  1797.       if($attachment[6] == $disposition_type) {
  1798.         // Check for string attachment
  1799.         $string = '';
  1800.         $path = '';
  1801.         $bString = $attachment[5];
  1802.         if ($bString) {
  1803.           $string = $attachment[0];
  1804.         } else {
  1805.           $path = $attachment[0];
  1806.         }
  1807.  
  1808.         $inclhash = md5(serialize($attachment));
  1809.         if (in_array($inclhash, $incl)) { continue; }
  1810.         $incl[]      = $inclhash;
  1811.         $filename    = $attachment[1];
  1812.         $name        = $attachment[2];
  1813.         $encoding    = $attachment[3];
  1814.         $type        = $attachment[4];
  1815.         $disposition = $attachment[6];
  1816.         $cid         = $attachment[7];
  1817.         if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
  1818.         $cidUniq[$cid] = true;
  1819.  
  1820.         $mime[] = sprintf("--%s%s", $boundary, $this->LE);
  1821.         $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
  1822.         $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
  1823.  
  1824.         if($disposition == 'inline') {
  1825.           $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
  1826.         }
  1827.  
  1828.         $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
  1829.  
  1830.         // Encode as string attachment
  1831.         if($bString) {
  1832.           $mime[] = $this->EncodeString($string, $encoding);
  1833.           if($this->IsError()) {
  1834.             return '';
  1835.           }
  1836.           $mime[] = $this->LE.$this->LE;
  1837.         } else {
  1838.           $mime[] = $this->EncodeFile($path, $encoding);
  1839.           if($this->IsError()) {
  1840.             return '';
  1841.           }
  1842.           $mime[] = $this->LE.$this->LE;
  1843.         }
  1844.       }
  1845.     }
  1846.  
  1847.     $mime[] = sprintf("--%s--%s", $boundary, $this->LE);
  1848.  
  1849.     return implode("", $mime);
  1850.   }
  1851.  
  1852.   /**
  1853.    * Encodes attachment in requested format.
  1854.    * Returns an empty string on failure.
  1855.    * @param string $path The full path to the file
  1856.    * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
  1857.    * @throws phpmailerException
  1858.    * @see EncodeFile()
  1859.    * @access protected
  1860.    * @return string
  1861.    */
  1862.   protected function EncodeFile($path, $encoding = 'base64') {
  1863.     try {
  1864.       if (!is_readable($path)) {
  1865.         throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
  1866.       }
  1867.       $magic_quotes = get_magic_quotes_runtime();
  1868.       if ($magic_quotes) {
  1869.         if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  1870.           set_magic_quotes_runtime(0);
  1871.         } else {
  1872.           ini_set('magic_quotes_runtime', 0);
  1873.         }
  1874.       }
  1875.       $file_buffer  = file_get_contents($path);
  1876.       $file_buffer  = $this->EncodeString($file_buffer, $encoding);
  1877.       if ($magic_quotes) {
  1878.         if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  1879.           set_magic_quotes_runtime($magic_quotes);
  1880.         } else {
  1881.           ini_set('magic_quotes_runtime', $magic_quotes);
  1882.         }
  1883.       }
  1884.       return $file_buffer;
  1885.     } catch (Exception $e) {
  1886.       $this->SetError($e->getMessage());
  1887.       return '';
  1888.     }
  1889.   }
  1890.  
  1891.   /**
  1892.    * Encodes string to requested format.
  1893.    * Returns an empty string on failure.
  1894.    * @param string $str The text to encode
  1895.    * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
  1896.    * @access public
  1897.    * @return string
  1898.    */
  1899.   public function EncodeString($str, $encoding = 'base64') {
  1900.     $encoded = '';
  1901.     switch(strtolower($encoding)) {
  1902.       case 'base64':
  1903.         $encoded = chunk_split(base64_encode($str), 76, $this->LE);
  1904.         break;
  1905.       case '7bit':
  1906.       case '8bit':
  1907.         $encoded = $this->FixEOL($str);
  1908.         //Make sure it ends with a line break
  1909.         if (substr($encoded, -(strlen($this->LE))) != $this->LE)
  1910.           $encoded .= $this->LE;
  1911.         break;
  1912.       case 'binary':
  1913.         $encoded = $str;
  1914.         break;
  1915.       case 'quoted-printable':
  1916.         $encoded = $this->EncodeQP($str);
  1917.         break;
  1918.       default:
  1919.         $this->SetError($this->Lang('encoding') . $encoding);
  1920.         break;
  1921.     }
  1922.     return $encoded;
  1923.   }
  1924.  
  1925.   /**
  1926.    * Encode a header string to best (shortest) of Q, B, quoted or none.
  1927.    * @access public
  1928.    * @param string $str
  1929.    * @param string $position
  1930.    * @return string
  1931.    */
  1932.   public function EncodeHeader($str, $position = 'text') {
  1933.     $x = 0;
  1934.  
  1935.     switch (strtolower($position)) {
  1936.       case 'phrase':
  1937.         if (!preg_match('/[\200-\377]/', $str)) {
  1938.           // Can't use addslashes as we don't know what value has magic_quotes_sybase
  1939.           $encoded = addcslashes($str, "\0..\37\177\\\"");
  1940.           if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
  1941.            return ($encoded);
  1942.          } else {
  1943.            return ("\"$encoded\"");
  1944.          }
  1945.        }
  1946.        $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
  1947.        break;
  1948.      case 'comment':
  1949.        $x = preg_match_all('/[()"]/', $str, $matches);
  1950.        // Fall-through
  1951.      case 'text':
  1952.      default:
  1953.        $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
  1954.        break;
  1955.    }
  1956.  
  1957.    if ($x == 0) { //There are no chars that need encoding
  1958.      return ($str);
  1959.    }
  1960.  
  1961.    $maxlen = 75 - 7 - strlen($this->CharSet);
  1962.    // Try to select the encoding which should produce the shortest output
  1963.    if ($x > strlen($str)/3) { //More than a third of the content will need encoding, so B encoding will be most efficient
  1964.      $encoding = 'B';
  1965.      if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
  1966.        // Use a custom function which correctly encodes and wraps long
  1967.        // multibyte strings without breaking lines within a character
  1968.        $encoded = $this->Base64EncodeWrapMB($str, "\n");
  1969.      } else {
  1970.        $encoded = base64_encode($str);
  1971.        $maxlen -= $maxlen % 4;
  1972.        $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
  1973.      }
  1974.    } else {
  1975.      $encoding = 'Q';
  1976.      $encoded = $this->EncodeQ($str, $position);
  1977.      $encoded = $this->WrapText($encoded, $maxlen, true);
  1978.      $encoded = str_replace('='.self::CRLF, "\n", trim($encoded));
  1979.    }
  1980.  
  1981.    $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
  1982.    $encoded = trim(str_replace("\n", $this->LE, $encoded));
  1983.  
  1984.    return $encoded;
  1985.  }
  1986.  
  1987.  /**
  1988.   * Checks if a string contains multibyte characters.
  1989.   * @access public
  1990.   * @param string $str multi-byte text to wrap encode
  1991.   * @return bool
  1992.   */
  1993.  public function HasMultiBytes($str) {
  1994.    if (function_exists('mb_strlen')) {
  1995.      return (strlen($str) > mb_strlen($str, $this->CharSet));
  1996.    } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
  1997.      return false;
  1998.    }
  1999.  }
  2000.  
  2001.  /**
  2002.   * Correctly encodes and wraps long multibyte strings for mail headers
  2003.   * without breaking lines within a character.
  2004.   * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
  2005.   * @access public
  2006.   * @param string $str multi-byte text to wrap encode
  2007.   * @param string $lf string to use as linefeed/end-of-line
  2008.   * @return string
  2009.   */
  2010.  public function Base64EncodeWrapMB($str, $lf=null) {
  2011.    $start = "=?".$this->CharSet."?B?";
  2012.    $end = "?=";
  2013.    $encoded = "";
  2014.    if ($lf === null) {
  2015.      $lf = $this->LE;
  2016.    }
  2017.  
  2018.    $mb_length = mb_strlen($str, $this->CharSet);
  2019.    // Each line must have length <= 75, including $start and $end
  2020.    $length = 75 - strlen($start) - strlen($end);
  2021.    // Average multi-byte ratio
  2022.    $ratio = $mb_length / strlen($str);
  2023.    // Base64 has a 4:3 ratio
  2024.    $offset = $avgLength = floor($length * $ratio * .75);
  2025.  
  2026.    for ($i = 0; $i < $mb_length; $i += $offset) {
  2027.      $lookBack = 0;
  2028.  
  2029.      do {
  2030.        $offset = $avgLength - $lookBack;
  2031.        $chunk = mb_substr($str, $i, $offset, $this->CharSet);
  2032.        $chunk = base64_encode($chunk);
  2033.        $lookBack++;
  2034.      }
  2035.      while (strlen($chunk) > $length);
  2036.  
  2037.      $encoded .= $chunk . $lf;
  2038.    }
  2039.  
  2040.    // Chomp the last linefeed
  2041.    $encoded = substr($encoded, 0, -strlen($lf));
  2042.    return $encoded;
  2043.  }
  2044.  
  2045.  /**
  2046.   * Encode string to RFC2045 (6.7) quoted-printable format
  2047.   * @access public
  2048.   * @param string $string The text to encode
  2049.   * @param integer $line_max Number of chars allowed on a line before wrapping
  2050.   * @return string
  2051.   * @link PHP version adapted from http://www.php.net/manual/en/function.quoted-printable-decode.php#89417
  2052.   */
  2053.  public function EncodeQP($string, $line_max = 76) {
  2054.    if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
  2055.      return quoted_printable_encode($string);
  2056.    }
  2057.    //Fall back to a pure PHP implementation
  2058.    $string = str_replace(array('%20', '%0D%0A.', '%0D%0A', '%'), array(' ', "\r\n=2E", "\r\n", '='), rawurlencode($string));
  2059.    $string = preg_replace('/[^\r\n]{'.($line_max - 3).'}[^=\r\n]{2}/', "$0=\r\n", $string);
  2060.    return $string;
  2061.  }
  2062.  
  2063.  /**
  2064.   * Wrapper to preserve BC for old QP encoding function that was removed
  2065.   * @see EncodeQP()
  2066.   * @access public
  2067.   * @param string $string
  2068.   * @param integer $line_max
  2069.   * @param bool $space_conv
  2070.   * @return string
  2071.   */
  2072.  public function EncodeQPphp($string, $line_max = 76, $space_conv = false) {
  2073.    return $this->EncodeQP($string, $line_max);
  2074.  }
  2075.  
  2076.  /**
  2077.   * Encode string to q encoding.
  2078.   * @link http://tools.ietf.org/html/rfc2047
  2079.   * @param string $str the text to encode
  2080.   * @param string $position Where the text is going to be used, see the RFC for what that means
  2081.   * @access public
  2082.   * @return string
  2083.   */
  2084.  public function EncodeQ($str, $position = 'text') {
  2085.    //There should not be any EOL in the string
  2086.  $pattern="";
  2087.    $encoded = str_replace(array("\r", "\n"), '', $str);
  2088.    switch (strtolower($position)) {
  2089.      case 'phrase':
  2090.        $pattern = '^A-Za-z0-9!*+\/ -';
  2091.        break;
  2092.  
  2093.      case 'comment':
  2094.        $pattern = '\(\)"';
  2095.        //note that we don't break here!
  2096.         //for this reason we build the $pattern without including delimiters and []
  2097.  
  2098.       case 'text':
  2099.       default:
  2100.         //Replace every high ascii, control =, ? and _ characters
  2101.         //We put \075 (=) as first value to make sure it's the first one in being converted, preventing double encode
  2102.         $pattern = '\075\000-\011\013\014\016-\037\077\137\177-\377' . $pattern;
  2103.         break;
  2104.     }
  2105.  
  2106.     if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
  2107.       foreach (array_unique($matches[0]) as $char) {
  2108.         $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
  2109.       }
  2110.     }
  2111.  
  2112.     //Replace every spaces to _ (more readable than =20)
  2113.     return str_replace(' ', '_', $encoded);
  2114. }
  2115.  
  2116.  
  2117.   /**
  2118.    * Adds a string or binary attachment (non-filesystem) to the list.
  2119.    * This method can be used to attach ascii or binary data,
  2120.    * such as a BLOB record from a database.
  2121.    * @param string $string String attachment data.
  2122.    * @param string $filename Name of the attachment.
  2123.    * @param string $encoding File encoding (see $Encoding).
  2124.    * @param string $type File extension (MIME) type.
  2125.    * @return void
  2126.    */
  2127.   public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
  2128.     // Append to $attachment array
  2129.     $this->attachment[] = array(
  2130.       0 => $string,
  2131.       1 => $filename,
  2132.       2 => basename($filename),
  2133.       3 => $encoding,
  2134.       4 => $type,
  2135.       5 => true,  // isStringAttachment
  2136.       6 => 'attachment',
  2137.       7 => 0
  2138.     );
  2139.   }
  2140.  
  2141.   /**
  2142.    * Add an embedded attachment from a file.
  2143.    * This can include images, sounds, and just about any other document type.
  2144.    * Be sure to set the $type to an image type for images:
  2145.    * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
  2146.    * @param string $path Path to the attachment.
  2147.    * @param string $cid Content ID of the attachment; Use this to reference
  2148.    *        the content when using an embedded image in HTML.
  2149.    * @param string $name Overrides the attachment name.
  2150.    * @param string $encoding File encoding (see $Encoding).
  2151.    * @param string $type File MIME type.
  2152.    * @return bool True on successfully adding an attachment
  2153.    */
  2154.   public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
  2155.  
  2156.     if ( !@is_file($path) ) {
  2157.       $this->SetError($this->Lang('file_access') . $path);
  2158.       return false;
  2159.     }
  2160.  
  2161.     $filename = basename($path);
  2162.     if ( $name == '' ) {
  2163.       $name = $filename;
  2164.     }
  2165.  
  2166.     // Append to $attachment array
  2167.     $this->attachment[] = array(
  2168.       0 => $path,
  2169.       1 => $filename,
  2170.       2 => $name,
  2171.       3 => $encoding,
  2172.       4 => $type,
  2173.       5 => false,  // isStringAttachment
  2174.       6 => 'inline',
  2175.       7 => $cid
  2176.     );
  2177.     return true;
  2178.   }
  2179.  
  2180.  
  2181.   /**
  2182.    * Add an embedded stringified attachment.
  2183.    * This can include images, sounds, and just about any other document type.
  2184.    * Be sure to set the $type to an image type for images:
  2185.    * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
  2186.    * @param string $string The attachment binary data.
  2187.    * @param string $cid Content ID of the attachment; Use this to reference
  2188.    *        the content when using an embedded image in HTML.
  2189.    * @param string $name
  2190.    * @param string $encoding File encoding (see $Encoding).
  2191.    * @param string $type MIME type.
  2192.    * @return bool True on successfully adding an attachment
  2193.    */
  2194.   public function AddStringEmbeddedImage($string, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
  2195.     // Append to $attachment array
  2196.     $this->attachment[] = array(
  2197.       0 => $string,
  2198.       1 => $name,
  2199.       2 => $name,
  2200.       3 => $encoding,
  2201.       4 => $type,
  2202.       5 => true,  // isStringAttachment
  2203.       6 => 'inline',
  2204.       7 => $cid
  2205.     );
  2206.     return true;
  2207.   }
  2208.  
  2209.   /**
  2210.    * Returns true if an inline attachment is present.
  2211.    * @access public
  2212.    * @return bool
  2213.    */
  2214.   public function InlineImageExists() {
  2215.     foreach($this->attachment as $attachment) {
  2216.       if ($attachment[6] == 'inline') {
  2217.         return true;
  2218.       }
  2219.     }
  2220.     return false;
  2221.   }
  2222.  
  2223.   /**
  2224.    * Returns true if an attachment (non-inline) is present.
  2225.    * @return bool
  2226.    */
  2227.   public function AttachmentExists() {
  2228.     foreach($this->attachment as $attachment) {
  2229.       if ($attachment[6] == 'attachment') {
  2230.         return true;
  2231.       }
  2232.     }
  2233.     return false;
  2234.   }
  2235.  
  2236.   /**
  2237.    * Does this message have an alternative body set?
  2238.    * @return bool
  2239.    */
  2240.   public function AlternativeExists() {
  2241.     return !empty($this->AltBody);
  2242.   }
  2243.  
  2244.   /////////////////////////////////////////////////
  2245.   // CLASS METHODS, MESSAGE RESET
  2246.   /////////////////////////////////////////////////
  2247.  
  2248.   /**
  2249.    * Clears all recipients assigned in the TO array.  Returns void.
  2250.    * @return void
  2251.    */
  2252.   public function ClearAddresses() {
  2253.     foreach($this->to as $to) {
  2254.       unset($this->all_recipients[strtolower($to[0])]);
  2255.     }
  2256.     $this->to = array();
  2257.   }
  2258.  
  2259.   /**
  2260.    * Clears all recipients assigned in the CC array.  Returns void.
  2261.    * @return void
  2262.    */
  2263.   public function ClearCCs() {
  2264.     foreach($this->cc as $cc) {
  2265.       unset($this->all_recipients[strtolower($cc[0])]);
  2266.     }
  2267.     $this->cc = array();
  2268.   }
  2269.  
  2270.   /**
  2271.    * Clears all recipients assigned in the BCC array.  Returns void.
  2272.    * @return void
  2273.    */
  2274.   public function ClearBCCs() {
  2275.     foreach($this->bcc as $bcc) {
  2276.       unset($this->all_recipients[strtolower($bcc[0])]);
  2277.     }
  2278.     $this->bcc = array();
  2279.   }
  2280.  
  2281.   /**
  2282.    * Clears all recipients assigned in the ReplyTo array.  Returns void.
  2283.    * @return void
  2284.    */
  2285.   public function ClearReplyTos() {
  2286.     $this->ReplyTo = array();
  2287.   }
  2288.  
  2289.   /**
  2290.    * Clears all recipients assigned in the TO, CC and BCC
  2291.    * array.  Returns void.
  2292.    * @return void
  2293.    */
  2294.   public function ClearAllRecipients() {
  2295.     $this->to = array();
  2296.     $this->cc = array();
  2297.     $this->bcc = array();
  2298.     $this->all_recipients = array();
  2299.   }
  2300.  
  2301.   /**
  2302.    * Clears all previously set filesystem, string, and binary
  2303.    * attachments.  Returns void.
  2304.    * @return void
  2305.    */
  2306.   public function ClearAttachments() {
  2307.     $this->attachment = array();
  2308.   }
  2309.  
  2310.   /**
  2311.    * Clears all custom headers.  Returns void.
  2312.    * @return void
  2313.    */
  2314.   public function ClearCustomHeaders() {
  2315.     $this->CustomHeader = array();
  2316.   }
  2317.  
  2318.   /////////////////////////////////////////////////
  2319.   // CLASS METHODS, MISCELLANEOUS
  2320.   /////////////////////////////////////////////////
  2321.  
  2322.   /**
  2323.    * Adds the error message to the error container.
  2324.    * @access protected
  2325.    * @param string $msg
  2326.    * @return void
  2327.    */
  2328.   protected function SetError($msg) {
  2329.     $this->error_count++;
  2330.     if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
  2331.       $lasterror = $this->smtp->getError();
  2332.       if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
  2333.         $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
  2334.       }
  2335.     }
  2336.     $this->ErrorInfo = $msg;
  2337.   }
  2338.  
  2339.   /**
  2340.    * Returns the proper RFC 822 formatted date.
  2341.    * @access public
  2342.    * @return string
  2343.    * @static
  2344.    */
  2345.   public static function RFCDate() {
  2346.     //Set the time zone to whatever the default is to avoid 500 errors
  2347.     //Will default to UTC if it's not set properly in php.ini
  2348.     date_default_timezone_set(@date_default_timezone_get());
  2349.     return date('D, j M Y H:i:s O');
  2350.   }
  2351.  
  2352.   /**
  2353.    * Returns the server hostname or 'localhost.localdomain' if unknown.
  2354.    * @access protected
  2355.    * @return string
  2356.    */
  2357.   protected function ServerHostname() {
  2358.     if (!empty($this->Hostname)) {
  2359.       $result = $this->Hostname;
  2360.     } elseif (isset($_SERVER['SERVER_NAME'])) {
  2361.       $result = $_SERVER['SERVER_NAME'];
  2362.     } else {
  2363.       $result = 'localhost.localdomain';
  2364.     }
  2365.  
  2366.     return $result;
  2367.   }
  2368.  
  2369.   /**
  2370.    * Returns a message in the appropriate language.
  2371.    * @access protected
  2372.    * @param string $key
  2373.    * @return string
  2374.    */
  2375.   protected function Lang($key) {
  2376.     if(count($this->language) < 1) {
  2377.       $this->SetLanguage('en'); // set the default language
  2378.     }
  2379.  
  2380.     if(isset($this->language[$key])) {
  2381.       return $this->language[$key];
  2382.     } else {
  2383.       return 'Language string failed to load: ' . $key;
  2384.     }
  2385.   }
  2386.  
  2387.   /**
  2388.    * Returns true if an error occurred.
  2389.    * @access public
  2390.    * @return bool
  2391.    */
  2392.   public function IsError() {
  2393.     return ($this->error_count > 0);
  2394.   }
  2395.  
  2396.   /**
  2397.    * Changes every end of line from CRLF, CR or LF to $this->LE.
  2398.    * @access public
  2399.    * @param string $str String to FixEOL
  2400.    * @return string
  2401.    */
  2402.   public function FixEOL($str) {
  2403.   // condense down to \n
  2404.   $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
  2405.   // Now convert LE as needed
  2406.   if ($this->LE !== "\n") {
  2407.     $nstr = str_replace("\n", $this->LE, $nstr);
  2408.   }
  2409.     return  $nstr;
  2410.   }
  2411.  
  2412.   /**
  2413.    * Adds a custom header. $name value can be overloaded to contain
  2414.    * both header name and value (name:value)
  2415.    * @access public
  2416.    * @param string $name custom header name
  2417.    * @param string $value header value
  2418.    * @return void
  2419.    */
  2420.   public function AddCustomHeader($name, $value=null) {
  2421.   if ($value === null) {
  2422.     // Value passed in as name:value
  2423.     $this->CustomHeader[] = explode(':', $name, 2);
  2424.   } else {
  2425.     $this->CustomHeader[] = array($name, $value);
  2426.   }
  2427.   }
  2428.  
  2429.   /**
  2430.    * Creates a message from an HTML string, making modifications for inline images and backgrounds
  2431.    * and creates a plain-text version by converting the HTML
  2432.    * Overwrites any existing values in $this->Body and $this->AltBody
  2433.    * @access public
  2434.    * @param string $message HTML message string
  2435.    * @param string $basedir baseline directory for path
  2436.    * @param bool $advanced Whether to use the advanced HTML to text converter
  2437.    * @return string $message
  2438.    */
  2439.   public function MsgHTML($message, $basedir = '', $advanced = false) {
  2440.     preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images);
  2441.     if(isset($images[2])) {
  2442.       foreach($images[2] as $i => $url) {
  2443.         // do not change urls for absolute images (thanks to corvuscorax)
  2444.         if (!preg_match('#^[A-z]+://#', $url)) {
  2445.           $filename = basename($url);
  2446.           $directory = dirname($url);
  2447.           if ($directory == '.') {
  2448.             $directory = '';
  2449.           }
  2450.           $cid = 'cid:' . md5($url);
  2451.           $ext = pathinfo($filename, PATHINFO_EXTENSION);
  2452.           $mimeType  = self::_mime_types($ext);
  2453.           if ( strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; }
  2454.           if ( strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; }
  2455.           if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($url), $filename, 'base64', $mimeType) ) {
  2456.             $message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"".$cid."\"", $message);
  2457.           }
  2458.         }
  2459.       }
  2460.     }
  2461.     $this->IsHTML(true);
  2462.     $this->Body = $message;
  2463.     $this->AltBody = $this->html2text($message, $advanced);
  2464.     if (empty($this->AltBody)) {
  2465.       $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
  2466.     }
  2467.     return $message;
  2468.   }
  2469.  
  2470.     /**
  2471.      * Convert an HTML string into a plain text version
  2472.      * @param string $html The HTML text to convert
  2473.      * @param bool $advanced Should this use the more complex html2text converter or just a simple one?
  2474.      * @return string
  2475.      */
  2476.   public function html2text($html, $advanced = false) {
  2477.     if ($advanced) {
  2478.       require_once (DIR_FS_CATALOG . 'includes/classes/support/class.html2text.php');
  2479.       $h = new html2text($html);
  2480.       return $h->get_text();
  2481.     }
  2482.     return html_entity_decode(trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $html))), ENT_QUOTES, $this->CharSet);
  2483.   }
  2484.  
  2485.   /**
  2486.    * Gets the MIME type of the embedded or inline image
  2487.    * @param string $ext File extension
  2488.    * @access public
  2489.    * @return string MIME type of ext
  2490.    * @static
  2491.    */
  2492.   public static function _mime_types($ext = '') {
  2493.     $mimes = array(
  2494.       'xl'    =>  'application/excel',
  2495.       'hqx'   =>  'application/mac-binhex40',
  2496.       'cpt'   =>  'application/mac-compactpro',
  2497.       'bin'   =>  'application/macbinary',
  2498.       'doc'   =>  'application/msword',
  2499.       'word'  =>  'application/msword',
  2500.       'class' =>  'application/octet-stream',
  2501.       'dll'   =>  'application/octet-stream',
  2502.       'dms'   =>  'application/octet-stream',
  2503.       'exe'   =>  'application/octet-stream',
  2504.       'lha'   =>  'application/octet-stream',
  2505.       'lzh'   =>  'application/octet-stream',
  2506.       'psd'   =>  'application/octet-stream',
  2507.       'sea'   =>  'application/octet-stream',
  2508.       'so'    =>  'application/octet-stream',
  2509.       'oda'   =>  'application/oda',
  2510.       'pdf'   =>  'application/pdf',
  2511.       'ai'    =>  'application/postscript',
  2512.       'eps'   =>  'application/postscript',
  2513.       'ps'    =>  'application/postscript',
  2514.       'smi'   =>  'application/smil',
  2515.       'smil'  =>  'application/smil',
  2516.       'mif'   =>  'application/vnd.mif',
  2517.       'xls'   =>  'application/vnd.ms-excel',
  2518.       'ppt'   =>  'application/vnd.ms-powerpoint',
  2519.       'wbxml' =>  'application/vnd.wap.wbxml',
  2520.       'wmlc'  =>  'application/vnd.wap.wmlc',
  2521.       'dcr'   =>  'application/x-director',
  2522.       'dir'   =>  'application/x-director',
  2523.       'dxr'   =>  'application/x-director',
  2524.       'dvi'   =>  'application/x-dvi',
  2525.       'gtar'  =>  'application/x-gtar',
  2526.       'php3'  =>  'application/x-httpd-php',
  2527.       'php4'  =>  'application/x-httpd-php',
  2528.       'php'   =>  'application/x-httpd-php',
  2529.       'phtml' =>  'application/x-httpd-php',
  2530.       'phps'  =>  'application/x-httpd-php-source',
  2531.       'js'    =>  'application/x-javascript',
  2532.       'swf'   =>  'application/x-shockwave-flash',
  2533.       'sit'   =>  'application/x-stuffit',
  2534.       'tar'   =>  'application/x-tar',
  2535.       'tgz'   =>  'application/x-tar',
  2536.       'xht'   =>  'application/xhtml+xml',
  2537.       'xhtml' =>  'application/xhtml+xml',
  2538.       'zip'   =>  'application/zip',
  2539.       'mid'   =>  'audio/midi',
  2540.       'midi'  =>  'audio/midi',
  2541.       'mp2'   =>  'audio/mpeg',
  2542.       'mp3'   =>  'audio/mpeg',
  2543.       'mpga'  =>  'audio/mpeg',
  2544.       'aif'   =>  'audio/x-aiff',
  2545.       'aifc'  =>  'audio/x-aiff',
  2546.       'aiff'  =>  'audio/x-aiff',
  2547.       'ram'   =>  'audio/x-pn-realaudio',
  2548.       'rm'    =>  'audio/x-pn-realaudio',
  2549.       'rpm'   =>  'audio/x-pn-realaudio-plugin',
  2550.       'ra'    =>  'audio/x-realaudio',
  2551.       'wav'   =>  'audio/x-wav',
  2552.       'bmp'   =>  'image/bmp',
  2553.       'gif'   =>  'image/gif',
  2554.       'jpeg'  =>  'image/jpeg',
  2555.       'jpe'   =>  'image/jpeg',
  2556.       'jpg'   =>  'image/jpeg',
  2557.       'png'   =>  'image/png',
  2558.       'tiff'  =>  'image/tiff',
  2559.       'tif'   =>  'image/tiff',
  2560.       'eml'   =>  'message/rfc822',
  2561.       'css'   =>  'text/css',
  2562.       'html'  =>  'text/html',
  2563.       'htm'   =>  'text/html',
  2564.       'shtml' =>  'text/html',
  2565.       'log'   =>  'text/plain',
  2566.       'text'  =>  'text/plain',
  2567.       'txt'   =>  'text/plain',
  2568.       'rtx'   =>  'text/richtext',
  2569.       'rtf'   =>  'text/rtf',
  2570.       'xml'   =>  'text/xml',
  2571.       'xsl'   =>  'text/xml',
  2572.       'mpeg'  =>  'video/mpeg',
  2573.       'mpe'   =>  'video/mpeg',
  2574.       'mpg'   =>  'video/mpeg',
  2575.       'mov'   =>  'video/quicktime',
  2576.       'qt'    =>  'video/quicktime',
  2577.       'rv'    =>  'video/vnd.rn-realvideo',
  2578.       'avi'   =>  'video/x-msvideo',
  2579.       'movie' =>  'video/x-sgi-movie'
  2580.     );
  2581.     return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
  2582.   }
  2583.  
  2584.   /**
  2585.    * Set (or reset) Class Objects (variables)
  2586.    *
  2587.    * Usage Example:
  2588.    * $page->set('X-Priority', '3');
  2589.    *
  2590.    * @access public
  2591.    * @param string $name
  2592.    * @param mixed $value
  2593.    * NOTE: will not work with arrays, there are no arrays to set/reset
  2594.    * @throws phpmailerException
  2595.    * @return bool
  2596.    * @todo Should this not be using __set() magic function?
  2597.    */
  2598.   public function set($name, $value = '') {
  2599.     try {
  2600.       if (isset($this->$name) ) {
  2601.         $this->$name = $value;
  2602.       } else {
  2603.         throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
  2604.       }
  2605.     } catch (Exception $e) {
  2606.       $this->SetError($e->getMessage());
  2607.       if ($e->getCode() == self::STOP_CRITICAL) {
  2608.         return false;
  2609.       }
  2610.     }
  2611.     return true;
  2612.   }
  2613.  
  2614.   /**
  2615.    * Strips newlines to prevent header injection.
  2616.    * @access public
  2617.    * @param string $str
  2618.    * @return string
  2619.    */
  2620.   public function SecureHeader($str) {
  2621.     return trim(str_replace(array("\r", "\n"), '', $str));
  2622.   }
  2623.  
  2624.   /**
  2625.    * Set the private key file and password to sign the message.
  2626.    *
  2627.    * @access public
  2628.    * @param string $cert_filename
  2629.    * @param string $key_filename
  2630.    * @param string $key_pass Password for private key
  2631.    */
  2632.   public function Sign($cert_filename, $key_filename, $key_pass) {
  2633.     $this->sign_cert_file = $cert_filename;
  2634.     $this->sign_key_file = $key_filename;
  2635.     $this->sign_key_pass = $key_pass;
  2636.   }
  2637.  
  2638.   /**
  2639.    * Set the private key file and password to sign the message.
  2640.    *
  2641.    * @access public
  2642.    * @param string $txt
  2643.    * @return string
  2644.    */
  2645.   public function DKIM_QP($txt) {
  2646.     $line = '';
  2647.     for ($i = 0; $i < strlen($txt); $i++) {
  2648.       $ord = ord($txt[$i]);
  2649.       if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
  2650.         $line .= $txt[$i];
  2651.       } else {
  2652.         $line .= "=".sprintf("%02X", $ord);
  2653.       }
  2654.     }
  2655.     return $line;
  2656.   }
  2657.  
  2658.   /**
  2659.    * Generate DKIM signature
  2660.    *
  2661.    * @access public
  2662.    * @param string $s Header
  2663.    * @throws phpmailerException
  2664.    * @return string
  2665.    */
  2666.   public function DKIM_Sign($s) {
  2667.     if (!defined('PKCS7_TEXT')) {
  2668.         if ($this->exceptions) {
  2669.             throw new phpmailerException($this->Lang("signing").' OpenSSL extension missing.');
  2670.         }
  2671.         return '';
  2672.     }
  2673.     $privKeyStr = file_get_contents($this->DKIM_private);
  2674.     if ($this->DKIM_passphrase != '') {
  2675.       $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
  2676.     } else {
  2677.       $privKey = $privKeyStr;
  2678.     }
  2679.     if (openssl_sign($s, $signature, $privKey)) {
  2680.       return base64_encode($signature);
  2681.     }
  2682.     return '';
  2683.   }
  2684.  
  2685.   /**
  2686.    * Generate DKIM Canonicalization Header
  2687.    *
  2688.    * @access public
  2689.    * @param string $s Header
  2690.    * @return string
  2691.    */
  2692.   public function DKIM_HeaderC($s) {
  2693.     $s = preg_replace("/\r\n\s+/", " ", $s);
  2694.     $lines = explode("\r\n", $s);
  2695.     foreach ($lines as $key => $line) {
  2696.       list($heading, $value) = explode(":", $line, 2);
  2697.       $heading = strtolower($heading);
  2698.       $value = preg_replace("/\s+/", " ", $value) ; // Compress useless spaces
  2699.       $lines[$key] = $heading.":".trim($value) ; // Don't forget to remove WSP around the value
  2700.     }
  2701.     $s = implode("\r\n", $lines);
  2702.     return $s;
  2703.   }
  2704.  
  2705.   /**
  2706.    * Generate DKIM Canonicalization Body
  2707.    *
  2708.    * @access public
  2709.    * @param string $body Message Body
  2710.    * @return string
  2711.    */
  2712.   public function DKIM_BodyC($body) {
  2713.     if ($body == '') return "\r\n";
  2714.     // stabilize line endings
  2715.     $body = str_replace("\r\n", "\n", $body);
  2716.     $body = str_replace("\n", "\r\n", $body);
  2717.     // END stabilize line endings
  2718.     while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
  2719.       $body = substr($body, 0, strlen($body) - 2);
  2720.     }
  2721.     return $body;
  2722.   }
  2723.  
  2724.   /**
  2725.    * Create the DKIM header, body, as new header
  2726.    *
  2727.    * @access public
  2728.    * @param string $headers_line Header lines
  2729.    * @param string $subject Subject
  2730.    * @param string $body Body
  2731.    * @return string
  2732.    */
  2733.   public function DKIM_Add($headers_line, $subject, $body) {
  2734.     $DKIMsignatureType    = 'rsa-sha1'; // Signature & hash algorithms
  2735.     $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
  2736.     $DKIMquery            = 'dns/txt'; // Query method
  2737.     $DKIMtime             = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
  2738.     $subject_header       = "Subject: $subject";
  2739.     $headers              = explode($this->LE, $headers_line);
  2740.     $from_header          = '';
  2741.     $to_header            = '';
  2742.     $current = '';
  2743.     foreach($headers as $header) {
  2744.       if (strpos($header, 'From:') === 0) {
  2745.         $from_header = $header;
  2746.         $current = 'from_header';
  2747.       } elseif (strpos($header, 'To:') === 0) {
  2748.         $to_header = $header;
  2749.         $current = 'to_header';
  2750.       } else {
  2751.         if($current && strpos($header, ' =?') === 0){
  2752.           $$current .= $header;
  2753.         } else {
  2754.           $current = '';
  2755.         }
  2756.       }
  2757.     }
  2758.     $from     = str_replace('|', '=7C', $this->DKIM_QP($from_header));
  2759.     $to       = str_replace('|', '=7C', $this->DKIM_QP($to_header));
  2760.     $subject  = str_replace('|', '=7C', $this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
  2761.     $body     = $this->DKIM_BodyC($body);
  2762.     $DKIMlen  = strlen($body) ; // Length of body
  2763.     $DKIMb64  = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
  2764.     $ident    = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
  2765.     $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
  2766.                 "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
  2767.                 "\th=From:To:Subject;\r\n".
  2768.                 "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
  2769.                 "\tz=$from\r\n".
  2770.                 "\t|$to\r\n".
  2771.                 "\t|$subject;\r\n".
  2772.                 "\tbh=" . $DKIMb64 . ";\r\n".
  2773.                 "\tb=";
  2774.     $toSign   = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
  2775.     $signed   = $this->DKIM_Sign($toSign);
  2776.     return $dkimhdrs.$signed."\r\n";
  2777.   }
  2778.  
  2779.   /**
  2780.    * Perform callback
  2781.    * @param boolean $isSent
  2782.    * @param string $to
  2783.    * @param string $cc
  2784.    * @param string $bcc
  2785.    * @param string $subject
  2786.    * @param string $body
  2787.    * @param string $from
  2788.    */
  2789.   protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from = null) {
  2790.     if (!empty($this->action_function) && is_callable($this->action_function)) {
  2791.       $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
  2792.       call_user_func_array($this->action_function, $params);
  2793.     }
  2794.   }
  2795. }
  2796.  
  2797. /**
  2798.  * Exception handler for PHPMailer
  2799.  * @package PHPMailer
  2800.  */
  2801. class phpmailerException extends Exception {
  2802.   /**
  2803.    * Prettify error message output
  2804.    * @return string
  2805.    */
  2806.   public function errorMessage() {
  2807.     $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
  2808.     return $errorMsg;
  2809.   }
  2810. }
  2811.