WordPress.org

Make WordPress Core

Ticket #39714: phpmailer2.diff

File phpmailer2.diff, 525.3 KB (added by JeffMatson, 4 years ago)

Diff including new files.

  • new file wp-includes/PHPMailer/LICENSE

    diff --git wp-includes/PHPMailer/LICENSE wp-includes/PHPMailer/LICENSE
    new file mode 100644
    index 0000000..8e0763d
    - +  
     1                  GNU LESSER GENERAL PUBLIC LICENSE
     2                       Version 2.1, February 1999
     3
     4 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
     5     59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     6 Everyone is permitted to copy and distribute verbatim copies
     7 of this license document, but changing it is not allowed.
     8
     9[This is the first released version of the Lesser GPL.  It also counts
     10 as the successor of the GNU Library Public License, version 2, hence
     11 the version number 2.1.]
     12
     13                            Preamble
     14
     15  The licenses for most software are designed to take away your
     16freedom to share and change it.  By contrast, the GNU General Public
     17Licenses are intended to guarantee your freedom to share and change
     18free software--to make sure the software is free for all its users.
     19
     20  This license, the Lesser General Public License, applies to some
     21specially designated software packages--typically libraries--of the
     22Free Software Foundation and other authors who decide to use it.  You
     23can use it too, but we suggest you first think carefully about whether
     24this license or the ordinary General Public License is the better
     25strategy to use in any particular case, based on the explanations below.
     26
     27  When we speak of free software, we are referring to freedom of use,
     28not price.  Our General Public Licenses are designed to make sure that
     29you have the freedom to distribute copies of free software (and charge
     30for this service if you wish); that you receive source code or can get
     31it if you want it; that you can change the software and use pieces of
     32it in new free programs; and that you are informed that you can do
     33these things.
     34
     35  To protect your rights, we need to make restrictions that forbid
     36distributors to deny you these rights or to ask you to surrender these
     37rights.  These restrictions translate to certain responsibilities for
     38you if you distribute copies of the library or if you modify it.
     39
     40  For example, if you distribute copies of the library, whether gratis
     41or for a fee, you must give the recipients all the rights that we gave
     42you.  You must make sure that they, too, receive or can get the source
     43code.  If you link other code with the library, you must provide
     44complete object files to the recipients, so that they can relink them
     45with the library after making changes to the library and recompiling
     46it.  And you must show them these terms so they know their rights.
     47
     48  We protect your rights with a two-step method: (1) we copyright the
     49library, and (2) we offer you this license, which gives you legal
     50permission to copy, distribute and/or modify the library.
     51
     52  To protect each distributor, we want to make it very clear that
     53there is no warranty for the free library.  Also, if the library is
     54modified by someone else and passed on, the recipients should know
     55that what they have is not the original version, so that the original
     56author's reputation will not be affected by problems that might be
     57introduced by others.
     58
     59  Finally, software patents pose a constant threat to the existence of
     60any free program.  We wish to make sure that a company cannot
     61effectively restrict the users of a free program by obtaining a
     62restrictive license from a patent holder.  Therefore, we insist that
     63any patent license obtained for a version of the library must be
     64consistent with the full freedom of use specified in this license.
     65
     66  Most GNU software, including some libraries, is covered by the
     67ordinary GNU General Public License.  This license, the GNU Lesser
     68General Public License, applies to certain designated libraries, and
     69is quite different from the ordinary General Public License.  We use
     70this license for certain libraries in order to permit linking those
     71libraries into non-free programs.
     72
     73  When a program is linked with a library, whether statically or using
     74a shared library, the combination of the two is legally speaking a
     75combined work, a derivative of the original library.  The ordinary
     76General Public License therefore permits such linking only if the
     77entire combination fits its criteria of freedom.  The Lesser General
     78Public License permits more lax criteria for linking other code with
     79the library.
     80
     81  We call this license the "Lesser" General Public License because it
     82does Less to protect the user's freedom than the ordinary General
     83Public License.  It also provides other free software developers Less
     84of an advantage over competing non-free programs.  These disadvantages
     85are the reason we use the ordinary General Public License for many
     86libraries.  However, the Lesser license provides advantages in certain
     87special circumstances.
     88
     89  For example, on rare occasions, there may be a special need to
     90encourage the widest possible use of a certain library, so that it becomes
     91a de-facto standard.  To achieve this, non-free programs must be
     92allowed to use the library.  A more frequent case is that a free
     93library does the same job as widely used non-free libraries.  In this
     94case, there is little to gain by limiting the free library to free
     95software only, so we use the Lesser General Public License.
     96
     97  In other cases, permission to use a particular library in non-free
     98programs enables a greater number of people to use a large body of
     99free software.  For example, permission to use the GNU C Library in
     100non-free programs enables many more people to use the whole GNU
     101operating system, as well as its variant, the GNU/Linux operating
     102system.
     103
     104  Although the Lesser General Public License is Less protective of the
     105users' freedom, it does ensure that the user of a program that is
     106linked with the Library has the freedom and the wherewithal to run
     107that program using a modified version of the Library.
     108
     109  The precise terms and conditions for copying, distribution and
     110modification follow.  Pay close attention to the difference between a
     111"work based on the library" and a "work that uses the library".  The
     112former contains code derived from the library, whereas the latter must
     113be combined with the library in order to run.
     114
     115                  GNU LESSER GENERAL PUBLIC LICENSE
     116   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
     117
     118  0. This License Agreement applies to any software library or other
     119program which contains a notice placed by the copyright holder or
     120other authorized party saying it may be distributed under the terms of
     121this Lesser General Public License (also called "this License").
     122Each licensee is addressed as "you".
     123
     124  A "library" means a collection of software functions and/or data
     125prepared so as to be conveniently linked with application programs
     126(which use some of those functions and data) to form executables.
     127
     128  The "Library", below, refers to any such software library or work
     129which has been distributed under these terms.  A "work based on the
     130Library" means either the Library or any derivative work under
     131copyright law: that is to say, a work containing the Library or a
     132portion of it, either verbatim or with modifications and/or translated
     133straightforwardly into another language.  (Hereinafter, translation is
     134included without limitation in the term "modification".)
     135
     136  "Source code" for a work means the preferred form of the work for
     137making modifications to it.  For a library, complete source code means
     138all the source code for all modules it contains, plus any associated
     139interface definition files, plus the scripts used to control compilation
     140and installation of the library.
     141
     142  Activities other than copying, distribution and modification are not
     143covered by this License; they are outside its scope.  The act of
     144running a program using the Library is not restricted, and output from
     145such a program is covered only if its contents constitute a work based
     146on the Library (independent of the use of the Library in a tool for
     147writing it).  Whether that is true depends on what the Library does
     148and what the program that uses the Library does.
     149 
     150  1. You may copy and distribute verbatim copies of the Library's
     151complete source code as you receive it, in any medium, provided that
     152you conspicuously and appropriately publish on each copy an
     153appropriate copyright notice and disclaimer of warranty; keep intact
     154all the notices that refer to this License and to the absence of any
     155warranty; and distribute a copy of this License along with the
     156Library.
     157
     158  You may charge a fee for the physical act of transferring a copy,
     159and you may at your option offer warranty protection in exchange for a
     160fee.
     161
     162  2. You may modify your copy or copies of the Library or any portion
     163of it, thus forming a work based on the Library, and copy and
     164distribute such modifications or work under the terms of Section 1
     165above, provided that you also meet all of these conditions:
     166
     167    a) The modified work must itself be a software library.
     168
     169    b) You must cause the files modified to carry prominent notices
     170    stating that you changed the files and the date of any change.
     171
     172    c) You must cause the whole of the work to be licensed at no
     173    charge to all third parties under the terms of this License.
     174
     175    d) If a facility in the modified Library refers to a function or a
     176    table of data to be supplied by an application program that uses
     177    the facility, other than as an argument passed when the facility
     178    is invoked, then you must make a good faith effort to ensure that,
     179    in the event an application does not supply such function or
     180    table, the facility still operates, and performs whatever part of
     181    its purpose remains meaningful.
     182
     183    (For example, a function in a library to compute square roots has
     184    a purpose that is entirely well-defined independent of the
     185    application.  Therefore, Subsection 2d requires that any
     186    application-supplied function or table used by this function must
     187    be optional: if the application does not supply it, the square
     188    root function must still compute square roots.)
     189
     190These requirements apply to the modified work as a whole.  If
     191identifiable sections of that work are not derived from the Library,
     192and can be reasonably considered independent and separate works in
     193themselves, then this License, and its terms, do not apply to those
     194sections when you distribute them as separate works.  But when you
     195distribute the same sections as part of a whole which is a work based
     196on the Library, the distribution of the whole must be on the terms of
     197this License, whose permissions for other licensees extend to the
     198entire whole, and thus to each and every part regardless of who wrote
     199it.
     200
     201Thus, it is not the intent of this section to claim rights or contest
     202your rights to work written entirely by you; rather, the intent is to
     203exercise the right to control the distribution of derivative or
     204collective works based on the Library.
     205
     206In addition, mere aggregation of another work not based on the Library
     207with the Library (or with a work based on the Library) on a volume of
     208a storage or distribution medium does not bring the other work under
     209the scope of this License.
     210
     211  3. You may opt to apply the terms of the ordinary GNU General Public
     212License instead of this License to a given copy of the Library.  To do
     213this, you must alter all the notices that refer to this License, so
     214that they refer to the ordinary GNU General Public License, version 2,
     215instead of to this License.  (If a newer version than version 2 of the
     216ordinary GNU General Public License has appeared, then you can specify
     217that version instead if you wish.)  Do not make any other change in
     218these notices.
     219
     220  Once this change is made in a given copy, it is irreversible for
     221that copy, so the ordinary GNU General Public License applies to all
     222subsequent copies and derivative works made from that copy.
     223
     224  This option is useful when you wish to copy part of the code of
     225the Library into a program that is not a library.
     226
     227  4. You may copy and distribute the Library (or a portion or
     228derivative of it, under Section 2) in object code or executable form
     229under the terms of Sections 1 and 2 above provided that you accompany
     230it with the complete corresponding machine-readable source code, which
     231must be distributed under the terms of Sections 1 and 2 above on a
     232medium customarily used for software interchange.
     233
     234  If distribution of object code is made by offering access to copy
     235from a designated place, then offering equivalent access to copy the
     236source code from the same place satisfies the requirement to
     237distribute the source code, even though third parties are not
     238compelled to copy the source along with the object code.
     239
     240  5. A program that contains no derivative of any portion of the
     241Library, but is designed to work with the Library by being compiled or
     242linked with it, is called a "work that uses the Library".  Such a
     243work, in isolation, is not a derivative work of the Library, and
     244therefore falls outside the scope of this License.
     245
     246  However, linking a "work that uses the Library" with the Library
     247creates an executable that is a derivative of the Library (because it
     248contains portions of the Library), rather than a "work that uses the
     249library".  The executable is therefore covered by this License.
     250Section 6 states terms for distribution of such executables.
     251
     252  When a "work that uses the Library" uses material from a header file
     253that is part of the Library, the object code for the work may be a
     254derivative work of the Library even though the source code is not.
     255Whether this is true is especially significant if the work can be
     256linked without the Library, or if the work is itself a library.  The
     257threshold for this to be true is not precisely defined by law.
     258
     259  If such an object file uses only numerical parameters, data
     260structure layouts and accessors, and small macros and small inline
     261functions (ten lines or less in length), then the use of the object
     262file is unrestricted, regardless of whether it is legally a derivative
     263work.  (Executables containing this object code plus portions of the
     264Library will still fall under Section 6.)
     265
     266  Otherwise, if the work is a derivative of the Library, you may
     267distribute the object code for the work under the terms of Section 6.
     268Any executables containing that work also fall under Section 6,
     269whether or not they are linked directly with the Library itself.
     270
     271  6. As an exception to the Sections above, you may also combine or
     272link a "work that uses the Library" with the Library to produce a
     273work containing portions of the Library, and distribute that work
     274under terms of your choice, provided that the terms permit
     275modification of the work for the customer's own use and reverse
     276engineering for debugging such modifications.
     277
     278  You must give prominent notice with each copy of the work that the
     279Library is used in it and that the Library and its use are covered by
     280this License.  You must supply a copy of this License.  If the work
     281during execution displays copyright notices, you must include the
     282copyright notice for the Library among them, as well as a reference
     283directing the user to the copy of this License.  Also, you must do one
     284of these things:
     285
     286    a) Accompany the work with the complete corresponding
     287    machine-readable source code for the Library including whatever
     288    changes were used in the work (which must be distributed under
     289    Sections 1 and 2 above); and, if the work is an executable linked
     290    with the Library, with the complete machine-readable "work that
     291    uses the Library", as object code and/or source code, so that the
     292    user can modify the Library and then relink to produce a modified
     293    executable containing the modified Library.  (It is understood
     294    that the user who changes the contents of definitions files in the
     295    Library will not necessarily be able to recompile the application
     296    to use the modified definitions.)
     297
     298    b) Use a suitable shared library mechanism for linking with the
     299    Library.  A suitable mechanism is one that (1) uses at run time a
     300    copy of the library already present on the user's computer system,
     301    rather than copying library functions into the executable, and (2)
     302    will operate properly with a modified version of the library, if
     303    the user installs one, as long as the modified version is
     304    interface-compatible with the version that the work was made with.
     305
     306    c) Accompany the work with a written offer, valid for at
     307    least three years, to give the same user the materials
     308    specified in Subsection 6a, above, for a charge no more
     309    than the cost of performing this distribution.
     310
     311    d) If distribution of the work is made by offering access to copy
     312    from a designated place, offer equivalent access to copy the above
     313    specified materials from the same place.
     314
     315    e) verify that the user has already received a copy of these
     316    materials or that you have already sent this user a copy.
     317
     318  For an executable, the required form of the "work that uses the
     319Library" must include any data and utility programs needed for
     320reproducing the executable from it.  However, as a special exception,
     321the materials to be distributed need not include anything that is
     322normally distributed (in either source or binary form) with the major
     323components (compiler, kernel, and so on) of the operating system on
     324which the executable runs, unless that component itself accompanies
     325the executable.
     326
     327  It may happen that this requirement contradicts the license
     328restrictions of other proprietary libraries that do not normally
     329accompany the operating system.  Such a contradiction means you cannot
     330use both them and the Library together in an executable that you
     331distribute.
     332
     333  7. You may place library facilities that are a work based on the
     334Library side-by-side in a single library together with other library
     335facilities not covered by this License, and distribute such a combined
     336library, provided that the separate distribution of the work based on
     337the Library and of the other library facilities is otherwise
     338permitted, and provided that you do these two things:
     339
     340    a) Accompany the combined library with a copy of the same work
     341    based on the Library, uncombined with any other library
     342    facilities.  This must be distributed under the terms of the
     343    Sections above.
     344
     345    b) Give prominent notice with the combined library of the fact
     346    that part of it is a work based on the Library, and explaining
     347    where to find the accompanying uncombined form of the same work.
     348
     349  8. You may not copy, modify, sublicense, link with, or distribute
     350the Library except as expressly provided under this License.  Any
     351attempt otherwise to copy, modify, sublicense, link with, or
     352distribute the Library is void, and will automatically terminate your
     353rights under this License.  However, parties who have received copies,
     354or rights, from you under this License will not have their licenses
     355terminated so long as such parties remain in full compliance.
     356
     357  9. You are not required to accept this License, since you have not
     358signed it.  However, nothing else grants you permission to modify or
     359distribute the Library or its derivative works.  These actions are
     360prohibited by law if you do not accept this License.  Therefore, by
     361modifying or distributing the Library (or any work based on the
     362Library), you indicate your acceptance of this License to do so, and
     363all its terms and conditions for copying, distributing or modifying
     364the Library or works based on it.
     365
     366  10. Each time you redistribute the Library (or any work based on the
     367Library), the recipient automatically receives a license from the
     368original licensor to copy, distribute, link with or modify the Library
     369subject to these terms and conditions.  You may not impose any further
     370restrictions on the recipients' exercise of the rights granted herein.
     371You are not responsible for enforcing compliance by third parties with
     372this License.
     373
     374  11. If, as a consequence of a court judgment or allegation of patent
     375infringement or for any other reason (not limited to patent issues),
     376conditions are imposed on you (whether by court order, agreement or
     377otherwise) that contradict the conditions of this License, they do not
     378excuse you from the conditions of this License.  If you cannot
     379distribute so as to satisfy simultaneously your obligations under this
     380License and any other pertinent obligations, then as a consequence you
     381may not distribute the Library at all.  For example, if a patent
     382license would not permit royalty-free redistribution of the Library by
     383all those who receive copies directly or indirectly through you, then
     384the only way you could satisfy both it and this License would be to
     385refrain entirely from distribution of the Library.
     386
     387If any portion of this section is held invalid or unenforceable under any
     388particular circumstance, the balance of the section is intended to apply,
     389and the section as a whole is intended to apply in other circumstances.
     390
     391It is not the purpose of this section to induce you to infringe any
     392patents or other property right claims or to contest validity of any
     393such claims; this section has the sole purpose of protecting the
     394integrity of the free software distribution system which is
     395implemented by public license practices.  Many people have made
     396generous contributions to the wide range of software distributed
     397through that system in reliance on consistent application of that
     398system; it is up to the author/donor to decide if he or she is willing
     399to distribute software through any other system and a licensee cannot
     400impose that choice.
     401
     402This section is intended to make thoroughly clear what is believed to
     403be a consequence of the rest of this License.
     404
     405  12. If the distribution and/or use of the Library is restricted in
     406certain countries either by patents or by copyrighted interfaces, the
     407original copyright holder who places the Library under this License may add
     408an explicit geographical distribution limitation excluding those countries,
     409so that distribution is permitted only in or among countries not thus
     410excluded.  In such case, this License incorporates the limitation as if
     411written in the body of this License.
     412
     413  13. The Free Software Foundation may publish revised and/or new
     414versions of the Lesser General Public License from time to time.
     415Such new versions will be similar in spirit to the present version,
     416but may differ in detail to address new problems or concerns.
     417
     418Each version is given a distinguishing version number.  If the Library
     419specifies a version number of this License which applies to it and
     420"any later version", you have the option of following the terms and
     421conditions either of that version or of any later version published by
     422the Free Software Foundation.  If the Library does not specify a
     423license version number, you may choose any version ever published by
     424the Free Software Foundation.
     425
     426  14. If you wish to incorporate parts of the Library into other free
     427programs whose distribution conditions are incompatible with these,
     428write to the author to ask for permission.  For software which is
     429copyrighted by the Free Software Foundation, write to the Free
     430Software Foundation; we sometimes make exceptions for this.  Our
     431decision will be guided by the two goals of preserving the free status
     432of all derivatives of our free software and of promoting the sharing
     433and reuse of software generally.
     434
     435                            NO WARRANTY
     436
     437  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
     438WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
     439EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
     440OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
     441KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
     442IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     443PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
     444LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
     445THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
     446
     447  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
     448WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
     449AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
     450FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
     451CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
     452LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
     453RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
     454FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
     455SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
     456DAMAGES.
     457
     458                     END OF TERMS AND CONDITIONS
     459
     460           How to Apply These Terms to Your New Libraries
     461
     462  If you develop a new library, and you want it to be of the greatest
     463possible use to the public, we recommend making it free software that
     464everyone can redistribute and change.  You can do so by permitting
     465redistribution under these terms (or, alternatively, under the terms of the
     466ordinary General Public License).
     467
     468  To apply these terms, attach the following notices to the library.  It is
     469safest to attach them to the start of each source file to most effectively
     470convey the exclusion of warranty; and each file should have at least the
     471"copyright" line and a pointer to where the full notice is found.
     472
     473    <one line to give the library's name and a brief idea of what it does.>
     474    Copyright (C) <year>  <name of author>
     475
     476    This library is free software; you can redistribute it and/or
     477    modify it under the terms of the GNU Lesser General Public
     478    License as published by the Free Software Foundation; either
     479    version 2.1 of the License, or (at your option) any later version.
     480
     481    This library is distributed in the hope that it will be useful,
     482    but WITHOUT ANY WARRANTY; without even the implied warranty of
     483    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     484    Lesser General Public License for more details.
     485
     486    You should have received a copy of the GNU Lesser General Public
     487    License along with this library; if not, write to the Free Software
     488    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     489
     490Also add information on how to contact you by electronic and paper mail.
     491
     492You should also get your employer (if you work as a programmer) or your
     493school, if any, to sign a "copyright disclaimer" for the library, if
     494necessary.  Here is a sample; alter the names:
     495
     496  Yoyodyne, Inc., hereby disclaims all copyright interest in the
     497  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
     498
     499  <signature of Ty Coon>, 1 April 1990
     500  Ty Coon, President of Vice
     501
     502That's all there is to it!
     503
     504
  • new file wp-includes/PHPMailer/PHPMailerAutoload.php

    diff --git wp-includes/PHPMailer/PHPMailerAutoload.php wp-includes/PHPMailer/PHPMailerAutoload.php
    new file mode 100644
    index 0000000..eaa2e30
    - +  
     1<?php
     2/**
     3 * PHPMailer SPL autoloader.
     4 * PHP Version 5
     5 * @package PHPMailer
     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
     13 * @copyright 2004 - 2009 Andy Prevost
     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.
     18 */
     19
     20/**
     21 * PHPMailer SPL autoloader.
     22 * @param string $classname The name of the class to load
     23 */
     24function PHPMailerAutoload($classname)
     25{
     26    //Can't use __DIR__ as it's only in PHP 5.3+
     27    $filename = dirname(__FILE__).DIRECTORY_SEPARATOR.'class.'.strtolower($classname).'.php';
     28    if (is_readable($filename)) {
     29        require $filename;
     30    }
     31}
     32
     33if (version_compare(PHP_VERSION, '5.1.2', '>=')) {
     34    //SPL autoloading was introduced in PHP 5.1.2
     35    if (version_compare(PHP_VERSION, '5.3.0', '>=')) {
     36        spl_autoload_register('PHPMailerAutoload', true, true);
     37    } else {
     38        spl_autoload_register('PHPMailerAutoload');
     39    }
     40} else {
     41    /**
     42     * Fall back to traditional autoload for old PHP versions
     43     * @param string $classname The name of the class to load
     44     */
     45    function __autoload($classname)
     46    {
     47        PHPMailerAutoload($classname);
     48    }
     49}
  • new file wp-includes/PHPMailer/class.phpmailer.php

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

    diff --git wp-includes/PHPMailer/class.phpmaileroauth.php wp-includes/PHPMailer/class.phpmaileroauth.php
    new file mode 100644
    index 0000000..b1bb09f
    - +  
     1<?php
     2/**
     3 * PHPMailer - PHP email creation and transport class.
     4 * PHP Version 5.4
     5 * @package PHPMailer
     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
     13 * @copyright 2004 - 2009 Andy Prevost
     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.
     18 */
     19
     20/**
     21 * PHPMailerOAuth - PHPMailer subclass adding OAuth support.
     22 * @package PHPMailer
     23 * @author @sherryl4george
     24 * @author Marcus Bointon (@Synchro) <phpmailer@synchromedia.co.uk>
     25 */
     26class PHPMailerOAuth extends PHPMailer
     27{
     28    /**
     29     * The OAuth user's email address
     30     * @var string
     31     */
     32    public $oauthUserEmail = '';
     33
     34    /**
     35     * The OAuth refresh token
     36     * @var string
     37     */
     38    public $oauthRefreshToken = '';
     39
     40    /**
     41     * The OAuth client ID
     42     * @var string
     43     */
     44    public $oauthClientId = '';
     45
     46    /**
     47     * The OAuth client secret
     48     * @var string
     49     */
     50    public $oauthClientSecret = '';
     51
     52    /**
     53     * An instance of the PHPMailerOAuthGoogle class.
     54     * @var PHPMailerOAuthGoogle
     55     * @access protected
     56     */
     57    protected $oauth = null;
     58
     59    /**
     60     * Get a PHPMailerOAuthGoogle instance to use.
     61     * @return PHPMailerOAuthGoogle
     62     */
     63    public function getOAUTHInstance()
     64    {
     65        if (!is_object($this->oauth)) {
     66            $this->oauth = new PHPMailerOAuthGoogle(
     67                $this->oauthUserEmail,
     68                $this->oauthClientSecret,
     69                $this->oauthClientId,
     70                $this->oauthRefreshToken
     71            );
     72        }
     73        return $this->oauth;
     74    }
     75
     76    /**
     77     * Initiate a connection to an SMTP server.
     78     * Overrides the original smtpConnect method to add support for OAuth.
     79     * @param array $options An array of options compatible with stream_context_create()
     80     * @uses SMTP
     81     * @access public
     82     * @return bool
     83     * @throws phpmailerException
     84     */
     85    public function smtpConnect($options = array())
     86    {
     87        if (is_null($this->smtp)) {
     88            $this->smtp = $this->getSMTPInstance();
     89        }
     90
     91        if (is_null($this->oauth)) {
     92            $this->oauth = $this->getOAUTHInstance();
     93        }
     94
     95        // Already connected?
     96        if ($this->smtp->connected()) {
     97            return true;
     98        }
     99
     100        $this->smtp->setTimeout($this->Timeout);
     101        $this->smtp->setDebugLevel($this->SMTPDebug);
     102        $this->smtp->setDebugOutput($this->Debugoutput);
     103        $this->smtp->setVerp($this->do_verp);
     104        $hosts = explode(';', $this->Host);
     105        $lastexception = null;
     106
     107        foreach ($hosts as $hostentry) {
     108            $hostinfo = array();
     109            if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
     110                // Not a valid host entry
     111                continue;
     112            }
     113            // $hostinfo[2]: optional ssl or tls prefix
     114            // $hostinfo[3]: the hostname
     115            // $hostinfo[4]: optional port number
     116            // The host string prefix can temporarily override the current setting for SMTPSecure
     117            // If it's not specified, the default value is used
     118            $prefix = '';
     119            $secure = $this->SMTPSecure;
     120            $tls = ($this->SMTPSecure == 'tls');
     121            if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
     122                $prefix = 'ssl://';
     123                $tls = false; // Can't have SSL and TLS at the same time
     124                $secure = 'ssl';
     125            } elseif ($hostinfo[2] == 'tls') {
     126                $tls = true;
     127                // tls doesn't use a prefix
     128                $secure = 'tls';
     129            }
     130            //Do we need the OpenSSL extension?
     131            $sslext = defined('OPENSSL_ALGO_SHA1');
     132            if ('tls' === $secure or 'ssl' === $secure) {
     133                //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
     134                if (!$sslext) {
     135                    throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
     136                }
     137            }
     138            $host = $hostinfo[3];
     139            $port = $this->Port;
     140            $tport = (integer)$hostinfo[4];
     141            if ($tport > 0 and $tport < 65536) {
     142                $port = $tport;
     143            }
     144            if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
     145                try {
     146                    if ($this->Helo) {
     147                        $hello = $this->Helo;
     148                    } else {
     149                        $hello = $this->serverHostname();
     150                    }
     151                    $this->smtp->hello($hello);
     152                    //Automatically enable TLS encryption if:
     153                    // * it's not disabled
     154                    // * we have openssl extension
     155                    // * we are not already using SSL
     156                    // * the server offers STARTTLS
     157                    if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
     158                        $tls = true;
     159                    }
     160                    if ($tls) {
     161                        if (!$this->smtp->startTLS()) {
     162                            throw new phpmailerException($this->lang('connect_host'));
     163                        }
     164                        // We must resend HELO after tls negotiation
     165                        $this->smtp->hello($hello);
     166                    }
     167                    if ($this->SMTPAuth) {
     168                        if (!$this->smtp->authenticate(
     169                            $this->Username,
     170                            $this->Password,
     171                            $this->AuthType,
     172                            $this->Realm,
     173                            $this->Workstation,
     174                            $this->oauth
     175                        )
     176                        ) {
     177                            throw new phpmailerException($this->lang('authenticate'));
     178                        }
     179                    }
     180                    return true;
     181                } catch (phpmailerException $exc) {
     182                    $lastexception = $exc;
     183                    $this->edebug($exc->getMessage());
     184                    // We must have connected, but then failed TLS or Auth, so close connection nicely
     185                    $this->smtp->quit();
     186                }
     187            }
     188        }
     189        // If we get here, all connection attempts have failed, so close connection hard
     190        $this->smtp->close();
     191        // As we've caught all exceptions, just report whatever the last one was
     192        if ($this->exceptions and !is_null($lastexception)) {
     193            throw $lastexception;
     194        }
     195        return false;
     196    }
     197}
  • new file wp-includes/PHPMailer/class.phpmaileroauthgoogle.php

    diff --git wp-includes/PHPMailer/class.phpmaileroauthgoogle.php wp-includes/PHPMailer/class.phpmaileroauthgoogle.php
    new file mode 100644
    index 0000000..71c9bd3
    - +  
     1<?php
     2/**
     3 * PHPMailer - PHP email creation and transport class.
     4 * PHP Version 5.4
     5 * @package PHPMailer
     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
     13 * @copyright 2004 - 2009 Andy Prevost
     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.
     18 */
     19
     20/**
     21 * PHPMailerOAuthGoogle - Wrapper for League OAuth2 Google provider.
     22 * @package PHPMailer
     23 * @author @sherryl4george
     24 * @author Marcus Bointon (@Synchro) <phpmailer@synchromedia.co.uk>
     25 * @link https://github.com/thephpleague/oauth2-client
     26 */
     27class PHPMailerOAuthGoogle
     28{
     29    private $oauthUserEmail = '';
     30    private $oauthRefreshToken = '';
     31    private $oauthClientId = '';
     32    private $oauthClientSecret = '';
     33
     34    /**
     35     * @param string $UserEmail
     36     * @param string $ClientSecret
     37     * @param string $ClientId
     38     * @param string $RefreshToken
     39     */
     40    public function __construct(
     41        $UserEmail,
     42        $ClientSecret,
     43        $ClientId,
     44        $RefreshToken
     45    ) {
     46        $this->oauthClientId = $ClientId;
     47        $this->oauthClientSecret = $ClientSecret;
     48        $this->oauthRefreshToken = $RefreshToken;
     49        $this->oauthUserEmail = $UserEmail;
     50    }
     51
     52    private function getProvider()
     53    {
     54        return new League\OAuth2\Client\Provider\Google([
     55            'clientId' => $this->oauthClientId,
     56            'clientSecret' => $this->oauthClientSecret
     57        ]);
     58    }
     59
     60    private function getGrant()
     61    {
     62        return new \League\OAuth2\Client\Grant\RefreshToken();
     63    }
     64
     65    private function getToken()
     66    {
     67        $provider = $this->getProvider();
     68        $grant = $this->getGrant();
     69        return $provider->getAccessToken($grant, ['refresh_token' => $this->oauthRefreshToken]);
     70    }
     71
     72    public function getOauth64()
     73    {
     74        $token = $this->getToken();
     75        return base64_encode("user=" . $this->oauthUserEmail . "\001auth=Bearer " . $token . "\001\001");
     76    }
     77}
  • new file wp-includes/PHPMailer/class.pop3.php

    diff --git wp-includes/PHPMailer/class.pop3.php wp-includes/PHPMailer/class.pop3.php
    new file mode 100644
    index 0000000..f10e688
    - +  
     1<?php
     2/**
     3 * PHPMailer POP-Before-SMTP Authentication Class.
     4 * PHP Version 5
     5 * @package PHPMailer
     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
     13 * @copyright 2004 - 2009 Andy Prevost
     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.
     18 */
     19
     20/**
     21 * PHPMailer POP-Before-SMTP Authentication Class.
     22 * Specifically for PHPMailer to use for RFC1939 POP-before-SMTP authentication.
     23 * Does not support APOP.
     24 * @package PHPMailer
     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>
     29 */
     30class POP3
     31{
     32    /**
     33     * The POP3 PHPMailer Version number.
     34     * @var string
     35     * @access public
     36     */
     37    public $Version = '5.2.22';
     38
     39    /**
     40     * Default POP3 port number.
     41     * @var integer
     42     * @access public
     43     */
     44    public $POP3_PORT = 110;
     45
     46    /**
     47     * Default timeout in seconds.
     48     * @var integer
     49     * @access public
     50     */
     51    public $POP3_TIMEOUT = 30;
     52
     53    /**
     54     * POP3 Carriage Return + Line Feed.
     55     * @var string
     56     * @access public
     57     * @deprecated Use the constant instead
     58     */
     59    public $CRLF = "\r\n";
     60
     61    /**
     62     * Debug display level.
     63     * Options: 0 = no, 1+ = yes
     64     * @var integer
     65     * @access public
     66     */
     67    public $do_debug = 0;
     68
     69    /**
     70     * POP3 mail server hostname.
     71     * @var string
     72     * @access public
     73     */
     74    public $host;
     75
     76    /**
     77     * POP3 port number.
     78     * @var integer
     79     * @access public
     80     */
     81    public $port;
     82
     83    /**
     84     * POP3 Timeout Value in seconds.
     85     * @var integer
     86     * @access public
     87     */
     88    public $tval;
     89
     90    /**
     91     * POP3 username
     92     * @var string
     93     * @access public
     94     */
     95    public $username;
     96
     97    /**
     98     * POP3 password.
     99     * @var string
     100     * @access public
     101     */
     102    public $password;
     103
     104    /**
     105     * Resource handle for the POP3 connection socket.
     106     * @var resource
     107     * @access protected
     108     */
     109    protected $pop_conn;
     110
     111    /**
     112     * Are we connected?
     113     * @var boolean
     114     * @access protected
     115     */
     116    protected $connected = false;
     117
     118    /**
     119     * Error container.
     120     * @var array
     121     * @access protected
     122     */
     123    protected $errors = array();
     124
     125    /**
     126     * Line break constant
     127     */
     128    const CRLF = "\r\n";
     129
     130    /**
     131     * Simple static wrapper for all-in-one POP before SMTP
     132     * @param $host
     133     * @param integer|boolean $port The port number to connect to
     134     * @param integer|boolean $timeout The timeout value
     135     * @param string $username
     136     * @param string $password
     137     * @param integer $debug_level
     138     * @return boolean
     139     */
     140    public static function popBeforeSmtp(
     141        $host,
     142        $port = false,
     143        $timeout = false,
     144        $username = '',
     145        $password = '',
     146        $debug_level = 0
     147    ) {
     148        $pop = new POP3;
     149        return $pop->authorise($host, $port, $timeout, $username, $password, $debug_level);
     150    }
     151
     152    /**
     153     * Authenticate with a POP3 server.
     154     * A connect, login, disconnect sequence
     155     * appropriate for POP-before SMTP authorisation.
     156     * @access public
     157     * @param string $host The hostname to connect to
     158     * @param integer|boolean $port The port number to connect to
     159     * @param integer|boolean $timeout The timeout value
     160     * @param string $username
     161     * @param string $password
     162     * @param integer $debug_level
     163     * @return boolean
     164     */
     165    public function authorise($host, $port = false, $timeout = false, $username = '', $password = '', $debug_level = 0)
     166    {
     167        $this->host = $host;
     168        // If no port value provided, use default
     169        if (false === $port) {
     170            $this->port = $this->POP3_PORT;
     171        } else {
     172            $this->port = (integer)$port;
     173        }
     174        // If no timeout value provided, use default
     175        if (false === $timeout) {
     176            $this->tval = $this->POP3_TIMEOUT;
     177        } else {
     178            $this->tval = (integer)$timeout;
     179        }
     180        $this->do_debug = $debug_level;
     181        $this->username = $username;
     182        $this->password = $password;
     183        //  Reset the error log
     184        $this->errors = array();
     185        //  connect
     186        $result = $this->connect($this->host, $this->port, $this->tval);
     187        if ($result) {
     188            $login_result = $this->login($this->username, $this->password);
     189            if ($login_result) {
     190                $this->disconnect();
     191                return true;
     192            }
     193        }
     194        // We need to disconnect regardless of whether the login succeeded
     195        $this->disconnect();
     196        return false;
     197    }
     198
     199    /**
     200     * Connect to a POP3 server.
     201     * @access public
     202     * @param string $host
     203     * @param integer|boolean $port
     204     * @param integer $tval
     205     * @return boolean
     206     */
     207    public function connect($host, $port = false, $tval = 30)
     208    {
     209        //  Are we already connected?
     210        if ($this->connected) {
     211            return true;
     212        }
     213
     214        //On Windows this will raise a PHP Warning error if the hostname doesn't exist.
     215        //Rather than suppress it with @fsockopen, capture it cleanly instead
     216        set_error_handler(array($this, 'catchWarning'));
     217
     218        if (false === $port) {
     219            $port = $this->POP3_PORT;
     220        }
     221
     222        //  connect to the POP3 server
     223        $this->pop_conn = fsockopen(
     224            $host, //  POP3 Host
     225            $port, //  Port #
     226            $errno, //  Error Number
     227            $errstr, //  Error Message
     228            $tval
     229        ); //  Timeout (seconds)
     230        //  Restore the error handler
     231        restore_error_handler();
     232
     233        //  Did we connect?
     234        if (false === $this->pop_conn) {
     235            //  It would appear not...
     236            $this->setError(array(
     237                'error' => "Failed to connect to server $host on port $port",
     238                'errno' => $errno,
     239                'errstr' => $errstr
     240            ));
     241            return false;
     242        }
     243
     244        //  Increase the stream time-out
     245        stream_set_timeout($this->pop_conn, $tval, 0);
     246
     247        //  Get the POP3 server response
     248        $pop3_response = $this->getResponse();
     249        //  Check for the +OK
     250        if ($this->checkResponse($pop3_response)) {
     251            //  The connection is established and the POP3 server is talking
     252            $this->connected = true;
     253            return true;
     254        }
     255        return false;
     256    }
     257
     258    /**
     259     * Log in to the POP3 server.
     260     * Does not support APOP (RFC 2828, 4949).
     261     * @access public
     262     * @param string $username
     263     * @param string $password
     264     * @return boolean
     265     */
     266    public function login($username = '', $password = '')
     267    {
     268        if (!$this->connected) {
     269            $this->setError('Not connected to POP3 server');
     270        }
     271        if (empty($username)) {
     272            $username = $this->username;
     273        }
     274        if (empty($password)) {
     275            $password = $this->password;
     276        }
     277
     278        // Send the Username
     279        $this->sendString("USER $username" . self::CRLF);
     280        $pop3_response = $this->getResponse();
     281        if ($this->checkResponse($pop3_response)) {
     282            // Send the Password
     283            $this->sendString("PASS $password" . self::CRLF);
     284            $pop3_response = $this->getResponse();
     285            if ($this->checkResponse($pop3_response)) {
     286                return true;
     287            }
     288        }
     289        return false;
     290    }
     291
     292    /**
     293     * Disconnect from the POP3 server.
     294     * @access public
     295     */
     296    public function disconnect()
     297    {
     298        $this->sendString('QUIT');
     299        //The QUIT command may cause the daemon to exit, which will kill our connection
     300        //So ignore errors here
     301        try {
     302            @fclose($this->pop_conn);
     303        } catch (Exception $e) {
     304            //Do nothing
     305        };
     306    }
     307
     308    /**
     309     * Get a response from the POP3 server.
     310     * $size is the maximum number of bytes to retrieve
     311     * @param integer $size
     312     * @return string
     313     * @access protected
     314     */
     315    protected function getResponse($size = 128)
     316    {
     317        $response = fgets($this->pop_conn, $size);
     318        if ($this->do_debug >= 1) {
     319            echo "Server -> Client: $response";
     320        }
     321        return $response;
     322    }
     323
     324    /**
     325     * Send raw data to the POP3 server.
     326     * @param string $string
     327     * @return integer
     328     * @access protected
     329     */
     330    protected function sendString($string)
     331    {
     332        if ($this->pop_conn) {
     333            if ($this->do_debug >= 2) { //Show client messages when debug >= 2
     334                echo "Client -> Server: $string";
     335            }
     336            return fwrite($this->pop_conn, $string, strlen($string));
     337        }
     338        return 0;
     339    }
     340
     341    /**
     342     * Checks the POP3 server response.
     343     * Looks for for +OK or -ERR.
     344     * @param string $string
     345     * @return boolean
     346     * @access protected
     347     */
     348    protected function checkResponse($string)
     349    {
     350        if (substr($string, 0, 3) !== '+OK') {
     351            $this->setError(array(
     352                'error' => "Server reported an error: $string",
     353                'errno' => 0,
     354                'errstr' => ''
     355            ));
     356            return false;
     357        } else {
     358            return true;
     359        }
     360    }
     361
     362    /**
     363     * Add an error to the internal error store.
     364     * Also display debug output if it's enabled.
     365     * @param $error
     366     * @access protected
     367     */
     368    protected function setError($error)
     369    {
     370        $this->errors[] = $error;
     371        if ($this->do_debug >= 1) {
     372            echo '<pre>';
     373            foreach ($this->errors as $error) {
     374                print_r($error);
     375            }
     376            echo '</pre>';
     377        }
     378    }
     379
     380    /**
     381     * Get an array of error messages, if any.
     382     * @return array
     383     */
     384    public function getErrors()
     385    {
     386        return $this->errors;
     387    }
     388
     389    /**
     390     * POP3 connection error handler.
     391     * @param integer $errno
     392     * @param string $errstr
     393     * @param string $errfile
     394     * @param integer $errline
     395     * @access protected
     396     */
     397    protected function catchWarning($errno, $errstr, $errfile, $errline)
     398    {
     399        $this->setError(array(
     400            'error' => "Connecting to the POP3 server raised a PHP warning: ",
     401            'errno' => $errno,
     402            'errstr' => $errstr,
     403            'errfile' => $errfile,
     404            'errline' => $errline
     405        ));
     406    }
     407}
  • new file wp-includes/PHPMailer/class.smtp.php

    diff --git wp-includes/PHPMailer/class.smtp.php wp-includes/PHPMailer/class.smtp.php
    new file mode 100644
    index 0000000..8932117
    - +  
     1<?php
     2/**
     3 * PHPMailer RFC821 SMTP email transport class.
     4 * PHP Version 5
     5 * @package PHPMailer
     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 2014 Marcus Bointon
     12 * @copyright 2010 - 2012 Jim Jagielski
     13 * @copyright 2004 - 2009 Andy Prevost
     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.
     18 */
     19
     20/**
     21 * PHPMailer RFC821 SMTP email transport class.
     22 * Implements RFC 821 SMTP commands and provides some utility methods for sending mail to an SMTP server.
     23 * @package PHPMailer
     24 * @author Chris Ryan
     25 * @author Marcus Bointon <phpmailer@synchromedia.co.uk>
     26 */
     27class SMTP
     28{
     29    /**
     30     * The PHPMailer SMTP version number.
     31     * @var string
     32     */
     33    const VERSION = '5.2.22';
     34
     35    /**
     36     * SMTP line break constant.
     37     * @var string
     38     */
     39    const CRLF = "\r\n";
     40
     41    /**
     42     * The SMTP port to use if one is not specified.
     43     * @var integer
     44     */
     45    const DEFAULT_SMTP_PORT = 25;
     46
     47    /**
     48     * The maximum line length allowed by RFC 2822 section 2.1.1
     49     * @var integer
     50     */
     51    const MAX_LINE_LENGTH = 998;
     52
     53    /**
     54     * Debug level for no output
     55     */
     56    const DEBUG_OFF = 0;
     57
     58    /**
     59     * Debug level to show client -> server messages
     60     */
     61    const DEBUG_CLIENT = 1;
     62
     63    /**
     64     * Debug level to show client -> server and server -> client messages
     65     */
     66    const DEBUG_SERVER = 2;
     67
     68    /**
     69     * Debug level to show connection status, client -> server and server -> client messages
     70     */
     71    const DEBUG_CONNECTION = 3;
     72
     73    /**
     74     * Debug level to show all messages
     75     */
     76    const DEBUG_LOWLEVEL = 4;
     77
     78    /**
     79     * The PHPMailer SMTP Version number.
     80     * @var string
     81     * @deprecated Use the `VERSION` constant instead
     82     * @see SMTP::VERSION
     83     */
     84    public $Version = '5.2.22';
     85
     86    /**
     87     * SMTP server port number.
     88     * @var integer
     89     * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead
     90     * @see SMTP::DEFAULT_SMTP_PORT
     91     */
     92    public $SMTP_PORT = 25;
     93
     94    /**
     95     * SMTP reply line ending.
     96     * @var string
     97     * @deprecated Use the `CRLF` constant instead
     98     * @see SMTP::CRLF
     99     */
     100    public $CRLF = "\r\n";
     101
     102    /**
     103     * Debug output level.
     104     * Options:
     105     * * self::DEBUG_OFF (`0`) No debug output, default
     106     * * self::DEBUG_CLIENT (`1`) Client commands
     107     * * self::DEBUG_SERVER (`2`) Client commands and server responses
     108     * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status
     109     * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages
     110     * @var integer
     111     */
     112    public $do_debug = self::DEBUG_OFF;
     113
     114    /**
     115     * How to handle debug output.
     116     * Options:
     117     * * `echo` Output plain-text as-is, appropriate for CLI
     118     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
     119     * * `error_log` Output to error log as configured in php.ini
     120     *
     121     * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
     122     * <code>
     123     * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
     124     * </code>
     125     * @var string|callable
     126     */
     127    public $Debugoutput = 'echo';
     128
     129    /**
     130     * Whether to use VERP.
     131     * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
     132     * @link http://www.postfix.org/VERP_README.html Info on VERP
     133     * @var boolean
     134     */
     135    public $do_verp = false;
     136
     137    /**
     138     * The timeout value for connection, in seconds.
     139     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
     140     * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
     141     * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2
     142     * @var integer
     143     */
     144    public $Timeout = 300;
     145
     146    /**
     147     * How long to wait for commands to complete, in seconds.
     148     * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
     149     * @var integer
     150     */
     151    public $Timelimit = 300;
     152
     153        /**
     154         * @var array patterns to extract smtp transaction id from smtp reply
     155         * Only first capture group will be use, use non-capturing group to deal with it
     156         * Extend this class to override this property to fulfil your needs.
     157         */
     158        protected $smtp_transaction_id_patterns = array(
     159                'exim' => '/[0-9]{3} OK id=(.*)/',
     160                'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
     161                'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
     162        );
     163
     164    /**
     165     * The socket for the server connection.
     166     * @var resource
     167     */
     168    protected $smtp_conn;
     169
     170    /**
     171     * Error information, if any, for the last SMTP command.
     172     * @var array
     173     */
     174    protected $error = array(
     175        'error' => '',
     176        'detail' => '',
     177        'smtp_code' => '',
     178        'smtp_code_ex' => ''
     179    );
     180
     181    /**
     182     * The reply the server sent to us for HELO.
     183     * If null, no HELO string has yet been received.
     184     * @var string|null
     185     */
     186    protected $helo_rply = null;
     187
     188    /**
     189     * The set of SMTP extensions sent in reply to EHLO command.
     190     * Indexes of the array are extension names.
     191     * Value at index 'HELO' or 'EHLO' (according to command that was sent)
     192     * represents the server name. In case of HELO it is the only element of the array.
     193     * Other values can be boolean TRUE or an array containing extension options.
     194     * If null, no HELO/EHLO string has yet been received.
     195     * @var array|null
     196     */
     197    protected $server_caps = null;
     198
     199    /**
     200     * The most recent reply received from the server.
     201     * @var string
     202     */
     203    protected $last_reply = '';
     204
     205    /**
     206     * Output debugging info via a user-selected method.
     207     * @see SMTP::$Debugoutput
     208     * @see SMTP::$do_debug
     209     * @param string $str Debug string to output
     210     * @param integer $level The debug level of this message; see DEBUG_* constants
     211     * @return void
     212     */
     213    protected function edebug($str, $level = 0)
     214    {
     215        if ($level > $this->do_debug) {
     216            return;
     217        }
     218        //Avoid clash with built-in function names
     219        if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
     220            call_user_func($this->Debugoutput, $str, $level);
     221            return;
     222        }
     223        switch ($this->Debugoutput) {
     224            case 'error_log':
     225                //Don't output, just log
     226                error_log($str);
     227                break;
     228            case 'html':
     229                //Cleans up output a bit for a better looking, HTML-safe output
     230                echo htmlentities(
     231                    preg_replace('/[\r\n]+/', '', $str),
     232                    ENT_QUOTES,
     233                    'UTF-8'
     234                )
     235                . "<br>\n";
     236                break;
     237            case 'echo':
     238            default:
     239                //Normalize line breaks
     240                $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
     241                echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
     242                    "\n",
     243                    "\n                   \t                  ",
     244                    trim($str)
     245                )."\n";
     246        }
     247    }
     248
     249    /**
     250     * Connect to an SMTP server.
     251     * @param string $host SMTP server IP or host name
     252     * @param integer $port The port number to connect to
     253     * @param integer $timeout How long to wait for the connection to open
     254     * @param array $options An array of options for stream_context_create()
     255     * @access public
     256     * @return boolean
     257     */
     258    public function connect($host, $port = null, $timeout = 30, $options = array())
     259    {
     260        static $streamok;
     261        //This is enabled by default since 5.0.0 but some providers disable it
     262        //Check this once and cache the result
     263        if (is_null($streamok)) {
     264            $streamok = function_exists('stream_socket_client');
     265        }
     266        // Clear errors to avoid confusion
     267        $this->setError('');
     268        // Make sure we are __not__ connected
     269        if ($this->connected()) {
     270            // Already connected, generate error
     271            $this->setError('Already connected to a server');
     272            return false;
     273        }
     274        if (empty($port)) {
     275            $port = self::DEFAULT_SMTP_PORT;
     276        }
     277        // Connect to the SMTP server
     278        $this->edebug(
     279            "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true),
     280            self::DEBUG_CONNECTION
     281        );
     282        $errno = 0;
     283        $errstr = '';
     284        if ($streamok) {
     285            $socket_context = stream_context_create($options);
     286            set_error_handler(array($this, 'errorHandler'));
     287            $this->smtp_conn = stream_socket_client(
     288                $host . ":" . $port,
     289                $errno,
     290                $errstr,
     291                $timeout,
     292                STREAM_CLIENT_CONNECT,
     293                $socket_context
     294            );
     295            restore_error_handler();
     296        } else {
     297            //Fall back to fsockopen which should work in more places, but is missing some features
     298            $this->edebug(
     299                "Connection: stream_socket_client not available, falling back to fsockopen",
     300                self::DEBUG_CONNECTION
     301            );
     302            set_error_handler(array($this, 'errorHandler'));
     303            $this->smtp_conn = fsockopen(
     304                $host,
     305                $port,
     306                $errno,
     307                $errstr,
     308                $timeout
     309            );
     310            restore_error_handler();
     311        }
     312        // Verify we connected properly
     313        if (!is_resource($this->smtp_conn)) {
     314            $this->setError(
     315                'Failed to connect to server',
     316                $errno,
     317                $errstr
     318            );
     319            $this->edebug(
     320                'SMTP ERROR: ' . $this->error['error']
     321                . ": $errstr ($errno)",
     322                self::DEBUG_CLIENT
     323            );
     324            return false;
     325        }
     326        $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
     327        // SMTP server can take longer to respond, give longer timeout for first read
     328        // Windows does not have support for this timeout function
     329        if (substr(PHP_OS, 0, 3) != 'WIN') {
     330            $max = ini_get('max_execution_time');
     331            // Don't bother if unlimited
     332            if ($max != 0 && $timeout > $max) {
     333                @set_time_limit($timeout);
     334            }
     335            stream_set_timeout($this->smtp_conn, $timeout, 0);
     336        }
     337        // Get any announcement
     338        $announce = $this->get_lines();
     339        $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
     340        return true;
     341    }
     342
     343    /**
     344     * Initiate a TLS (encrypted) session.
     345     * @access public
     346     * @return boolean
     347     */
     348    public function startTLS()
     349    {
     350        if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
     351            return false;
     352        }
     353
     354        //Allow the best TLS version(s) we can
     355        $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
     356
     357        //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
     358        //so add them back in manually if we can
     359        if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
     360            $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
     361            $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
     362        }
     363
     364        // Begin encrypted connection
     365        if (!stream_socket_enable_crypto(
     366            $this->smtp_conn,
     367            true,
     368            $crypto_method
     369        )) {
     370            return false;
     371        }
     372        return true;
     373    }
     374
     375    /**
     376     * Perform SMTP authentication.
     377     * Must be run after hello().
     378     * @see hello()
     379     * @param string $username The user name
     380     * @param string $password The password
     381     * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2)
     382     * @param string $realm The auth realm for NTLM
     383     * @param string $workstation The auth workstation for NTLM
     384     * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth)
     385     * @return bool True if successfully authenticated.* @access public
     386     */
     387    public function authenticate(
     388        $username,
     389        $password,
     390        $authtype = null,
     391        $realm = '',
     392        $workstation = '',
     393        $OAuth = null
     394    ) {
     395        if (!$this->server_caps) {
     396            $this->setError('Authentication is not allowed before HELO/EHLO');
     397            return false;
     398        }
     399
     400        if (array_key_exists('EHLO', $this->server_caps)) {
     401        // SMTP extensions are available. Let's try to find a proper authentication method
     402
     403            if (!array_key_exists('AUTH', $this->server_caps)) {
     404                $this->setError('Authentication is not allowed at this stage');
     405                // 'at this stage' means that auth may be allowed after the stage changes
     406                // e.g. after STARTTLS
     407                return false;
     408            }
     409
     410            self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
     411            self::edebug(
     412                'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
     413                self::DEBUG_LOWLEVEL
     414            );
     415
     416            if (empty($authtype)) {
     417                foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) {
     418                    if (in_array($method, $this->server_caps['AUTH'])) {
     419                        $authtype = $method;
     420                        break;
     421                    }
     422                }
     423                if (empty($authtype)) {
     424                    $this->setError('No supported authentication methods found');
     425                    return false;
     426                }
     427                self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
     428            }
     429
     430            if (!in_array($authtype, $this->server_caps['AUTH'])) {
     431                $this->setError("The requested authentication method \"$authtype\" is not supported by the server");
     432                return false;
     433            }
     434        } elseif (empty($authtype)) {
     435            $authtype = 'LOGIN';
     436        }
     437        switch ($authtype) {
     438            case 'PLAIN':
     439                // Start authentication
     440                if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
     441                    return false;
     442                }
     443                // Send encoded username and password
     444                if (!$this->sendCommand(
     445                    'User & Password',
     446                    base64_encode("\0" . $username . "\0" . $password),
     447                    235
     448                )
     449                ) {
     450                    return false;
     451                }
     452                break;
     453            case 'LOGIN':
     454                // Start authentication
     455                if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
     456                    return false;
     457                }
     458                if (!$this->sendCommand("Username", base64_encode($username), 334)) {
     459                    return false;
     460                }
     461                if (!$this->sendCommand("Password", base64_encode($password), 235)) {
     462                    return false;
     463                }
     464                break;
     465            case 'XOAUTH2':
     466                //If the OAuth Instance is not set. Can be a case when PHPMailer is used
     467                //instead of PHPMailerOAuth
     468                if (is_null($OAuth)) {
     469                    return false;
     470                }
     471                $oauth = $OAuth->getOauth64();
     472
     473                // Start authentication
     474                if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
     475                    return false;
     476                }
     477                break;
     478            case 'NTLM':
     479                /*
     480                 * ntlm_sasl_client.php
     481                 * Bundled with Permission
     482                 *
     483                 * How to telnet in windows:
     484                 * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
     485                 * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
     486                 */
     487                require_once 'extras/ntlm_sasl_client.php';
     488                $temp = new stdClass;
     489                $ntlm_client = new ntlm_sasl_client_class;
     490                //Check that functions are available
     491                if (!$ntlm_client->initialize($temp)) {
     492                    $this->setError($temp->error);
     493                    $this->edebug(
     494                        'You need to enable some modules in your php.ini file: '
     495                        . $this->error['error'],
     496                        self::DEBUG_CLIENT
     497                    );
     498                    return false;
     499                }
     500                //msg1
     501                $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1
     502
     503                if (!$this->sendCommand(
     504                    'AUTH NTLM',
     505                    'AUTH NTLM ' . base64_encode($msg1),
     506                    334
     507                )
     508                ) {
     509                    return false;
     510                }
     511                //Though 0 based, there is a white space after the 3 digit number
     512                //msg2
     513                $challenge = substr($this->last_reply, 3);
     514                $challenge = base64_decode($challenge);
     515                $ntlm_res = $ntlm_client->NTLMResponse(
     516                    substr($challenge, 24, 8),
     517                    $password
     518                );
     519                //msg3
     520                $msg3 = $ntlm_client->typeMsg3(
     521                    $ntlm_res,
     522                    $username,
     523                    $realm,
     524                    $workstation
     525                );
     526                // send encoded username
     527                return $this->sendCommand('Username', base64_encode($msg3), 235);
     528            case 'CRAM-MD5':
     529                // Start authentication
     530                if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
     531                    return false;
     532                }
     533                // Get the challenge
     534                $challenge = base64_decode(substr($this->last_reply, 4));
     535
     536                // Build the response
     537                $response = $username . ' ' . $this->hmac($challenge, $password);
     538
     539                // send encoded credentials
     540                return $this->sendCommand('Username', base64_encode($response), 235);
     541            default:
     542                $this->setError("Authentication method \"$authtype\" is not supported");
     543                return false;
     544        }
     545        return true;
     546    }
     547
     548    /**
     549     * Calculate an MD5 HMAC hash.
     550     * Works like hash_hmac('md5', $data, $key)
     551     * in case that function is not available
     552     * @param string $data The data to hash
     553     * @param string $key  The key to hash with
     554     * @access protected
     555     * @return string
     556     */
     557    protected function hmac($data, $key)
     558    {
     559        if (function_exists('hash_hmac')) {
     560            return hash_hmac('md5', $data, $key);
     561        }
     562
     563        // The following borrowed from
     564        // http://php.net/manual/en/function.mhash.php#27225
     565
     566        // RFC 2104 HMAC implementation for php.
     567        // Creates an md5 HMAC.
     568        // Eliminates the need to install mhash to compute a HMAC
     569        // by Lance Rushing
     570
     571        $bytelen = 64; // byte length for md5
     572        if (strlen($key) > $bytelen) {
     573            $key = pack('H*', md5($key));
     574        }
     575        $key = str_pad($key, $bytelen, chr(0x00));
     576        $ipad = str_pad('', $bytelen, chr(0x36));
     577        $opad = str_pad('', $bytelen, chr(0x5c));
     578        $k_ipad = $key ^ $ipad;
     579        $k_opad = $key ^ $opad;
     580
     581        return md5($k_opad . pack('H*', md5($k_ipad . $data)));
     582    }
     583
     584    /**
     585     * Check connection state.
     586     * @access public
     587     * @return boolean True if connected.
     588     */
     589    public function connected()
     590    {
     591        if (is_resource($this->smtp_conn)) {
     592            $sock_status = stream_get_meta_data($this->smtp_conn);
     593            if ($sock_status['eof']) {
     594                // The socket is valid but we are not connected
     595                $this->edebug(
     596                    'SMTP NOTICE: EOF caught while checking if connected',
     597                    self::DEBUG_CLIENT
     598                );
     599                $this->close();
     600                return false;
     601            }
     602            return true; // everything looks good
     603        }
     604        return false;
     605    }
     606
     607    /**
     608     * Close the socket and clean up the state of the class.
     609     * Don't use this function without first trying to use QUIT.
     610     * @see quit()
     611     * @access public
     612     * @return void
     613     */
     614    public function close()
     615    {
     616        $this->setError('');
     617        $this->server_caps = null;
     618        $this->helo_rply = null;
     619        if (is_resource($this->smtp_conn)) {
     620            // close the connection and cleanup
     621            fclose($this->smtp_conn);
     622            $this->smtp_conn = null; //Makes for cleaner serialization
     623            $this->edebug('Connection: closed', self::DEBUG_CONNECTION);
     624        }
     625    }
     626
     627    /**
     628     * Send an SMTP DATA command.
     629     * Issues a data command and sends the msg_data to the server,
     630     * finializing the mail transaction. $msg_data is the message
     631     * that is to be send with the headers. Each header needs to be
     632     * on a single line followed by a <CRLF> with the message headers
     633     * and the message body being separated by and additional <CRLF>.
     634     * Implements rfc 821: DATA <CRLF>
     635     * @param string $msg_data Message data to send
     636     * @access public
     637     * @return boolean
     638     */
     639    public function data($msg_data)
     640    {
     641        //This will use the standard timelimit
     642        if (!$this->sendCommand('DATA', 'DATA', 354)) {
     643            return false;
     644        }
     645
     646        /* The server is ready to accept data!
     647         * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF)
     648         * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into
     649         * smaller lines to fit within the limit.
     650         * We will also look for lines that start with a '.' and prepend an additional '.'.
     651         * NOTE: this does not count towards line-length limit.
     652         */
     653
     654        // Normalize line breaks before exploding
     655        $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
     656
     657        /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
     658         * of the first line (':' separated) does not contain a space then it _should_ be a header and we will
     659         * process all lines before a blank line as headers.
     660         */
     661
     662        $field = substr($lines[0], 0, strpos($lines[0], ':'));
     663        $in_headers = false;
     664        if (!empty($field) && strpos($field, ' ') === false) {
     665            $in_headers = true;
     666        }
     667
     668        foreach ($lines as $line) {
     669            $lines_out = array();
     670            if ($in_headers and $line == '') {
     671                $in_headers = false;
     672            }
     673            //Break this line up into several smaller lines if it's too long
     674            //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len),
     675            while (isset($line[self::MAX_LINE_LENGTH])) {
     676                //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on
     677                //so as to avoid breaking in the middle of a word
     678                $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
     679                //Deliberately matches both false and 0
     680                if (!$pos) {
     681                    //No nice break found, add a hard break
     682                    $pos = self::MAX_LINE_LENGTH - 1;
     683                    $lines_out[] = substr($line, 0, $pos);
     684                    $line = substr($line, $pos);
     685                } else {
     686                    //Break at the found point
     687                    $lines_out[] = substr($line, 0, $pos);
     688                    //Move along by the amount we dealt with
     689                    $line = substr($line, $pos + 1);
     690                }
     691                //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1
     692                if ($in_headers) {
     693                    $line = "\t" . $line;
     694                }
     695            }
     696            $lines_out[] = $line;
     697
     698            //Send the lines to the server
     699            foreach ($lines_out as $line_out) {
     700                //RFC2821 section 4.5.2
     701                if (!empty($line_out) and $line_out[0] == '.') {
     702                    $line_out = '.' . $line_out;
     703                }
     704                $this->client_send($line_out . self::CRLF);
     705            }
     706        }
     707
     708        //Message data has been sent, complete the command
     709        //Increase timelimit for end of DATA command
     710        $savetimelimit = $this->Timelimit;
     711        $this->Timelimit = $this->Timelimit * 2;
     712        $result = $this->sendCommand('DATA END', '.', 250);
     713        //Restore timelimit
     714        $this->Timelimit = $savetimelimit;
     715        return $result;
     716    }
     717
     718    /**
     719     * Send an SMTP HELO or EHLO command.
     720     * Used to identify the sending server to the receiving server.
     721     * This makes sure that client and server are in a known state.
     722     * Implements RFC 821: HELO <SP> <domain> <CRLF>
     723     * and RFC 2821 EHLO.
     724     * @param string $host The host name or IP to connect to
     725     * @access public
     726     * @return boolean
     727     */
     728    public function hello($host = '')
     729    {
     730        //Try extended hello first (RFC 2821)
     731        return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
     732    }
     733
     734    /**
     735     * Send an SMTP HELO or EHLO command.
     736     * Low-level implementation used by hello()
     737     * @see hello()
     738     * @param string $hello The HELO string
     739     * @param string $host The hostname to say we are
     740     * @access protected
     741     * @return boolean
     742     */
     743    protected function sendHello($hello, $host)
     744    {
     745        $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
     746        $this->helo_rply = $this->last_reply;
     747        if ($noerror) {
     748            $this->parseHelloFields($hello);
     749        } else {
     750            $this->server_caps = null;
     751        }
     752        return $noerror;
     753    }
     754
     755    /**
     756     * Parse a reply to HELO/EHLO command to discover server extensions.
     757     * In case of HELO, the only parameter that can be discovered is a server name.
     758     * @access protected
     759     * @param string $type - 'HELO' or 'EHLO'
     760     */
     761    protected function parseHelloFields($type)
     762    {
     763        $this->server_caps = array();
     764        $lines = explode("\n", $this->helo_rply);
     765
     766        foreach ($lines as $n => $s) {
     767            //First 4 chars contain response code followed by - or space
     768            $s = trim(substr($s, 4));
     769            if (empty($s)) {
     770                continue;
     771            }
     772            $fields = explode(' ', $s);
     773            if (!empty($fields)) {
     774                if (!$n) {
     775                    $name = $type;
     776                    $fields = $fields[0];
     777                } else {
     778                    $name = array_shift($fields);
     779                    switch ($name) {
     780                        case 'SIZE':
     781                            $fields = ($fields ? $fields[0] : 0);
     782                            break;
     783                        case 'AUTH':
     784                            if (!is_array($fields)) {
     785                                $fields = array();
     786                            }
     787                            break;
     788                        default:
     789                            $fields = true;
     790                    }
     791                }
     792                $this->server_caps[$name] = $fields;
     793            }
     794        }
     795    }
     796
     797    /**
     798     * Send an SMTP MAIL command.
     799     * Starts a mail transaction from the email address specified in
     800     * $from. Returns true if successful or false otherwise. If True
     801     * the mail transaction is started and then one or more recipient
     802     * commands may be called followed by a data command.
     803     * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
     804     * @param string $from Source address of this message
     805     * @access public
     806     * @return boolean
     807     */
     808    public function mail($from)
     809    {
     810        $useVerp = ($this->do_verp ? ' XVERP' : '');
     811        return $this->sendCommand(
     812            'MAIL FROM',
     813            'MAIL FROM:<' . $from . '>' . $useVerp,
     814            250
     815        );
     816    }
     817
     818    /**
     819     * Send an SMTP QUIT command.
     820     * Closes the socket if there is no error or the $close_on_error argument is true.
     821     * Implements from rfc 821: QUIT <CRLF>
     822     * @param boolean $close_on_error Should the connection close if an error occurs?
     823     * @access public
     824     * @return boolean
     825     */
     826    public function quit($close_on_error = true)
     827    {
     828        $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
     829        $err = $this->error; //Save any error
     830        if ($noerror or $close_on_error) {
     831            $this->close();
     832            $this->error = $err; //Restore any error from the quit command
     833        }
     834        return $noerror;
     835    }
     836
     837    /**
     838     * Send an SMTP RCPT command.
     839     * Sets the TO argument to $toaddr.
     840     * Returns true if the recipient was accepted false if it was rejected.
     841     * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
     842     * @param string $address The address the message is being sent to
     843     * @access public
     844     * @return boolean
     845     */
     846    public function recipient($address)
     847    {
     848        return $this->sendCommand(
     849            'RCPT TO',
     850            'RCPT TO:<' . $address . '>',
     851            array(250, 251)
     852        );
     853    }
     854
     855    /**
     856     * Send an SMTP RSET command.
     857     * Abort any transaction that is currently in progress.
     858     * Implements rfc 821: RSET <CRLF>
     859     * @access public
     860     * @return boolean True on success.
     861     */
     862    public function reset()
     863    {
     864        return $this->sendCommand('RSET', 'RSET', 250);
     865    }
     866
     867    /**
     868     * Send a command to an SMTP server and check its return code.
     869     * @param string $command The command name - not sent to the server
     870     * @param string $commandstring The actual command to send
     871     * @param integer|array $expect One or more expected integer success codes
     872     * @access protected
     873     * @return boolean True on success.
     874     */
     875    protected function sendCommand($command, $commandstring, $expect)
     876    {
     877        if (!$this->connected()) {
     878            $this->setError("Called $command without being connected");
     879            return false;
     880        }
     881        //Reject line breaks in all commands
     882        if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) {
     883            $this->setError("Command '$command' contained line breaks");
     884            return false;
     885        }
     886        $this->client_send($commandstring . self::CRLF);
     887
     888        $this->last_reply = $this->get_lines();
     889        // Fetch SMTP code and possible error code explanation
     890        $matches = array();
     891        if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
     892            $code = $matches[1];
     893            $code_ex = (count($matches) > 2 ? $matches[2] : null);
     894            // Cut off error code from each response line
     895            $detail = preg_replace(
     896                "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m",
     897                '',
     898                $this->last_reply
     899            );
     900        } else {
     901            // Fall back to simple parsing if regex fails
     902            $code = substr($this->last_reply, 0, 3);
     903            $code_ex = null;
     904            $detail = substr($this->last_reply, 4);
     905        }
     906
     907        $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
     908
     909        if (!in_array($code, (array)$expect)) {
     910            $this->setError(
     911                "$command command failed",
     912                $detail,
     913                $code,
     914                $code_ex
     915            );
     916            $this->edebug(
     917                'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
     918                self::DEBUG_CLIENT
     919            );
     920            return false;
     921        }
     922
     923        $this->setError('');
     924        return true;
     925    }
     926
     927    /**
     928     * Send an SMTP SAML command.
     929     * Starts a mail transaction from the email address specified in $from.
     930     * Returns true if successful or false otherwise. If True
     931     * the mail transaction is started and then one or more recipient
     932     * commands may be called followed by a data command. This command
     933     * will send the message to the users terminal if they are logged
     934     * in and send them an email.
     935     * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>