Changeset 89555 in spip-zone for _plugins_/facteur


Ignore:
Timestamp:
May 20, 2015, 7:36:29 AM (4 years ago)
Author:
marcimat@…
Message:

Passage de la librairie PHP Maileur de 5.1 à 5.2.10

Location:
_plugins_/facteur/trunk/phpmailer-php5
Files:
33 added
1 deleted
28 edited

Legend:

Unmodified
Added
Removed
  • _plugins_/facteur/trunk/phpmailer-php5/LICENSE

    r28344 r89555  
    313313    specified materials from the same place.
    314314
    315     e) Verify that the user has already received a copy of these
     315    e) verify that the user has already received a copy of these
    316316    materials or that you have already sent this user a copy.
    317317
  • _plugins_/facteur/trunk/phpmailer-php5/class.phpmailer.php

    r79378 r89555  
    11<?php
    2 /*~ class.phpmailer.php
    3 .---------------------------------------------------------------------------.
    4 |  Software: PHPMailer - PHP email class                                    |
    5 |   Version: 5.1                                                            |
    6 |   Contact: via sourceforge.net support pages (also www.worxware.com)      |
    7 |      Info: http://phpmailer.sourceforge.net                               |
    8 |   Support: http://sourceforge.net/projects/phpmailer/                     |
    9 | ------------------------------------------------------------------------- |
    10 |     Admin: Andy Prevost (project admininistrator)                         |
    11 |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
    12 |          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
    13 |   Founder: Brent R. Matzelle (original founder)                           |
    14 | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
    15 | Copyright (c) 2001-2003, Brent R. Matzelle                                |
    16 | ------------------------------------------------------------------------- |
    17 |   License: Distributed under the Lesser General Public License (LGPL)     |
    18 |            http://www.gnu.org/copyleft/lesser.html                        |
    19 | This program is distributed in the hope that it will be useful - WITHOUT  |
    20 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
    21 | FITNESS FOR A PARTICULAR PURPOSE.                                         |
    22 | ------------------------------------------------------------------------- |
    23 | We offer a number of paid services (www.worxware.com):                    |
    24 | - Web Hosting on highly optimized fast and secure servers                 |
    25 | - Technology Consulting                                                   |
    26 | - Oursourcing (highly qualified programmers and graphic designers)        |
    27 '---------------------------------------------------------------------------'
    28 */
    29 
    302/**
    31  * PHPMailer - PHP email transport class
    32  * NOTE: Requires PHP version 5 or later
     3 * PHPMailer - PHP email creation and transport class.
     4 * PHP Version 5
    335 * @package PHPMailer
    34  * @author Andy Prevost
    35  * @author Marcus Bointon
     6 * @link https://github.com/PHPMailer/PHPMailer/ The PHPMailer GitHub project
     7 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
     8 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
     9 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
     10 * @author Brent R. Matzelle (original founder)
     11 * @copyright 2012 - 2014 Marcus Bointon
     12 * @copyright 2010 - 2012 Jim Jagielski
    3613 * @copyright 2004 - 2009 Andy Prevost
    37  * @version $Id: class.phpmailer.php 447 2009-05-25 01:36:38Z codeworxtech $
    3814 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
     15 * @note This program is distributed in the hope that it will be useful - WITHOUT
     16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     17 * FITNESS FOR A PARTICULAR PURPOSE.
    3918 */
    4019
    41 if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
    42 
    43 class PHPMailer {
    44 
    45   /////////////////////////////////////////////////
    46   // PROPERTIES, PUBLIC
    47   /////////////////////////////////////////////////
    48 
    49   /**
    50    * Email priority (1 = High, 3 = Normal, 5 = low).
    51    * @var int
    52    */
    53   public $Priority          = 3;
    54 
    55   /**
    56    * Sets the CharSet of the message.
    57    * @var string
    58    */
    59   public $CharSet           = 'iso-8859-1';
    60 
    61   /**
    62    * Sets the Content-type of the message.
    63    * @var string
    64    */
    65   public $ContentType       = 'text/plain';
    66 
    67   /**
    68    * Sets the Encoding of the message. Options for this are
    69    *  "8bit", "7bit", "binary", "base64", and "quoted-printable".
    70    * @var string
    71    */
    72   public $Encoding          = '8bit';
    73 
    74   /**
    75    * Holds the most recent mailer error message.
    76    * @var string
    77    */
    78   public $ErrorInfo         = '';
    79 
    80   /**
    81    * Sets the From email address for the message.
    82    * @var string
    83    */
    84   public $From              = 'root@localhost';
    85 
    86   /**
    87    * Sets the From name of the message.
    88    * @var string
    89    */
    90   public $FromName          = 'Root User';
    91 
    92   /**
    93    * Sets the Sender email (Return-Path) of the message.  If not empty,
    94    * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
    95    * @var string
    96    */
    97   public $Sender            = '';
    98 
    99   /**
    100    * Sets the Subject of the message.
    101    * @var string
    102    */
    103   public $Subject           = '';
    104 
    105   /**
    106    * Sets the Body of the message.  This can be either an HTML or text body.
    107    * If HTML then run IsHTML(true).
    108    * @var string
    109    */
    110   public $Body              = '';
    111 
    112   /**
    113    * Sets the text-only body of the message.  This automatically sets the
    114    * email to multipart/alternative.  This body can be read by mail
    115    * clients that do not have HTML email capability such as mutt. Clients
    116    * that can read HTML will view the normal Body.
    117    * @var string
    118    */
    119   public $AltBody           = '';
    120 
    121   /**
    122    * Sets word wrapping on the body of the message to a given number of
    123    * characters.
    124    * @var int
    125    */
    126   public $WordWrap          = 0;
    127 
    128   /**
    129    * Method to send mail: ("mail", "sendmail", or "smtp").
    130    * @var string
    131    */
    132   public $Mailer            = 'mail';
    133 
    134   /**
    135    * Sets the path of the sendmail program.
    136    * @var string
    137    */
    138   public $Sendmail          = '/usr/sbin/sendmail';
    139 
    140   /**
    141    * Path to PHPMailer plugins.  Useful if the SMTP class
    142    * is in a different directory than the PHP include path.
    143    * @var string
    144    */
    145   public $PluginDir         = '';
    146 
    147   /**
    148    * Sets the email address that a reading confirmation will be sent.
    149    * @var string
    150    */
    151   public $ConfirmReadingTo  = '';
    152 
    153   /**
    154    * Sets the hostname to use in Message-Id and Received headers
    155    * and as default HELO string. If empty, the value returned
    156    * by SERVER_NAME is used or 'localhost.localdomain'.
    157    * @var string
    158    */
    159   public $Hostname          = '';
    160 
    161   /**
    162    * Sets the message ID to be used in the Message-Id header.
    163    * If empty, a unique id will be generated.
    164    * @var string
    165    */
    166   public $MessageID         = '';
    167 
    168   /////////////////////////////////////////////////
    169   // PROPERTIES FOR SMTP
    170   /////////////////////////////////////////////////
    171 
    172   /**
    173    * Sets the SMTP hosts.  All hosts must be separated by a
    174    * semicolon.  You can also specify a different port
    175    * for each host by using this format: [hostname:port]
    176    * (e.g. "smtp1.example.com:25;smtp2.example.com").
    177    * Hosts will be tried in order.
    178    * @var string
    179    */
    180   public $Host          = 'localhost';
    181 
    182   /**
    183    * Sets the default SMTP server port.
    184    * @var int
    185    */
    186   public $Port          = 25;
    187 
    188   /**
    189    * Sets the SMTP HELO of the message (Default is $Hostname).
    190    * @var string
    191    */
    192   public $Helo          = '';
    193 
    194   /**
    195    * Sets connection prefix.
    196    * Options are "", "ssl" or "tls"
    197    * @var string
    198    */
    199   public $SMTPSecure    = '';
    200 
    201   /**
    202    * Sets SMTP authentication. Utilizes the Username and Password variables.
    203    * @var bool
    204    */
    205   public $SMTPAuth      = false;
    206 
    207   /**
    208    * Sets SMTP username.
    209    * @var string
    210    */
    211   public $Username      = '';
    212 
    213   /**
    214    * Sets SMTP password.
    215    * @var string
    216    */
    217   public $Password      = '';
    218 
    219   /**
    220    * Sets the SMTP server timeout in seconds.
    221    * This function will not work with the win32 version.
    222    * @var int
    223    */
    224   public $Timeout       = 10;
    225 
    226   /**
    227    * Sets SMTP class debugging on or off.
    228    * @var bool
    229    */
    230   public $SMTPDebug     = false;
    231 
    232   /**
    233    * Prevents the SMTP connection from being closed after each mail
    234    * sending.  If this is set to true then to close the connection
    235    * requires an explicit call to SmtpClose().
    236    * @var bool
    237    */
    238   public $SMTPKeepAlive = false;
    239 
    240   /**
    241    * Provides the ability to have the TO field process individual
    242    * emails, instead of sending to entire TO addresses
    243    * @var bool
    244    */
    245   public $SingleTo      = false;
    246 
    247    /**
    248    * If SingleTo is true, this provides the array to hold the email addresses
    249    * @var bool
    250    */
    251   public $SingleToArray = array();
    252 
    253  /**
    254    * Provides the ability to change the line ending
    255    * @var string
    256    */
    257   public $LE              = "\n";
    258 
    259   /**
    260    * Used with DKIM DNS Resource Record
    261    * @var string
    262    */
    263   public $DKIM_selector   = 'phpmailer';
    264 
    265   /**
    266    * Used with DKIM DNS Resource Record
    267    * optional, in format of email address 'you@yourdomain.com'
    268    * @var string
    269    */
    270   public $DKIM_identity   = '';
    271 
    272   /**
    273    * Used with DKIM DNS Resource Record
    274    * optional, in format of email address 'you@yourdomain.com'
    275    * @var string
    276    */
    277   public $DKIM_domain     = '';
    278 
    279   /**
    280    * Used with DKIM DNS Resource Record
    281    * optional, in format of email address 'you@yourdomain.com'
    282    * @var string
    283    */
    284   public $DKIM_private    = '';
    285 
    286   /**
    287    * Callback Action function name
    288    * the function that handles the result of the send email action. Parameters:
    289    *   bool    $result        result of the send action
    290    *   string  $to            email address of the recipient
    291    *   string  $cc            cc email addresses
    292    *   string  $bcc           bcc email addresses
    293    *   string  $subject       the subject
    294    *   string  $body          the email body
    295    * @var string
    296    */
    297   public $action_function = ''; //'callbackAction';
    298 
    299   /**
    300    * Sets the PHPMailer Version number
    301    * @var string
    302    */
    303   public $Version         = '5.1';
    304 
    305   /////////////////////////////////////////////////
    306   // PROPERTIES, PRIVATE AND PROTECTED
    307   /////////////////////////////////////////////////
    308 
    309   private   $smtp           = NULL;
    310   private   $to             = array();
    311   private   $cc             = array();
    312   private   $bcc            = array();
    313   private   $ReplyTo        = array();
    314   private   $all_recipients = array();
    315   private   $attachment     = array();
    316   private   $CustomHeader   = array();
    317   private   $message_type   = '';
    318   private   $boundary       = array();
    319   protected $language       = array();
    320   private   $error_count    = 0;
    321   private   $sign_cert_file = "";
    322   private   $sign_key_file  = "";
    323   private   $sign_key_pass  = "";
    324   private   $exceptions     = false;
    325 
    326   /////////////////////////////////////////////////
    327   // CONSTANTS
    328   /////////////////////////////////////////////////
    329 
    330   const STOP_MESSAGE  = 0; // message only, continue processing
    331   const STOP_CONTINUE = 1; // message?, likely ok to continue processing
    332   const STOP_CRITICAL = 2; // message, plus full stop, critical error reached
    333 
    334   /////////////////////////////////////////////////
    335   // METHODS, VARIABLES
    336   /////////////////////////////////////////////////
    337 
    338   /**
    339    * Constructor
    340    * @param boolean $exceptions Should we throw external exceptions?
    341    */
    342   public function __construct($exceptions = false) {
    343     $this->exceptions = ($exceptions == true);
    344   }
    345 
    346   /**
    347    * Sets message type to HTML.
    348    * @param bool $ishtml
    349    * @return void
    350    */
    351   public function IsHTML($ishtml = true) {
    352     if ($ishtml) {
    353       $this->ContentType = 'text/html';
    354     } else {
    355       $this->ContentType = 'text/plain';
    356     }
    357   }
    358 
    359   /**
    360    * Sets Mailer to send message using SMTP.
    361    * @return void
    362    */
    363   public function IsSMTP() {
    364     $this->Mailer = 'smtp';
    365   }
    366 
    367   /**
    368    * Sets Mailer to send message using PHP mail() function.
    369    * @return void
    370    */
    371   public function IsMail() {
    372     $this->Mailer = 'mail';
    373   }
    374 
    375   /**
    376    * Sets Mailer to send message using the $Sendmail program.
    377    * @return void
    378    */
    379   public function IsSendmail() {
    380     if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
    381       $this->Sendmail = '/var/qmail/bin/sendmail';
    382     }
    383     $this->Mailer = 'sendmail';
    384   }
    385 
    386   /**
    387    * Sets Mailer to send message using the qmail MTA.
    388    * @return void
    389    */
    390   public function IsQmail() {
    391     if (stristr(ini_get('sendmail_path'), 'qmail')) {
    392       $this->Sendmail = '/var/qmail/bin/sendmail';
    393     }
    394     $this->Mailer = 'sendmail';
    395   }
    396 
    397   /////////////////////////////////////////////////
    398   // METHODS, RECIPIENTS
    399   /////////////////////////////////////////////////
    400 
    401   /**
    402    * Adds a "To" address.
    403    * @param string $address
    404    * @param string $name
    405    * @return boolean true on success, false if address already used
    406    */
    407   public function AddAddress($address, $name = '') {
    408     return $this->AddAnAddress('to', $address, $name);
    409   }
    410 
    411   /**
    412    * Adds a "Cc" address.
    413    * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
    414    * @param string $address
    415    * @param string $name
    416    * @return boolean true on success, false if address already used
    417    */
    418   public function AddCC($address, $name = '') {
    419     return $this->AddAnAddress('cc', $address, $name);
    420   }
    421 
    422   /**
    423    * Adds a "Bcc" address.
    424    * Note: this function works with the SMTP mailer on win32, not with the "mail" mailer.
    425    * @param string $address
    426    * @param string $name
    427    * @return boolean true on success, false if address already used
    428    */
    429   public function AddBCC($address, $name = '') {
    430     return $this->AddAnAddress('bcc', $address, $name);
    431   }
    432 
    433   /**
    434    * Adds a "Reply-to" address.
    435    * @param string $address
    436    * @param string $name
    437    * @return boolean
    438    */
    439   public function AddReplyTo($address, $name = '') {
    440     return $this->AddAnAddress('ReplyTo', $address, $name);
    441   }
    442 
    443   /**
    444    * Adds an address to one of the recipient arrays
    445    * Addresses that have been added already return false, but do not throw exceptions
    446    * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
    447    * @param string $address The email address to send to
    448    * @param string $name
    449    * @return boolean true on success, false if address already used or invalid in some way
    450    * @access private
    451    */
    452   private function AddAnAddress($kind, $address, $name = '') {
    453     if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
    454       echo 'Invalid recipient array: ' . kind;
    455       return false;
    456     }
    457     $address = trim($address);
    458     $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    459     if (!self::ValidateAddress($address)) {
    460       $this->SetError($this->Lang('invalid_address').': '. $address);
    461       if ($this->exceptions) {
    462         throw new phpmailerException($this->Lang('invalid_address').': '.$address);
    463       }
    464       echo $this->Lang('invalid_address').': '.$address;
    465       return false;
    466     }
    467     if ($kind != 'ReplyTo') {
    468       if (!isset($this->all_recipients[strtolower($address)])) {
    469         array_push($this->$kind, array($address, $name));
    470         $this->all_recipients[strtolower($address)] = true;
     20/**
     21 * PHPMailer - PHP email creation and transport class.
     22 * @package PHPMailer
     23 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
     24 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
     25 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
     26 * @author Brent R. Matzelle (original founder)
     27 */
     28class PHPMailer
     29{
     30    /**
     31     * The PHPMailer Version number.
     32     * @type string
     33     */
     34    public $Version = '5.2.10';
     35
     36    /**
     37     * Email priority.
     38     * Options: 1 = High, 3 = Normal, 5 = low.
     39     * @type integer
     40     */
     41    public $Priority = 3;
     42
     43    /**
     44     * The character set of the message.
     45     * @type string
     46     */
     47    public $CharSet = 'iso-8859-1';
     48
     49    /**
     50     * The MIME Content-type of the message.
     51     * @type string
     52     */
     53    public $ContentType = 'text/plain';
     54
     55    /**
     56     * The message encoding.
     57     * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
     58     * @type string
     59     */
     60    public $Encoding = '8bit';
     61
     62    /**
     63     * Holds the most recent mailer error message.
     64     * @type string
     65     */
     66    public $ErrorInfo = '';
     67
     68    /**
     69     * The From email address for the message.
     70     * @type string
     71     */
     72    public $From = 'root@localhost';
     73
     74    /**
     75     * The From name of the message.
     76     * @type string
     77     */
     78    public $FromName = 'Root User';
     79
     80    /**
     81     * The Sender email (Return-Path) of the message.
     82     * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
     83     * @type string
     84     */
     85    public $Sender = '';
     86
     87    /**
     88     * The Return-Path of the message.
     89     * If empty, it will be set to either From or Sender.
     90     * @type string
     91     * @deprecated Email senders should never set a return-path header;
     92     * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
     93     * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
     94     */
     95    public $ReturnPath = '';
     96
     97    /**
     98     * The Subject of the message.
     99     * @type string
     100     */
     101    public $Subject = '';
     102
     103    /**
     104     * An HTML or plain text message body.
     105     * If HTML then call isHTML(true).
     106     * @type string
     107     */
     108    public $Body = '';
     109
     110    /**
     111     * The plain-text message body.
     112     * This body can be read by mail clients that do not have HTML email
     113     * capability such as mutt & Eudora.
     114     * Clients that can read HTML will view the normal Body.
     115     * @type string
     116     */
     117    public $AltBody = '';
     118
     119    /**
     120     * An iCal message part body.
     121     * Only supported in simple alt or alt_inline message types
     122     * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
     123     * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
     124     * @link http://kigkonsult.se/iCalcreator/
     125     * @type string
     126     */
     127    public $Ical = '';
     128
     129    /**
     130     * The complete compiled MIME message body.
     131     * @access protected
     132     * @type string
     133     */
     134    protected $MIMEBody = '';
     135
     136    /**
     137     * The complete compiled MIME message headers.
     138     * @type string
     139     * @access protected
     140     */
     141    protected $MIMEHeader = '';
     142
     143    /**
     144     * Extra headers that createHeader() doesn't fold in.
     145     * @type string
     146     * @access protected
     147     */
     148    protected $mailHeader = '';
     149
     150    /**
     151     * Word-wrap the message body to this number of chars.
     152     * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
     153     * @type integer
     154     */
     155    public $WordWrap = 0;
     156
     157    /**
     158     * Which method to use to send mail.
     159     * Options: "mail", "sendmail", or "smtp".
     160     * @type string
     161     */
     162    public $Mailer = 'mail';
     163
     164    /**
     165     * The path to the sendmail program.
     166     * @type string
     167     */
     168    public $Sendmail = '/usr/sbin/sendmail';
     169
     170    /**
     171     * Whether mail() uses a fully sendmail-compatible MTA.
     172     * One which supports sendmail's "-oi -f" options.
     173     * @type boolean
     174     */
     175    public $UseSendmailOptions = true;
     176
     177    /**
     178     * Path to PHPMailer plugins.
     179     * Useful if the SMTP class is not in the PHP include path.
     180     * @type string
     181     * @deprecated Should not be needed now there is an autoloader.
     182     */
     183    public $PluginDir = '';
     184
     185    /**
     186     * The email address that a reading confirmation should be sent to.
     187     * @type string
     188     */
     189    public $ConfirmReadingTo = '';
     190
     191    /**
     192     * The hostname to use in Message-Id and Received headers
     193     * and as default HELO string.
     194     * If empty, the value returned
     195     * by SERVER_NAME is used or 'localhost.localdomain'.
     196     * @type string
     197     */
     198    public $Hostname = '';
     199
     200    /**
     201     * An ID to be used in the Message-Id header.
     202     * If empty, a unique id will be generated.
     203     * @type string
     204     */
     205    public $MessageID = '';
     206
     207    /**
     208     * The message Date to be used in the Date header.
     209     * If empty, the current date will be added.
     210     * @type string
     211     */
     212    public $MessageDate = '';
     213
     214    /**
     215     * SMTP hosts.
     216     * Either a single hostname or multiple semicolon-delimited hostnames.
     217     * You can also specify a different port
     218     * for each host by using this format: [hostname:port]
     219     * (e.g. "smtp1.example.com:25;smtp2.example.com").
     220     * You can also specify encryption type, for example:
     221     * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
     222     * Hosts will be tried in order.
     223     * @type string
     224     */
     225    public $Host = 'localhost';
     226
     227    /**
     228     * The default SMTP server port.
     229     * @type integer
     230     * @TODO Why is this needed when the SMTP class takes care of it?
     231     */
     232    public $Port = 25;
     233
     234    /**
     235     * The SMTP HELO of the message.
     236     * Default is $Hostname.
     237     * @type string
     238     * @see PHPMailer::$Hostname
     239     */
     240    public $Helo = '';
     241
     242    /**
     243     * What kind of encryption to use on the SMTP connection.
     244     * Options: '', 'ssl' or 'tls'
     245     * @type string
     246     */
     247    public $SMTPSecure = '';
     248
     249    /**
     250     * Whether to enable TLS encryption automatically if a server supports it,
     251     * even if `SMTPSecure` is not set to 'tls'.
     252     * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
     253     * @type boolean
     254     */
     255    public $SMTPAutoTLS = true;
     256
     257    /**
     258     * Whether to use SMTP authentication.
     259     * Uses the Username and Password properties.
     260     * @type boolean
     261     * @see PHPMailer::$Username
     262     * @see PHPMailer::$Password
     263     */
     264    public $SMTPAuth = false;
     265
     266    /**
     267     * Options array passed to stream_context_create when connecting via SMTP.
     268     * @type array
     269     */
     270    public $SMTPOptions = array();
     271
     272    /**
     273     * SMTP username.
     274     * @type string
     275     */
     276    public $Username = '';
     277
     278    /**
     279     * SMTP password.
     280     * @type string
     281     */
     282    public $Password = '';
     283
     284    /**
     285     * SMTP auth type.
     286     * Options are LOGIN (default), PLAIN, NTLM, CRAM-MD5
     287     * @type string
     288     */
     289    public $AuthType = '';
     290
     291    /**
     292     * SMTP realm.
     293     * Used for NTLM auth
     294     * @type string
     295     */
     296    public $Realm = '';
     297
     298    /**
     299     * SMTP workstation.
     300     * Used for NTLM auth
     301     * @type string
     302     */
     303    public $Workstation = '';
     304
     305    /**
     306     * The SMTP server timeout in seconds.
     307     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
     308     * @type integer
     309     */
     310    public $Timeout = 300;
     311
     312    /**
     313     * SMTP class debug output mode.
     314     * Debug output level.
     315     * Options:
     316     * * `0` No output
     317     * * `1` Commands
     318     * * `2` Data and commands
     319     * * `3` As 2 plus connection status
     320     * * `4` Low-level data output
     321     * @type integer
     322     * @see SMTP::$do_debug
     323     */
     324    public $SMTPDebug = 0;
     325
     326    /**
     327     * How to handle debug output.
     328     * Options:
     329     * * `echo` Output plain-text as-is, appropriate for CLI
     330     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
     331     * * `error_log` Output to error log as configured in php.ini
     332     *
     333     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
     334     * <code>
     335     * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
     336     * </code>
     337     * @type string|callable
     338     * @see SMTP::$Debugoutput
     339     */
     340    public $Debugoutput = 'echo';
     341
     342    /**
     343     * Whether to keep SMTP connection open after each message.
     344     * If this is set to true then to close the connection
     345     * requires an explicit call to smtpClose().
     346     * @type boolean
     347     */
     348    public $SMTPKeepAlive = false;
     349
     350    /**
     351     * Whether to split multiple to addresses into multiple messages
     352     * or send them all in one message.
     353     * @type boolean
     354     */
     355    public $SingleTo = false;
     356
     357    /**
     358     * Storage for addresses when SingleTo is enabled.
     359     * @type array
     360     * @TODO This should really not be public
     361     */
     362    public $SingleToArray = array();
     363
     364    /**
     365     * Whether to generate VERP addresses on send.
     366     * Only applicable when sending via SMTP.
     367     * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
     368     * @link http://www.postfix.org/VERP_README.html Postfix VERP info
     369     * @type boolean
     370     */
     371    public $do_verp = false;
     372
     373    /**
     374     * Whether to allow sending messages with an empty body.
     375     * @type boolean
     376     */
     377    public $AllowEmpty = false;
     378
     379    /**
     380     * The default line ending.
     381     * @note The default remains "\n". We force CRLF where we know
     382     *        it must be used via self::CRLF.
     383     * @type string
     384     */
     385    public $LE = "\n";
     386
     387    /**
     388     * DKIM selector.
     389     * @type string
     390     */
     391    public $DKIM_selector = '';
     392
     393    /**
     394     * DKIM Identity.
     395     * Usually the email address used as the source of the email
     396     * @type string
     397     */
     398    public $DKIM_identity = '';
     399
     400    /**
     401     * DKIM passphrase.
     402     * Used if your key is encrypted.
     403     * @type string
     404     */
     405    public $DKIM_passphrase = '';
     406
     407    /**
     408     * DKIM signing domain name.
     409     * @example 'example.com'
     410     * @type string
     411     */
     412    public $DKIM_domain = '';
     413
     414    /**
     415     * DKIM private key file path.
     416     * @type string
     417     */
     418    public $DKIM_private = '';
     419
     420    /**
     421     * Callback Action function name.
     422     *
     423     * The function that handles the result of the send email action.
     424     * It is called out by send() for each email sent.
     425     *
     426     * Value can be any php callable: http://www.php.net/is_callable
     427     *
     428     * Parameters:
     429     *   boolean $result        result of the send action
     430     *   string  $to            email address of the recipient
     431     *   string  $cc            cc email addresses
     432     *   string  $bcc           bcc email addresses
     433     *   string  $subject       the subject
     434     *   string  $body          the email body
     435     *   string  $from          email address of sender
     436     * @type string
     437     */
     438    public $action_function = '';
     439
     440    /**
     441     * What to put in the X-Mailer header.
     442     * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
     443     * @type string
     444     */
     445    public $XMailer = '';
     446
     447    /**
     448     * An instance of the SMTP sender class.
     449     * @type SMTP
     450     * @access protected
     451     */
     452    protected $smtp = null;
     453
     454    /**
     455     * The array of 'to' addresses.
     456     * @type array
     457     * @access protected
     458     */
     459    protected $to = array();
     460
     461    /**
     462     * The array of 'cc' addresses.
     463     * @type array
     464     * @access protected
     465     */
     466    protected $cc = array();
     467
     468    /**
     469     * The array of 'bcc' addresses.
     470     * @type array
     471     * @access protected
     472     */
     473    protected $bcc = array();
     474
     475    /**
     476     * The array of reply-to names and addresses.
     477     * @type array
     478     * @access protected
     479     */
     480    protected $ReplyTo = array();
     481
     482    /**
     483     * An array of all kinds of addresses.
     484     * Includes all of $to, $cc, $bcc
     485     * @type array
     486     * @access protected
     487     */
     488    protected $all_recipients = array();
     489
     490    /**
     491     * The array of attachments.
     492     * @type array
     493     * @access protected
     494     */
     495    protected $attachment = array();
     496
     497    /**
     498     * The array of custom headers.
     499     * @type array
     500     * @access protected
     501     */
     502    protected $CustomHeader = array();
     503
     504    /**
     505     * The most recent Message-ID (including angular brackets).
     506     * @type string
     507     * @access protected
     508     */
     509    protected $lastMessageID = '';
     510
     511    /**
     512     * The message's MIME type.
     513     * @type string
     514     * @access protected
     515     */
     516    protected $message_type = '';
     517
     518    /**
     519     * The array of MIME boundary strings.
     520     * @type array
     521     * @access protected
     522     */
     523    protected $boundary = array();
     524
     525    /**
     526     * The array of available languages.
     527     * @type array
     528     * @access protected
     529     */
     530    protected $language = array();
     531
     532    /**
     533     * The number of errors encountered.
     534     * @type integer
     535     * @access protected
     536     */
     537    protected $error_count = 0;
     538
     539    /**
     540     * The S/MIME certificate file path.
     541     * @type string
     542     * @access protected
     543     */
     544    protected $sign_cert_file = '';
     545
     546    /**
     547     * The S/MIME key file path.
     548     * @type string
     549     * @access protected
     550     */
     551    protected $sign_key_file = '';
     552
     553    /**
     554     * The optional S/MIME extra certificates ("CA Chain") file path.
     555     * @type string
     556     * @access protected
     557     */
     558    protected $sign_extracerts_file = '';
     559
     560    /**
     561     * The S/MIME password for the key.
     562     * Used only if the key is encrypted.
     563     * @type string
     564     * @access protected
     565     */
     566    protected $sign_key_pass = '';
     567
     568    /**
     569     * Whether to throw exceptions for errors.
     570     * @type boolean
     571     * @access protected
     572     */
     573    protected $exceptions = false;
     574
     575    /**
     576     * Unique ID used for message ID and boundaries.
     577     * @type string
     578     * @access protected
     579     */
     580    protected $uniqueid = '';
     581
     582    /**
     583     * Error severity: message only, continue processing.
     584     */
     585    const STOP_MESSAGE = 0;
     586
     587    /**
     588     * Error severity: message, likely ok to continue processing.
     589     */
     590    const STOP_CONTINUE = 1;
     591
     592    /**
     593     * Error severity: message, plus full stop, critical error reached.
     594     */
     595    const STOP_CRITICAL = 2;
     596
     597    /**
     598     * SMTP RFC standard line ending.
     599     */
     600    const CRLF = "\r\n";
     601
     602    /**
     603     * The maximum line length allowed by RFC 2822 section 2.1.1
     604     * @type integer
     605     */
     606    const MAX_LINE_LENGTH = 998;
     607
     608    /**
     609     * Constructor.
     610     * @param boolean $exceptions Should we throw external exceptions?
     611     */
     612    public function __construct($exceptions = false)
     613    {
     614        $this->exceptions = (boolean)$exceptions;
     615    }
     616
     617    /**
     618     * Destructor.
     619     */
     620    public function __destruct()
     621    {
     622        //Close any open SMTP connection nicely
     623        if ($this->Mailer == 'smtp') {
     624            $this->smtpClose();
     625        }
     626    }
     627
     628    /**
     629     * Call mail() in a safe_mode-aware fashion.
     630     * Also, unless sendmail_path points to sendmail (or something that
     631     * claims to be sendmail), don't pass params (not a perfect fix,
     632     * but it will do)
     633     * @param string $to To
     634     * @param string $subject Subject
     635     * @param string $body Message Body
     636     * @param string $header Additional Header(s)
     637     * @param string $params Params
     638     * @access private
     639     * @return boolean
     640     */
     641    private function mailPassthru($to, $subject, $body, $header, $params)
     642    {
     643        //Check overloading of mail function to avoid double-encoding
     644        if (ini_get('mbstring.func_overload') & 1) {
     645            $subject = $this->secureHeader($subject);
     646        } else {
     647            $subject = $this->encodeHeader($this->secureHeader($subject));
     648        }
     649        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
     650            $result = @mail($to, $subject, $body, $header);
     651        } else {
     652            $result = @mail($to, $subject, $body, $header, $params);
     653        }
     654        return $result;
     655    }
     656
     657    /**
     658     * Output debugging info via user-defined method.
     659     * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
     660     * @see PHPMailer::$Debugoutput
     661     * @see PHPMailer::$SMTPDebug
     662     * @param string $str
     663     */
     664    protected function edebug($str)
     665    {
     666        if ($this->SMTPDebug <= 0) {
     667            return;
     668        }
     669        //Avoid clash with built-in function names
     670        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
     671            call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
     672            return;
     673        }
     674        switch ($this->Debugoutput) {
     675            case 'error_log':
     676                //Don't output, just log
     677                error_log($str);
     678                break;
     679            case 'html':
     680                //Cleans up output a bit for a better looking, HTML-safe output
     681                echo htmlentities(
     682                    preg_replace('/[\r\n]+/', '', $str),
     683                    ENT_QUOTES,
     684                    'UTF-8'
     685                )
     686                . "<br>\n";
     687                break;
     688            case 'echo':
     689            default:
     690                //Normalize line breaks
     691                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
     692                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
     693                    "\n",
     694                    "\n                   \t                  ",
     695                    trim($str)
     696                ) . "\n";
     697        }
     698    }
     699
     700    /**
     701     * Sets message type to HTML or plain.
     702     * @param boolean $isHtml True for HTML mode.
     703     * @return void
     704     */
     705    public function isHTML($isHtml = true)
     706    {
     707        if ($isHtml) {
     708            $this->ContentType = 'text/html';
     709        } else {
     710            $this->ContentType = 'text/plain';
     711        }
     712    }
     713
     714    /**
     715     * Send messages using SMTP.
     716     * @return void
     717     */
     718    public function isSMTP()
     719    {
     720        $this->Mailer = 'smtp';
     721    }
     722
     723    /**
     724     * Send messages using PHP's mail() function.
     725     * @return void
     726     */
     727    public function isMail()
     728    {
     729        $this->Mailer = 'mail';
     730    }
     731
     732    /**
     733     * Send messages using $Sendmail.
     734     * @return void
     735     */
     736    public function isSendmail()
     737    {
     738        $ini_sendmail_path = ini_get('sendmail_path');
     739
     740        if (!stristr($ini_sendmail_path, 'sendmail')) {
     741            $this->Sendmail = '/usr/sbin/sendmail';
     742        } else {
     743            $this->Sendmail = $ini_sendmail_path;
     744        }
     745        $this->Mailer = 'sendmail';
     746    }
     747
     748    /**
     749     * Send messages using qmail.
     750     * @return void
     751     */
     752    public function isQmail()
     753    {
     754        $ini_sendmail_path = ini_get('sendmail_path');
     755
     756        if (!stristr($ini_sendmail_path, 'qmail')) {
     757            $this->Sendmail = '/var/qmail/bin/qmail-inject';
     758        } else {
     759            $this->Sendmail = $ini_sendmail_path;
     760        }
     761        $this->Mailer = 'qmail';
     762    }
     763
     764    /**
     765     * Add a "To" address.
     766     * @param string $address
     767     * @param string $name
     768     * @return boolean true on success, false if address already used
     769     */
     770    public function addAddress($address, $name = '')
     771    {
     772        return $this->addAnAddress('to', $address, $name);
     773    }
     774
     775    /**
     776     * Add a "CC" address.
     777     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
     778     * @param string $address
     779     * @param string $name
     780     * @return boolean true on success, false if address already used
     781     */
     782    public function addCC($address, $name = '')
     783    {
     784        return $this->addAnAddress('cc', $address, $name);
     785    }
     786
     787    /**
     788     * Add a "BCC" address.
     789     * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
     790     * @param string $address
     791     * @param string $name
     792     * @return boolean true on success, false if address already used
     793     */
     794    public function addBCC($address, $name = '')
     795    {
     796        return $this->addAnAddress('bcc', $address, $name);
     797    }
     798
     799    /**
     800     * Add a "Reply-to" address.
     801     * @param string $address
     802     * @param string $name
     803     * @return boolean
     804     */
     805    public function addReplyTo($address, $name = '')
     806    {
     807        return $this->addAnAddress('Reply-To', $address, $name);
     808    }
     809
     810    /**
     811     * Add an address to one of the recipient arrays.
     812     * Addresses that have been added already return false, but do not throw exceptions
     813     * @param string $kind One of 'to', 'cc', 'bcc', 'ReplyTo'
     814     * @param string $address The email address to send to
     815     * @param string $name
     816     * @throws phpmailerException
     817     * @return boolean true on success, false if address already used or invalid in some way
     818     * @access protected
     819     */
     820    protected function addAnAddress($kind, $address, $name = '')
     821    {
     822        if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
     823            $this->setError($this->lang('Invalid recipient array') . ': ' . $kind);
     824            $this->edebug($this->lang('Invalid recipient array') . ': ' . $kind);
     825            if ($this->exceptions) {
     826                throw new phpmailerException('Invalid recipient array: ' . $kind);
     827            }
     828            return false;
     829        }
     830        $address = trim($address);
     831        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     832        if (!$this->validateAddress($address)) {
     833            $this->setError($this->lang('invalid_address') . ': ' . $address);
     834            $this->edebug($this->lang('invalid_address') . ': ' . $address);
     835            if ($this->exceptions) {
     836                throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
     837            }
     838            return false;
     839        }
     840        if ($kind != 'Reply-To') {
     841            if (!isset($this->all_recipients[strtolower($address)])) {
     842                array_push($this->$kind, array($address, $name));
     843                $this->all_recipients[strtolower($address)] = true;
     844                return true;
     845            }
     846        } else {
     847            if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
     848                $this->ReplyTo[strtolower($address)] = array($address, $name);
     849                return true;
     850            }
     851        }
     852        return false;
     853    }
     854
     855    /**
     856     * Set the From and FromName properties.
     857     * @param string $address
     858     * @param string $name
     859     * @param boolean $auto Whether to also set the Sender address, defaults to true
     860     * @throws phpmailerException
     861     * @return boolean
     862     */
     863    public function setFrom($address, $name = '', $auto = true)
     864    {
     865        $address = trim($address);
     866        $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
     867        if (!$this->validateAddress($address)) {
     868            $this->setError($this->lang('invalid_address') . ': ' . $address);
     869            $this->edebug($this->lang('invalid_address') . ': ' . $address);
     870            if ($this->exceptions) {
     871                throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
     872            }
     873            return false;
     874        }
     875        $this->From = $address;
     876        $this->FromName = $name;
     877        if ($auto) {
     878            if (empty($this->Sender)) {
     879                $this->Sender = $address;
     880            }
     881        }
    471882        return true;
    472       }
    473     } else {
    474       if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
    475         $this->ReplyTo[strtolower($address)] = array($address, $name);
    476       return true;
    477     }
    478   }
    479   return false;
     883    }
     884
     885    /**
     886     * Return the Message-ID header of the last email.
     887     * Technically this is the value from the last time the headers were created,
     888     * but it's also the message ID of the last sent message except in
     889     * pathological cases.
     890     * @return string
     891     */
     892    public function getLastMessageID()
     893    {
     894        return $this->lastMessageID;
     895    }
     896
     897    /**
     898     * Check that a string looks like an email address.
     899     * @param string $address The email address to check
     900     * @param string $patternselect A selector for the validation pattern to use :
     901     * * `auto` Pick strictest one automatically;
     902     * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
     903     * * `pcre` Use old PCRE implementation;
     904     * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL; same as pcre8 but does not allow 'dotless' domains;
     905     * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
     906     * * `noregex` Don't use a regex: super fast, really dumb.
     907     * @return boolean
     908     * @static
     909     * @access public
     910     */
     911    public static function validateAddress($address, $patternselect = 'auto')
     912    {
     913        if (!$patternselect or $patternselect == 'auto') {
     914            //Check this constant first so it works when extension_loaded() is disabled by safe mode
     915            //Constant was added in PHP 5.2.4
     916            if (defined('PCRE_VERSION')) {
     917                //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
     918                if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
     919                    $patternselect = 'pcre8';
     920                } else {
     921                    $patternselect = 'pcre';
     922                }
     923            } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
     924                //Fall back to older PCRE
     925                $patternselect = 'pcre';
     926            } else {
     927                //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
     928                if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
     929                    $patternselect = 'php';
     930                } else {
     931                    $patternselect = 'noregex';
     932                }
     933            }
     934        }
     935        switch ($patternselect) {
     936            case 'pcre8':
     937                /**
     938                 * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
     939                 * @link http://squiloople.com/2009/12/20/email-address-validation/
     940                 * @copyright 2009-2010 Michael Rushton
     941                 * Feel free to use and redistribute this code. But please keep this copyright notice.
     942                 */
     943                return (boolean)preg_match(
     944                    '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
     945                    '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
     946                    '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
     947                    '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
     948                    '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
     949                    '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
     950                    '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
     951                    '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
     952                    '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
     953                    $address
     954                );
     955            case 'pcre':
     956                //An older regex that doesn't need a recent PCRE
     957                return (boolean)preg_match(
     958                    '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
     959                    '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
     960                    '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
     961                    '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
     962                    '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
     963                    '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
     964                    '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
     965                    '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
     966                    '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
     967                    '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
     968                    $address
     969                );
     970            case 'html5':
     971                /**
     972                 * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
     973                 * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
     974                 */
     975                return (boolean)preg_match(
     976                    '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
     977                    '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
     978                    $address
     979                );
     980            case 'noregex':
     981                //No PCRE! Do something _very_ approximate!
     982                //Check the address is 3 chars or longer and contains an @ that's not the first or last char
     983                return (strlen($address) >= 3
     984                    and strpos($address, '@') >= 1
     985                    and strpos($address, '@') != strlen($address) - 1);
     986            case 'php':
     987            default:
     988                return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
     989        }
     990    }
     991
     992    /**
     993     * Create a message and send it.
     994     * Uses the sending method specified by $Mailer.
     995     * @throws phpmailerException
     996     * @return boolean false on error - See the ErrorInfo property for details of the error.
     997     */
     998    public function send()
     999    {
     1000        try {
     1001            if (!$this->preSend()) {
     1002                return false;
     1003            }
     1004            return $this->postSend();
     1005        } catch (phpmailerException $exc) {
     1006            $this->mailHeader = '';
     1007            $this->setError($exc->getMessage());
     1008            if ($this->exceptions) {
     1009                throw $exc;
     1010            }
     1011            return false;
     1012        }
     1013    }
     1014
     1015    /**
     1016     * Prepare a message for sending.
     1017     * @throws phpmailerException
     1018     * @return boolean
     1019     */
     1020    public function preSend()
     1021    {
     1022        try {
     1023            $this->mailHeader = '';
     1024            if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
     1025                throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
     1026            }
     1027
     1028            // Set whether the message is multipart/alternative
     1029            if (!empty($this->AltBody)) {
     1030                $this->ContentType = 'multipart/alternative';
     1031            }
     1032
     1033            $this->error_count = 0; // Reset errors
     1034            $this->setMessageType();
     1035            // Refuse to send an empty message unless we are specifically allowing it
     1036            if (!$this->AllowEmpty and empty($this->Body)) {
     1037                throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
     1038            }
     1039
     1040            // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
     1041            $this->MIMEHeader = '';
     1042            $this->MIMEBody = $this->createBody();
     1043            // createBody may have added some headers, so retain them
     1044            $tempheaders = $this->MIMEHeader;
     1045            $this->MIMEHeader = $this->createHeader();
     1046            $this->MIMEHeader .= $tempheaders;
     1047
     1048            // To capture the complete message when using mail(), create
     1049            // an extra header list which createHeader() doesn't fold in
     1050            if ($this->Mailer == 'mail') {
     1051                if (count($this->to) > 0) {
     1052                    $this->mailHeader .= $this->addrAppend('To', $this->to);
     1053                } else {
     1054                    $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
     1055                }
     1056                $this->mailHeader .= $this->headerLine(
     1057                    'Subject',
     1058                    $this->encodeHeader($this->secureHeader(trim($this->Subject)))
     1059                );
     1060            }
     1061
     1062            // Sign with DKIM if enabled
     1063            if (!empty($this->DKIM_domain)
     1064                && !empty($this->DKIM_private)
     1065                && !empty($this->DKIM_selector)
     1066                && file_exists($this->DKIM_private)) {
     1067                $header_dkim = $this->DKIM_Add(
     1068                    $this->MIMEHeader . $this->mailHeader,
     1069                    $this->encodeHeader($this->secureHeader($this->Subject)),
     1070                    $this->MIMEBody
     1071                );
     1072                $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
     1073                    str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
     1074            }
     1075            return true;
     1076        } catch (phpmailerException $exc) {
     1077            $this->setError($exc->getMessage());
     1078            if ($this->exceptions) {
     1079                throw $exc;
     1080            }
     1081            return false;
     1082        }
     1083    }
     1084
     1085    /**
     1086     * Actually send a message.
     1087     * Send the email via the selected mechanism
     1088     * @throws phpmailerException
     1089     * @return boolean
     1090     */
     1091    public function postSend()
     1092    {
     1093        try {
     1094            // Choose the mailer and send through it
     1095            switch ($this->Mailer) {
     1096                case 'sendmail':
     1097                case 'qmail':
     1098                    return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
     1099                case 'smtp':
     1100                    return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
     1101                case 'mail':
     1102                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
     1103                default:
     1104                    $sendMethod = $this->Mailer.'Send';
     1105                    if (method_exists($this, $sendMethod)) {
     1106                        return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
     1107                    }
     1108
     1109                    return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
     1110            }
     1111        } catch (phpmailerException $exc) {
     1112            $this->setError($exc->getMessage());
     1113            $this->edebug($exc->getMessage());
     1114            if ($this->exceptions) {
     1115                throw $exc;
     1116            }
     1117        }
     1118        return false;
     1119    }
     1120
     1121    /**
     1122     * Send mail using the $Sendmail program.
     1123     * @param string $header The message headers
     1124     * @param string $body The message body
     1125     * @see PHPMailer::$Sendmail
     1126     * @throws phpmailerException
     1127     * @access protected
     1128     * @return boolean
     1129     */
     1130    protected function sendmailSend($header, $body)
     1131    {
     1132        if ($this->Sender != '') {
     1133            if ($this->Mailer == 'qmail') {
     1134                $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
     1135            } else {
     1136                $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
     1137            }
     1138        } else {
     1139            if ($this->Mailer == 'qmail') {
     1140                $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
     1141            } else {
     1142                $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
     1143            }
     1144        }
     1145        if ($this->SingleTo) {
     1146            foreach ($this->SingleToArray as $toAddr) {
     1147                if (!@$mail = popen($sendmail, 'w')) {
     1148                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1149                }
     1150                fputs($mail, 'To: ' . $toAddr . "\n");
     1151                fputs($mail, $header);
     1152                fputs($mail, $body);
     1153                $result = pclose($mail);
     1154                $this->doCallback(
     1155                    ($result == 0),
     1156                    array($toAddr),
     1157                    $this->cc,
     1158                    $this->bcc,
     1159                    $this->Subject,
     1160                    $body,
     1161                    $this->From
     1162                );
     1163                if ($result != 0) {
     1164                    throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1165                }
     1166            }
     1167        } else {
     1168            if (!@$mail = popen($sendmail, 'w')) {
     1169                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1170            }
     1171            fputs($mail, $header);
     1172            fputs($mail, $body);
     1173            $result = pclose($mail);
     1174            $this->doCallback(($result == 0), $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1175            if ($result != 0) {
     1176                throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
     1177            }
     1178        }
     1179        return true;
     1180    }
     1181
     1182    /**
     1183     * Send mail using the PHP mail() function.
     1184     * @param string $header The message headers
     1185     * @param string $body The message body
     1186     * @link http://www.php.net/manual/en/book.mail.php
     1187     * @throws phpmailerException
     1188     * @access protected
     1189     * @return boolean
     1190     */
     1191    protected function mailSend($header, $body)
     1192    {
     1193        $toArr = array();
     1194        foreach ($this->to as $toaddr) {
     1195            $toArr[] = $this->addrFormat($toaddr);
     1196        }
     1197        $to = implode(', ', $toArr);
     1198
     1199        if (empty($this->Sender)) {
     1200            $params = ' ';
     1201        } else {
     1202            $params = sprintf('-f%s', $this->Sender);
     1203        }
     1204        if ($this->Sender != '' and !ini_get('safe_mode')) {
     1205            $old_from = ini_get('sendmail_from');
     1206            ini_set('sendmail_from', $this->Sender);
     1207        }
     1208        $result = false;
     1209        if ($this->SingleTo && count($toArr) > 1) {
     1210            foreach ($toArr as $toAddr) {
     1211                $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
     1212                $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1213            }
     1214        } else {
     1215            $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
     1216            $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
     1217        }
     1218        if (isset($old_from)) {
     1219            ini_set('sendmail_from', $old_from);
     1220        }
     1221        if (!$result) {
     1222            throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
     1223        }
     1224        return true;
     1225    }
     1226
     1227    /**
     1228     * Get an instance to use for SMTP operations.
     1229     * Override this function to load your own SMTP implementation
     1230     * @return SMTP
     1231     */
     1232    public function getSMTPInstance()
     1233    {
     1234        if (!is_object($this->smtp)) {
     1235            $this->smtp = new SMTP;
     1236        }
     1237        return $this->smtp;
     1238    }
     1239
     1240    /**
     1241     * Send mail via SMTP.
     1242     * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
     1243     * Uses the PHPMailerSMTP class by default.
     1244     * @see PHPMailer::getSMTPInstance() to use a different class.
     1245     * @param string $header The message headers
     1246     * @param string $body The message body
     1247     * @throws phpmailerException
     1248     * @uses SMTP
     1249     * @access protected
     1250     * @return boolean
     1251     */
     1252    protected function smtpSend($header, $body)
     1253    {
     1254        $bad_rcpt = array();
     1255        if (!$this->smtpConnect($this->SMTPOptions)) {
     1256            throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
     1257        }
     1258        if ('' == $this->Sender) {
     1259            $smtp_from = $this->From;
     1260        } else {
     1261            $smtp_from = $this->Sender;
     1262        }
     1263        if (!$this->smtp->mail($smtp_from)) {
     1264            $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
     1265            throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
     1266        }
     1267
     1268        // Attempt to send to all recipients
     1269        foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
     1270            foreach ($togroup as $to) {
     1271                if (!$this->smtp->recipient($to[0])) {
     1272                    $error = $this->smtp->getError();
     1273                    $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
     1274                    $isSent = false;
     1275                } else {
     1276                    $isSent = true;
     1277                }
     1278                $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
     1279            }
     1280        }
     1281
     1282        // Only send the DATA command if we have viable recipients
     1283        if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
     1284            throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
     1285        }
     1286        if ($this->SMTPKeepAlive) {
     1287            $this->smtp->reset();
     1288        } else {
     1289            $this->smtp->quit();
     1290            $this->smtp->close();
     1291        }
     1292        //Create error message for any bad addresses
     1293        if (count($bad_rcpt) > 0) {
     1294            $errstr = '';
     1295            foreach ($bad_rcpt as $bad) {
     1296                $errstr .= $bad['to'] . ': ' . $bad['error'];
     1297            }
     1298            throw new phpmailerException(
     1299                $this->lang('recipients_failed') . $errstr,
     1300                self::STOP_CONTINUE
     1301            );
     1302        }
     1303        return true;
     1304    }
     1305
     1306    /**
     1307     * Initiate a connection to an SMTP server.
     1308     * Returns false if the operation failed.
     1309     * @param array $options An array of options compatible with stream_context_create()
     1310     * @uses SMTP
     1311     * @access public
     1312     * @throws phpmailerException
     1313     * @return boolean
     1314     */
     1315    public function smtpConnect($options = array())
     1316    {
     1317        if (is_null($this->smtp)) {
     1318            $this->smtp = $this->getSMTPInstance();
     1319        }
     1320
     1321        // Already connected?
     1322        if ($this->smtp->connected()) {
     1323            return true;
     1324        }
     1325
     1326        $this->smtp->setTimeout($this->Timeout);
     1327        $this->smtp->setDebugLevel($this->SMTPDebug);
     1328        $this->smtp->setDebugOutput($this->Debugoutput);
     1329        $this->smtp->setVerp($this->do_verp);
     1330        $hosts = explode(';', $this->Host);
     1331        $lastexception = null;
     1332
     1333        foreach ($hosts as $hostentry) {
     1334            $hostinfo = array();
     1335            if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
     1336                // Not a valid host entry
     1337                continue;
     1338            }
     1339            // $hostinfo[2]: optional ssl or tls prefix
     1340            // $hostinfo[3]: the hostname
     1341            // $hostinfo[4]: optional port number
     1342            // The host string prefix can temporarily override the current setting for SMTPSecure
     1343            // If it's not specified, the default value is used
     1344            $prefix = '';
     1345            $secure = $this->SMTPSecure;
     1346            $tls = ($this->SMTPSecure == 'tls');
     1347            if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
     1348                $prefix = 'ssl://';
     1349                $tls = false; // Can't have SSL and TLS at the same time
     1350                $secure = 'ssl';
     1351            } elseif ($hostinfo[2] == 'tls') {
     1352                $tls = true;
     1353                // tls doesn't use a prefix
     1354                $secure = 'tls';
     1355            }
     1356            //Do we need the OpenSSL extension?
     1357            $sslext = defined('OPENSSL_ALGO_SHA1');
     1358            if ('tls' === $secure or 'ssl' === $secure) {
     1359                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
     1360                if (!$sslext) {
     1361                    throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
     1362                }
     1363            }
     1364            $host = $hostinfo[3];
     1365            $port = $this->Port;
     1366            $tport = (integer)$hostinfo[4];
     1367            if ($tport > 0 and $tport < 65536) {
     1368                $port = $tport;
     1369            }
     1370            if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
     1371                try {
     1372                    if ($this->Helo) {
     1373                        $hello = $this->Helo;
     1374                    } else {
     1375                        $hello = $this->serverHostname();
     1376                    }
     1377                    $this->smtp->hello($hello);
     1378                    //Automatically enable TLS encryption if:
     1379                    // * it's not disabled
     1380                    // * we have openssl extension
     1381                    // * we are not already using SSL
     1382                    // * the server offers STARTTLS
     1383                    if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
     1384                        $tls = true;
     1385                    }
     1386                    if ($tls) {
     1387                        if (!$this->smtp->startTLS()) {
     1388                            throw new phpmailerException($this->lang('connect_host'));
     1389                        }
     1390                        // We must resend HELO after tls negotiation
     1391                        $this->smtp->hello($hello);
     1392                    }
     1393                    if ($this->SMTPAuth) {
     1394                        if (!$this->smtp->authenticate(
     1395                            $this->Username,
     1396                            $this->Password,
     1397                            $this->AuthType,
     1398                            $this->Realm,
     1399                            $this->Workstation
     1400                        )
     1401                        ) {
     1402                            throw new phpmailerException($this->lang('authenticate'));
     1403                        }
     1404                    }
     1405                    return true;
     1406                } catch (phpmailerException $exc) {
     1407                    $lastexception = $exc;
     1408                    $this->edebug($exc->getMessage());
     1409                    // We must have connected, but then failed TLS or Auth, so close connection nicely
     1410                    $this->smtp->quit();
     1411                }
     1412            }
     1413        }
     1414        // If we get here, all connection attempts have failed, so close connection hard
     1415        $this->smtp->close();
     1416        // As we've caught all exceptions, just report whatever the last one was
     1417        if ($this->exceptions and !is_null($lastexception)) {
     1418            throw $lastexception;
     1419        }
     1420        return false;
     1421    }
     1422
     1423    /**
     1424     * Close the active SMTP session if one exists.
     1425     * @return void
     1426     */
     1427    public function smtpClose()
     1428    {
     1429        if ($this->smtp !== null) {
     1430            if ($this->smtp->connected()) {
     1431                $this->smtp->quit();
     1432                $this->smtp->close();
     1433            }
     1434        }
     1435    }
     1436
     1437    /**
     1438     * Set the language for error messages.
     1439     * Returns false if it cannot load the language file.
     1440     * The default language is English.
     1441     * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
     1442     * @param string $lang_path Path to the language file directory, with trailing separator (slash)
     1443     * @return boolean
     1444     * @access public
     1445     */
     1446    public function setLanguage($langcode = 'en', $lang_path = '')
     1447    {
     1448        // Define full set of translatable strings in English
     1449        $PHPMAILER_LANG = array(
     1450            'authenticate' => 'SMTP Error: Could not authenticate.',
     1451            'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
     1452            'data_not_accepted' => 'SMTP Error: data not accepted.',
     1453            'empty_message' => 'Message body empty',
     1454            'encoding' => 'Unknown encoding: ',
     1455            'execute' => 'Could not execute: ',
     1456            'file_access' => 'Could not access file: ',
     1457            'file_open' => 'File Error: Could not open file: ',
     1458            'from_failed' => 'The following From address failed: ',
     1459            'instantiate' => 'Could not instantiate mail function.',
     1460            'invalid_address' => 'Invalid address',
     1461            'mailer_not_supported' => ' mailer is not supported.',
     1462            'provide_address' => 'You must provide at least one recipient email address.',
     1463            'recipients_failed' => 'SMTP Error: The following recipients failed: ',
     1464            'signing' => 'Signing Error: ',
     1465            'smtp_connect_failed' => 'SMTP connect() failed.',
     1466            'smtp_error' => 'SMTP server error: ',
     1467            'variable_set' => 'Cannot set or reset variable: ',
     1468            'extension_missing' => 'Extension missing: '
     1469        );
     1470        if (empty($lang_path)) {
     1471            // Calculate an absolute path so it can work if CWD is not here
     1472            $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
     1473        }
     1474        $foundlang = true;
     1475        $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
     1476        // There is no English translation file
     1477        if ($langcode != 'en') {
     1478            // Make sure language file path is readable
     1479            if (!is_readable($lang_file)) {
     1480                $foundlang = false;
     1481            } else {
     1482                // Overwrite language-specific strings.
     1483                // This way we'll never have missing translation keys.
     1484                $foundlang = include $lang_file;
     1485            }
     1486        }
     1487        $this->language = $PHPMAILER_LANG;
     1488        return (boolean)$foundlang; // Returns false if language not found
     1489    }
     1490
     1491    /**
     1492     * Get the array of strings for the current language.
     1493     * @return array
     1494     */
     1495    public function getTranslations()
     1496    {
     1497        return $this->language;
     1498    }
     1499
     1500    /**
     1501     * Create recipient headers.
     1502     * @access public
     1503     * @param string $type
     1504     * @param array $addr An array of recipient,
     1505     * where each recipient is a 2-element indexed array with element 0 containing an address
     1506     * and element 1 containing a name, like:
     1507     * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
     1508     * @return string
     1509     */
     1510    public function addrAppend($type, $addr)
     1511    {
     1512        $addresses = array();
     1513        foreach ($addr as $address) {
     1514            $addresses[] = $this->addrFormat($address);
     1515        }
     1516        return $type . ': ' . implode(', ', $addresses) . $this->LE;
     1517    }
     1518
     1519    /**
     1520     * Format an address for use in a message header.
     1521     * @access public
     1522     * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
     1523     *      like array('joe@example.com', 'Joe User')
     1524     * @return string
     1525     */
     1526    public function addrFormat($addr)
     1527    {
     1528        if (empty($addr[1])) { // No name provided
     1529            return $this->secureHeader($addr[0]);
     1530        } else {
     1531            return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
     1532                $addr[0]
     1533            ) . '>';
     1534        }
     1535    }
     1536
     1537    /**
     1538     * Word-wrap message.
     1539     * For use with mailers that do not automatically perform wrapping
     1540     * and for quoted-printable encoded messages.
     1541     * Original written by philippe.
     1542     * @param string $message The message to wrap
     1543     * @param integer $length The line length to wrap to
     1544     * @param boolean $qp_mode Whether to run in Quoted-Printable mode
     1545     * @access public
     1546     * @return string
     1547     */
     1548    public function wrapText($message, $length, $qp_mode = false)
     1549    {
     1550        if ($qp_mode) {
     1551            $soft_break = sprintf(' =%s', $this->LE);
     1552        } else {
     1553            $soft_break = $this->LE;
     1554        }
     1555        // If utf-8 encoding is used, we will need to make sure we don't
     1556        // split multibyte characters when we wrap
     1557        $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
     1558        $lelen = strlen($this->LE);
     1559        $crlflen = strlen(self::CRLF);
     1560
     1561        $message = $this->fixEOL($message);
     1562        //Remove a trailing line break
     1563        if (substr($message, -$lelen) == $this->LE) {
     1564            $message = substr($message, 0, -$lelen);
     1565        }
     1566
     1567        //Split message into lines
     1568        $lines = explode($this->LE, $message);
     1569        //Message will be rebuilt in here
     1570        $message = '';
     1571        foreach ($lines as $line) {
     1572            $words = explode(' ', $line);
     1573            $buf = '';
     1574            $firstword = true;
     1575            foreach ($words as $word) {
     1576                if ($qp_mode and (strlen($word) > $length)) {
     1577                    $space_left = $length - strlen($buf) - $crlflen;
     1578                    if (!$firstword) {
     1579                        if ($space_left > 20) {
     1580                            $len = $space_left;
     1581                            if ($is_utf8) {
     1582                                $len = $this->utf8CharBoundary($word, $len);
     1583                            } elseif (substr($word, $len - 1, 1) == '=') {
     1584                                $len--;
     1585                            } elseif (substr($word, $len - 2, 1) == '=') {
     1586                                $len -= 2;
     1587                            }
     1588                            $part = substr($word, 0, $len);
     1589                            $word = substr($word, $len);
     1590                            $buf .= ' ' . $part;
     1591                            $message .= $buf . sprintf('=%s', self::CRLF);
     1592                        } else {
     1593                            $message .= $buf . $soft_break;
     1594                        }
     1595                        $buf = '';
     1596                    }
     1597                    while (strlen($word) > 0) {
     1598                        if ($length <= 0) {
     1599                            break;
     1600                        }
     1601                        $len = $length;
     1602                        if ($is_utf8) {
     1603                            $len = $this->utf8CharBoundary($word, $len);
     1604                        } elseif (substr($word, $len - 1, 1) == '=') {
     1605                            $len--;
     1606                        } elseif (substr($word, $len - 2, 1) == '=') {
     1607                            $len -= 2;
     1608                        }
     1609                        $part = substr($word, 0, $len);
     1610                        $word = substr($word, $len);
     1611
     1612                        if (strlen($word) > 0) {
     1613                            $message .= $part . sprintf('=%s', self::CRLF);
     1614                        } else {
     1615                            $buf = $part;
     1616                        }
     1617                    }
     1618                } else {
     1619                    $buf_o = $buf;
     1620                    if (!$firstword) {
     1621                        $buf .= ' ';
     1622                    }
     1623                    $buf .= $word;
     1624
     1625                    if (strlen($buf) > $length and $buf_o != '') {
     1626                        $message .= $buf_o . $soft_break;
     1627                        $buf = $word;
     1628                    }
     1629                }
     1630                $firstword = false;
     1631            }
     1632            $message .= $buf . self::CRLF;
     1633        }
     1634
     1635        return $message;
     1636    }
     1637
     1638    /**
     1639     * Find the last character boundary prior to $maxLength in a utf-8
     1640     * quoted-printable encoded string.
     1641     * Original written by Colin Brown.
     1642     * @access public
     1643     * @param string $encodedText utf-8 QP text
     1644     * @param integer $maxLength Find the last character boundary prior to this length
     1645     * @return integer
     1646     */
     1647    public function utf8CharBoundary($encodedText, $maxLength)
     1648    {
     1649        $foundSplitPos = false;
     1650        $lookBack = 3;
     1651        while (!$foundSplitPos) {
     1652            $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
     1653            $encodedCharPos = strpos($lastChunk, '=');
     1654            if (false !== $encodedCharPos) {
     1655                // Found start of encoded character byte within $lookBack block.
     1656                // Check the encoded byte value (the 2 chars after the '=')
     1657                $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
     1658                $dec = hexdec($hex);
     1659                if ($dec < 128) {
     1660                    // Single byte character.
     1661                    // If the encoded char was found at pos 0, it will fit
     1662                    // otherwise reduce maxLength to start of the encoded char
     1663                    if ($encodedCharPos > 0) {
     1664                        $maxLength = $maxLength - ($lookBack - $encodedCharPos);
     1665                    }
     1666                    $foundSplitPos = true;
     1667                } elseif ($dec >= 192) {
     1668                    // First byte of a multi byte character
     1669                    // Reduce maxLength to split at start of character
     1670                    $maxLength = $maxLength - ($lookBack - $encodedCharPos);
     1671                    $foundSplitPos = true;
     1672                } elseif ($dec < 192) {
     1673                    // Middle byte of a multi byte character, look further back
     1674                    $lookBack += 3;
     1675                }
     1676            } else {
     1677                // No encoded character found
     1678                $foundSplitPos = true;
     1679            }
     1680        }
     1681        return $maxLength;
     1682    }
     1683
     1684    /**
     1685     * Apply word wrapping to the message body.
     1686     * Wraps the message body to the number of chars set in the WordWrap property.
     1687     * You should only do this to plain-text bodies as wrapping HTML tags may break them.
     1688     * This is called automatically by createBody(), so you don't need to call it yourself.
     1689     * @access public
     1690     * @return void
     1691     */
     1692    public function setWordWrap()
     1693    {
     1694        if ($this->WordWrap < 1) {
     1695            return;
     1696        }
     1697
     1698        switch ($this->message_type) {
     1699            case 'alt':
     1700            case 'alt_inline':
     1701            case 'alt_attach':
     1702            case 'alt_inline_attach':
     1703                $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
     1704                break;
     1705            default:
     1706                $this->Body = $this->wrapText($this->Body, $this->WordWrap);
     1707                break;
     1708        }
     1709    }
     1710
     1711    /**
     1712     * Assemble message headers.
     1713     * @access public
     1714     * @return string The assembled headers
     1715     */
     1716    public function createHeader()
     1717    {
     1718        $result = '';
     1719
     1720        if ($this->MessageDate == '') {
     1721            $this->MessageDate = self::rfcDate();
     1722        }
     1723        $result .= $this->headerLine('Date', $this->MessageDate);
     1724
     1725
     1726        // To be created automatically by mail()
     1727        if ($this->SingleTo) {
     1728            if ($this->Mailer != 'mail') {
     1729                foreach ($this->to as $toaddr) {
     1730                    $this->SingleToArray[] = $this->addrFormat($toaddr);
     1731                }
     1732            }
     1733        } else {
     1734            if (count($this->to) > 0) {
     1735                if ($this->Mailer != 'mail') {
     1736                    $result .= $this->addrAppend('To', $this->to);
     1737                }
     1738            } elseif (count($this->cc) == 0) {
     1739                $result .= $this->headerLine('To', 'undisclosed-recipients:;');
     1740            }
     1741        }
     1742
     1743        $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
     1744
     1745        // sendmail and mail() extract Cc from the header before sending
     1746        if (count($this->cc) > 0) {
     1747            $result .= $this->addrAppend('Cc', $this->cc);
     1748        }
     1749
     1750        // sendmail and mail() extract Bcc from the header before sending
     1751        if ((
     1752                $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
     1753            )
     1754            and count($this->bcc) > 0
     1755        ) {
     1756            $result .= $this->addrAppend('Bcc', $this->bcc);
     1757        }
     1758
     1759        if (count($this->ReplyTo) > 0) {
     1760            $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
     1761        }
     1762
     1763        // mail() sets the subject itself
     1764        if ($this->Mailer != 'mail') {
     1765            $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
     1766        }
     1767
     1768        if ($this->MessageID != '') {
     1769            $this->lastMessageID = $this->MessageID;
     1770        } else {
     1771            $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->ServerHostname());
     1772        }
     1773        $result .= $this->headerLine('Message-ID', $this->lastMessageID);
     1774        $result .= $this->headerLine('X-Priority', $this->Priority);
     1775        if ($this->XMailer == '') {
     1776            $result .= $this->headerLine(
     1777                'X-Mailer',
     1778                'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer/)'
     1779            );
     1780        } else {
     1781            $myXmailer = trim($this->XMailer);
     1782            if ($myXmailer) {
     1783                $result .= $this->headerLine('X-Mailer', $myXmailer);
     1784            }
     1785        }
     1786
     1787        if ($this->ConfirmReadingTo != '') {
     1788            $result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
     1789        }
     1790
     1791        // Add custom headers
     1792        foreach ($this->CustomHeader as $header) {
     1793            $result .= $this->headerLine(
     1794                trim($header[0]),
     1795                $this->encodeHeader(trim($header[1]))
     1796            );
     1797        }
     1798        if (!$this->sign_key_file) {
     1799            $result .= $this->headerLine('MIME-Version', '1.0');
     1800            $result .= $this->getMailMIME();
     1801        }
     1802
     1803        return $result;
     1804    }
     1805
     1806    /**
     1807     * Get the message MIME type headers.
     1808     * @access public
     1809     * @return string
     1810     */
     1811    public function getMailMIME()
     1812    {
     1813        $result = '';
     1814        $ismultipart = true;
     1815        switch ($this->message_type) {
     1816            case 'inline':
     1817                $result .= $this->headerLine('Content-Type', 'multipart/related;');
     1818                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     1819                break;
     1820            case 'attach':
     1821            case 'inline_attach':
     1822            case 'alt_attach':
     1823            case 'alt_inline_attach':
     1824                $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
     1825                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     1826                break;
     1827            case 'alt':
     1828            case 'alt_inline':
     1829                $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
     1830                $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
     1831                break;
     1832            default:
     1833                // Catches case 'plain': and case '':
     1834                $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
     1835                $ismultipart = false;
     1836                break;
     1837        }
     1838        // RFC1341 part 5 says 7bit is assumed if not specified
     1839        if ($this->Encoding != '7bit') {
     1840            // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
     1841            if ($ismultipart) {
     1842                if ($this->Encoding == '8bit') {
     1843                    $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
     1844                }
     1845                // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
     1846            } else {
     1847                $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
     1848            }
     1849        }
     1850
     1851        if ($this->Mailer != 'mail') {
     1852            $result .= $this->LE;
     1853        }
     1854
     1855        return $result;
     1856    }
     1857
     1858    /**
     1859     * Returns the whole MIME message.
     1860     * Includes complete headers and body.
     1861     * Only valid post preSend().
     1862     * @see PHPMailer::preSend()
     1863     * @access public
     1864     * @return string
     1865     */
     1866    public function getSentMIMEMessage()
     1867    {
     1868        return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
     1869    }
     1870
     1871    /**
     1872     * Assemble the message body.
     1873     * Returns an empty string on failure.
     1874     * @access public
     1875     * @throws phpmailerException
     1876     * @return string The assembled message body
     1877     */
     1878    public function createBody()
     1879    {
     1880        $body = '';
     1881        //Create unique IDs and preset boundaries
     1882        $this->uniqueid = md5(uniqid(time()));
     1883        $this->boundary[1] = 'b1_' . $this->uniqueid;
     1884        $this->boundary[2] = 'b2_' . $this->uniqueid;
     1885        $this->boundary[3] = 'b3_' . $this->uniqueid;
     1886
     1887        if ($this->sign_key_file) {
     1888            $body .= $this->getMailMIME() . $this->LE;
     1889        }
     1890
     1891        $this->setWordWrap();
     1892
     1893        $bodyEncoding = $this->Encoding;
     1894        $bodyCharSet = $this->CharSet;
     1895        //Can we do a 7-bit downgrade?
     1896        if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
     1897            $bodyEncoding = '7bit';
     1898            $bodyCharSet = 'us-ascii';
     1899        }
     1900        //If lines are too long, change to quoted-printable transfer encoding
     1901        if (self::hasLineLongerThanMax($this->Body)) {
     1902            $this->Encoding = 'quoted-printable';
     1903            $bodyEncoding = 'quoted-printable';
     1904        }
     1905
     1906        $altBodyEncoding = $this->Encoding;
     1907        $altBodyCharSet = $this->CharSet;
     1908        //Can we do a 7-bit downgrade?
     1909        if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
     1910            $altBodyEncoding = '7bit';
     1911            $altBodyCharSet = 'us-ascii';
     1912        }
     1913        //If lines are too long, change to quoted-printable transfer encoding
     1914        if (self::hasLineLongerThanMax($this->AltBody)) {
     1915            $altBodyEncoding = 'quoted-printable';
     1916        }
     1917        //Use this as a preamble in all multipart message types
     1918        $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
     1919        switch ($this->message_type) {
     1920            case 'inline':
     1921                $body .= $mimepre;
     1922                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
     1923                $body .= $this->encodeString($this->Body, $bodyEncoding);
     1924                $body .= $this->LE . $this->LE;
     1925                $body .= $this->attachAll('inline', $this->boundary[1]);
     1926                break;
     1927            case 'attach':
     1928                $body .= $mimepre;
     1929                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
     1930                $body .= $this->encodeString($this->Body, $bodyEncoding);
     1931                $body .= $this->LE . $this->LE;
     1932                $body .= $this->attachAll('attachment', $this->boundary[1]);
     1933                break;
     1934            case 'inline_attach':
     1935                $body .= $mimepre;
     1936                $body .= $this->textLine('--' . $this->boundary[1]);
     1937                $body .= $this->headerLine('Content-Type', 'multipart/related;');
     1938                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     1939                $body .= $this->LE;
     1940                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
     1941                $body .= $this->encodeString($this->Body, $bodyEncoding);
     1942                $body .= $this->LE . $this->LE;
     1943                $body .= $this->attachAll('inline', $this->boundary[2]);
     1944                $body .= $this->LE;
     1945                $body .= $this->attachAll('attachment', $this->boundary[1]);
     1946                break;
     1947            case 'alt':
     1948                $body .= $mimepre;
     1949                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     1950                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     1951                $body .= $this->LE . $this->LE;
     1952                $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
     1953                $body .= $this->encodeString($this->Body, $bodyEncoding);
     1954                $body .= $this->LE . $this->LE;
     1955                if (!empty($this->Ical)) {
     1956                    $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
     1957                    $body .= $this->encodeString($this->Ical, $this->Encoding);
     1958                    $body .= $this->LE . $this->LE;
     1959                }
     1960                $body .= $this->endBoundary($this->boundary[1]);
     1961                break;
     1962            case 'alt_inline':
     1963                $body .= $mimepre;
     1964                $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     1965                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     1966                $body .= $this->LE . $this->LE;
     1967                $body .= $this->textLine('--' . $this->boundary[1]);
     1968                $body .= $this->headerLine('Content-Type', 'multipart/related;');
     1969                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     1970                $body .= $this->LE;
     1971                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
     1972                $body .= $this->encodeString($this->Body, $bodyEncoding);
     1973                $body .= $this->LE . $this->LE;
     1974                $body .= $this->attachAll('inline', $this->boundary[2]);
     1975                $body .= $this->LE;
     1976                $body .= $this->endBoundary($this->boundary[1]);
     1977                break;
     1978            case 'alt_attach':
     1979                $body .= $mimepre;
     1980                $body .= $this->textLine('--' . $this->boundary[1]);
     1981                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
     1982                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     1983                $body .= $this->LE;
     1984                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     1985                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     1986                $body .= $this->LE . $this->LE;
     1987                $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
     1988                $body .= $this->encodeString($this->Body, $bodyEncoding);
     1989                $body .= $this->LE . $this->LE;
     1990                $body .= $this->endBoundary($this->boundary[2]);
     1991                $body .= $this->LE;
     1992                $body .= $this->attachAll('attachment', $this->boundary[1]);
     1993                break;
     1994            case 'alt_inline_attach':
     1995                $body .= $mimepre;
     1996                $body .= $this->textLine('--' . $this->boundary[1]);
     1997                $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
     1998                $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
     1999                $body .= $this->LE;
     2000                $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
     2001                $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
     2002                $body .= $this->LE . $this->LE;
     2003                $body .= $this->textLine('--' . $this->boundary[2]);
     2004                $body .= $this->headerLine('Content-Type', 'multipart/related;');
     2005                $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
     2006                $body .= $this->LE;
     2007                $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
     2008                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2009                $body .= $this->LE . $this->LE;
     2010                $body .= $this->attachAll('inline', $this->boundary[3]);
     2011                $body .= $this->LE;
     2012                $body .= $this->endBoundary($this->boundary[2]);
     2013                $body .= $this->LE;
     2014                $body .= $this->attachAll('attachment', $this->boundary[1]);
     2015                break;
     2016            default:
     2017                // catch case 'plain' and case ''
     2018                $body .= $this->encodeString($this->Body, $bodyEncoding);
     2019                break;
     2020        }
     2021
     2022        if ($this->isError()) {
     2023            $body = '';
     2024        } elseif ($this->sign_key_file) {
     2025            try {
     2026                if (!defined('PKCS7_TEXT')) {
     2027                    throw new phpmailerException($this->lang('extension_missing') . 'openssl');
     2028                }
     2029                // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
     2030                $file = tempnam(sys_get_temp_dir(), 'mail');
     2031                if (false === file_put_contents($file, $body)) {
     2032                    throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
     2033                }
     2034                $signed = tempnam(sys_get_temp_dir(), 'signed');
     2035                //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
     2036                if (empty($this->sign_extracerts_file)) {
     2037                    $sign = @openssl_pkcs7_sign(
     2038                        $file,
     2039                        $signed,
     2040                        'file://' . realpath($this->sign_cert_file),
     2041                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
     2042                        null
     2043                    );
     2044                } else {
     2045                    $sign = @openssl_pkcs7_sign(
     2046                        $file,
     2047                        $signed,
     2048                        'file://' . realpath($this->sign_cert_file),
     2049                        array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
     2050                        null,
     2051                        PKCS7_DETACHED,
     2052                        $this->sign_extracerts_file
     2053                    );
     2054                }
     2055                if ($sign) {
     2056                    @unlink($file);
     2057                    $body = file_get_contents($signed);
     2058                    @unlink($signed);
     2059                    //The message returned by openssl contains both headers and body, so need to split them up
     2060                    $parts = explode("\n\n", $body, 2);
     2061                    $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
     2062                    $body = $parts[1];
     2063                } else {
     2064                    @unlink($file);
     2065                    @unlink($signed);
     2066                    throw new phpmailerException($this->lang('signing') . openssl_error_string());
     2067                }
     2068            } catch (phpmailerException $exc) {
     2069                $body = '';
     2070                if ($this->exceptions) {
     2071                    throw $exc;
     2072                }
     2073            }
     2074        }
     2075        return $body;
     2076    }
     2077
     2078    /**
     2079     * Return the start of a message boundary.
     2080     * @access protected
     2081     * @param string $boundary
     2082     * @param string $charSet
     2083     * @param string $contentType
     2084     * @param string $encoding
     2085     * @return string
     2086     */
     2087    protected function getBoundary($boundary, $charSet, $contentType, $encoding)
     2088    {
     2089        $result = '';
     2090        if ($charSet == '') {
     2091            $charSet = $this->CharSet;
     2092        }
     2093        if ($contentType == '') {
     2094            $contentType = $this->ContentType;
     2095        }
     2096        if ($encoding == '') {
     2097            $encoding = $this->Encoding;
     2098        }
     2099        $result .= $this->textLine('--' . $boundary);
     2100        $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
     2101        $result .= $this->LE;
     2102        // RFC1341 part 5 says 7bit is assumed if not specified
     2103        if ($encoding != '7bit') {
     2104            $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
     2105        }
     2106        $result .= $this->LE;
     2107
     2108        return $result;
     2109    }
     2110
     2111    /**
     2112     * Return the end of a message boundary.
     2113     * @access protected
     2114     * @param string $boundary
     2115     * @return string
     2116     */
     2117    protected function endBoundary($boundary)
     2118    {
     2119        return $this->LE . '--' . $boundary . '--' . $this->LE;
     2120    }
     2121
     2122    /**
     2123     * Set the message type.
     2124     * PHPMailer only supports some preset message types,
     2125     * not arbitrary MIME structures.
     2126     * @access protected
     2127     * @return void
     2128     */
     2129    protected function setMessageType()
     2130    {
     2131        $type = array();
     2132        if ($this->alternativeExists()) {
     2133            $type[] = 'alt';
     2134        }
     2135        if ($this->inlineImageExists()) {
     2136            $type[] = 'inline';
     2137        }
     2138        if ($this->attachmentExists()) {
     2139            $type[] = 'attach';
     2140        }
     2141        $this->message_type = implode('_', $type);
     2142        if ($this->message_type == '') {
     2143            $this->message_type = 'plain';
     2144        }
     2145    }
     2146
     2147    /**
     2148     * Format a header line.
     2149     * @access public
     2150     * @param string $name
     2151     * @param string $value
     2152     * @return string
     2153     */
     2154    public function headerLine($name, $value)
     2155    {
     2156        return $name . ': ' . $value . $this->LE;
     2157    }
     2158
     2159    /**
     2160     * Return a formatted mail line.
     2161     * @access public
     2162     * @param string $value
     2163     * @return string
     2164     */
     2165    public function textLine($value)
     2166    {
     2167        return $value . $this->LE;
     2168    }
     2169
     2170    /**
     2171     * Add an attachment from a path on the filesystem.
     2172     * Returns false if the file could not be found or read.
     2173     * @param string $path Path to the attachment.
     2174     * @param string $name Overrides the attachment name.
     2175     * @param string $encoding File encoding (see $Encoding).
     2176     * @param string $type File extension (MIME) type.
     2177     * @param string $disposition Disposition to use
     2178     * @throws phpmailerException
     2179     * @return boolean
     2180     */
     2181    public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
     2182    {
     2183        try {
     2184            if (!@is_file($path)) {
     2185                throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
     2186            }
     2187
     2188            // If a MIME type is not specified, try to work it out from the file name
     2189            if ($type == '') {
     2190                $type = self::filenameToType($path);
     2191            }
     2192
     2193            $filename = basename($path);
     2194            if ($name == '') {
     2195                $name = $filename;
     2196            }
     2197
     2198            $this->attachment[] = array(
     2199                0 => $path,
     2200                1 => $filename,
     2201                2 => $name,
     2202                3 => $encoding,
     2203                4 => $type,
     2204                5 => false, // isStringAttachment
     2205                6 => $disposition,
     2206                7 => 0
     2207            );
     2208
     2209        } catch (phpmailerException $exc) {
     2210            $this->setError($exc->getMessage());
     2211            $this->edebug($exc->getMessage());
     2212            if ($this->exceptions) {
     2213                throw $exc;
     2214            }
     2215            return false;
     2216        }
     2217        return true;
     2218    }
     2219
     2220    /**
     2221     * Return the array of attachments.
     2222     * @return array
     2223     */
     2224    public function getAttachments()
     2225    {
     2226        return $this->attachment;
     2227    }
     2228
     2229    /**
     2230     * Attach all file, string, and binary attachments to the message.
     2231     * Returns an empty string on failure.
     2232     * @access protected
     2233     * @param string $disposition_type
     2234     * @param string $boundary
     2235     * @return string
     2236     */
     2237    protected function attachAll($disposition_type, $boundary)
     2238    {
     2239        // Return text of body
     2240        $mime = array();
     2241        $cidUniq = array();
     2242        $incl = array();
     2243
     2244        // Add all attachments
     2245        foreach ($this->attachment as $attachment) {
     2246            // Check if it is a valid disposition_filter
     2247            if ($attachment[6] == $disposition_type) {
     2248                // Check for string attachment
     2249                $string = '';
     2250                $path = '';
     2251                $bString = $attachment[5];
     2252                if ($bString) {
     2253                    $string = $attachment[0];
     2254                } else {
     2255                    $path = $attachment[0];
     2256                }
     2257
     2258                $inclhash = md5(serialize($attachment));
     2259                if (in_array($inclhash, $incl)) {
     2260                    continue;
     2261                }
     2262                $incl[] = $inclhash;
     2263                $name = $attachment[2];
     2264                $encoding = $attachment[3];
     2265                $type = $attachment[4];
     2266                $disposition = $attachment[6];
     2267                $cid = $attachment[7];
     2268                if ($disposition == 'inline' && isset($cidUniq[$cid])) {
     2269                    continue;
     2270                }
     2271                $cidUniq[$cid] = true;
     2272
     2273                $mime[] = sprintf('--%s%s', $boundary, $this->LE);
     2274                $mime[] = sprintf(
     2275                    'Content-Type: %s; name="%s"%s',
     2276                    $type,
     2277                    $this->encodeHeader($this->secureHeader($name)),
     2278                    $this->LE
     2279                );
     2280                // RFC1341 part 5 says 7bit is assumed if not specified
     2281                if ($encoding != '7bit') {
     2282                    $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
     2283                }
     2284
     2285                if ($disposition == 'inline') {
     2286                    $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
     2287                }
     2288
     2289                // If a filename contains any of these chars, it should be quoted,
     2290                // but not otherwise: RFC2183 & RFC2045 5.1
     2291                // Fixes a warning in IETF's msglint MIME checker
     2292                // Allow for bypassing the Content-Disposition header totally
     2293                if (!(empty($disposition))) {
     2294                    $encoded_name = $this->encodeHeader($this->secureHeader($name));
     2295                    if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
     2296                        $mime[] = sprintf(
     2297                            'Content-Disposition: %s; filename="%s"%s',
     2298                            $disposition,
     2299                            $encoded_name,
     2300                            $this->LE . $this->LE
     2301                        );
     2302                    } else {
     2303                        $mime[] = sprintf(
     2304                            'Content-Disposition: %s; filename=%s%s',
     2305                            $disposition,
     2306                            $encoded_name,
     2307                            $this->LE . $this->LE
     2308                        );
     2309                    }
     2310                } else {
     2311                    $mime[] = $this->LE;
     2312                }
     2313
     2314                // Encode as string attachment
     2315                if ($bString) {
     2316                    $mime[] = $this->encodeString($string, $encoding);
     2317                    if ($this->isError()) {
     2318                        return '';
     2319                    }
     2320                    $mime[] = $this->LE . $this->LE;
     2321                } else {
     2322                    $mime[] = $this->encodeFile($path, $encoding);
     2323                    if ($this->isError()) {
     2324                        return '';
     2325                    }
     2326                    $mime[] = $this->LE . $this->LE;
     2327                }
     2328            }
     2329        }
     2330
     2331        $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
     2332
     2333        return implode('', $mime);
     2334    }
     2335
     2336    /**
     2337     * Encode a file attachment in requested format.
     2338     * Returns an empty string on failure.
     2339     * @param string $path The full path to the file
     2340     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
     2341     * @throws phpmailerException
     2342     * @see EncodeFile(encodeFile
     2343     * @access protected
     2344     * @return string
     2345     */
     2346    protected function encodeFile($path, $encoding = 'base64')
     2347    {
     2348        try {
     2349            if (!is_readable($path)) {
     2350                throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
     2351            }
     2352            $magic_quotes = get_magic_quotes_runtime();
     2353            if ($magic_quotes) {
     2354                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
     2355                    set_magic_quotes_runtime(false);
     2356                } else {
     2357                    //Doesn't exist in PHP 5.4, but we don't need to check because
     2358                    //get_magic_quotes_runtime always returns false in 5.4+
     2359                    //so it will never get here
     2360                    ini_set('magic_quotes_runtime', false);
     2361                }
     2362            }
     2363            $file_buffer = file_get_contents($path);
     2364            $file_buffer = $this->encodeString($file_buffer, $encoding);
     2365            if ($magic_quotes) {
     2366                if (version_compare(PHP_VERSION, '5.3.0', '<')) {
     2367                    set_magic_quotes_runtime($magic_quotes);
     2368                } else {
     2369                    ini_set('magic_quotes_runtime', $magic_quotes);
     2370                }
     2371            }
     2372            return $file_buffer;
     2373        } catch (Exception $exc) {
     2374            $this->setError($exc->getMessage());
     2375            return '';
     2376        }
     2377    }
     2378
     2379    /**
     2380     * Encode a string in requested format.
     2381     * Returns an empty string on failure.
     2382     * @param string $str The text to encode
     2383     * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
     2384     * @access public
     2385     * @return string
     2386     */
     2387    public function encodeString($str, $encoding = 'base64')
     2388    {
     2389        $encoded = '';
     2390        switch (strtolower($encoding)) {
     2391            case 'base64':
     2392                $encoded = chunk_split(base64_encode($str), 76, $this->LE);
     2393                break;
     2394            case '7bit':
     2395            case '8bit':
     2396                $encoded = $this->fixEOL($str);
     2397                // Make sure it ends with a line break
     2398                if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
     2399                    $encoded .= $this->LE;
     2400                }
     2401                break;
     2402            case 'binary':
     2403                $encoded = $str;
     2404                break;
     2405            case 'quoted-printable':
     2406                $encoded = $this->encodeQP($str);
     2407                break;
     2408            default:
     2409                $this->setError($this->lang('encoding') . $encoding);
     2410                break;
     2411        }
     2412        return $encoded;
     2413    }
     2414
     2415    /**
     2416     * Encode a header string optimally.
     2417     * Picks shortest of Q, B, quoted-printable or none.
     2418     * @access public
     2419     * @param string $str
     2420     * @param string $position
     2421     * @return string
     2422     */
     2423    public function encodeHeader($str, $position = 'text')
     2424    {
     2425        $matchcount = 0;
     2426        switch (strtolower($position)) {
     2427            case 'phrase':
     2428                if (!preg_match('/[\200-\377]/', $str)) {
     2429                    // Can't use addslashes as we don't know the value of magic_quotes_sybase
     2430                    $encoded = addcslashes($str, "\0..\37\177\\\"");
     2431                    if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
     2432                        return ($encoded);
     2433                    } else {
     2434                        return ("\"$encoded\"");
     2435                    }
     2436                }
     2437                $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
     2438                break;
     2439            /** @noinspection PhpMissingBreakStatementInspection */
     2440            case 'comment':
     2441                $matchcount = preg_match_all('/[()"]/', $str, $matches);
     2442                // Intentional fall-through
     2443            case 'text':
     2444            default:
     2445                $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
     2446                break;
     2447        }
     2448
     2449        //There are no chars that need encoding
     2450        if ($matchcount == 0) {
     2451            return ($str);
     2452        }
     2453
     2454        $maxlen = 75 - 7 - strlen($this->CharSet);
     2455        // Try to select the encoding which should produce the shortest output
     2456        if ($matchcount > strlen($str) / 3) {
     2457            // More than a third of the content will need encoding, so B encoding will be most efficient
     2458            $encoding = 'B';
     2459            if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
     2460                // Use a custom function which correctly encodes and wraps long
     2461                // multibyte strings without breaking lines within a character
     2462                $encoded = $this->base64EncodeWrapMB($str, "\n");
     2463            } else {
     2464                $encoded = base64_encode($str);
     2465                $maxlen -= $maxlen % 4;
     2466                $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
     2467            }
     2468        } else {
     2469            $encoding = 'Q';
     2470            $encoded = $this->encodeQ($str, $position);
     2471            $encoded = $this->wrapText($encoded, $maxlen, true);
     2472            $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
     2473        }
     2474
     2475        $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
     2476        $encoded = trim(str_replace("\n", $this->LE, $encoded));
     2477
     2478        return $encoded;
     2479    }
     2480
     2481    /**
     2482     * Check if a string contains multi-byte characters.
     2483     * @access public
     2484     * @param string $str multi-byte text to wrap encode
     2485     * @return boolean
     2486     */
     2487    public function hasMultiBytes($str)
     2488    {
     2489        if (function_exists('mb_strlen')) {
     2490            return (strlen($str) > mb_strlen($str, $this->CharSet));
     2491        } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
     2492            return false;
     2493        }
     2494    }
     2495
     2496    /**
     2497     * Does a string contain any 8-bit chars (in any charset)?
     2498     * @param string $text
     2499     * @return boolean
     2500     */
     2501    public function has8bitChars($text)
     2502    {
     2503        return (boolean)preg_match('/[\x80-\xFF]/', $text);
     2504    }
     2505
     2506    /**
     2507     * Encode and wrap long multibyte strings for mail headers
     2508     * without breaking lines within a character.
     2509     * Adapted from a function by paravoid
     2510     * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
     2511     * @access public
     2512     * @param string $str multi-byte text to wrap encode
     2513     * @param string $linebreak string to use as linefeed/end-of-line
     2514     * @return string
     2515     */
     2516    public function base64EncodeWrapMB($str, $linebreak = null)
     2517    {
     2518        $start = '=?' . $this->CharSet . '?B?';
     2519        $end = '?=';
     2520        $encoded = '';
     2521        if ($linebreak === null) {
     2522            $linebreak = $this->LE;
     2523        }
     2524
     2525        $mb_length = mb_strlen($str, $this->CharSet);
     2526        // Each line must have length <= 75, including $start and $end
     2527        $length = 75 - strlen($start) - strlen($end);
     2528        // Average multi-byte ratio
     2529        $ratio = $mb_length / strlen($str);
     2530        // Base64 has a 4:3 ratio
     2531        $avgLength = floor($length * $ratio * .75);
     2532
     2533        for ($i = 0; $i < $mb_length; $i += $offset) {
     2534            $lookBack = 0;
     2535            do {
     2536                $offset = $avgLength - $lookBack;
     2537                $chunk = mb_substr($str, $i, $offset, $this->CharSet);
     2538                $chunk = base64_encode($chunk);
     2539                $lookBack++;
     2540            } while (strlen($chunk) > $length);
     2541            $encoded .= $chunk . $linebreak;
     2542        }
     2543
     2544        // Chomp the last linefeed
     2545        $encoded = substr($encoded, 0, -strlen($linebreak));
     2546        return $encoded;
     2547    }
     2548
     2549    /**
     2550     * Encode a string in quoted-printable format.
     2551     * According to RFC2045 section 6.7.
     2552     * @access public
     2553     * @param string $string The text to encode
     2554     * @param integer $line_max Number of chars allowed on a line before wrapping
     2555     * @return string
     2556     * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
     2557     */
     2558    public function encodeQP($string, $line_max = 76)
     2559    {
     2560        // Use native function if it's available (>= PHP5.3)
     2561        if (function_exists('quoted_printable_encode')) {
     2562            return $this->fixEOL(quoted_printable_encode($string));
     2563        }
     2564        // Fall back to a pure PHP implementation
     2565        $string = str_replace(
     2566            array('%20', '%0D%0A.', '%0D%0A', '%'),
     2567            array(' ', "\r\n=2E", "\r\n", '='),
     2568            rawurlencode($string)
     2569        );
     2570        $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
     2571        return $this->fixEOL($string);
     2572    }
     2573
     2574    /**
     2575     * Backward compatibility wrapper for an old QP encoding function that was removed.
     2576     * @see PHPMailer::encodeQP()
     2577     * @access public
     2578     * @param string $string
     2579     * @param integer $line_max
     2580     * @param boolean $space_conv
     2581     * @return string
     2582     * @deprecated Use encodeQP instead.
     2583     */
     2584    public function encodeQPphp(
     2585        $string,
     2586        $line_max = 76,
     2587        /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
     2588    ) {
     2589        return $this->encodeQP($string, $line_max);
     2590    }
     2591
     2592    /**
     2593     * Encode a string using Q encoding.
     2594     * @link http://tools.ietf.org/html/rfc2047
     2595     * @param string $str the text to encode
     2596     * @param string $position Where the text is going to be used, see the RFC for what that means
     2597     * @access public
     2598     * @return string
     2599     */
     2600    public function encodeQ($str, $position = 'text')
     2601    {
     2602        // There should not be any EOL in the string
     2603        $pattern = '';
     2604        $encoded = str_replace(array("\r", "\n"), '', $str);
     2605        switch (strtolower($position)) {
     2606            case 'phrase':
     2607                // RFC 2047 section 5.3
     2608                $pattern = '^A-Za-z0-9!*+\/ -';
     2609                break;
     2610            /** @noinspection PhpMissingBreakStatementInspection */
     2611            case 'comment':
     2612                // RFC 2047 section 5.2
     2613                $pattern = '\(\)"';
     2614                // intentional fall-through
     2615                // for this reason we build the $pattern without including delimiters and []
     2616            case 'text':
     2617            default:
     2618                // RFC 2047 section 5.1
     2619                // Replace every high ascii, control, =, ? and _ characters
     2620                $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
     2621                break;
     2622        }
     2623        $matches = array();
     2624        if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
     2625            // If the string contains an '=', make sure it's the first thing we replace
     2626            // so as to avoid double-encoding
     2627            $eqkey = array_search('=', $matches[0]);
     2628            if (false !== $eqkey) {
     2629                unset($matches[0][$eqkey]);
     2630                array_unshift($matches[0], '=');
     2631            }
     2632            foreach (array_unique($matches[0]) as $char) {
     2633                $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
     2634            }
     2635        }
     2636        // Replace every spaces to _ (more readable than =20)
     2637        return str_replace(' ', '_', $encoded);
     2638    }
     2639
     2640
     2641    /**
     2642     * Add a string or binary attachment (non-filesystem).
     2643     * This method can be used to attach ascii or binary data,
     2644     * such as a BLOB record from a database.
     2645     * @param string $string String attachment data.
     2646     * @param string $filename Name of the attachment.
     2647     * @param string $encoding File encoding (see $Encoding).
     2648     * @param string $type File extension (MIME) type.
     2649     * @param string $disposition Disposition to use
     2650     * @return void
     2651     */
     2652    public function addStringAttachment(
     2653        $string,
     2654        $filename,
     2655        $encoding = 'base64',
     2656        $type = '',
     2657        $disposition = 'attachment'
     2658    ) {
     2659        // If a MIME type is not specified, try to work it out from the file name
     2660        if ($type == '') {
     2661            $type = self::filenameToType($filename);
     2662        }
     2663        // Append to $attachment array
     2664        $this->attachment[] = array(
     2665            0 => $string,
     2666            1 => $filename,
     2667            2 => basename($filename),
     2668            3 => $encoding,
     2669            4 => $type,
     2670            5 => true, // isStringAttachment
     2671            6 => $disposition,
     2672            7 => 0
     2673        );
     2674    }
     2675
     2676    /**
     2677     * Add an embedded (inline) attachment from a file.
     2678     * This can include images, sounds, and just about any other document type.
     2679     * These differ from 'regular' attachments in that they are intended to be
     2680     * displayed inline with the message, not just attached for download.
     2681     * This is used in HTML messages that embed the images
     2682     * the HTML refers to using the $cid value.
     2683     * @param string $path Path to the attachment.
     2684     * @param string $cid Content ID of the attachment; Use this to reference
     2685     *        the content when using an embedded image in HTML.
     2686     * @param string $name Overrides the attachment name.
     2687     * @param string $encoding File encoding (see $Encoding).
     2688     * @param string $type File MIME type.
     2689     * @param string $disposition Disposition to use
     2690     * @return boolean True on successfully adding an attachment
     2691     */
     2692    public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
     2693    {
     2694        if (!@is_file($path)) {
     2695            $this->setError($this->lang('file_access') . $path);
     2696            return false;
     2697        }
     2698
     2699        // If a MIME type is not specified, try to work it out from the file name
     2700        if ($type == '') {
     2701            $type = self::filenameToType($path);
     2702        }
     2703
     2704        $filename = basename($path);
     2705        if ($name == '') {
     2706            $name = $filename;
     2707        }
     2708
     2709        // Append to $attachment array
     2710        $this->attachment[] = array(
     2711            0 => $path,
     2712            1 => $filename,
     2713            2 => $name,
     2714            3 => $encoding,
     2715            4 => $type,
     2716            5 => false, // isStringAttachment
     2717            6 => $disposition,
     2718            7 => $cid
     2719        );
     2720        return true;
     2721    }
     2722
     2723    /**
     2724     * Add an embedded stringified attachment.
     2725     * This can include images, sounds, and just about any other document type.
     2726     * Be sure to set the $type to an image type for images:
     2727     * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
     2728     * @param string $string The attachment binary data.
     2729     * @param string $cid Content ID of the attachment; Use this to reference
     2730     *        the content when using an embedded image in HTML.
     2731     * @param string $name
     2732     * @param string $encoding File encoding (see $Encoding).
     2733     * @param string $type MIME type.
     2734     * @param string $disposition Disposition to use
     2735     * @return boolean True on successfully adding an attachment
     2736     */
     2737    public function addStringEmbeddedImage(
     2738        $string,
     2739        $cid,
     2740        $name = '',
     2741        $encoding = 'base64',
     2742        $type = '',
     2743        $disposition = 'inline'
     2744    ) {
     2745        // If a MIME type is not specified, try to work it out from the name
     2746        if ($type == '') {
     2747            $type = self::filenameToType($name);
     2748        }
     2749
     2750        // Append to $attachment array
     2751        $this->attachment[] = array(
     2752            0 => $string,
     2753            1 => $name,
     2754            2 => $name,
     2755            3 => $encoding,
     2756            4 => $type,
     2757            5 => true, // isStringAttachment
     2758            6 => $disposition,
     2759            7 => $cid
     2760        );
     2761        return true;
     2762    }
     2763
     2764    /**
     2765     * Check if an inline attachment is present.
     2766     * @access public
     2767     * @return boolean
     2768     */
     2769    public function inlineImageExists()
     2770    {
     2771        foreach ($this->attachment as $attachment) {
     2772            if ($attachment[6] == 'inline') {
     2773                return true;
     2774            }
     2775        }
     2776        return false;
     2777    }
     2778
     2779    /**
     2780     * Check if an attachment (non-inline) is present.
     2781     * @return boolean
     2782     */
     2783    public function attachmentExists()
     2784    {
     2785        foreach ($this->attachment as $attachment) {
     2786            if ($attachment[6] == 'attachment') {
     2787                return true;
     2788            }
     2789        }
     2790        return false;
     2791    }
     2792
     2793    /**
     2794     * Check if this message has an alternative body set.
     2795     * @return boolean
     2796     */
     2797    public function alternativeExists()
     2798    {
     2799        return !empty($this->AltBody);
     2800    }
     2801
     2802    /**
     2803     * Clear all To recipients.
     2804     * @return void
     2805     */
     2806    public function clearAddresses()
     2807    {
     2808        foreach ($this->to as $to) {
     2809            unset($this->all_recipients[strtolower($to[0])]);
     2810        }
     2811        $this->to = array();
     2812    }
     2813
     2814    /**
     2815     * Clear all CC recipients.
     2816     * @return void
     2817     */
     2818    public function clearCCs()
     2819    {
     2820        foreach ($this->cc as $cc) {
     2821            unset($this->all_recipients[strtolower($cc[0])]);
     2822        }
     2823        $this->cc = array();
     2824    }
     2825
     2826    /**
     2827     * Clear all BCC recipients.
     2828     * @return void
     2829     */
     2830    public function clearBCCs()
     2831    {
     2832        foreach ($this->bcc as $bcc) {
     2833            unset($this->all_recipients[strtolower($bcc[0])]);
     2834        }
     2835        $this->bcc = array();
     2836    }
     2837
     2838    /**
     2839     * Clear all ReplyTo recipients.
     2840     * @return void
     2841     */
     2842    public function clearReplyTos()
     2843    {
     2844        $this->ReplyTo = array();
     2845    }
     2846
     2847    /**
     2848     * Clear all recipient types.
     2849     * @return void
     2850     */
     2851    public function clearAllRecipients()
     2852    {
     2853        $this->to = array();
     2854        $this->cc = array();
     2855        $this->bcc = array();
     2856        $this->all_recipients = array();
     2857    }
     2858
     2859    /**
     2860     * Clear all filesystem, string, and binary attachments.
     2861     * @return void
     2862     */
     2863    public function clearAttachments()
     2864    {
     2865        $this->attachment = array();
     2866    }
     2867
     2868    /**
     2869     * Clear all custom headers.
     2870     * @return void
     2871     */
     2872    public function clearCustomHeaders()
     2873    {
     2874        $this->CustomHeader = array();
     2875    }
     2876
     2877    /**
     2878     * Add an error message to the error container.
     2879     * @access protected
     2880     * @param string $msg
     2881     * @return void
     2882     */
     2883    protected function setError($msg)
     2884    {
     2885        $this->error_count++;
     2886        if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
     2887            $lasterror = $this->smtp->getError();
     2888            if (!empty($lasterror['error'])) {
     2889                $msg .= $this->lang('smtp_error') . $lasterror['error'];
     2890                if (!empty($lasterror['detail'])) {
     2891                    $msg .= ' Detail: '. $lasterror['detail'];
     2892                }
     2893                if (!empty($lasterror['smtp_code'])) {
     2894                    $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
     2895                }
     2896                if (!empty($lasterror['smtp_code_ex'])) {
     2897                    $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
     2898                }
     2899            }
     2900        }
     2901        $this->ErrorInfo = $msg;
     2902    }
     2903
     2904    /**
     2905     * Return an RFC 822 formatted date.
     2906     * @access public
     2907     * @return string
     2908     * @static
     2909     */
     2910    public static function rfcDate()
     2911    {
     2912        // Set the time zone to whatever the default is to avoid 500 errors
     2913        // Will default to UTC if it's not set properly in php.ini
     2914        date_default_timezone_set(@date_default_timezone_get());
     2915        return date('D, j M Y H:i:s O');
     2916    }
     2917
     2918    /**
     2919     * Get the server hostname.
     2920     * Returns 'localhost.localdomain' if unknown.
     2921     * @access protected
     2922     * @return string
     2923     */
     2924    protected function serverHostname()
     2925    {
     2926        $result = 'localhost.localdomain';
     2927        if (!empty($this->Hostname)) {
     2928            $result = $this->Hostname;
     2929        } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
     2930            $result = $_SERVER['SERVER_NAME'];
     2931        } elseif (function_exists('gethostname') && gethostname() !== false) {
     2932            $result = gethostname();
     2933        } elseif (php_uname('n') !== false) {
     2934            $result = php_uname('n');
     2935        }
     2936        return $result;
     2937    }
     2938
     2939    /**
     2940     * Get an error message in the current language.
     2941     * @access protected
     2942     * @param string $key
     2943     * @return string
     2944     */
     2945    protected function lang($key)
     2946    {
     2947        if (count($this->language) < 1) {
     2948            $this->setLanguage('en'); // set the default language
     2949        }
     2950
     2951        if (array_key_exists($key, $this->language)) {
     2952            if ($key == 'smtp_connect_failed') {
     2953                //Include a link to troubleshooting docs on SMTP connection failure
     2954                //this is by far the biggest cause of support questions
     2955                //but it's usually not PHPMailer's fault.
     2956                return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
     2957            }
     2958            return $this->language[$key];
     2959        } else {
     2960            //Return the key as a fallback
     2961            return $key;
     2962        }
     2963    }
     2964
     2965    /**
     2966     * Check if an error occurred.
     2967     * @access public
     2968     * @return boolean True if an error did occur.
     2969     */
     2970    public function isError()
     2971    {
     2972        return ($this->error_count > 0);
     2973    }
     2974
     2975    /**
     2976     * Ensure consistent line endings in a string.
     2977     * Changes every end of line from CRLF, CR or LF to $this->LE.
     2978     * @access public
     2979     * @param string $str String to fixEOL
     2980     * @return string
     2981     */
     2982    public function fixEOL($str)
     2983    {
     2984        // Normalise to \n
     2985        $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
     2986        // Now convert LE as needed
     2987        if ($this->LE !== "\n") {
     2988            $nstr = str_replace("\n", $this->LE, $nstr);
     2989        }
     2990        return $nstr;
     2991    }
     2992
     2993    /**
     2994     * Add a custom header.
     2995     * $name value can be overloaded to contain
     2996     * both header name and value (name:value)
     2997     * @access public
     2998     * @param string $name Custom header name
     2999     * @param string $value Header value
     3000     * @return void
     3001     */
     3002    public function addCustomHeader($name, $value = null)
     3003    {
     3004        if ($value === null) {
     3005            // Value passed in as name:value
     3006            $this->CustomHeader[] = explode(':', $name, 2);
     3007        } else {
     3008            $this->CustomHeader[] = array($name, $value);
     3009        }
     3010    }
     3011
     3012    /**
     3013     * Returns all custom headers
     3014     *
     3015     * @return array
     3016     */
     3017    public function getCustomHeaders()
     3018    {
     3019        return $this->CustomHeader;
     3020    }
     3021
     3022    /**
     3023     * Create a message from an HTML string.
     3024     * Automatically makes modifications for inline images and backgrounds
     3025     * and creates a plain-text version by converting the HTML.
     3026     * Overwrites any existing values in $this->Body and $this->AltBody
     3027     * @access public
     3028     * @param string $message HTML message string
     3029     * @param string $basedir baseline directory for path
     3030     * @param boolean|callable $advanced Whether to use the internal HTML to text converter
     3031     *    or your own custom converter @see html2text()
     3032     * @return string $message
     3033     */
     3034    public function msgHTML($message, $basedir = '', $advanced = false)
     3035    {
     3036        preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
     3037        if (isset($images[2])) {
     3038            foreach ($images[2] as $imgindex => $url) {
     3039                // Convert data URIs into embedded images
     3040                if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
     3041                    $data = substr($url, strpos($url, ','));
     3042                    if ($match[2]) {
     3043                        $data = base64_decode($data);
     3044                    } else {
     3045                        $data = rawurldecode($data);
     3046                    }
     3047                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
     3048                    if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) {
     3049                        $message = str_replace(
     3050                            $images[0][$imgindex],
     3051                            $images[1][$imgindex] . '="cid:' . $cid . '"',
     3052                            $message
     3053                        );
     3054                    }
     3055                } elseif (!preg_match('#^[A-z]+://#', $url)) {
     3056                    // Do not change urls for absolute images (thanks to corvuscorax)
     3057                    $filename = basename($url);
     3058                    $directory = dirname($url);
     3059                    if ($directory == '.') {
     3060                        $directory = '';
     3061                    }
     3062                    $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
     3063                    if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
     3064                        $basedir .= '/';
     3065                    }
     3066                    if (strlen($directory) > 1 && substr($directory, -1) != '/') {
     3067                        $directory .= '/';
     3068                    }
     3069                    if ($this->addEmbeddedImage(
     3070                        $basedir . $directory . $filename,
     3071                        $cid,
     3072                        $filename,
     3073                        'base64',
     3074                        self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
     3075                    )
     3076                    ) {
     3077                        $message = preg_replace(
     3078                            '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
     3079                            $images[1][$imgindex] . '="cid:' . $cid . '"',
     3080                            $message
     3081                        );
     3082                    }
     3083                }
     3084            }
     3085        }
     3086        $this->isHTML(true);
     3087        // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
     3088        $this->Body = $this->normalizeBreaks($message);
     3089        $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
     3090        if (empty($this->AltBody)) {
     3091            $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
     3092                self::CRLF . self::CRLF;
     3093        }
     3094        return $this->Body;
     3095    }
     3096
     3097    /**
     3098     * Convert an HTML string into plain text.
     3099     * This is used by msgHTML().
     3100     * Note - older versions of this function used a bundled advanced converter
     3101     * which was been removed for license reasons in #232
     3102     * Example usage:
     3103     * <code>
     3104     * // Use default conversion
     3105     * $plain = $mail->html2text($html);
     3106     * // Use your own custom converter
     3107     * $plain = $mail->html2text($html, function($html) {
     3108     *     $converter = new MyHtml2text($html);
     3109     *     return $converter->get_text();
     3110     * });
     3111     * </code>
     3112     * @param string $html The HTML text to convert
     3113     * @param boolean|callable $advanced Any boolean value to use the internal converter,
     3114     *   or provide your own callable for custom conversion.
     3115     * @return string
     3116     */
     3117    public function html2text($html, $advanced = false)
     3118    {
     3119        if (is_callable($advanced)) {
     3120            return call_user_func($advanced, $html);
     3121        }
     3122        return html_entity_decode(
     3123            trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
     3124            ENT_QUOTES,
     3125            $this->CharSet
     3126        );
     3127    }
     3128
     3129    /**
     3130     * Get the MIME type for a file extension.
     3131     * @param string $ext File extension
     3132     * @access public
     3133     * @return string MIME type of file.
     3134     * @static
     3135     */
     3136    public static function _mime_types($ext = '')
     3137    {
     3138        $mimes = array(
     3139            'xl'    => 'application/excel',
     3140            'js'    => 'application/javascript',
     3141            'hqx'   => 'application/mac-binhex40',
     3142            'cpt'   => 'application/mac-compactpro',
     3143            'bin'   => 'application/macbinary',
     3144            'doc'   => 'application/msword',
     3145            'word'  => 'application/msword',
     3146            'class' => 'application/octet-stream',
     3147            'dll'   => 'application/octet-stream',
     3148            'dms'   => 'application/octet-stream',
     3149            'exe'   => 'application/octet-stream',
     3150            'lha'   => 'application/octet-stream',
     3151            'lzh'   => 'application/octet-stream',
     3152            'psd'   => 'application/octet-stream',
     3153            'sea'   => 'application/octet-stream',
     3154            'so'    => 'application/octet-stream',
     3155            'oda'   => 'application/oda',
     3156            'pdf'   => 'application/pdf',
     3157            'ai'    => 'application/postscript',
     3158            'eps'   => 'application/postscript',
     3159            'ps'    => 'application/postscript',
     3160            'smi'   => 'application/smil',
     3161            'smil'  => 'application/smil',
     3162            'mif'   => 'application/vnd.mif',
     3163            'xls'   => 'application/vnd.ms-excel',
     3164            'ppt'   => 'application/vnd.ms-powerpoint',
     3165            'wbxml' => 'application/vnd.wap.wbxml',
     3166            'wmlc'  => 'application/vnd.wap.wmlc',
     3167            'dcr'   => 'application/x-director',
     3168            'dir'   => 'application/x-director',
     3169            'dxr'   => 'application/x-director',
     3170            'dvi'   => 'application/x-dvi',
     3171            'gtar'  => 'application/x-gtar',
     3172            'php3'  => 'application/x-httpd-php',
     3173            'php4'  => 'application/x-httpd-php',
     3174            'php'   => 'application/x-httpd-php',
     3175            'phtml' => 'application/x-httpd-php',
     3176            'phps'  => 'application/x-httpd-php-source',
     3177            'swf'   => 'application/x-shockwave-flash',
     3178            'sit'   => 'application/x-stuffit',
     3179            'tar'   => 'application/x-tar',
     3180            'tgz'   => 'application/x-tar',
     3181            'xht'   => 'application/xhtml+xml',
     3182            'xhtml' => 'application/xhtml+xml',
     3183            'zip'   => 'application/zip',
     3184            'mid'   => 'audio/midi',
     3185            'midi'  => 'audio/midi',
     3186            'mp2'   => 'audio/mpeg',
     3187            'mp3'   => 'audio/mpeg',
     3188            'mpga'  => 'audio/mpeg',
     3189            'aif'   => 'audio/x-aiff',
     3190            'aifc'  => 'audio/x-aiff',
     3191            'aiff'  => 'audio/x-aiff',
     3192            'ram'   => 'audio/x-pn-realaudio',
     3193            'rm'    => 'audio/x-pn-realaudio',
     3194            'rpm'   => 'audio/x-pn-realaudio-plugin',
     3195            'ra'    => 'audio/x-realaudio',
     3196            'wav'   => 'audio/x-wav',
     3197            'bmp'   => 'image/bmp',
     3198            'gif'   => 'image/gif',
     3199            'jpeg'  => 'image/jpeg',
     3200            'jpe'   => 'image/jpeg',
     3201            'jpg'   => 'image/jpeg',
     3202            'png'   => 'image/png',
     3203            'tiff'  => 'image/tiff',
     3204            'tif'   => 'image/tiff',
     3205            'eml'   => 'message/rfc822',
     3206            'css'   => 'text/css',
     3207            'html'  => 'text/html',
     3208            'htm'   => 'text/html',
     3209            'shtml' => 'text/html',
     3210            'log'   => 'text/plain',
     3211            'text'  => 'text/plain',
     3212            'txt'   => 'text/plain',
     3213            'rtx'   => 'text/richtext',
     3214            'rtf'   => 'text/rtf',
     3215            'vcf'   => 'text/vcard',
     3216            'vcard' => 'text/vcard',
     3217            'xml'   => 'text/xml',
     3218            'xsl'   => 'text/xml',
     3219            'mpeg'  => 'video/mpeg',
     3220            'mpe'   => 'video/mpeg',
     3221            'mpg'   => 'video/mpeg',
     3222            'mov'   => 'video/quicktime',
     3223            'qt'    => 'video/quicktime',
     3224            'rv'    => 'video/vnd.rn-realvideo',
     3225            'avi'   => 'video/x-msvideo',
     3226            'movie' => 'video/x-sgi-movie'
     3227        );
     3228        if (array_key_exists(strtolower($ext), $mimes)) {
     3229            return $mimes[strtolower($ext)];
     3230        }
     3231        return 'application/octet-stream';
     3232    }
     3233
     3234    /**
     3235     * Map a file name to a MIME type.
     3236     * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
     3237     * @param string $filename A file name or full path, does not need to exist as a file
     3238     * @return string
     3239     * @static
     3240     */
     3241    public static function filenameToType($filename)
     3242    {
     3243        // In case the path is a URL, strip any query string before getting extension
     3244        $qpos = strpos($filename, '?');
     3245        if (false !== $qpos) {
     3246            $filename = substr($filename, 0, $qpos);
     3247        }
     3248        $pathinfo = self::mb_pathinfo($filename);
     3249        return self::_mime_types($pathinfo['extension']);
     3250    }
     3251
     3252    /**
     3253     * Multi-byte-safe pathinfo replacement.
     3254     * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
     3255     * Works similarly to the one in PHP >= 5.2.0
     3256     * @link http://www.php.net/manual/en/function.pathinfo.php#107461
     3257     * @param string $path A filename or path, does not need to exist as a file
     3258     * @param integer|string $options Either a PATHINFO_* constant,
     3259     *      or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
     3260     * @return string|array
     3261     * @static
     3262     */
     3263    public static function mb_pathinfo($path, $options = null)
     3264    {
     3265        $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
     3266        $pathinfo = array();
     3267        if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
     3268            if (array_key_exists(1, $pathinfo)) {
     3269                $ret['dirname'] = $pathinfo[1];
     3270            }
     3271            if (array_key_exists(2, $pathinfo)) {
     3272                $ret['basename'] = $pathinfo[2];
     3273            }
     3274            if (array_key_exists(5, $pathinfo)) {
     3275                $ret['extension'] = $pathinfo[5];
     3276            }
     3277            if (array_key_exists(3, $pathinfo)) {
     3278                $ret['filename'] = $pathinfo[3];
     3279            }
     3280        }
     3281        switch ($options) {
     3282            case PATHINFO_DIRNAME:
     3283            case 'dirname':
     3284                return $ret['dirname'];
     3285            case PATHINFO_BASENAME:
     3286            case 'basename':
     3287                return $ret['basename'];
     3288            case PATHINFO_EXTENSION:
     3289            case 'extension':
     3290                return $ret['extension'];
     3291            case PATHINFO_FILENAME:
     3292            case 'filename':
     3293                return $ret['filename'];
     3294            default:
     3295                return $ret;
     3296        }
     3297    }
     3298
     3299    /**
     3300     * Set or reset instance properties.
     3301     * You should avoid this function - it's more verbose, less efficient, more error-prone and
     3302     * harder to debug than setting properties directly.
     3303     * Usage Example:
     3304     * `$mail->set('SMTPSecure', 'tls');`
     3305     *   is the same as:
     3306     * `$mail->SMTPSecure = 'tls';`
     3307     * @access public
     3308     * @param string $name The property name to set
     3309     * @param mixed $value The value to set the property to
     3310     * @return boolean
     3311     * @TODO Should this not be using the __set() magic function?
     3312     */
     3313    public function set($name, $value = '')
     3314    {
     3315        if (property_exists($this, $name)) {
     3316            $this->$name = $value;
     3317            return true;
     3318        } else {
     3319            $this->setError($this->lang('variable_set') . $name);
     3320            return false;
     3321        }
     3322    }
     3323
     3324    /**
     3325     * Strip newlines to prevent header injection.
     3326     * @access public
     3327     * @param string $str
     3328     * @return string
     3329     */
     3330    public function secureHeader($str)
     3331    {
     3332        return trim(str_replace(array("\r", "\n"), '', $str));
     3333    }
     3334
     3335    /**
     3336     * Normalize line breaks in a string.
     3337     * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
     3338     * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
     3339     * @param string $text
     3340     * @param string $breaktype What kind of line break to use, defaults to CRLF
     3341     * @return string
     3342     * @access public
     3343     * @static
     3344     */
     3345    public static function normalizeBreaks($text, $breaktype = "\r\n")
     3346    {
     3347        return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
     3348    }
     3349
     3350
     3351    /**
     3352     * Set the public and private key files and password for S/MIME signing.
     3353     * @access public
     3354     * @param string $cert_filename
     3355     * @param string $key_filename
     3356     * @param string $key_pass Password for private key
     3357     * @param string $extracerts_filename Optional path to chain certificate
     3358     */
     3359    public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
     3360    {
     3361        $this->sign_cert_file = $cert_filename;
     3362        $this->sign_key_file = $key_filename;
     3363        $this->sign_key_pass = $key_pass;
     3364        $this->sign_extracerts_file = $extracerts_filename;
     3365    }
     3366
     3367    /**
     3368     * Quoted-Printable-encode a DKIM header.
     3369     * @access public
     3370     * @param string $txt
     3371     * @return string
     3372     */
     3373    public function DKIM_QP($txt)
     3374    {
     3375        $line = '';
     3376        for ($i = 0; $i < strlen($txt); $i++) {
     3377            $ord = ord($txt[$i]);
     3378            if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
     3379                $line .= $txt[$i];
     3380            } else {
     3381                $line .= '=' . sprintf('%02X', $ord);
     3382            }
     3383        }
     3384        return $line;
     3385    }
     3386
     3387    /**
     3388     * Generate a DKIM signature.
     3389     * @access public
     3390     * @param string $signHeader
     3391     * @throws phpmailerException
     3392     * @return string
     3393     */
     3394    public function DKIM_Sign($signHeader)
     3395    {
     3396        if (!defined('PKCS7_TEXT')) {
     3397            if ($this->exceptions) {
     3398                throw new phpmailerException($this->lang('extension_missing') . 'openssl');
     3399            }
     3400            return '';
     3401        }
     3402        $privKeyStr = file_get_contents($this->DKIM_private);
     3403        if ($this->DKIM_passphrase != '') {
     3404            $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
     3405        } else {
     3406            $privKey = $privKeyStr;
     3407        }
     3408        if (openssl_sign($signHeader, $signature, $privKey)) {
     3409            return base64_encode($signature);
     3410        }
     3411        return '';
     3412    }
     3413
     3414    /**
     3415     * Generate a DKIM canonicalization header.
     3416     * @access public
     3417     * @param string $signHeader Header
     3418     * @return string
     3419     */
     3420    public function DKIM_HeaderC($signHeader)
     3421    {
     3422        $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
     3423        $lines = explode("\r\n", $signHeader);
     3424        foreach ($lines as $key => $line) {
     3425            list($heading, $value) = explode(':', $line, 2);
     3426            $heading = strtolower($heading);
     3427            $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
     3428            $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
     3429        }
     3430        $signHeader = implode("\r\n", $lines);
     3431        return $signHeader;
     3432    }
     3433
     3434    /**
     3435     * Generate a DKIM canonicalization body.
     3436     * @access public
     3437     * @param string $body Message Body
     3438     * @return string
     3439     */
     3440    public function DKIM_BodyC($body)
     3441    {
     3442        if ($body == '') {
     3443            return "\r\n";
     3444        }
     3445        // stabilize line endings
     3446        $body = str_replace("\r\n", "\n", $body);
     3447        $body = str_replace("\n", "\r\n", $body);
     3448        // END stabilize line endings
     3449        while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
     3450            $body = substr($body, 0, strlen($body) - 2);
     3451        }
     3452        return $body;
     3453    }
     3454
     3455    /**
     3456     * Create the DKIM header and body in a new message header.
     3457     * @access public
     3458     * @param string $headers_line Header lines
     3459     * @param string $subject Subject
     3460     * @param string $body Body
     3461     * @return string
     3462     */
     3463    public function DKIM_Add($headers_line, $subject, $body)
     3464    {
     3465        $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
     3466        $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
     3467        $DKIMquery = 'dns/txt'; // Query method
     3468        $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
     3469        $subject_header = "Subject: $subject";
     3470        $headers = explode($this->LE, $headers_line);
     3471        $from_header = '';
     3472        $to_header = '';
     3473        $current = '';
     3474        foreach ($headers as $header) {
     3475            if (strpos($header, 'From:') === 0) {
     3476                $from_header = $header;
     3477                $current = 'from_header';
     3478            } elseif (strpos($header, 'To:') === 0) {
     3479                $to_header = $header;
     3480                $current = 'to_header';
     3481            } else {
     3482                if (!empty($$current) && strpos($header, ' =?') === 0) {
     3483                    $$current .= $header;
     3484                } else {
     3485                    $current = '';
     3486                }
     3487            }
     3488        }
     3489        $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
     3490        $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
     3491        $subject = str_replace(
     3492            '|',
     3493            '=7C',
     3494            $this->DKIM_QP($subject_header)
     3495        ); // Copied header fields (dkim-quoted-printable)
     3496        $body = $this->DKIM_BodyC($body);
     3497        $DKIMlen = strlen($body); // Length of body
     3498        $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
     3499        if ('' == $this->DKIM_identity) {
     3500            $ident = '';
     3501        } else {
     3502            $ident = ' i=' . $this->DKIM_identity . ';';
     3503        }
     3504        $dkimhdrs = 'DKIM-Signature: v=1; a=' .
     3505            $DKIMsignatureType . '; q=' .
     3506            $DKIMquery . '; l=' .
     3507            $DKIMlen . '; s=' .
     3508            $this->DKIM_selector .
     3509            ";\r\n" .
     3510            "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
     3511            "\th=From:To:Subject;\r\n" .
     3512            "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
     3513            "\tz=$from\r\n" .
     3514            "\t|$to\r\n" .
     3515            "\t|$subject;\r\n" .
     3516            "\tbh=" . $DKIMb64 . ";\r\n" .
     3517            "\tb=";
     3518        $toSign = $this->DKIM_HeaderC(
     3519            $from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs
     3520        );
     3521        $signed = $this->DKIM_Sign($toSign);
     3522        return $dkimhdrs . $signed . "\r\n";
     3523    }
     3524
     3525    /**
     3526     * Detect if a string contains a line longer than the maximum line length allowed.
     3527     * @param string $str
     3528     * @return boolean
     3529     * @static
     3530     */
     3531    public static function hasLineLongerThanMax($str)
     3532    {
     3533        //+2 to include CRLF line break for a 1000 total
     3534        return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
     3535    }
     3536
     3537    /**
     3538     * Allows for public read access to 'to' property.
     3539     * @access public
     3540     * @return array
     3541     */
     3542    public function getToAddresses()
     3543    {
     3544        return $this->to;
     3545    }
     3546
     3547    /**
     3548     * Allows for public read access to 'cc' property.
     3549     * @access public
     3550     * @return array
     3551     */
     3552    public function getCcAddresses()
     3553    {
     3554        return $this->cc;
     3555    }
     3556
     3557    /**
     3558     * Allows for public read access to 'bcc' property.
     3559     * @access public
     3560     * @return array
     3561     */
     3562    public function getBccAddresses()
     3563    {
     3564        return $this->bcc;
     3565    }
     3566
     3567    /**
     3568     * Allows for public read access to 'ReplyTo' property.
     3569     * @access public
     3570     * @return array
     3571     */
     3572    public function getReplyToAddresses()
     3573    {
     3574        return $this->ReplyTo;
     3575    }
     3576
     3577    /**
     3578     * Allows for public read access to 'all_recipients' property.
     3579     * @access public
     3580     * @return array
     3581     */
     3582    public function getAllRecipientAddresses()
     3583    {
     3584        return $this->all_recipients;
     3585    }
     3586
     3587    /**
     3588     * Perform a callback.
     3589     * @param boolean $isSent
     3590     * @param array $to
     3591     * @param array $cc
     3592     * @param array $bcc
     3593     * @param string $subject
     3594     * @param string $body
     3595     * @param string $from
     3596     */
     3597    protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
     3598    {
     3599        if (!empty($this->action_function) && is_callable($this->action_function)) {
     3600            $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
     3601            call_user_func_array($this->action_function, $params);
     3602        }
     3603    }
    4803604}
    4813605
    4823606/**
    483  * Set the From and FromName properties
    484  * @param string $address
    485  * @param string $name
    486  * @return boolean
     3607 * PHPMailer exception handler
     3608 * @package PHPMailer
    4873609 */
    488   public function SetFrom($address, $name = '',$auto=1) {
    489     $address = trim($address);
    490     $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
    491     if (!self::ValidateAddress($address)) {
    492       $this->SetError($this->Lang('invalid_address').': '. $address);
    493       if ($this->exceptions) {
    494         throw new phpmailerException($this->Lang('invalid_address').': '.$address);
    495       }
    496       echo $this->Lang('invalid_address').': '.$address;
    497       return false;
    498     }
    499     $this->From = $address;
    500     $this->FromName = $name;
    501     if ($auto) {
    502       if (empty($this->ReplyTo)) {
    503         $this->AddAnAddress('ReplyTo', $address, $name);
    504       }
    505       if (empty($this->Sender)) {
    506         $this->Sender = $address;
    507       }
    508     }
    509     return true;
    510   }
    511 
    512   /**
    513    * Check that a string looks roughly like an email address should
    514    * Static so it can be used without instantiation
    515    * Tries to use PHP built-in validator in the filter extension (from PHP 5.2), falls back to a reasonably competent regex validator
    516    * Conforms approximately to RFC2822
    517    * @link http://www.hexillion.com/samples/#Regex Original pattern found here
    518    * @param string $address The email address to check
    519    * @return boolean
    520    * @static
    521    * @access public
    522    */
    523   public static function ValidateAddress($address) {
    524     if (function_exists('filter_var')) { //Introduced in PHP 5.2
    525       if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
    526         return false;
    527       } else {
    528         return true;
    529       }
    530     } else {
    531       return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
    532     }
    533   }
    534 
    535   /////////////////////////////////////////////////
    536   // METHODS, MAIL SENDING
    537   /////////////////////////////////////////////////
    538 
    539   /**
    540    * Creates message and assigns Mailer. If the message is
    541    * not sent successfully then it returns false.  Use the ErrorInfo
    542    * variable to view description of the error.
    543    * @return bool
    544    */
    545   public function Send() {
    546     try {
    547       if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
    548         throw new phpmailerException($this->Lang('provide_address'), self::STOP_CRITICAL);
    549       }
    550 
    551       // Set whether the message is multipart/alternative
    552       if(!empty($this->AltBody)) {
    553         $this->ContentType = 'multipart/alternative';
    554       }
    555 
    556       $this->error_count = 0; // reset errors
    557       $this->SetMessageType();
    558       $header = $this->CreateHeader();
    559       $body = $this->CreateBody();
    560 
    561       if (empty($this->Body)) {
    562         throw new phpmailerException($this->Lang('empty_message'), self::STOP_CRITICAL);
    563       }
    564 
    565       // digitally sign with DKIM if enabled
    566       if ($this->DKIM_domain && $this->DKIM_private) {
    567         $header_dkim = $this->DKIM_Add($header,$this->Subject,$body);
    568         $header = str_replace("\r\n","\n",$header_dkim) . $header;
    569       }
    570 
    571       // Choose the mailer and send through it
    572       switch($this->Mailer) {
    573         case 'sendmail':
    574           return $this->SendmailSend($header, $body);
    575         case 'smtp':
    576           return $this->SmtpSend($header, $body);
    577         default:
    578           return $this->MailSend($header, $body);
    579       }
    580 
    581     } catch (phpmailerException $e) {
    582       $this->SetError($e->getMessage());
    583       if ($this->exceptions) {
    584         throw $e;
    585       }
    586       echo $e->getMessage()."\n";
    587       return false;
    588     }
    589   }
    590 
    591   /**
    592    * Sends mail using the $Sendmail program.
    593    * @param string $header The message headers
    594    * @param string $body The message body
    595    * @access protected
    596    * @return bool
    597    */
    598   protected function SendmailSend($header, $body) {
    599     if ($this->Sender != '') {
    600       $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
    601     } else {
    602       $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
    603     }
    604     if ($this->SingleTo === true) {
    605       foreach ($this->SingleToArray as $key => $val) {
    606         if(!@$mail = popen($sendmail, 'w')) {
    607           throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    608         }
    609         fputs($mail, "To: " . $val . "\n");
    610         fputs($mail, $header);
    611         fputs($mail, $body);
    612         $result = pclose($mail);
    613         // implement call back function if it exists
    614         $isSent = ($result == 0) ? 1 : 0;
    615         $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
    616         if($result != 0) {
    617           throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    618         }
    619       }
    620     } else {
    621       if(!@$mail = popen($sendmail, 'w')) {
    622         throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    623       }
    624       fputs($mail, $header);
    625       fputs($mail, $body);
    626       $result = pclose($mail);
    627       // implement call back function if it exists
    628       $isSent = ($result == 0) ? 1 : 0;
    629       $this->doCallback($isSent,$this->to,$this->cc,$this->bcc,$this->Subject,$body);
    630       if($result != 0) {
    631         throw new phpmailerException($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
    632       }
    633     }
    634     return true;
    635   }
    636 
    637   /**
    638    * Sends mail using the PHP mail() function.
    639    * @param string $header The message headers
    640    * @param string $body The message body
    641    * @access protected
    642    * @return bool
    643    */
    644   protected function MailSend($header, $body) {
    645     $toArr = array();
    646     foreach($this->to as $t) {
    647       $toArr[] = $this->AddrFormat($t);
    648     }
    649     $to = implode(', ', $toArr);
    650 
    651     $params = sprintf("-oi -f %s", $this->Sender);
    652     if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
    653       $old_from = ini_get('sendmail_from');
    654       ini_set('sendmail_from', $this->Sender);
    655       if ($this->SingleTo === true && count($toArr) > 1) {
    656         foreach ($toArr as $key => $val) {
    657           $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
    658           // implement call back function if it exists
    659           $isSent = ($rt == 1) ? 1 : 0;
    660           $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
    661         }
    662       } else {
    663         $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
    664         // implement call back function if it exists
    665         $isSent = ($rt == 1) ? 1 : 0;
    666         $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
    667       }
    668     } else {
    669       if ($this->SingleTo === true && count($toArr) > 1) {
    670         foreach ($toArr as $key => $val) {
    671           $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
    672           // implement call back function if it exists
    673           $isSent = ($rt == 1) ? 1 : 0;
    674           $this->doCallback($isSent,$val,$this->cc,$this->bcc,$this->Subject,$body);
    675         }
    676       } else {
    677         $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
    678         // implement call back function if it exists
    679         $isSent = ($rt == 1) ? 1 : 0;
    680         $this->doCallback($isSent,$to,$this->cc,$this->bcc,$this->Subject,$body);
    681       }
    682     }
    683     if (isset($old_from)) {
    684       ini_set('sendmail_from', $old_from);
    685     }
    686     if(!$rt) {
    687       throw new phpmailerException($this->Lang('instantiate'), self::STOP_CRITICAL);
    688     }
    689     return true;
    690   }
    691 
    692   /**
    693    * Sends mail via SMTP using PhpSMTP
    694    * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
    695    * @param string $header The message headers
    696    * @param string $body The message body
    697    * @uses SMTP
    698    * @access protected
    699    * @return bool
    700    */
    701   protected function SmtpSend($header, $body) {
    702     require_once $this->PluginDir . 'class.smtp.php';
    703     $bad_rcpt = array();
    704 
    705     if(!$this->SmtpConnect()) {
    706       throw new phpmailerException($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
    707     }
    708     $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
    709     if(!$this->smtp->Mail($smtp_from)) {
    710       throw new phpmailerException($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
    711     }
    712 
    713     // Attempt to send attach all recipients
    714     foreach($this->to as $to) {
    715       if (!$this->smtp->Recipient($to[0])) {
    716         $bad_rcpt[] = $to[0];
    717         // implement call back function if it exists
    718         $isSent = 0;
    719         $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
    720       } else {
    721         // implement call back function if it exists
    722         $isSent = 1;
    723         $this->doCallback($isSent,$to[0],'','',$this->Subject,$body);
    724       }
    725     }
    726     foreach($this->cc as $cc) {
    727       if (!$this->smtp->Recipient($cc[0])) {
    728         $bad_rcpt[] = $cc[0];
    729         // implement call back function if it exists
    730         $isSent = 0;
    731         $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
    732       } else {
    733         // implement call back function if it exists
    734         $isSent = 1;
    735         $this->doCallback($isSent,'',$cc[0],'',$this->Subject,$body);
    736       }
    737     }
    738     foreach($this->bcc as $bcc) {
    739       if (!$this->smtp->Recipient($bcc[0])) {
    740         $bad_rcpt[] = $bcc[0];
    741         // implement call back function if it exists
    742         $isSent = 0;
    743         $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
    744       } else {
    745         // implement call back function if it exists
    746         $isSent = 1;
    747         $this->doCallback($isSent,'','',$bcc[0],$this->Subject,$body);
    748       }
    749     }
    750 
    751 
    752     if (count($bad_rcpt) > 0 ) { //Create error message for any bad addresses
    753       $badaddresses = implode(', ', $bad_rcpt);
    754       throw new phpmailerException($this->Lang('recipients_failed') . $badaddresses);
    755     }
    756     if(!$this->smtp->Data($header . $body)) {
    757       throw new phpmailerException($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
    758     }
    759     if($this->SMTPKeepAlive == true) {
    760       $this->smtp->Reset();
    761     }
    762     return true;
    763   }
    764 
    765   /**
    766    * Initiates a connection to an SMTP server.
    767    * Returns false if the operation failed.
    768    * @uses SMTP
    769    * @access public
    770    * @return bool
    771    */
    772   public function SmtpConnect() {
    773     if(is_null($this->smtp)) {
    774       $this->smtp = new SMTP();
    775     }
    776 
    777     $this->smtp->do_debug = $this->SMTPDebug;
    778     $hosts = explode(';', $this->Host);
    779     $index = 0;
    780     $connection = $this->smtp->Connected();
    781 
    782     // Retry while there is no connection
    783     try {
    784       while($index < count($hosts) && !$connection) {
    785         $hostinfo = array();
    786         if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
    787           $host = $hostinfo[1];
    788           $port = $hostinfo[2];
    789         } else {
    790           $host = $hosts[$index];
    791           $port = $this->Port;
    792         }
    793 
    794         $tls = ($this->SMTPSecure == 'tls');
    795         $ssl = ($this->SMTPSecure == 'ssl');
    796 
    797         if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
    798 
    799           $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
    800           $this->smtp->Hello($hello);
    801 
    802           if ($tls) {
    803             if (!$this->smtp->StartTLS()) {
    804               throw new phpmailerException($this->Lang('tls'));
    805             }
    806 
    807             //We must resend HELO after tls negotiation
    808             $this->smtp->Hello($hello);
    809           }
    810 
    811           $connection = true;
    812           if ($this->SMTPAuth) {
    813             if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
    814               throw new phpmailerException($this->Lang('authenticate'));
    815             }
    816           }
    817         }
    818         $index++;
    819         if (!$connection) {
    820           throw new phpmailerException($this->Lang('connect_host'));
    821         }
    822       }
    823     } catch (phpmailerException $e) {
    824       $this->smtp->Reset();
    825       throw $e;
    826     }
    827     return true;
    828   }
    829 
    830   /**
    831    * Closes the active SMTP session if one exists.
    832    * @return void
    833    */
    834   public function SmtpClose() {
    835     if(!is_null($this->smtp)) {
    836       if($this->smtp->Connected()) {
    837         $this->smtp->Quit();
    838         $this->smtp->Close();
    839       }
    840     }
    841   }
    842 
    843   /**
    844   * Sets the language for all class error messages.
    845   * Returns false if it cannot load the language file.  The default language is English.
    846   * @param string $langcode ISO 639-1 2-character language code (e.g. Portuguese: "br")
    847   * @param string $lang_path Path to the language file directory
    848   * @access public
    849   */
    850   function SetLanguage($langcode = 'en', $lang_path = 'language/') {
    851     //Define full set of translatable strings
    852     $PHPMAILER_LANG = array(
    853       'provide_address' => 'You must provide at least one recipient email address.',
    854       'mailer_not_supported' => ' mailer is not supported.',
    855       'execute' => 'Could not execute: ',
    856       'instantiate' => 'Could not instantiate mail function.',
    857       'authenticate' => 'SMTP Error: Could not authenticate.',
    858       'from_failed' => 'The following From address failed: ',
    859       'recipients_failed' => 'SMTP Error: The following recipients failed: ',
    860       'data_not_accepted' => 'SMTP Error: Data not accepted.',
    861       'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
    862       'file_access' => 'Could not access file: ',
    863       'file_open' => 'File Error: Could not open file: ',
    864       'encoding' => 'Unknown encoding: ',
    865       'signing' => 'Signing Error: ',
    866       'smtp_error' => 'SMTP server error: ',
    867       'empty_message' => 'Message body empty',
    868       'invalid_address' => 'Invalid address',
    869       'variable_set' => 'Cannot set or reset variable: '
    870     );
    871     //Overwrite language-specific strings. This way we'll never have missing translations - no more "language string failed to load"!
    872     $l = true;
    873     if ($langcode != 'en') { //There is no English translation file
    874       $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
    875     }
    876     $this->language = $PHPMAILER_LANG;
    877     return ($l == true); //Returns false if language not found
    878   }
    879 
    880   /**
    881   * Return the current array of language strings
    882   * @return array
    883   */
    884   public function GetTranslations() {
    885     return $this->language;
    886   }
    887 
    888   /////////////////////////////////////////////////
    889   // METHODS, MESSAGE CREATION
    890   /////////////////////////////////////////////////
    891 
    892   /**
    893    * Creates recipient headers.
    894    * @access public
    895    * @return string
    896    */
    897   public function AddrAppend($type, $addr) {
    898     $addr_str = $type . ': ';
    899     $addresses = array();
    900     foreach ($addr as $a) {
    901       $addresses[] = $this->AddrFormat($a);
    902     }
    903     $addr_str .= implode(', ', $addresses);
    904     $addr_str .= $this->LE;
    905 
    906     return $addr_str;
    907   }
    908 
    909   /**
    910    * Formats an address correctly.
    911    * @access public
    912    * @return string
    913    */
    914   public function AddrFormat($addr) {
    915     if (empty($addr[1])) {
    916       return $this->SecureHeader($addr[0]);
    917     } else {
    918       return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
    919     }
    920   }
    921 
    922   /**
    923    * Wraps message for use with mailers that do not
    924    * automatically perform wrapping and for quoted-printable.
    925    * Original written by philippe.
    926    * @param string $message The message to wrap
    927    * @param integer $length The line length to wrap to
    928    * @param boolean $qp_mode Whether to run in Quoted-Printable mode
    929    * @access public
    930    * @return string
    931    */
    932   public function WrapText($message, $length, $qp_mode = false) {
    933     $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
    934     // If utf-8 encoding is used, we will need to make sure we don't
    935     // split multibyte characters when we wrap
    936     $is_utf8 = (strtolower($this->CharSet) == "utf-8");
    937 
    938     $message = $this->FixEOL($message);
    939     if (substr($message, -1) == $this->LE) {
    940       $message = substr($message, 0, -1);
    941     }
    942 
    943     $line = explode($this->LE, $message);
    944     $message = '';
    945     for ($i=0 ;$i < count($line); $i++) {
    946       $line_part = explode(' ', $line[$i]);
    947       $buf = '';
    948       for ($e = 0; $e<count($line_part); $e++) {
    949         $word = $line_part[$e];
    950         if ($qp_mode and (strlen($word) > $length)) {
    951           $space_left = $length - strlen($buf) - 1;
    952           if ($e != 0) {
    953             if ($space_left > 20) {
    954               $len = $space_left;
    955               if ($is_utf8) {
    956                 $len = $this->UTF8CharBoundary($word, $len);
    957               } elseif (substr($word, $len - 1, 1) == "=") {
    958                 $len--;
    959               } elseif (substr($word, $len - 2, 1) == "=") {
    960                 $len -= 2;
    961               }
    962               $part = substr($word, 0, $len);
    963               $word = substr($word, $len);
    964               $buf .= ' ' . $part;
    965               $message .= $buf . sprintf("=%s", $this->LE);
    966             } else {
    967               $message .= $buf . $soft_break;
    968             }
    969             $buf = '';
    970           }
    971           while (strlen($word) > 0) {
    972             $len = $length;
    973             if ($is_utf8) {
    974               $len = $this->UTF8CharBoundary($word, $len);
    975             } elseif (substr($word, $len - 1, 1) == "=") {
    976               $len--;
    977             } elseif (substr($word, $len - 2, 1) == "=") {
    978               $len -= 2;
    979             }
    980             $part = substr($word, 0, $len);
    981             $word = substr($word, $len);
    982 
    983             if (strlen($word) > 0) {
    984               $message .= $part . sprintf("=%s", $this->LE);
    985             } else {
    986               $buf = $part;
    987             }
    988           }
    989         } else {
    990           $buf_o = $buf;
    991           $buf .= ($e == 0) ? $word : (' ' . $word);
    992 
    993           if (strlen($buf) > $length and $buf_o != '') {
    994             $message .= $buf_o . $soft_break;
    995             $buf = $word;
    996           }
    997         }
    998       }
    999       $message .= $buf . $this->LE;
    1000     }
    1001 
    1002     return $message;
    1003   }
    1004 
    1005   /**
    1006    * Finds last character boundary prior to maxLength in a utf-8
    1007    * quoted (printable) encoded string.
    1008    * Original written by Colin Brown.
    1009    * @access public
    1010    * @param string $encodedText utf-8 QP text
    1011    * @param int    $maxLength   find last character boundary prior to this length
    1012    * @return int
    1013    */
    1014   public function UTF8CharBoundary($encodedText, $maxLength) {
    1015     $foundSplitPos = false;
    1016     $lookBack = 3;
    1017     while (!$foundSplitPos) {
    1018       $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
    1019       $encodedCharPos = strpos($lastChunk, "=");
    1020       if ($encodedCharPos !== false) {
    1021         // Found start of encoded character byte within $lookBack block.
    1022         // Check the encoded byte value (the 2 chars after the '=')
    1023         $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
    1024         $dec = hexdec($hex);
    1025         if ($dec < 128) { // Single byte character.
    1026           // If the encoded char was found at pos 0, it will fit
    1027           // otherwise reduce maxLength to start of the encoded char
    1028           $maxLength = ($encodedCharPos == 0) ? $maxLength :
    1029           $maxLength - ($lookBack - $encodedCharPos);
    1030           $foundSplitPos = true;
    1031         } elseif ($dec >= 192) { // First byte of a multi byte character
    1032           // Reduce maxLength to split at start of character
    1033           $maxLength = $maxLength - ($lookBack - $encodedCharPos);
    1034           $foundSplitPos = true;
    1035         } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
    1036           $lookBack += 3;
    1037         }
    1038       } else {
    1039         // No encoded character found
    1040         $foundSplitPos = true;
    1041       }
    1042     }
    1043     return $maxLength;
    1044   }
    1045 
    1046 
    1047   /**
    1048    * Set the body wrapping.
    1049    * @access public
    1050    * @return void
    1051    */
    1052   public function SetWordWrap() {
    1053     if($this->WordWrap < 1) {
    1054       return;
    1055     }
    1056 
    1057     switch($this->message_type) {
    1058       case 'alt':
    1059       case 'alt_attachments':
    1060         $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
    1061         break;
    1062       default:
    1063         $this->Body = $this->WrapText($this->Body, $this->WordWrap);
    1064         break;
    1065     }
    1066   }
    1067 
    1068   /**
    1069    * Assembles message header.
    1070    * @access public
    1071    * @return string The assembled header
    1072    */
    1073   public function CreateHeader() {
    1074     $result = '';
    1075 
    1076     // Set the boundaries
    1077     $uniq_id = md5(uniqid(time()));
    1078     $this->boundary[1] = 'b1_' . $uniq_id;
    1079     $this->boundary[2] = 'b2_' . $uniq_id;
    1080 
    1081     $result .= $this->HeaderLine('Date', self::RFCDate());
    1082     if($this->Sender == '') {
    1083       $result .= $this->HeaderLine('Return-Path', trim($this->From));
    1084     } else {
    1085       $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
    1086     }
    1087 
    1088     // To be created automatically by mail()
    1089     if($this->Mailer != 'mail') {
    1090       if ($this->SingleTo === true) {
    1091         foreach($this->to as $t) {
    1092           $this->SingleToArray[] = $this->AddrFormat($t);
    1093         }
    1094       } else {
    1095         if(count($this->to) > 0) {
    1096           $result .= $this->AddrAppend('To', $this->to);
    1097         } elseif (count($this->cc) == 0) {
    1098           $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
    1099         }
    1100       }
    1101     }
    1102 
    1103     $from = array();
    1104     $from[0][0] = trim($this->From);
    1105     $from[0][1] = $this->FromName;
    1106     $result .= $this->AddrAppend('From', $from);
    1107 
    1108     // sendmail and mail() extract Cc from the header before sending
    1109     if(count($this->cc) > 0) {
    1110       $result .= $this->AddrAppend('Cc', $this->cc);
    1111     }
    1112 
    1113     // sendmail and mail() extract Bcc from the header before sending
    1114     if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
    1115       $result .= $this->AddrAppend('Bcc', $this->bcc);
    1116     }
    1117 
    1118     if(count($this->ReplyTo) > 0) {
    1119       $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
    1120     }
    1121 
    1122     // mail() sets the subject itself
    1123     if($this->Mailer != 'mail') {
    1124       $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
    1125     }
    1126 
    1127     if($this->MessageID != '') {
    1128       $result .= $this->HeaderLine('Message-ID',$this->MessageID);
    1129     } else {
    1130       $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
    1131     }
    1132     $result .= $this->HeaderLine('X-Priority', $this->Priority);
    1133     $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (phpmailer.sourceforge.net)');
    1134 
    1135     if($this->ConfirmReadingTo != '') {
    1136       $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
    1137     }
    1138 
    1139     // Add custom headers
    1140     for($index = 0; $index < count($this->CustomHeader); $index++) {
    1141       $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
    1142     }
    1143     if (!$this->sign_key_file) {
    1144       $result .= $this->HeaderLine('MIME-Version', '1.0');
    1145       $result .= $this->GetMailMIME();
    1146     }
    1147 
    1148     return $result;
    1149   }
    1150 
    1151   /**
    1152    * Returns the message MIME.
    1153    * @access public
    1154    * @return string
    1155    */
    1156   public function GetMailMIME() {
    1157     $result = '';
    1158     switch($this->message_type) {
    1159       case 'plain':
    1160         $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
    1161         $result .= sprintf("Content-Type: %s; charset=%s", $this->ContentType, $this->CharSet);
    1162         break;
    1163       case 'attachments':
    1164       case 'alt_attachments':
    1165         if($this->InlineImageExists()){
    1166           $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
    1167         } else {
    1168           $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
    1169           $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
    1170         }
    1171         break;
    1172       case 'alt':
    1173         $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
    1174         $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
    1175         break;
    1176     }
    1177 
    1178     if($this->Mailer != 'mail') {
    1179       $result .= $this->LE.$this->LE;
    1180     }
    1181 
    1182     return $result;
    1183   }
    1184 
    1185   /**
    1186    * Assembles the message body.  Returns an empty string on failure.
    1187    * @access public
    1188    * @return string The assembled message body
    1189    */
    1190   public function CreateBody() {
    1191     $body = '';
    1192 
    1193     if ($this->sign_key_file) {
    1194       $body .= $this->GetMailMIME();
    1195     }
    1196 
    1197     $this->SetWordWrap();
    1198 
    1199     switch($this->message_type) {
    1200       case 'alt':
    1201         $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
    1202         $body .= $this->EncodeString($this->AltBody, $this->Encoding);
    1203         $body .= $this->LE.$this->LE;
    1204         $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
    1205         $body .= $this->EncodeString($this->Body, $this->Encoding);
    1206         $body .= $this->LE.$this->LE;
    1207         $body .= $this->EndBoundary($this->boundary[1]);
    1208         break;
    1209       case 'plain':
    1210         $body .= $this->EncodeString($this->Body, $this->Encoding);
    1211         break;
    1212       case 'attachments':
    1213         $body .= $this->GetBoundary($this->boundary[1], '', '', '');
    1214         $body .= $this->EncodeString($this->Body, $this->Encoding);
    1215         $body .= $this->LE;
    1216         $body .= $this->AttachAll();
    1217         break;
    1218       case 'alt_attachments':
    1219         $body .= sprintf("--%s%s", $this->boundary[1], $this->LE);
    1220         $body .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
    1221         $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
    1222         $body .= $this->EncodeString($this->AltBody, $this->Encoding);
    1223         $body .= $this->LE.$this->LE;
    1224         $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
    1225         $body .= $this->EncodeString($this->Body, $this->Encoding);
    1226         $body .= $this->LE.$this->LE;
    1227         $body .= $this->EndBoundary($this->boundary[2]);
    1228         $body .= $this->AttachAll();
    1229         break;
    1230     }
    1231 
    1232     if ($this->IsError()) {
    1233       $body = '';
    1234     } elseif ($this->sign_key_file) {
    1235       try {
    1236         $file = tempnam('', 'mail');
    1237         file_put_contents($file, $body); //TODO check this worked
    1238         $signed = tempnam("", "signed");
    1239         if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
    1240           @unlink($file);
    1241           @unlink($signed);
    1242           $body = file_get_contents($signed);
    1243         } else {
    1244           @unlink($file);
    1245           @unlink($signed);
    1246           throw new phpmailerException($this->Lang("signing").openssl_error_string());
    1247         }
    1248       } catch (phpmailerException $e) {
    1249         $body = '';
    1250         if ($this->exceptions) {
    1251           throw $e;
    1252         }
    1253       }
    1254     }
    1255 
    1256     return $body;
    1257   }
    1258 
    1259   /**
    1260    * Returns the start of a message boundary.
    1261    * @access private
    1262    */
    1263   private function GetBoundary($boundary, $charSet, $contentType, $encoding) {
    1264     $result = '';
    1265     if($charSet == '') {
    1266       $charSet = $this->CharSet;
    1267     }
    1268     if($contentType == '') {
    1269       $contentType = $this->ContentType;
    1270     }
    1271     if($encoding == '') {
    1272       $encoding = $this->Encoding;
    1273     }
    1274     $result .= $this->TextLine('--' . $boundary);
    1275     $result .= sprintf("Content-Type: %s; charset=%s", $contentType, $charSet);
    1276     $result .= $this->LE;
    1277     $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
    1278     $result .= $this->LE;
    1279 
    1280     return $result;
    1281   }
    1282 
    1283   /**
    1284    * Returns the end of a message boundary.
    1285    * @access private
    1286    */
    1287   private function EndBoundary($boundary) {
    1288     return $this->LE . '--' . $boundary . '--' . $this->LE;
    1289   }
    1290 
    1291   /**
    1292    * Sets the message type.
    1293    * @access private
    1294    * @return void
    1295    */
    1296   private function SetMessageType() {
    1297     if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
    1298       $this->message_type = 'plain';
    1299     } else {
    1300       if(count($this->attachment) > 0) {
    1301         $this->message_type = 'attachments';
    1302       }
    1303       if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
    1304         $this->message_type = 'alt';
    1305       }
    1306       if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
    1307         $this->message_type = 'alt_attachments';
    1308       }
    1309     }
    1310   }
    1311 
    1312   /**
    1313    *  Returns a formatted header line.
    1314    * @access public
    1315    * @return string
    1316    */
    1317   public function HeaderLine($name, $value) {
    1318     return $name . ': ' . $value . $this->LE;
    1319   }
    1320 
    1321   /**
    1322    * Returns a formatted mail line.
    1323    * @access public
    1324    * @return string
    1325    */
    1326   public function TextLine($value) {
    1327     return $value . $this->LE;
    1328   }
    1329 
    1330   /////////////////////////////////////////////////
    1331   // CLASS METHODS, ATTACHMENTS
    1332   /////////////////////////////////////////////////
    1333 
    1334   /**
    1335    * Adds an attachment from a path on the filesystem.
    1336    * Returns false if the file could not be found
    1337    * or accessed.
    1338    * @param string $path Path to the attachment.
    1339    * @param string $name Overrides the attachment name.
    1340    * @param string $encoding File encoding (see $Encoding).
    1341    * @param string $type File extension (MIME) type.
    1342    * @return bool
    1343    */
    1344   public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
    1345     try {
    1346       if ( !@is_file($path) ) {
    1347         throw new phpmailerException($this->Lang('file_access') . $path, self::STOP_CONTINUE);
    1348       }
    1349       $filename = basename($path);
    1350       if ( $name == '' ) {
    1351         $name = $filename;
    1352       }
    1353 
    1354       $this->attachment[] = array(
    1355         0 => $path,
    1356         1 => $filename,
    1357         2 => $name,
    1358         3 => $encoding,
    1359         4 => $type,
    1360         5 => false,  // isStringAttachment
    1361         6 => 'attachment',
    1362         7 => 0
    1363       );
    1364 
    1365     } catch (phpmailerException $e) {
    1366       $this->SetError($e->getMessage());
    1367       if ($this->exceptions) {
    1368         throw $e;
    1369       }
    1370       echo $e->getMessage()."\n";
    1371       if ( $e->getCode() == self::STOP_CRITICAL ) {
    1372         return false;
    1373       }
    1374     }
    1375     return true;
    1376   }
    1377 
    1378   /**
    1379   * Return the current array of attachments
    1380   * @return array
    1381   */
    1382   public function GetAttachments() {
    1383     return $this->attachment;
    1384   }
    1385 
    1386   /**
    1387    * Attaches all fs, string, and binary attachments to the message.
    1388    * Returns an empty string on failure.
    1389    * @access private
    1390    * @return string
    1391    */
    1392   private function AttachAll() {
    1393     // Return text of body
    1394     $mime = array();
    1395     $cidUniq = array();
    1396     $incl = array();
    1397 
    1398     // Add all attachments
    1399     foreach ($this->attachment as $attachment) {
    1400       // Check for string attachment
    1401       $bString = $attachment[5];
    1402       if ($bString) {
    1403         $string = $attachment[0];
    1404       } else {
    1405         $path = $attachment[0];
    1406       }
    1407 
    1408       if (in_array($attachment[0], $incl)) { continue; }
    1409       $filename    = $attachment[1];
    1410       $name        = $attachment[2];
    1411       $encoding    = $attachment[3];
    1412       $type        = $attachment[4];
    1413       $disposition = $attachment[6];
    1414       $cid         = $attachment[7];
    1415       $incl[]      = $attachment[0];
    1416       if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
    1417       $cidUniq[$cid] = true;
    1418 
    1419       $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
    1420       $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
    1421       $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
    1422 
    1423       if($disposition == 'inline') {
    1424         $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
    1425       }
    1426 
    1427       $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
    1428 
    1429       // Encode as string attachment
    1430       if($bString) {
    1431         $mime[] = $this->EncodeString($string, $encoding);
    1432         if($this->IsError()) {
    1433           return '';
    1434         }
    1435         $mime[] = $this->LE.$this->LE;
    1436       } else {
    1437         $mime[] = $this->EncodeFile($path, $encoding);
    1438         if($this->IsError()) {
    1439           return '';
    1440         }
    1441         $mime[] = $this->LE.$this->LE;
    1442       }
    1443     }
    1444 
    1445     $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
    1446 
    1447     return join('', $mime);
    1448   }
    1449 
    1450   /**
    1451    * Encodes attachment in requested format.
    1452    * Returns an empty string on failure.
    1453    * @param string $path The full path to the file
    1454    * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
    1455    * @see EncodeFile()
    1456    * @access private
    1457    * @return string
    1458    */
    1459   private function EncodeFile($path, $encoding = 'base64') {
    1460     try {
    1461       if (!is_readable($path)) {
    1462         throw new phpmailerException($this->Lang('file_open') . $path, self::STOP_CONTINUE);
    1463       }
    1464       if (!function_exists('get_magic_quotes')) {
    1465         function get_magic_quotes() {
    1466           return false;
    1467         }
    1468       }
    1469       if (PHP_VERSION < 6
    1470                           AND $magic_quotes = get_magic_quotes_runtime()) {
    1471         set_magic_quotes_runtime(0);
    1472       }
    1473       $file_buffer  = file_get_contents($path);
    1474       $file_buffer  = $this->EncodeString($file_buffer, $encoding);
    1475       if (PHP_VERSION < 6 AND $magic_quotes) { set_magic_quotes_runtime($magic_quotes); }
    1476       return $file_buffer;
    1477     } catch (Exception $e) {
    1478       $this->SetError($e->getMessage());
    1479       return '';
    1480     }
    1481   }
    1482 
    1483   /**
    1484    * Encodes string to requested format.
    1485    * Returns an empty string on failure.
    1486    * @param string $str The text to encode
    1487    * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
    1488    * @access public
    1489    * @return string
    1490    */
    1491   public function EncodeString ($str, $encoding = 'base64') {
    1492     $encoded = '';
    1493     switch(strtolower($encoding)) {
    1494       case 'base64':
    1495         $encoded = chunk_split(base64_encode($str), 76, $this->LE);
    1496         break;
    1497       case '7bit':
    1498       case '8bit':
    1499         $encoded = $this->FixEOL($str);
    1500         //Make sure it ends with a line break
    1501         if (substr($encoded, -(strlen($this->LE))) != $this->LE)
    1502           $encoded .= $this->LE;
    1503         break;
    1504       case 'binary':
    1505         $encoded = $str;
    1506         break;
    1507       case 'quoted-printable':
    1508         $encoded = $this->EncodeQP($str);
    1509         break;
    1510       default:
    1511         $this->SetError($this->Lang('encoding') . $encoding);
    1512         break;
    1513     }
    1514     return $encoded;
    1515   }
    1516 
    1517   /**
    1518    * Encode a header string to best (shortest) of Q, B, quoted or none.
    1519    * @access public
    1520    * @return string
    1521    */
    1522   public function EncodeHeader($str, $position = 'text') {
    1523     $x = 0;
    1524 
    1525     switch (strtolower($position)) {
    1526       case 'phrase':
    1527         if (!preg_match('/[\200-\377]/', $str)) {
    1528           // Can't use addslashes as we don't know what value has magic_quotes_sybase
    1529           $encoded = addcslashes($str, "\0..\37\177\\\"");
    1530           if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
    1531             return ($encoded);
    1532           } else {
    1533             return ("\"$encoded\"");
    1534           }
    1535         }
    1536         $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
    1537         break;
    1538       case 'comment':
    1539         $x = preg_match_all('/[()"]/', $str, $matches);
    1540         // Fall-through
    1541       case 'text':
    1542       default:
    1543         $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
    1544         break;
    1545     }
    1546 
    1547     if ($x == 0) {
    1548       return ($str);
    1549     }
    1550 
    1551     $maxlen = 75 - 7 - strlen($this->CharSet);
    1552     // Try to select the encoding which should produce the shortest output
    1553     if (strlen($str)/3 < $x) {
    1554       $encoding = 'B';
    1555       if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
    1556         // Use a custom function which correctly encodes and wraps long
    1557         // multibyte strings without breaking lines within a character
    1558         $encoded = $this->Base64EncodeWrapMB($str);
    1559       } else {
    1560         $encoded = base64_encode($str);
    1561         $maxlen -= $maxlen % 4;
    1562         $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
    1563       }
    1564     } else {
    1565       $encoding = 'Q';
    1566       $encoded = $this->EncodeQ($str, $position);
    1567       $encoded = $this->WrapText($encoded, $maxlen, true);
    1568       $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
    1569     }
    1570 
    1571     $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
    1572     $encoded = trim(str_replace("\n", $this->LE, $encoded));
    1573 
    1574     return $encoded;
    1575   }
    1576 
    1577   /**
    1578    * Checks if a string contains multibyte characters.
    1579    * @access public
    1580    * @param string $str multi-byte text to wrap encode
    1581    * @return bool
    1582    */
    1583   public function HasMultiBytes($str) {
    1584     if (function_exists('mb_strlen')) {
    1585       return (strlen($str) > mb_strlen($str, $this->CharSet));
    1586     } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
    1587       return false;
    1588     }
    1589   }
    1590 
    1591   /**
    1592    * Correctly encodes and wraps long multibyte strings for mail headers
    1593    * without breaking lines within a character.
    1594    * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
    1595    * @access public
    1596    * @param string $str multi-byte text to wrap encode
    1597    * @return string
    1598    */
    1599   public function Base64EncodeWrapMB($str) {
    1600     $start = "=?".$this->CharSet."?B?";
    1601     $end = "?=";
    1602     $encoded = "";
    1603 
    1604     $mb_length = mb_strlen($str, $this->CharSet);
    1605     // Each line must have length <= 75, including $start and $end
    1606     $length = 75 - strlen($start) - strlen($end);
    1607     // Average multi-byte ratio
    1608     $ratio = $mb_length / strlen($str);
    1609     // Base64 has a 4:3 ratio
    1610     $offset = $avgLength = floor($length * $ratio * .75);
    1611 
    1612     for ($i = 0; $i < $mb_length; $i += $offset) {
    1613       $lookBack = 0;
    1614 
    1615       do {
    1616         $offset = $avgLength - $lookBack;
    1617         $chunk = mb_substr($str, $i, $offset, $this->CharSet);
    1618         $chunk = base64_encode($chunk);
    1619         $lookBack++;
    1620       }
    1621       while (strlen($chunk) > $length);
    1622 
    1623       $encoded .= $chunk . $this->LE;
    1624     }
    1625 
    1626     // Chomp the last linefeed
    1627     $encoded = substr($encoded, 0, -strlen($this->LE));
    1628     return $encoded;
    1629   }
    1630 
    1631   /**
    1632   * Encode string to quoted-printable.
    1633   * Only uses standard PHP, slow, but will always work
    1634   * @access public
    1635   * @param string $string the text to encode
    1636   * @param integer $line_max Number of chars allowed on a line before wrapping
    1637   * @return string
    1638   */
    1639   public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
    1640     $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
    1641     $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
    1642     $eol = "\r\n";
    1643     $escape = '=';
    1644     $output = '';
    1645     while( list(, $line) = each($lines) ) {
    1646       $linlen = strlen($line);
    1647       $newline = '';
    1648       for($i = 0; $i < $linlen; $i++) {
    1649         $c = substr( $line, $i, 1 );
    1650         $dec = ord( $c );
    1651         if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
    1652           $c = '=2E';
    1653         }
    1654         if ( $dec == 32 ) {
    1655           if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
    1656             $c = '=20';
    1657           } else if ( $space_conv ) {
    1658             $c = '=20';
    1659           }
    1660         } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
    1661           $h2 = floor($dec/16);
    1662           $h1 = floor($dec%16);
    1663           $c = $escape.$hex[$h2].$hex[$h1];
    1664         }
    1665         if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
    1666           $output .= $newline.$escape.$eol; //  soft line break; " =\r\n" is okay
    1667           $newline = '';
    1668           // check if newline first character will be point or not
    1669           if ( $dec == 46 ) {
    1670             $c = '=2E';
    1671           }
    1672         }
    1673         $newline .= $c;
    1674       } // end of for
    1675       $output .= $newline.$eol;
    1676     } // end of while
    1677     return $output;
    1678   }
    1679 
    1680   /**
    1681   * Encode string to RFC2045 (6.7) quoted-printable format
    1682   * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version
    1683   * Also results in same content as you started with after decoding
    1684   * @see EncodeQPphp()
    1685   * @access public
    1686   * @param string $string the text to encode
    1687   * @param integer $line_max Number of chars allowed on a line before wrapping
    1688   * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function
    1689   * @return string
    1690   * @author Marcus Bointon
    1691   */
    1692   public function EncodeQP($string, $line_max = 76, $space_conv = false) {
    1693     if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3)
    1694       return quoted_printable_encode($string);
    1695     }
    1696     $filters = stream_get_filters();
    1697     if (!in_array('convert.*', $filters)) { //Got convert stream filter?
    1698       return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation
    1699     }
    1700     $fp = fopen('php://temp/', 'r+');
    1701     $string = preg_replace('/\r\n?/', $this->LE, $string); //Normalise line breaks
    1702     $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
    1703     $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
    1704     fputs($fp, $string);
    1705     rewind($fp);
    1706     $out = stream_get_contents($fp);
    1707     stream_filter_remove($s);
    1708     $out = preg_replace('/^\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange
    1709     fclose($fp);
    1710     return $out;
    1711   }
    1712 
    1713   /**
    1714    * Encode string to q encoding.
    1715    * @link http://tools.ietf.org/html/rfc2047
    1716    * @param string $str the text to encode
    1717    * @param string $position Where the text is going to be used, see the RFC for what that means
    1718    * @access public
    1719    * @return string
    1720    */
    1721   public function EncodeQ ($str, $position = 'text') {
    1722     // There should not be any EOL in the string
    1723     $encoded = preg_replace('/[\r\n]*/', '', $str);
    1724 
    1725     switch (strtolower($position)) {
    1726       case 'phrase':
    1727         $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1728         break;
    1729       case 'comment':
    1730         $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1731       case 'text':
    1732       default:
    1733         // Replace every high ascii, control =, ? and _ characters
    1734         //TODO using /e (equivalent to eval()) is probably not a good idea
    1735         $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
    1736               "'='.sprintf('%02X', ord('\\1'))", $encoded);
    1737         break;
    1738     }
    1739 
    1740     // Replace every spaces to _ (more readable than =20)
    1741     $encoded = str_replace(' ', '_', $encoded);
    1742 
    1743     return $encoded;
    1744   }
    1745 
    1746   /**
    1747    * Adds a string or binary attachment (non-filesystem) to the list.
    1748    * This method can be used to attach ascii or binary data,
    1749    * such as a BLOB record from a database.
    1750    * @param string $string String attachment data.
    1751    * @param string $filename Name of the attachment.
    1752    * @param string $encoding File encoding (see $Encoding).
    1753    * @param string $type File extension (MIME) type.
    1754    * @return void
    1755    */
    1756   public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
    1757     // Append to $attachment array
    1758     $this->attachment[] = array(
    1759       0 => $string,
    1760       1 => $filename,
    1761       2 => basename($filename),
    1762       3 => $encoding,
    1763       4 => $type,
    1764       5 => true,  // isStringAttachment
    1765       6 => 'attachment',
    1766       7 => 0
    1767     );
    1768   }
    1769 
    1770   /**
    1771    * Adds an embedded attachment.  This can include images, sounds, and
    1772    * just about any other document.  Make sure to set the $type to an
    1773    * image type.  For JPEG images use "image/jpeg" and for GIF images
    1774    * use "image/gif".
    1775    * @param string $path Path to the attachment.
    1776    * @param string $cid Content ID of the attachment.  Use this to identify
    1777    *        the Id for accessing the image in an HTML form.
    1778    * @param string $name Overrides the attachment name.
    1779    * @param string $encoding File encoding (see $Encoding).
    1780    * @param string $type File extension (MIME) type.
    1781    * @return bool
    1782    */
    1783   public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
    1784 
    1785     if ( !@is_file($path) ) {
    1786       $this->SetError($this->Lang('file_access') . $path);
    1787       return false;
    1788     }
    1789 
    1790     $filename = basename($path);
    1791     if ( $name == '' ) {
    1792       $name = $filename;
    1793     }
    1794 
    1795     // Append to $attachment array
    1796     $this->attachment[] = array(
    1797       0 => $path,
    1798       1 => $filename,
    1799       2 => $name,
    1800       3 => $encoding,
    1801       4 => $type,
    1802       5 => false,  // isStringAttachment
    1803       6 => 'inline',
    1804       7 => $cid
    1805     );
    1806 
    1807     return true;
    1808   }
    1809 
    1810   /**
    1811    * Returns true if an inline attachment is present.
    1812    * @access public
    1813    * @return bool
    1814    */
    1815   public function InlineImageExists() {
    1816     foreach($this->attachment as $attachment) {
    1817       if ($attachment[6] == 'inline') {
    1818         return true;
    1819       }
    1820     }
    1821     return false;
    1822   }
    1823 
    1824   /////////////////////////////////////////////////
    1825   // CLASS METHODS, MESSAGE RESET
    1826   /////////////////////////////////////////////////
    1827 
    1828   /**
    1829    * Clears all recipients assigned in the TO array.  Returns void.
    1830    * @return void
    1831    */
    1832   public function ClearAddresses() {
    1833     foreach($this->to as $to) {
    1834       unset($this->all_recipients[strtolower($to[0])]);
    1835     }
    1836     $this->to = array();
    1837   }
    1838 
    1839   /**
    1840    * Clears all recipients assigned in the CC array.  Returns void.
    1841    * @return void
    1842    */
    1843   public function ClearCCs() {
    1844     foreach($this->cc as $cc) {
    1845       unset($this->all_recipients[strtolower($cc[0])]);
    1846     }
    1847     $this->cc = array();
    1848   }
    1849 
    1850   /**
    1851    * Clears all recipients assigned in the BCC array.  Returns void.
    1852    * @return void
    1853    */
    1854   public function ClearBCCs() {
    1855     foreach($this->bcc as $bcc) {
    1856       unset($this->all_recipients[strtolower($bcc[0])]);
    1857     }
    1858     $this->bcc = array();
    1859   }
    1860 
    1861   /**
    1862    * Clears all recipients assigned in the ReplyTo array.  Returns void.
    1863    * @return void
    1864    */
    1865   public function ClearReplyTos() {
    1866     $this->ReplyTo = array();
    1867   }
    1868 
    1869   /**
    1870    * Clears all recipients assigned in the TO, CC and BCC
    1871    * array.  Returns void.
    1872    * @return void
    1873    */
    1874   public function ClearAllRecipients() {
    1875     $this->to = array();
    1876     $this->cc = array();
    1877     $this->bcc = array();
    1878     $this->all_recipients = array();
    1879   }
    1880 
    1881   /**
    1882    * Clears all previously set filesystem, string, and binary
    1883    * attachments.  Returns void.
    1884    * @return void
    1885    */
    1886   public function ClearAttachments() {
    1887     $this->attachment = array();
    1888   }
    1889 
    1890   /**
    1891    * Clears all custom headers.  Returns void.
    1892    * @return void
    1893    */
    1894   public function ClearCustomHeaders() {
    1895     $this->CustomHeader = array();
    1896   }
    1897 
    1898   /////////////////////////////////////////////////
    1899   // CLASS METHODS, MISCELLANEOUS
    1900   /////////////////////////////////////////////////
    1901 
    1902   /**
    1903    * Adds the error message to the error container.
    1904    * @access protected
    1905    * @return void
    1906    */
    1907   protected function SetError($msg) {
    1908     $this->error_count++;
    1909     if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
    1910       $lasterror = $this->smtp->getError();
    1911       if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
    1912         $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
    1913       }
    1914     }
    1915     $this->ErrorInfo = $msg;
    1916   }
    1917 
    1918   /**
    1919    * Returns the proper RFC 822 formatted date.
    1920    * @access public
    1921    * @return string
    1922    * @static
    1923    */
    1924   public static function RFCDate() {
    1925     $tz = date('Z');
    1926     $tzs = ($tz < 0) ? '-' : '+';
    1927     $tz = abs($tz);
    1928     $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
    1929     $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
    1930 
    1931     return $result;
    1932   }
    1933 
    1934   /**
    1935    * Returns the server hostname or 'localhost.localdomain' if unknown.
    1936    * @access private
    1937    * @return string
    1938    */
    1939   private function ServerHostname() {
    1940     if (!empty($this->Hostname)) {
    1941       $result = $this->Hostname;
    1942     } elseif (isset($_SERVER['SERVER_NAME'])) {
    1943       $result = $_SERVER['SERVER_NAME'];
    1944     } else {
    1945       $result = 'localhost.localdomain';
    1946     }
    1947 
    1948     return $result;
    1949   }
    1950 
    1951   /**
    1952    * Returns a message in the appropriate language.
    1953    * @access private
    1954    * @return string
    1955    */
    1956   private function Lang($key) {
    1957     if(count($this->language) < 1) {
    1958       $this->SetLanguage('en'); // set the default language
    1959     }
    1960 
    1961     if(isset($this->language[$key])) {
    1962       return $this->language[$key];
    1963     } else {
    1964       return 'Language string failed to load: ' . $key;
    1965     }
    1966   }
    1967 
    1968   /**
    1969    * Returns true if an error occurred.
    1970    * @access public
    1971    * @return bool
    1972    */
    1973   public function IsError() {
    1974     return ($this->error_count > 0);
    1975   }
    1976 
    1977   /**
    1978    * Changes every end of line from CR or LF to CRLF.
    1979    * @access private
    1980    * @return string
    1981    */
    1982   private function FixEOL($str) {
    1983     $str = str_replace("\r\n", "\n", $str);
    1984     $str = str_replace("\r", "\n", $str);
    1985     $str = str_replace("\n", $this->LE, $str);
    1986     return $str;
    1987   }
    1988 
    1989   /**
    1990    * Adds a custom header.
    1991    * @access public
    1992    * @return void
    1993    */
    1994   public function AddCustomHeader($custom_header) {
    1995     $this->CustomHeader[] = explode(':', $custom_header, 2);
    1996   }
    1997 
    1998   /**
    1999    * Evaluates the message and returns modifications for inline images and backgrounds
    2000    * @access public
    2001    * @return $message
    2002    */
    2003   public function MsgHTML($message, $basedir = '') {
    2004     preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
    2005     if(isset($images[2])) {
    2006       foreach($images[2] as $i => $url) {
    2007         // do not change urls for absolute images (thanks to corvuscorax)
    2008         if (!preg_match('#^[A-z]+://#',$url)) {
    2009           $filename = basename($url);
    2010           $directory = dirname($url);
    2011           ($directory == '.')?$directory='':'';
    2012           $cid = 'cid:' . md5($filename);
    2013           $ext = pathinfo($filename, PATHINFO_EXTENSION);
    2014           $mimeType  = self::_mime_types($ext);
    2015           if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
    2016           if ( strlen($directory) > 1 && substr($directory,-1) != '/') { $directory .= '/'; }
    2017           if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
    2018             $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
    2019           }
    2020         }
    2021       }
    2022     }
    2023     $this->IsHTML(true);
    2024     $this->Body = $message;
    2025     $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
    2026     if (!empty($textMsg) && empty($this->AltBody)) {
    2027       $this->AltBody = html_entity_decode($textMsg,ENT_COMPAT | ENT_HTML401, strtoupper($this->CharSet));
    2028     }
    2029     if (empty($this->AltBody)) {
    2030       $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
    2031     }
    2032   }
    2033 
    2034   /**
    2035    * Gets the MIME type of the embedded or inline image
    2036    * @param string File extension
    2037    * @access public
    2038    * @return string MIME type of ext
    2039    * @static
    2040    */
    2041   public static function _mime_types($ext = '') {
    2042     $mimes = array(
    2043       'hqx'   =>  'application/mac-binhex40',
    2044       'cpt'   =>  'application/mac-compactpro',
    2045       'doc'   =>  'application/msword',
    2046       'bin'   =>  'application/macbinary',
    2047       'dms'   =>  'application/octet-stream',
    2048       'lha'   =>  'application/octet-stream',
    2049       'lzh'   =>  'application/octet-stream',
    2050       'exe'   =>  'application/octet-stream',
    2051       'class' =>  'application/octet-stream',
    2052       'psd'   =>  'application/octet-stream',
    2053       'so'    =>  'application/octet-stream',
    2054       'sea'   =>  'application/octet-stream',
    2055       'dll'   =>  'application/octet-stream',
    2056       'oda'   =>  'application/oda',
    2057       'pdf'   =>  'application/pdf',
    2058       'ai'    =>  'application/postscript',
    2059       'eps'   =>  'application/postscript',
    2060       'ps'    =>  'application/postscript',
    2061       'smi'   =>  'application/smil',
    2062       'smil'  =>  'application/smil',
    2063       'mif'   =>  'application/vnd.mif',
    2064       'xls'   =>  'application/vnd.ms-excel',
    2065       'ppt'   =>  'application/vnd.ms-powerpoint',
    2066       'wbxml' =>  'application/vnd.wap.wbxml',
    2067       'wmlc'  =>  'application/vnd.wap.wmlc',
    2068       'dcr'   =>  'application/x-director',
    2069       'dir'   =>  'application/x-director',
    2070       'dxr'   =>  'application/x-director',
    2071       'dvi'   =>  'application/x-dvi',
    2072       'gtar'  =>  'application/x-gtar',
    2073       'php'   =>  'application/x-httpd-php',
    2074       'php4'  =>  'application/x-httpd-php',
    2075       'php3'  =>  'application/x-httpd-php',
    2076       'phtml' =>  'application/x-httpd-php',
    2077       'phps'  =>  'application/x-httpd-php-source',
    2078       'js'    =>  'application/x-javascript',
    2079       'swf'   =>  'application/x-shockwave-flash',
    2080       'sit'   =>  'application/x-stuffit',
    2081       'tar'   =>  'application/x-tar',
    2082       'tgz'   =>  'application/x-tar',
    2083       'xhtml' =>  'application/xhtml+xml',
    2084       'xht'   =>  'application/xhtml+xml',
    2085       'zip'   =>  'application/zip',
    2086       'mid'   =>  'audio/midi',
    2087       'midi'  =>  'audio/midi',
    2088       'mpga'  =>  'audio/mpeg',
    2089       'mp2'   =>  'audio/mpeg',
    2090       'mp3'   =>  'audio/mpeg',
    2091       'aif'   =>  'audio/x-aiff',
    2092       'aiff'  =>  'audio/x-aiff',
    2093       'aifc'  =>  'audio/x-aiff',
    2094       'ram'   =>  'audio/x-pn-realaudio',
    2095       'rm'    =>  'audio/x-pn-realaudio',
    2096       'rpm'   =>  'audio/x-pn-realaudio-plugin',
    2097       'ra'    =>  'audio/x-realaudio',
    2098       'rv'    =>  'video/vnd.rn-realvideo',
    2099       'wav'   =>  'audio/x-wav',
    2100       'bmp'   =>  'image/bmp',
    2101       'gif'   =>  'image/gif',
    2102       'jpeg'  =>  'image/jpeg',
    2103       'jpg'   =>  'image/jpeg',
    2104       'jpe'   =>  'image/jpeg',
    2105       'png'   =>  'image/png',
    2106       'tiff'  =>  'image/tiff',
    2107       'tif'   =>  'image/tiff',
    2108       'css'   =>  'text/css',
    2109       'html'  =>  'text/html',
    2110       'htm'   =>  'text/html',
    2111       'shtml' =>  'text/html',
    2112       'txt'   =>  'text/plain',
    2113       'text'  =>  'text/plain',
    2114       'log'   =>  'text/plain',
    2115       'rtx'   =>  'text/richtext',
    2116       'rtf'   =>  'text/rtf',
    2117       'xml'   =>  'text/xml',
    2118       'xsl'   =>  'text/xml',
    2119       'mpeg'  =>  'video/mpeg',
    2120       'mpg'   =>  'video/mpeg',
    2121       'mpe'   =>  'video/mpeg',
    2122       'qt'    =>  'video/quicktime',
    2123       'mov'   =>  'video/quicktime',
    2124       'avi'   =>  'video/x-msvideo',
    2125       'movie' =>  'video/x-sgi-movie',
    2126       'doc'   =>  'application/msword',
    2127       'word'  =>  'application/msword',
    2128       'xl'    =>  'application/excel',
    2129       'eml'   =>  'message/rfc822'
    2130     );
    2131     return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
    2132   }
    2133 
    2134   /**
    2135   * Set (or reset) Class Objects (variables)
    2136   *
    2137   * Usage Example:
    2138   * $page->set('X-Priority', '3');
    2139   *
    2140   * @access public
    2141   * @param string $name Parameter Name
    2142   * @param mixed $value Parameter Value
    2143   * NOTE: will not work with arrays, there are no arrays to set/reset
    2144   * @todo Should this not be using __set() magic function?
    2145   */
    2146   public function set($name, $value = '') {
    2147     try {
    2148       if (isset($this->$name) ) {
    2149         $this->$name = $value;
    2150       } else {
    2151         throw new phpmailerException($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
    2152       }
    2153     } catch (Exception $e) {
    2154       $this->SetError($e->getMessage());
    2155       if ($e->getCode() == self::STOP_CRITICAL) {
    2156         return false;
    2157       }
    2158     }
    2159     return true;
    2160   }
    2161 
    2162   /**
    2163    * Strips newlines to prevent header injection.
    2164    * @access public
    2165    * @param string $str String
    2166    * @return string
    2167    */
    2168   public function SecureHeader($str) {
    2169     $str = str_replace("\r", '', $str);
    2170     $str = str_replace("\n", '', $str);
    2171     return trim($str);
    2172   }
    2173 
    2174   /**
    2175    * Set the private key file and password to sign the message.
    2176    *
    2177    * @access public
    2178    * @param string $key_filename Parameter File Name
    2179    * @param string $key_pass Password for private key
    2180    */
    2181   public function Sign($cert_filename, $key_filename, $key_pass) {
    2182     $this->sign_cert_file = $cert_filename;
    2183     $this->sign_key_file = $key_filename;
    2184     $this->sign_key_pass = $key_pass;
    2185   }
    2186 
    2187   /**
    2188    * Set the private key file and password to sign the message.
    2189    *
    2190    * @access public
    2191    * @param string $key_filename Parameter File Name
    2192    * @param string $key_pass Password for private key
    2193    */
    2194   public function DKIM_QP($txt) {
    2195     $tmp="";
    2196     $line="";
    2197     for ($i=0;$i<strlen($txt);$i++) {
    2198       $ord=ord($txt[$i]);
    2199       if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
    2200         $line.=$txt[$i];
    2201       } else {
    2202         $line.="=".sprintf("%02X",$ord);
    2203       }
    2204     }
    2205     return $line;
    2206   }
    2207 
    2208   /**
    2209    * Generate DKIM signature
    2210    *
    2211    * @access public
    2212    * @param string $s Header
    2213    */
    2214   public function DKIM_Sign($s) {
    2215     $privKeyStr = file_get_contents($this->DKIM_private);
    2216     if ($this->DKIM_passphrase!='') {
    2217       $privKey = openssl_pkey_get_private($privKeyStr,$this->DKIM_passphrase);
    2218     } else {
    2219       $privKey = $privKeyStr;
    2220     }
    2221     if (openssl_sign($s, $signature, $privKey)) {
    2222       return base64_encode($signature);
    2223     }
    2224   }
    2225 
    2226   /**
    2227    * Generate DKIM Canonicalization Header
    2228    *
    2229    * @access public
    2230    * @param string $s Header
    2231    */
    2232   public function DKIM_HeaderC($s) {
    2233     $s=preg_replace("/\r\n\s+/"," ",$s);
    2234     $lines=explode("\r\n",$s);
    2235     foreach ($lines as $key=>$line) {
    2236       list($heading,$value)=explode(":",$line,2);
    2237       $heading=strtolower($heading);
    2238       $value=preg_replace("/\s+/"," ",$value) ; // Compress useless spaces
    2239       $lines[$key]=$heading.":".trim($value) ; // Don't forget to remove WSP around the value
    2240     }
    2241     $s=implode("\r\n",$lines);
    2242     return $s;
    2243   }
    2244 
    2245   /**
    2246    * Generate DKIM Canonicalization Body
    2247    *
    2248    * @access public
    2249    * @param string $body Message Body
    2250    */
    2251   public function DKIM_BodyC($body) {
    2252     if ($body == '') return "\r\n";
    2253     // stabilize line endings
    2254     $body=str_replace("\r\n","\n",$body);
    2255     $body=str_replace("\n","\r\n",$body);
    2256     // END stabilize line endings
    2257     while (substr($body,strlen($body)-4,4) == "\r\n\r\n") {
    2258       $body=substr($body,0,strlen($body)-2);
    2259     }
    2260     return $body;
    2261   }
    2262 
    2263   /**
    2264    * Create the DKIM header, body, as new header
    2265    *
    2266    * @access public
    2267    * @param string $headers_line Header lines
    2268    * @param string $subject Subject
    2269    * @param string $body Body
    2270    */
    2271   public function DKIM_Add($headers_line,$subject,$body) {
    2272     $DKIMsignatureType    = 'rsa-sha1'; // Signature & hash algorithms
    2273     $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
    2274     $DKIMquery            = 'dns/txt'; // Query method
    2275     $DKIMtime             = time() ; // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
    2276     $subject_header       = "Subject: $subject";
    2277     $headers              = explode("\r\n",$headers_line);
    2278     foreach($headers as $header) {
    2279       if (strpos($header,'From:') === 0) {
    2280         $from_header=$header;
    2281       } elseif (strpos($header,'To:') === 0) {
    2282         $to_header=$header;
    2283       }
    2284     }
    2285     $from     = str_replace('|','=7C',$this->DKIM_QP($from_header));
    2286     $to       = str_replace('|','=7C',$this->DKIM_QP($to_header));
    2287     $subject  = str_replace('|','=7C',$this->DKIM_QP($subject_header)) ; // Copied header fields (dkim-quoted-printable
    2288     $body     = $this->DKIM_BodyC($body);
    2289     $DKIMlen  = strlen($body) ; // Length of body
    2290     $DKIMb64  = base64_encode(pack("H*", sha1($body))) ; // Base64 of packed binary SHA-1 hash of body
    2291     $ident    = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
    2292     $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
    2293                 "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
    2294                 "\th=From:To:Subject;\r\n".
    2295                 "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
    2296                 "\tz=$from\r\n".
    2297                 "\t|$to\r\n".
    2298                 "\t|$subject;\r\n".
    2299                 "\tbh=" . $DKIMb64 . ";\r\n".
    2300                 "\tb=";
    2301     $toSign   = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
    2302     $signed   = $this->DKIM_Sign($toSign);
    2303     return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n";
    2304   }
    2305 
    2306   protected function doCallback($isSent,$to,$cc,$bcc,$subject,$body) {
    2307     if (!empty($this->action_function) && function_exists($this->action_function)) {
    2308       $params = array($isSent,$to,$cc,$bcc,$subject,$body);
    2309       call_user_func_array($this->action_function,$params);
    2310     }
    2311   }
     3610class phpmailerException extends Exception
     3611{
     3612    /**
     3613     * Prettify error message output
     3614     * @return string
     3615     */
     3616    public function errorMessage()
     3617    {
     3618        $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
     3619        return $errorMsg;
     3620    }
    23123621}
    2313 
    2314 class phpmailerException extends Exception {
    2315   public function errorMessage() {
    2316     $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
    2317     return $errorMsg;
    2318   }
    2319 }
    2320 ?>
  • _plugins_/facteur/trunk/phpmailer-php5/class.pop3.php

    r37096 r89555  
    11<?php
    2 /*~ class.pop3.php
    3 .---------------------------------------------------------------------------.
    4 |  Software: PHPMailer - PHP email class                                    |
    5 |   Version: 5.1                                                            |
    6 |   Contact: via sourceforge.net support pages (also www.codeworxtech.com)  |
    7 |      Info: http://phpmailer.sourceforge.net                               |
    8 |   Support: http://sourceforge.net/projects/phpmailer/                     |
    9 | ------------------------------------------------------------------------- |
    10 |     Admin: Andy Prevost (project admininistrator)                         |
    11 |   Authors: Andy Prevost (codeworxtech) codeworxtech@users.sourceforge.net |
    12 |          : Marcus Bointon (coolbru) coolbru@users.sourceforge.net         |
    13 |   Founder: Brent R. Matzelle (original founder)                           |
    14 | Copyright (c) 2004-2009, Andy Prevost. All Rights Reserved.               |
    15 | Copyright (c) 2001-2003, Brent R. Matzelle                                |
    16 | ------------------------------------------------------------------------- |
    17 |   License: Distributed under the Lesser General Public License (LGPL)     |
    18 |            http://www.gnu.org/copyleft/lesser.html                        |
    19 | This program is distributed in the hope that it will be useful - WITHOUT  |
    20 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or     |
    21 | FITNESS FOR A PARTICULAR PURPOSE.                                         |
    22 | ------------------------------------------------------------------------- |
    23 | We offer a number of paid services (www.codeworxtech.com):                |
    24 | - Web Hosting on highly optimized fast and secure servers                 |
    25 | - Technology Consulting                                                   |
    26 | - Oursourcing (highly qualified programmers and graphic designers)        |
    27 '---------------------------------------------------------------------------'
    28 */
    29 
    302/**
    31  * PHPMailer - PHP POP Before SMTP Authentication Class
    32  * NOTE: Designed for use with PHP version 5 and up
     3 * PHPMailer POP-Before-SMTP Authentication Class.
     4 * PHP Version 5
    335 * @package PHPMailer
    34  * @author Andy Prevost
    35  * @author Marcus Bointon
     6 * @link https://github.com/PHPMailer/PHPMailer/
     7 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
     8 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
     9 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
     10 * @author Brent R. Matzelle (original founder)
     11 * @copyright 2012 - 2014 Marcus Bointon
     12 * @copyright 2010 - 2012 Jim Jagielski
    3613 * @copyright 2004 - 2009 Andy Prevost
    37  * @license http://www.gnu.org/copyleft/lesser.html Distributed under the Lesser General Public License (LGPL)
    38  * @version $Id: class.pop3.php 444 2009-05-05 11:22:26Z coolbru $
     14 * @license http://www.gnu.org/copyleft/lesser.html GNU Lesser General Public License
     15 * @note This program is distributed in the hope that it will be useful - WITHOUT
     16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     17 * FITNESS FOR A PARTICULAR PURPOSE.
    3918 */
    4019
    4120/**
    42  * POP Before SMTP Authentication Class
    43  * Version 5.0.0
    44  *
    45  * Author: Richard Davey (rich@corephp.co.uk)
    46  * Modifications: Andy Prevost
    47  * License: LGPL, see PHPMailer License
    48  *
    49  * Specifically for PHPMailer to allow POP before SMTP authentication.
    50  * Does not yet work with APOP - if you have an APOP account, contact Richard Davey
    51  * and we can test changes to this script.
    52  *
    53  * This class is based on the structure of the SMTP class originally authored by Chris Ryan
    54  *
    55  * This class is rfc 1939 compliant and implements all the commands
    56  * required for POP3 connection, authentication and disconnection.
    57  *
     21 * PHPMailer POP-Before-SMTP Authentication Class.
     22 * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
     23 * Does not support APOP.
    5824 * @package PHPMailer
    59  * @author Richard Davey
     25 * @author Richard Davey (original author) <rich@corephp.co.uk>
     26 * @author Marcus Bointon (Synchro/coolbru) <phpmailer@synchromedia.co.uk>
     27 * @author Jim Jagielski (jimjag) <jimjag@gmail.com>
     28 * @author Andy Prevost (codeworxtech) <codeworxtech@users.sourceforge.net>
    6029 */
    61 
    62 class POP3 {
    63   /**
    64    * Default POP3 port
    65    * @var int
    66    */
    67   public $POP3_PORT = 110;
    68 
    69   /**
    70    * Default Timeout
    71    * @var int
    72    */
    73   public $POP3_TIMEOUT = 30;
    74 
    75   /**
    76    * POP3 Carriage Return + Line Feed
    77    * @var string
    78    */
    79   public $CRLF = "\r\n";
    80 
    81   /**
    82    * Displaying Debug warnings? (0 = now, 1+ = yes)
    83    * @var int
    84    */
    85   public $do_debug = 2;
    86 
    87   /**
    88    * POP3 Mail Server
    89    * @var string
    90    */
    91   public $host;
    92 
    93   /**
    94    * POP3 Port
    95    * @var int
    96    */
    97   public $port;
    98 
    99   /**
    100    * POP3 Timeout Value
    101    * @var int
    102    */
    103   public $tval;
    104 
    105   /**
    106    * POP3 Username
    107    * @var string
    108    */
    109   public $username;
    110 
    111   /**
    112    * POP3 Password
    113    * @var string
    114    */
    115   public $password;
    116 
    117   /////////////////////////////////////////////////
    118   // PROPERTIES, PRIVATE AND PROTECTED
    119   /////////////////////////////////////////////////
    120 
    121   private $pop_conn;
    122   private $connected;
    123   private $error;     //  Error log array
    124 
    125   /**
    126    * Constructor, sets the initial values
    127    * @access public
    128    * @return POP3
    129    */
    130   public function __construct() {
    131     $this->pop_conn  = 0;
    132     $this->connected = false;
    133     $this->error     = null;
    134   }
    135 
    136   /**
    137    * Combination of public events - connect, login, disconnect
    138    * @access public
    139    * @param string $host
    140    * @param integer $port
    141    * @param integer $tval
    142    * @param string $username
    143    * @param string $password
    144    */
    145   public function Authorise ($host, $port = false, $tval = false, $username, $password, $debug_level = 0) {
    146     $this->host = $host;
    147 
    148     //  If no port value is passed, retrieve it
    149     if ($port == false) {
    150       $this->port = $this->POP3_PORT;
    151     } else {
    152       $this->port = $port;
    153     }
    154 
    155     //  If no port value is passed, retrieve it
    156     if ($tval == false) {
    157       $this->tval = $this->POP3_TIMEOUT;
    158     } else {
    159       $this->tval = $tval;
    160     }
    161 
    162     $this->do_debug = $debug_level;
    163     $this->username = $username;
    164     $this->password = $password;
    165