diff --git a/cron.php b/cron.php
index 9643008..ff3bf18 100644
--- a/cron.php
+++ b/cron.php
@@ -10,11 +10,11 @@
//test();
$_SERVER["PHP_AUTH_USER"] = "cron";
//peripetieDatee();
- print "envoi des courriers en attente" . EOL;
+ print "envoi des courriers en attente" . EOLH;
envoiCourrielEnattente();
- print "envoi des péripéties" . EOL;
+ print "envoi des péripéties" . EOLH;
peripeties();
- print "Envoi des arrivées" . EOL;
+ print "Envoi des arrivées" . EOLH;
arrivee();
function peripetieDatee()
@@ -38,8 +38,8 @@
$indexObjet = "Objet_" . $p['indexText'];
$objetMail = $dicoExpe["Objet_" . $p['indexText']];
$mailText = $dicoExpe[$p['indexText']] .EOL .EOL ;
- print $objetMail .EOLH;
- print $mailText .EOLH;
+ print $objetMail . EOLH;
+ print $mailText . EOLH;
envoiMail( $result['destMail'], $objetMail, $mailText, false);
sleep(1);
envoiMail( $result['expeMail'], $objetMail, $mailText, true);
@@ -51,6 +51,8 @@
function peripeties() //recherche des péripéties non datées
{
global $db, $base_url;
+ $r = 0;
+ $s = 0;
// ouverture DB peripéties
$dbPeripetie = new db();
// requête Mysql
@@ -58,55 +60,63 @@
$dbPeripetie->query($query);
$peripeties = $dbPeripetie->result->fetch_all(MYSQLI_ASSOC);
$dbPeripetie->close();
-
foreach ( $peripeties as $peripetie)
{
- print "avion poème n° " . $peripetie['idAvion'] .EOL;
+ print "péripétie " . $peripetie["idAP"] . " - avion poème n° " . $peripetie['idAvion'] .EOLH;
$db->getPlane($peripetie['idAvion']);
- $dicoExpe = getLang( $db->expeLang );
- $dicoDest = getLang( $db->destLang );
- // TODO calcul de la nouvelle date d'arrivée
- $dateExpe = new DateTime("@$db->startTime");
- $dateDest = new DateTime("@$db->deliveryTime");
- $interval = $dateExpe->diff($dateDest);
- $numericInterval = (($interval->days*24 + $interval->h)*60 + $interval->i)*60 + $interval->s;
- $addDate = $numericInterval * 15/100;
- $db->deliveryTime += $addDate;
- $db->deliveryTimeServer += $addDate;
- $query = "UPDATE avionpoeme SET deliveryTime=FROM_UNIXTIME(" . $db->deliveryTime . "), deliveryTimeServer=FROM_UNIXTIME(" . $db->deliveryTimeServer . ") WHERE idAvion='" . $peripetie['idAvion'] . "'" ;
- $db->query($query);
- $db->urlAvion = $base_url . "/?avionpoeme=" . $db->uid;
- $db->datePeripetie = formatteDate($db->expeLang, $db->deliveryTime, $db->startTZ);
- $indexObjet = "Objet_" . $peripetie['indexText'];
- $result = replaceVariables($db, $dicoExpe["Objet_" . $peripetie['indexText']], $dicoExpe);
- $objetMail = $result["text"];
- $result = replaceVariables($db, $dicoExpe[$peripetie['indexText']], $dicoExpe);
- $mailText = $result["text"];
- //$html = $result['html'];
- sleep(1);
- print "envoi courriel à l'expéditeur" .EOL;
- $r = envoiMail( $db->expeMail, $objetMail, $mailText);
- $db->datePeripetie = formatteDate($db->destLang, $db->deliveryTime, $db->deliveryTZ);
- $result = replaceVariables($db, $dicoDest["Objet_" . $peripetie['indexText']], $dicoDest);
- $objetMail = $result["text"];
- $result = replaceVariables($db, $dicoDest[$peripetie['indexText']], $dicoDest);
- $mailText = $result["text"] .EOLH .EOLH;
- print "envoi courriel au destinataire" .EOL;
- $s = envoiMail( $db->destMail, $objetMail, $mailText);
- sleep(1);
- //print "r=" . $r ." => s=" .$s .EOLH;
-
- if ($r AND $s)
+ if ($db->connect->affected_rows == 0)
{
- $query = "UPDATE avionPeripetie SET mailSent=true WHERE idAP='" . $peripetie['idAP'] ."'";
- $db->query($query);
- }else
- {
- print "table avion péripétie non mise à jour" .EOL;
- print "UPDATE avionPeripetie SET mailSent=true WHERE idAP='" . $peripetie['idAP'] ."'" .EOL;
+ log_error("Péripétie " . $peripetie["idAP"] . "n'a pas d'avion associé idAvion=>" . $peripetie['idAvion']);
+ print "Péripétie " . $peripetie["idAP"] . "n'a pas d'avion associé idAvion=>" . $peripetie['idAvion'];
}
+ else
+ {
+ //print_r($db);
+ $dicoExpe = getLang( $db->expeLang );
+ $dicoDest = getLang( $db->destLang );
+ // TODO calcul de la nouvelle date d'arrivée
+ $dateExpe = new DateTime("@$db->startTime");
+ $dateDest = new DateTime("@$db->deliveryTime");
+ $interval = $dateExpe->diff($dateDest);
+ $numericInterval = (($interval->days*24 + $interval->h)*60 + $interval->i)*60 + $interval->s;
+ $addDate = $numericInterval * 15/100;
+ $db->deliveryTime += $addDate;
+ $db->deliveryTimeServer += $addDate;
+ $query = "UPDATE avionpoeme SET deliveryTime=FROM_UNIXTIME(" . $db->deliveryTime . "), deliveryTimeServer=FROM_UNIXTIME(" . $db->deliveryTimeServer . ") WHERE idAvion='" . $peripetie['idAvion'] . "'" ;
+ $db->query($query);
+ $db->urlAvion = $base_url . "/?avionpoeme=" . $db->uid;
+ $db->datePeripetie = formatteDate($db->expeLang, $db->deliveryTime, $db->startTZ);
+ $indexObjet = "Objet_" . $peripetie['indexText'];
+ $result = replaceVariables($db, $dicoExpe["Objet_" . $peripetie['indexText']], $dicoExpe);
+ $objetMail = $result["text"];
+ $result = replaceVariables($db, $dicoExpe[$peripetie['indexText']], $dicoExpe);
+ $mailText = $result["text"];
+ //$html = $result['html'];
+ sleep(1);
+ print "envoi courriel à l'expéditeur : " . $db->expeMail . EOLH . $mailText .EOLH;
+ $r = envoiMail( $db->expeMail, $objetMail, $mailText);
+ $db->datePeripetie = formatteDate($db->destLang, $db->deliveryTime, $db->deliveryTZ);
+ $result = replaceVariables($db, $dicoDest["Objet_" . $peripetie['indexText']], $dicoDest);
+ $objetMail = $result["text"];
+ $result = replaceVariables($db, $dicoDest[$peripetie['indexText']], $dicoDest);
+ $mailText = $result["text"] . EOLH . EOLH;
+ print "envoi courriel au destinataire : " . $db->destMail . EOLH . $mailText .EOLH;
+ $s = envoiMail( $db->destMail, $objetMail, $mailText);
+ sleep(1);
+ //print "r=" . $r ." => s=" .$s .EOLH;
- sleep(1);
+ if ($r AND $s)
+ {
+ $query = "UPDATE avionPeripetie SET mailSent=true WHERE idAP='" . $peripetie['idAP'] ."'";
+ $db->query($query);
+ }else
+ {
+ print "table avion péripétie non mise à jour" .EOL;
+ print "UPDATE avionPeripetie SET mailSent=true WHERE idAP='" . $peripetie['idAP'] ."'" .EOLH;
+ }
+
+ sleep(1);
+ }
}
}
@@ -114,35 +124,40 @@
function arrivee()
{
global $db;
+ $r = 0;
+ $s = 0;
//recherche des avions atteris
$query = "SELECT * FROM avionpoeme WHERE atteri = 0 AND TIMEDIFF(CONCAT_WS(' ',CURDATE(),CURTIME()),deliveryTimeServer) > '00:00'";
$db->query($query);
$avionArrive = $db->result->fetch_all(MYSQLI_ASSOC);
+ var_dump($avionArrive);
foreach ($avionArrive as $avion)
{
- print "avion poème n° " . $avion['idAvion'] . EOLH;
+ print "avion poème n° " . $avion['idAvion'] . "a atterri" . EOLH;
$dicoExpe = getLang( $avion['expeLang'] );
$dicoDest = getLang( $avion['destLang'] );
- $index = "Notification_Arrivee_Expediteur";
- $indexObjet = "Objet_";
- $objetMail = replaceVariables($db, $dicoExpe[$indexObjet . $index], $dicoExpe);
- $result = replaceVariables($db, $dicoExpe[$index], $dicoExpe);
- $mailText= $result["text"];
- print "envoi courriel à l'expéditeur". EOLH;
- $r = envoiMail( $avion['expeMail'], $objetMail["text"], $mailText);
- sleep(1);
- $index = "Notification_Arrivee_Destinataire";
- $objetMail = replaceVariables($db, $dicoDest[$indexObjet . $index], $dicoDest);
- $result = replaceVariables($db, $dicoDest[$index], $dicoDest);
- log_write(__FILE__ . EOL . __LINE__ . EOL . "#" .print_r($result, true) . "#", INFO);
+ //envoi notification arrivée expéditeur
+ $indexObjet = "Objet_";
+ $index = "Notification_Arrivee_Expediteur";
+ $objetMail = replaceVariables( (object)$avion, $dicoExpe[$indexObjet . $index], $dicoExpe);
+ $result = replaceVariables((object)$avion, $dicoExpe[$index], $dicoExpe);
+ $mailText= $result["text"];
+ print "envoi courriel à l'expéditeur : " . $avion['expeMail'] . EOLH . $mailText .EOLH;
+ $r = envoiMail( $avion['expeMail'], $objetMail["text"], $mailText);
+
+ //envoi notification arrivée destinataire
+ $index = "Notification_Arrivee_Destinataire";
+ $objetMail = replaceVariables((object)$avion, $dicoDest[$indexObjet . $index], $dicoDest);
+ $result = replaceVariables((object)$avion, $dicoDest[$index], $dicoDest);
$mailText = $result["text"];
$html = $result['html'];
if ( $html )
{
$mailText = "
\n" . $mailText . "";
}
- print "envoi courriel au destinataire" . EOLH;
+ print "envoi courriel au destinataire : " . $avion['destMail'] . EOLH . $mailText .EOLH;
+ sleep(1);
$s = envoiMail( $avion['destMail'], $objetMail["text"], $mailText, $html);
if ($r AND $s)
{
diff --git a/gestion/genere_lang.php b/gestion/genere_lang.php
index fbc7601..8a06e40 100644
--- a/gestion/genere_lang.php
+++ b/gestion/genere_lang.php
@@ -7,8 +7,8 @@
if ( isset($_GET["ok"] ))
{
$fisrt_line = false;
- $fh = fopen("../lang/9mfo-traduction.csv", "r") or die("Can't open csv");
- $fhIndex = fopen("../lang/lang.json", "w") or die("Can't open lang/lang.json");
+ $fh = fopen("../lang/9mfo-traduction.csv", "r") or die( __FILE__ ." ligne: " . __LINE__ . " Can't open csv");
+ $fhIndex = fopen("../lang/lang.json", "w") or die( __FILE__ ." ligne: " . __LINE__ . " Can't open lang/lang.json");
fwrite($fhIndex, '{');
$first_line = true;
$first_column_line = true;
@@ -36,7 +36,7 @@
$index = explode("/",$column);
echo "opening ../lang/" . $index[0] . EOLH;
- $fhl[++$i] = fopen("../lang/" . $index[0], "wb") or die("can't open lang/" . $index[0]);
+ $fhl[++$i] = fopen("../lang/" . $index[0], "wb") or die( __FILE__ ." ligne: " . __LINE__ . " can't open lang/" . $index[0]);
fwrite($fhl[$i], '{');
if ( $first_column == true )
{
@@ -92,19 +92,21 @@
fwrite($fhx, '}');
fclose($fhx);
}
- $fh = fopen("../lang/lang.json","r");
+ $fh = fopen("../lang/lang.json","r") or die("Can't open ../lang/lang.json" . __FILE__ ." ligne: " . __LINE__);
$str = fgets($fh);
fclose($fh);
- $lang = json_decode( $str, true);
- foreach ($lang as $key => $value)
+ $langArray = json_decode( $str, true);
+ foreach ($langArray as $key => $value)
{
- print $key ." : ";
- if ( getLang($key, true) !== false )
+
+ $lang = getLang($key, true);
+ if ( $lang != false )
{
+ print $key ." : ";
print json_last_error_msg() . EOLH;
}else
{
- print "erreur à l'ouverture du fichier";
+ print __FILE__ ." ligne: " . __LINE__ . " erreur à l'ouverture du fichier";
}
}
}
diff --git a/gestion/gestionDB.php b/gestion/gestionDB.php
new file mode 100644
index 0000000..6f0f059
--- /dev/null
+++ b/gestion/gestionDB.php
@@ -0,0 +1,83 @@
+" . $accueil;
+ header( 'Location: ' . $accueil );
+}*/
+require_once '../session_init.php';
+require_once 'config.inc.php';
+require_once 'db.class.php';
+require_once 'envoi_courriel.inc.php';
+require_once 'log.php';
+print '
+
+
+
+
+ Administration
+
+
+
+
+
+
+';
+
+
+verifPeripetieAvion();
+
+function verifAvionpoeme()
+{
+ $query = "SELECT * FROM avionpoeme";
+ $db->query($query);
+ $avions = $db->result->fetch_all(MYSQLI_ASSOC);
+ foreach($avions as $avion)
+ {
+
+ }
+ return $fresult;
+}
+
+function verifPeripetieAvion()
+{
+ print "Vérification des liens péripétie/avionpoème" . EOLH;
+ $db = new db();
+ // requête Mysql
+ $query = "SELECT * FROM avionPeripetie";
+ $db->query($query);
+ $peripeties = $db->result->fetch_all(MYSQLI_ASSOC);
+
+ $query = "SELECT * FROM avionpoeme";
+ $db->query($query);
+ $avions = $db->result->fetch_all(MYSQLI_ASSOC);
+ $avionsId = array_column($avions, 'expeMail', 'idAvion');
+ print_r($avionsId);
+ foreach($peripeties as $peripetie)
+ {
+ print "Péripétie " . $peripetie["idAP"] . EOLH;
+ $idAvion = $peripetie["idAvion"];
+ if ( empty($avionsId[$idAvion]) )
+ {
+ print "Péripétie " . $peripetie["idAP"] . " n'a pas d'avion poème idAvion=>" . $idAvion . EOLH;
+ }
+ }
+ $db->close();
+}
+print "";
+?>
diff --git a/gestion/index.php b/gestion/index.php
index d194559..b58d888 100644
--- a/gestion/index.php
+++ b/gestion/index.php
@@ -1,4 +1,7 @@
-
+
@@ -27,5 +30,9 @@
-Générer les fichiers de langue
-Lire les logs
+Générer les fichiers de langue
+Lire les logs
+Vérifier la base de données
+
+
+
diff --git a/include/db.class.php b/include/db.class.php
index 3fa0e69..079f9c5 100644
--- a/include/db.class.php
+++ b/include/db.class.php
@@ -169,6 +169,7 @@ class db
$this->query($query);
$planes = $this->result->fetch_all(MYSQLI_ASSOC);
print json_encode($planes);
+ //log_write(json_encode($planes), INFO);
return $planes;
}
@@ -203,7 +204,7 @@ class db
log_write("savePeripetie " . $query);
//$query .= $this->protect($this->effetPeripetie) . "', '";
//$query .= $this->protect($this->expeMail) . "', '";
- //$query .= $this->protect($this->destMail) . "')"; echo $query . EOL;
+ //$query .= $this->protect($this->destMail) . "')";
$this->query($query);
}
diff --git a/include/envoi_courriel.inc.php b/include/envoi_courriel.inc.php
index 7a37fbf..9e64a2c 100644
--- a/include/envoi_courriel.inc.php
+++ b/include/envoi_courriel.inc.php
@@ -19,20 +19,22 @@ function courrielEnvoi( $db )
log_write("indexObjet" .EOLH . print_r($result, true));
$mailText = $result['text'];
$html = $result['html'];
- if ( $html )
- {
- $mailText = "\n" . $mailText . "";
- }
- if ( $db->expeKnown == false )
+
+ saveMail( $db, $db->expeMail, $objetMail, $mailText, $html);
+
+ //log_write(print_r($db,true));
+
+ // message au destinataire
+ if ( $db->expeKnown == 'true' )
{
$destinataireIndex = "Notification_denvoi_Destinataire_ExpediteurConnu";
+ //log_write("Expéditeur connu => ");
}else
{
$destinataireIndex = "Notification_denvoi_Destinataire_ExpediteurAnonyme";
+ //log_write("Expéditeur inconnu => ");
}
- saveMail( $db, $db->expeMail, $objetMail, $mailText, $html);
- // message au destinataire
$indexObjet = "Objet_" . $destinataireIndex;
$result = replaceVariables($db, $dicoDest[$indexObjet], $dicoDest);
log_write("indexObjet" .EOLH . print_r($result, true));
@@ -56,32 +58,42 @@ function saveMail( $db, $destinataire, $objet, $text, $html=false)
function envoiMail($destinataire, $sujet, $text, $html=false, $cc='', $bcc='')
{
- $headers = "From: contact@avion-poe.me" . LF;
- if ( !empty($cc)) $headers .= "Cc: " . $cc . LF;
- if ( !empty($bcc)) $headers .= "Bcc: " . $bcc . LF;
-
+ require_once 'include/swiftmailer/autoload.php';
+ //require_once 'include/swiftmailer/swiftmailer/lib/swift_init.php';
+ $transport = (new Swift_SmtpTransport('smtpauth.online.net', 465, 'ssl'))
+ ->setUsername('contact@avion-poe.me')
+ ->setPassword('AvionPoème*27juillet');
+ $mailer = new Swift_Mailer($transport);
+ $message = (new Swift_Message($sujet))
+ ->setFrom(["contact@avion-poe.me"])
+ ->setTo([$destinataire])
+ ->setCharset('utf-8');
+ $type = $message->getHeaders()->get('Content-Type');
if ($html)
{
- $headers .= "Content-type: text/html; charset=UTF-8" . LF;
- nl2br($text);
+ // setParameters() takes an associative array
+ $type->setValue('text/html');
+ $type->setParameter('charset', 'utf-8');
+ $str = nl2br($text);
+ $text = "\n" . $str . "";
+ log_write(__FILE__ . EOL . __LINE__ . EOL . wordwrap($text, 1000, "\r\n"), INFO);
}else
{
- $headers .= "Content-type: text/plain; charset=UTF-8" . LF;
+ $type->setValue('text/plain');
+ $type->setParameter('charset', 'utf-8');
$text = str_replace("\n","\r\n", $text);
}
- $headers .= "DATE: " . date( 'r' ) . LF . LF;
- $destinataire = "dtux@free.fr";
- log_write(__FILE__ . __LINE__ . " Envoi d'un courriel à " . $destinataire . "sujet:" . $sujet, INFO);
- if( !mail($destinataire, $sujet, wordwrap($text, 1000 , "\r\n"), $headers) ) //Sending mail
+ $message->setBody($text);
+ //add date header
+ $headers = $message->getHeaders();
+ $headers->addDateHeader('Your-Header', new DateTimeImmutable('3 days ago'));
+ if (!$mailer->send($message, $failures))
{
- $error = error_get_last();
- log_write(__FILE__ . EOL . __LINE__ . EOL . "Le courriel n'est pas parti:" .$destinataire . EOL . $sujet . EOL . print_r($error, true) . EOL . wordwrap($text, 1000 , "\r\n"), ERROR);
+ echo "Failures:";
+ print_r($failures);
+ log_write(__FILE__ . EOL . __LINE__ . EOL . "Le courriel n'est pas parti:" . $destinataire . EOL . $sujet . EOL . print_r($failure, true) . EOL . wordwrap($text, 1000 , "\r\n"), ERROR);
return false;
- }else
- {
- log_write(__FILE__ . EOL . __LINE__ . EOL . "Le courriel est parti: " . $destinataire . EOL . "text:" . $text, INFO);
- return true;
}
+ return true;
}
-
?>
diff --git a/include/swiftmailer/autoload.php b/include/swiftmailer/autoload.php
new file mode 100644
index 0000000..3376cd2
--- /dev/null
+++ b/include/swiftmailer/autoload.php
@@ -0,0 +1,14 @@
+register();
diff --git a/include/swiftmailer/autoload.php~ b/include/swiftmailer/autoload.php~
new file mode 100644
index 0000000..83d241b
--- /dev/null
+++ b/include/swiftmailer/autoload.php~
@@ -0,0 +1,13 @@
+register();
diff --git a/include/swiftmailer/egulias/email-validator/AutoLoader.php b/include/swiftmailer/egulias/email-validator/AutoLoader.php
new file mode 100644
index 0000000..06339e8
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/AutoLoader.php
@@ -0,0 +1,82 @@
+
+ */
+class EguliasAutoLoader
+{
+ /**
+ * @var string The namespace prefix for this instance.
+ */
+ protected $namespace = '';
+
+ /**
+ * @var string The filesystem prefix to use for this instance
+ */
+ protected $path = '';
+
+ /**
+ * Build the instance of the autoloader
+ *
+ * @param string $namespace The prefixed namespace this instance will load
+ * @param string $path The filesystem path to the root of the namespace
+ */
+ public function __construct($namespace, $path)
+ {
+ $this->namespace = ltrim($namespace, '\\');
+ $this->path = rtrim($path, '/\\') . DIRECTORY_SEPARATOR;
+ }
+
+ /**
+ * Try to load a class
+ *
+ * @param string $class The class name to load
+ *
+ * @return boolean If the loading was successful
+ */
+ public function load($class)
+ {
+ $class = ltrim($class, '\\');
+ if (strpos($class, $this->namespace) === 0) {
+ $nsparts = explode('\\', $class);
+ $class = array_pop($nsparts);
+ $path = $this->path . 'swiftmailer/egulias/email-validator/EmailValidator/';
+ $max=count($nsparts);
+ for ($i=2; $i<$max;$i++) {
+ $path .= $nsparts[$i].'/';
+ }
+ $nsparts = array();
+ $path .= str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
+ if (file_exists($path)) {
+ require $path;
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Register the autoloader to PHP
+ *
+ * @return boolean The status of the registration
+ */
+ public function register()
+ {
+ return spl_autoload_register(array($this, 'load'));
+ }
+
+ /**
+ * Unregister the autoloader to PHP
+ *
+ * @return boolean The status of the unregistration
+ */
+ public function unregister()
+ {
+ return spl_autoload_unregister(array($this, 'load'));
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/EmailLexer.php b/include/swiftmailer/egulias/email-validator/EmailValidator/EmailLexer.php
new file mode 100644
index 0000000..882c968
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/EmailLexer.php
@@ -0,0 +1,221 @@
+ self::S_OPENPARENTHESIS,
+ ')' => self::S_CLOSEPARENTHESIS,
+ '<' => self::S_LOWERTHAN,
+ '>' => self::S_GREATERTHAN,
+ '[' => self::S_OPENBRACKET,
+ ']' => self::S_CLOSEBRACKET,
+ ':' => self::S_COLON,
+ ';' => self::S_SEMICOLON,
+ '@' => self::S_AT,
+ '\\' => self::S_BACKSLASH,
+ '/' => self::S_SLASH,
+ ',' => self::S_COMMA,
+ '.' => self::S_DOT,
+ '"' => self::S_DQUOTE,
+ '-' => self::S_HYPHEN,
+ '::' => self::S_DOUBLECOLON,
+ ' ' => self::S_SP,
+ "\t" => self::S_HTAB,
+ "\r" => self::S_CR,
+ "\n" => self::S_LF,
+ "\r\n" => self::CRLF,
+ 'IPv6' => self::S_IPV6TAG,
+ '{' => self::S_OPENQBRACKET,
+ '}' => self::S_CLOSEQBRACKET,
+ '' => self::S_EMPTY,
+ '\0' => self::C_NUL,
+ );
+
+ protected $hasInvalidTokens = false;
+
+ protected $previous;
+
+ public function reset()
+ {
+ $this->hasInvalidTokens = false;
+ parent::reset();
+ }
+
+ public function hasInvalidTokens()
+ {
+ return $this->hasInvalidTokens;
+ }
+
+ /**
+ * @param $type
+ * @throws \UnexpectedValueException
+ * @return boolean
+ */
+ public function find($type)
+ {
+ $search = clone $this;
+ $search->skipUntil($type);
+
+ if (!$search->lookahead) {
+ throw new \UnexpectedValueException($type . ' not found');
+ }
+ return true;
+ }
+
+ /**
+ * getPrevious
+ *
+ * @return array token
+ */
+ public function getPrevious()
+ {
+ return $this->previous;
+ }
+
+ /**
+ * moveNext
+ *
+ * @return boolean
+ */
+ public function moveNext()
+ {
+ $this->previous = $this->token;
+
+ return parent::moveNext();
+ }
+
+ /**
+ * Lexical catchable patterns.
+ *
+ * @return string[]
+ */
+ protected function getCatchablePatterns()
+ {
+ return array(
+ '[a-zA-Z_]+[46]?', //ASCII and domain literal
+ '[^\x00-\x7F]', //UTF-8
+ '[0-9]+',
+ '\r\n',
+ '::',
+ '\s+?',
+ '.',
+ );
+ }
+
+ /**
+ * Lexical non-catchable patterns.
+ *
+ * @return string[]
+ */
+ protected function getNonCatchablePatterns()
+ {
+ return array('[\xA0-\xff]+');
+ }
+
+ /**
+ * Retrieve token type. Also processes the token value if necessary.
+ *
+ * @param string $value
+ * @throws \InvalidArgumentException
+ * @return integer
+ */
+ protected function getType(&$value)
+ {
+ if ($this->isNullType($value)) {
+ return self::C_NUL;
+ }
+
+ if ($this->isValid($value)) {
+ return $this->charValue[$value];
+ }
+
+ if ($this->isUTF8Invalid($value)) {
+ $this->hasInvalidTokens = true;
+ return self::INVALID;
+ }
+
+ return self::GENERIC;
+ }
+
+ protected function isValid($value)
+ {
+ if (isset($this->charValue[$value])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param $value
+ * @return bool
+ */
+ protected function isNullType($value)
+ {
+ if ($value === "\0") {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @param $value
+ * @return bool
+ */
+ protected function isUTF8Invalid($value)
+ {
+ if (preg_match('/\p{Cc}+/u', $value)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function getModifiers()
+ {
+ return 'iu';
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/EmailParser.php b/include/swiftmailer/egulias/email-validator/EmailValidator/EmailParser.php
new file mode 100644
index 0000000..d0627d8
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/EmailParser.php
@@ -0,0 +1,104 @@
+
+ */
+class EmailParser
+{
+ const EMAIL_MAX_LENGTH = 254;
+
+ protected $warnings;
+ protected $domainPart = '';
+ protected $localPart = '';
+ protected $lexer;
+ protected $localPartParser;
+ protected $domainPartParser;
+
+ public function __construct(EmailLexer $lexer)
+ {
+ $this->lexer = $lexer;
+ $this->localPartParser = new LocalPart($this->lexer);
+ $this->domainPartParser = new DomainPart($this->lexer);
+ $this->warnings = new \SplObjectStorage();
+ }
+
+ /**
+ * @param $str
+ * @return array
+ */
+ public function parse($str)
+ {
+ $this->lexer->setInput($str);
+
+ if (!$this->hasAtToken()) {
+ throw new NoLocalPart();
+ }
+
+
+ $this->localPartParser->parse($str);
+ $this->domainPartParser->parse($str);
+
+ $this->setParts($str);
+
+ if ($this->lexer->hasInvalidTokens()) {
+ throw new ExpectingATEXT();
+ }
+
+ return array('local' => $this->localPart, 'domain' => $this->domainPart);
+ }
+
+ public function getWarnings()
+ {
+ $localPartWarnings = $this->localPartParser->getWarnings();
+ $domainPartWarnings = $this->domainPartParser->getWarnings();
+ $this->warnings = array_merge($localPartWarnings, $domainPartWarnings);
+
+ $this->addLongEmailWarning($this->localPart, $this->domainPart);
+
+ return $this->warnings;
+ }
+
+ public function getParsedDomainPart()
+ {
+ return $this->domainPart;
+ }
+
+ protected function setParts($email)
+ {
+ $parts = explode('@', $email);
+ $this->domainPart = $this->domainPartParser->getDomainPart();
+ $this->localPart = $parts[0];
+ }
+
+ protected function hasAtToken()
+ {
+ $this->lexer->moveNext();
+ $this->lexer->moveNext();
+ if ($this->lexer->token['type'] === EmailLexer::S_AT) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * @param string $localPart
+ * @param string $parsedDomainPart
+ */
+ protected function addLongEmailWarning($localPart, $parsedDomainPart)
+ {
+ if (strlen($localPart . '@' . $parsedDomainPart) > self::EMAIL_MAX_LENGTH) {
+ $this->warnings[EmailTooLong::CODE] = new EmailTooLong();
+ }
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/EmailValidator.php b/include/swiftmailer/egulias/email-validator/EmailValidator/EmailValidator.php
new file mode 100644
index 0000000..44b4b93
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/EmailValidator.php
@@ -0,0 +1,67 @@
+lexer = new EmailLexer();
+ }
+
+ /**
+ * @param $email
+ * @param EmailValidation $emailValidation
+ * @return bool
+ */
+ public function isValid($email, EmailValidation $emailValidation)
+ {
+ $isValid = $emailValidation->isValid($email, $this->lexer);
+ $this->warnings = $emailValidation->getWarnings();
+ $this->error = $emailValidation->getError();
+
+ return $isValid;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function hasWarnings()
+ {
+ return !empty($this->warnings);
+ }
+
+ /**
+ * @return array
+ */
+ public function getWarnings()
+ {
+ return $this->warnings;
+ }
+
+ /**
+ * @return InvalidEmail
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php
new file mode 100644
index 0000000..97f41a2
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Exception/AtextAfterCFWS.php
@@ -0,0 +1,9 @@
+lexer->moveNext();
+
+ if ($this->lexer->token['type'] === EmailLexer::S_DOT) {
+ throw new DotAtStart();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_EMPTY) {
+ throw new NoDomainPart();
+ }
+ if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN) {
+ throw new DomainHyphened();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
+ $this->warnings[DeprecatedComment::CODE] = new DeprecatedComment();
+ $this->parseDomainComments();
+ }
+
+ $domain = $this->doParseDomainPart();
+
+ $prev = $this->lexer->getPrevious();
+ $length = strlen($domain);
+
+ if ($prev['type'] === EmailLexer::S_DOT) {
+ throw new DotAtEnd();
+ }
+ if ($prev['type'] === EmailLexer::S_HYPHEN) {
+ throw new DomainHyphened();
+ }
+ if ($length > self::DOMAIN_MAX_LENGTH) {
+ $this->warnings[DomainTooLong::CODE] = new DomainTooLong();
+ }
+ if ($prev['type'] === EmailLexer::S_CR) {
+ throw new CRLFAtTheEnd();
+ }
+ $this->domainPart = $domain;
+ }
+
+ public function getDomainPart()
+ {
+ return $this->domainPart;
+ }
+
+ public function checkIPV6Tag($addressLiteral, $maxGroups = 8)
+ {
+ $prev = $this->lexer->getPrevious();
+ if ($prev['type'] === EmailLexer::S_COLON) {
+ $this->warnings[IPV6ColonEnd::CODE] = new IPV6ColonEnd();
+ }
+
+ $IPv6 = substr($addressLiteral, 5);
+ //Daniel Marschall's new IPv6 testing strategy
+ $matchesIP = explode(':', $IPv6);
+ $groupCount = count($matchesIP);
+ $colons = strpos($IPv6, '::');
+
+ if (count(preg_grep('/^[0-9A-Fa-f]{0,4}$/', $matchesIP, PREG_GREP_INVERT)) !== 0) {
+ $this->warnings[IPV6BadChar::CODE] = new IPV6BadChar();
+ }
+
+ if ($colons === false) {
+ // We need exactly the right number of groups
+ if ($groupCount !== $maxGroups) {
+ $this->warnings[IPV6GroupCount::CODE] = new IPV6GroupCount();
+ }
+ return;
+ }
+
+ if ($colons !== strrpos($IPv6, '::')) {
+ $this->warnings[IPV6DoubleColon::CODE] = new IPV6DoubleColon();
+ return;
+ }
+
+ if ($colons === 0 || $colons === (strlen($IPv6) - 2)) {
+ // RFC 4291 allows :: at the start or end of an address
+ //with 7 other groups in addition
+ ++$maxGroups;
+ }
+
+ if ($groupCount > $maxGroups) {
+ $this->warnings[IPV6MaxGroups::CODE] = new IPV6MaxGroups();
+ } elseif ($groupCount === $maxGroups) {
+ $this->warnings[IPV6Deprecated::CODE] = new IPV6Deprecated();
+ }
+ }
+
+ protected function doParseDomainPart()
+ {
+ $domain = '';
+ $openedParenthesis = 0;
+ do {
+ $prev = $this->lexer->getPrevious();
+
+ $this->checkNotAllowedChars($this->lexer->token);
+
+ if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
+ $this->parseComments();
+ $openedParenthesis += $this->getOpenedParenthesis();
+ $this->lexer->moveNext();
+ $tmpPrev = $this->lexer->getPrevious();
+ if ($tmpPrev['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
+ $openedParenthesis--;
+ }
+ }
+ if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
+ if ($openedParenthesis === 0) {
+ throw new UnopenedComment();
+ } else {
+ $openedParenthesis--;
+ }
+ }
+
+ $this->checkConsecutiveDots();
+ $this->checkDomainPartExceptions($prev);
+
+ if ($this->hasBrackets()) {
+ $this->parseDomainLiteral();
+ }
+
+ $this->checkLabelLength($prev);
+
+ if ($this->isFWS()) {
+ $this->parseFWS();
+ }
+
+ $domain .= $this->lexer->token['value'];
+ $this->lexer->moveNext();
+ } while ($this->lexer->token);
+
+ return $domain;
+ }
+
+ private function checkNotAllowedChars($token)
+ {
+ $notAllowed = [EmailLexer::S_BACKSLASH => true, EmailLexer::S_SLASH=> true];
+ if (isset($notAllowed[$token['type']])) {
+ throw new CharNotAllowed();
+ }
+ }
+
+ protected function parseDomainLiteral()
+ {
+ if ($this->lexer->isNextToken(EmailLexer::S_COLON)) {
+ $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
+ }
+ if ($this->lexer->isNextToken(EmailLexer::S_IPV6TAG)) {
+ $lexer = clone $this->lexer;
+ $lexer->moveNext();
+ if ($lexer->isNextToken(EmailLexer::S_DOUBLECOLON)) {
+ $this->warnings[IPV6ColonStart::CODE] = new IPV6ColonStart();
+ }
+ }
+
+ return $this->doParseDomainLiteral();
+ }
+
+ protected function doParseDomainLiteral()
+ {
+ $IPv6TAG = false;
+ $addressLiteral = '';
+ do {
+ if ($this->lexer->token['type'] === EmailLexer::C_NUL) {
+ throw new ExpectingDTEXT();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::INVALID ||
+ $this->lexer->token['type'] === EmailLexer::C_DEL ||
+ $this->lexer->token['type'] === EmailLexer::S_LF
+ ) {
+ $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
+ }
+
+ if ($this->lexer->isNextTokenAny(array(EmailLexer::S_OPENQBRACKET, EmailLexer::S_OPENBRACKET))) {
+ throw new ExpectingDTEXT();
+ }
+
+ if ($this->lexer->isNextTokenAny(
+ array(EmailLexer::S_HTAB, EmailLexer::S_SP, $this->lexer->token['type'] === EmailLexer::CRLF)
+ )) {
+ $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
+ $this->parseFWS();
+ }
+
+ if ($this->lexer->isNextToken(EmailLexer::S_CR)) {
+ throw new CRNoLF();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH) {
+ $this->warnings[ObsoleteDTEXT::CODE] = new ObsoleteDTEXT();
+ $addressLiteral .= $this->lexer->token['value'];
+ $this->lexer->moveNext();
+ $this->validateQuotedPair();
+ }
+ if ($this->lexer->token['type'] === EmailLexer::S_IPV6TAG) {
+ $IPv6TAG = true;
+ }
+ if ($this->lexer->token['type'] === EmailLexer::S_CLOSEQBRACKET) {
+ break;
+ }
+
+ $addressLiteral .= $this->lexer->token['value'];
+
+ } while ($this->lexer->moveNext());
+
+ $addressLiteral = str_replace('[', '', $addressLiteral);
+ $addressLiteral = $this->checkIPV4Tag($addressLiteral);
+
+ if (false === $addressLiteral) {
+ return $addressLiteral;
+ }
+
+ if (!$IPv6TAG) {
+ $this->warnings[DomainLiteral::CODE] = new DomainLiteral();
+ return $addressLiteral;
+ }
+
+ $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
+
+ $this->checkIPV6Tag($addressLiteral);
+
+ return $addressLiteral;
+ }
+
+ protected function checkIPV4Tag($addressLiteral)
+ {
+ $matchesIP = array();
+
+ // Extract IPv4 part from the end of the address-literal (if there is one)
+ if (preg_match(
+ '/\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/',
+ $addressLiteral,
+ $matchesIP
+ ) > 0
+ ) {
+ $index = strrpos($addressLiteral, $matchesIP[0]);
+ if ($index === 0) {
+ $this->warnings[AddressLiteral::CODE] = new AddressLiteral();
+ return false;
+ }
+ // Convert IPv4 part to IPv6 format for further testing
+ $addressLiteral = substr($addressLiteral, 0, $index) . '0:0';
+ }
+
+ return $addressLiteral;
+ }
+
+ protected function checkDomainPartExceptions($prev)
+ {
+ $invalidDomainTokens = array(
+ EmailLexer::S_DQUOTE => true,
+ EmailLexer::S_SEMICOLON => true,
+ EmailLexer::S_GREATERTHAN => true,
+ EmailLexer::S_LOWERTHAN => true,
+ );
+
+ if (isset($invalidDomainTokens[$this->lexer->token['type']])) {
+ throw new ExpectingATEXT();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_COMMA) {
+ throw new CommaInDomain();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_AT) {
+ throw new ConsecutiveAt();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_OPENQBRACKET && $prev['type'] !== EmailLexer::S_AT) {
+ throw new ExpectingATEXT();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_HYPHEN && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
+ throw new DomainHyphened();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH
+ && $this->lexer->isNextToken(EmailLexer::GENERIC)) {
+ throw new ExpectingATEXT();
+ }
+ }
+
+ protected function hasBrackets()
+ {
+ if ($this->lexer->token['type'] !== EmailLexer::S_OPENBRACKET) {
+ return false;
+ }
+
+ try {
+ $this->lexer->find(EmailLexer::S_CLOSEBRACKET);
+ } catch (\RuntimeException $e) {
+ throw new ExpectingDomainLiteralClose();
+ }
+
+ return true;
+ }
+
+ protected function checkLabelLength($prev)
+ {
+ if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
+ $prev['type'] === EmailLexer::GENERIC &&
+ strlen($prev['value']) > 63
+ ) {
+ $this->warnings[LabelTooLong::CODE] = new LabelTooLong();
+ }
+ }
+
+ protected function parseDomainComments()
+ {
+ $this->isUnclosedComment();
+ while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
+ $this->warnEscaping();
+ $this->lexer->moveNext();
+ }
+
+ $this->lexer->moveNext();
+ if ($this->lexer->isNextToken(EmailLexer::S_DOT)) {
+ throw new ExpectingATEXT();
+ }
+ }
+
+ protected function addTLDWarnings()
+ {
+ if ($this->warnings[DomainLiteral::CODE]) {
+ $this->warnings[TLD::CODE] = new TLD();
+ }
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Parser/LocalPart.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Parser/LocalPart.php
new file mode 100644
index 0000000..8ab16ab
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Parser/LocalPart.php
@@ -0,0 +1,138 @@
+lexer->token['type'] !== EmailLexer::S_AT && $this->lexer->token) {
+ if ($this->lexer->token['type'] === EmailLexer::S_DOT && !$this->lexer->getPrevious()) {
+ throw new DotAtStart();
+ }
+
+ $closingQuote = $this->checkDQUOTE($closingQuote);
+ if ($closingQuote && $parseDQuote) {
+ $parseDQuote = $this->parseDoubleQuote();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_OPENPARENTHESIS) {
+ $this->parseComments();
+ $openedParenthesis += $this->getOpenedParenthesis();
+ }
+ if ($this->lexer->token['type'] === EmailLexer::S_CLOSEPARENTHESIS) {
+ if ($openedParenthesis === 0) {
+ throw new UnopenedComment();
+ } else {
+ $openedParenthesis--;
+ }
+ }
+
+ $this->checkConsecutiveDots();
+
+ if ($this->lexer->token['type'] === EmailLexer::S_DOT &&
+ $this->lexer->isNextToken(EmailLexer::S_AT)
+ ) {
+ throw new DotAtEnd();
+ }
+
+ $this->warnEscaping();
+ $this->isInvalidToken($this->lexer->token, $closingQuote);
+
+ if ($this->isFWS()) {
+ $this->parseFWS();
+ }
+
+ $this->lexer->moveNext();
+ }
+
+ $prev = $this->lexer->getPrevious();
+ if (strlen($prev['value']) > LocalTooLong::LOCAL_PART_LENGTH) {
+ $this->warnings[LocalTooLong::CODE] = new LocalTooLong();
+ }
+ }
+
+ protected function parseDoubleQuote()
+ {
+ $parseAgain = true;
+ $special = array(
+ EmailLexer::S_CR => true,
+ EmailLexer::S_HTAB => true,
+ EmailLexer::S_LF => true
+ );
+
+ $invalid = array(
+ EmailLexer::C_NUL => true,
+ EmailLexer::S_HTAB => true,
+ EmailLexer::S_CR => true,
+ EmailLexer::S_LF => true
+ );
+ $setSpecialsWarning = true;
+
+ $this->lexer->moveNext();
+
+ while ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE && $this->lexer->token) {
+ $parseAgain = false;
+ if (isset($special[$this->lexer->token['type']]) && $setSpecialsWarning) {
+ $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
+ $setSpecialsWarning = false;
+ }
+ if ($this->lexer->token['type'] === EmailLexer::S_BACKSLASH && $this->lexer->isNextToken(EmailLexer::S_DQUOTE)) {
+ $this->lexer->moveNext();
+ }
+
+ $this->lexer->moveNext();
+
+ if (!$this->escaped() && isset($invalid[$this->lexer->token['type']])) {
+ throw new ExpectingATEXT();
+ }
+ }
+
+ $prev = $this->lexer->getPrevious();
+
+ if ($prev['type'] === EmailLexer::S_BACKSLASH) {
+ if (!$this->checkDQUOTE(false)) {
+ throw new UnclosedQuotedString();
+ }
+ }
+
+ if (!$this->lexer->isNextToken(EmailLexer::S_AT) && $prev['type'] !== EmailLexer::S_BACKSLASH) {
+ throw new ExpectingAT();
+ }
+
+ return $parseAgain;
+ }
+
+ protected function isInvalidToken($token, $closingQuote)
+ {
+ $forbidden = array(
+ EmailLexer::S_COMMA,
+ EmailLexer::S_CLOSEBRACKET,
+ EmailLexer::S_OPENBRACKET,
+ EmailLexer::S_GREATERTHAN,
+ EmailLexer::S_LOWERTHAN,
+ EmailLexer::S_COLON,
+ EmailLexer::S_SEMICOLON,
+ EmailLexer::INVALID
+ );
+
+ if (in_array($token['type'], $forbidden) && !$closingQuote) {
+ throw new ExpectingATEXT();
+ }
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Parser/Parser.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Parser/Parser.php
new file mode 100644
index 0000000..e5042e1
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Parser/Parser.php
@@ -0,0 +1,215 @@
+lexer = $lexer;
+ }
+
+ public function getWarnings()
+ {
+ return $this->warnings;
+ }
+
+ abstract public function parse($str);
+
+ /** @return int */
+ public function getOpenedParenthesis()
+ {
+ return $this->openedParenthesis;
+ }
+
+ /**
+ * validateQuotedPair
+ */
+ protected function validateQuotedPair()
+ {
+ if (!($this->lexer->token['type'] === EmailLexer::INVALID
+ || $this->lexer->token['type'] === EmailLexer::C_DEL)) {
+ throw new ExpectedQPair();
+ }
+
+ $this->warnings[QuotedPart::CODE] =
+ new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
+ }
+
+ protected function parseComments()
+ {
+ $this->openedParenthesis = 1;
+ $this->isUnclosedComment();
+ $this->warnings[Comment::CODE] = new Comment();
+ while (!$this->lexer->isNextToken(EmailLexer::S_CLOSEPARENTHESIS)) {
+ if ($this->lexer->isNextToken(EmailLexer::S_OPENPARENTHESIS)) {
+ $this->openedParenthesis++;
+ }
+ $this->warnEscaping();
+ $this->lexer->moveNext();
+ }
+
+ $this->lexer->moveNext();
+ if ($this->lexer->isNextTokenAny(array(EmailLexer::GENERIC, EmailLexer::S_EMPTY))) {
+ throw new ExpectingATEXT();
+ }
+
+ if ($this->lexer->isNextToken(EmailLexer::S_AT)) {
+ $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
+ }
+ }
+
+ protected function isUnclosedComment()
+ {
+ try {
+ $this->lexer->find(EmailLexer::S_CLOSEPARENTHESIS);
+ return true;
+ } catch (\RuntimeException $e) {
+ throw new UnclosedComment();
+ }
+ }
+
+ protected function parseFWS()
+ {
+ $previous = $this->lexer->getPrevious();
+
+ $this->checkCRLFInFWS();
+
+ if ($this->lexer->token['type'] === EmailLexer::S_CR) {
+ throw new CRNoLF();
+ }
+
+ if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] !== EmailLexer::S_AT) {
+ throw new AtextAfterCFWS();
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_LF || $this->lexer->token['type'] === EmailLexer::C_NUL) {
+ throw new ExpectingCTEXT();
+ }
+
+ if ($this->lexer->isNextToken(EmailLexer::S_AT) || $previous['type'] === EmailLexer::S_AT) {
+ $this->warnings[CFWSNearAt::CODE] = new CFWSNearAt();
+ } else {
+ $this->warnings[CFWSWithFWS::CODE] = new CFWSWithFWS();
+ }
+ }
+
+ protected function checkConsecutiveDots()
+ {
+ if ($this->lexer->token['type'] === EmailLexer::S_DOT && $this->lexer->isNextToken(EmailLexer::S_DOT)) {
+ throw new ConsecutiveDot();
+ }
+ }
+
+ protected function isFWS()
+ {
+ if ($this->escaped()) {
+ return false;
+ }
+
+ if ($this->lexer->token['type'] === EmailLexer::S_SP ||
+ $this->lexer->token['type'] === EmailLexer::S_HTAB ||
+ $this->lexer->token['type'] === EmailLexer::S_CR ||
+ $this->lexer->token['type'] === EmailLexer::S_LF ||
+ $this->lexer->token['type'] === EmailLexer::CRLF
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function escaped()
+ {
+ $previous = $this->lexer->getPrevious();
+
+ if ($previous['type'] === EmailLexer::S_BACKSLASH
+ &&
+ $this->lexer->token['type'] !== EmailLexer::GENERIC
+ ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function warnEscaping()
+ {
+ if ($this->lexer->token['type'] !== EmailLexer::S_BACKSLASH) {
+ return false;
+ }
+
+ if ($this->lexer->isNextToken(EmailLexer::GENERIC)) {
+ throw new ExpectingATEXT();
+ }
+
+ if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) {
+ return false;
+ }
+
+ $this->warnings[QuotedPart::CODE] =
+ new QuotedPart($this->lexer->getPrevious()['type'], $this->lexer->token['type']);
+ return true;
+
+ }
+
+ protected function checkDQUOTE($hasClosingQuote)
+ {
+ if ($this->lexer->token['type'] !== EmailLexer::S_DQUOTE) {
+ return $hasClosingQuote;
+ }
+ if ($hasClosingQuote) {
+ return $hasClosingQuote;
+ }
+ $previous = $this->lexer->getPrevious();
+ if ($this->lexer->isNextToken(EmailLexer::GENERIC) && $previous['type'] === EmailLexer::GENERIC) {
+ throw new ExpectingATEXT();
+ }
+
+ try {
+ $this->lexer->find(EmailLexer::S_DQUOTE);
+ $hasClosingQuote = true;
+ } catch (\Exception $e) {
+ throw new UnclosedQuotedString();
+ }
+ $this->warnings[QuotedString::CODE] = new QuotedString($previous['value'], $this->lexer->token['value']);
+
+ return $hasClosingQuote;
+ }
+
+ protected function checkCRLFInFWS()
+ {
+ if ($this->lexer->token['type'] !== EmailLexer::CRLF) {
+ return;
+ }
+
+ if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
+ throw new CRLFX2();
+ }
+
+ if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB))) {
+ throw new CRLFAtTheEnd();
+ }
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php
new file mode 100644
index 0000000..ecca1dd
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/DNSCheckValidation.php
@@ -0,0 +1,61 @@
+checkDNS($host);
+ }
+
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ public function getWarnings()
+ {
+ return $this->warnings;
+ }
+
+ protected function checkDNS($host)
+ {
+ $host = rtrim($host, '.') . '.';
+
+ $Aresult = true;
+ $MXresult = checkdnsrr($host, 'MX');
+
+ if (!$MXresult) {
+ $this->warnings[NoDNSMXRecord::CODE] = new NoDNSMXRecord();
+ $Aresult = checkdnsrr($host, 'A') || checkdnsrr($host, 'AAAA');
+ if (!$Aresult) {
+ $this->error = new NoDNSRecord();
+ }
+ }
+ return $MXresult || $Aresult;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/EmailValidation.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/EmailValidation.php
new file mode 100644
index 0000000..d5a015b
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/EmailValidation.php
@@ -0,0 +1,34 @@
+errors = $errors;
+ parent::__construct();
+ }
+
+ public function getErrors()
+ {
+ return $this->errors;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php
new file mode 100644
index 0000000..43fa42a
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/MultipleValidationWithAnd.php
@@ -0,0 +1,110 @@
+validations = $validations;
+ $this->mode = $mode;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isValid($email, EmailLexer $emailLexer)
+ {
+ $result = true;
+ $errors = [];
+ foreach ($this->validations as $validation) {
+ $emailLexer->reset();
+ $result = $result && $validation->isValid($email, $emailLexer);
+ $this->warnings = array_merge($this->warnings, $validation->getWarnings());
+ $errors = $this->addNewError($validation->getError(), $errors);
+
+ if ($this->shouldStop($result)) {
+ break;
+ }
+ }
+
+ if (!empty($errors)) {
+ $this->error = new MultipleErrors($errors);
+ }
+
+ return $result;
+ }
+
+ private function addNewError($possibleError, array $errors)
+ {
+ if (null !== $possibleError) {
+ $errors[] = $possibleError;
+ }
+
+ return $errors;
+ }
+
+ private function shouldStop($result)
+ {
+ return !$result && $this->mode === self::STOP_ON_ERROR;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getWarnings()
+ {
+ return $this->warnings;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php
new file mode 100644
index 0000000..f3656b3
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/NoRFCWarningsValidation.php
@@ -0,0 +1,42 @@
+getWarnings();
+ if (empty($ret)) {
+ return true;
+ }
+
+ $this->error = new RFCWarnings();
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getError()
+ {
+ return $this->error ?: parent::getError();
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/RFCValidation.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/RFCValidation.php
new file mode 100644
index 0000000..c4ffe35
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/RFCValidation.php
@@ -0,0 +1,49 @@
+parser = new EmailParser($emailLexer);
+ try {
+ $this->parser->parse((string)$email);
+ } catch (InvalidEmail $invalid) {
+ $this->error = $invalid;
+ return false;
+ }
+
+ $this->warnings = $this->parser->getWarnings();
+ return true;
+ }
+
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ public function getWarnings()
+ {
+ return $this->warnings;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php
new file mode 100644
index 0000000..4721f0d
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Validation/SpoofCheckValidation.php
@@ -0,0 +1,45 @@
+setChecks(Spoofchecker::SINGLE_SCRIPT);
+
+ if ($checker->isSuspicious($email)) {
+ $this->error = new SpoofEmail();
+ }
+
+ return $this->error === null;
+ }
+
+ public function getError()
+ {
+ return $this->error;
+ }
+
+ public function getWarnings()
+ {
+ return [];
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php
new file mode 100644
index 0000000..77e70f7
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/AddressLiteral.php
@@ -0,0 +1,14 @@
+message = 'Address literal in domain part';
+ $this->rfcNumber = 5321;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php
new file mode 100644
index 0000000..be43bbe
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/CFWSNearAt.php
@@ -0,0 +1,13 @@
+message = "Deprecated folding white space near @";
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php
new file mode 100644
index 0000000..dea3450
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/CFWSWithFWS.php
@@ -0,0 +1,13 @@
+message = 'Folding whites space followed by folding white space';
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/Comment.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/Comment.php
new file mode 100644
index 0000000..704c290
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/Comment.php
@@ -0,0 +1,13 @@
+message = "Comments found in this email";
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php
new file mode 100644
index 0000000..ad43bd7
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DeprecatedComment.php
@@ -0,0 +1,13 @@
+message = 'Deprecated comments';
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php
new file mode 100644
index 0000000..6f36b5e
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DomainLiteral.php
@@ -0,0 +1,14 @@
+message = 'Domain Literal';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php
new file mode 100644
index 0000000..61ff17a
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/DomainTooLong.php
@@ -0,0 +1,14 @@
+message = 'Domain is too long, exceeds 255 chars';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php
new file mode 100644
index 0000000..497309d
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/EmailTooLong.php
@@ -0,0 +1,15 @@
+message = 'Email is too long, exceeds ' . EmailParser::EMAIL_MAX_LENGTH;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php
new file mode 100644
index 0000000..ba2fcc0
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6BadChar.php
@@ -0,0 +1,14 @@
+message = 'Bad char in IPV6 domain literal';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php
new file mode 100644
index 0000000..41afa78
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6ColonEnd.php
@@ -0,0 +1,14 @@
+message = ':: found at the end of the domain literal';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php
new file mode 100644
index 0000000..1bf754e
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6ColonStart.php
@@ -0,0 +1,14 @@
+message = ':: found at the start of the domain literal';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php
new file mode 100644
index 0000000..d752caa
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6Deprecated.php
@@ -0,0 +1,14 @@
+message = 'Deprecated form of IPV6';
+ $this->rfcNumber = 5321;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php
new file mode 100644
index 0000000..4f82394
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6DoubleColon.php
@@ -0,0 +1,14 @@
+message = 'Double colon found after IPV6 tag';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php
new file mode 100644
index 0000000..a59d317
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6GroupCount.php
@@ -0,0 +1,14 @@
+message = 'Group count is not IPV6 valid';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php
new file mode 100644
index 0000000..936274c
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/IPV6MaxGroups.php
@@ -0,0 +1,14 @@
+message = 'Reached the maximum number of IPV6 groups allowed';
+ $this->rfcNumber = 5321;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php
new file mode 100644
index 0000000..daf07f4
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/LabelTooLong.php
@@ -0,0 +1,14 @@
+message = 'Label too long';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php
new file mode 100644
index 0000000..0d08d8b
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/LocalTooLong.php
@@ -0,0 +1,15 @@
+message = 'Local part is too long, exceeds 64 chars (octets)';
+ $this->rfcNumber = 5322;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php
new file mode 100644
index 0000000..b3c21a1
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/NoDNSMXRecord.php
@@ -0,0 +1,14 @@
+message = 'No MX DSN record was found for this email';
+ $this->rfcNumber = 5321;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php
new file mode 100644
index 0000000..10f19e3
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/ObsoleteDTEXT.php
@@ -0,0 +1,14 @@
+rfcNumber = 5322;
+ $this->message = 'Obsolete DTEXT in domain literal';
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/QuotedPart.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/QuotedPart.php
new file mode 100644
index 0000000..7be9e6a
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/QuotedPart.php
@@ -0,0 +1,13 @@
+message = "Deprecated Quoted String found between $prevToken and $postToken";
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/QuotedString.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/QuotedString.php
new file mode 100644
index 0000000..e9d56e1
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/QuotedString.php
@@ -0,0 +1,13 @@
+message = "Quoted String found between $prevToken and $postToken";
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/TLD.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/TLD.php
new file mode 100644
index 0000000..2338b9f
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/TLD.php
@@ -0,0 +1,13 @@
+message = "RFC5321, TLD";
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/Warning.php b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/Warning.php
new file mode 100644
index 0000000..ec6a365
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/EmailValidator/Warning/Warning.php
@@ -0,0 +1,30 @@
+message;
+ }
+
+ public function code()
+ {
+ return self::CODE;
+ }
+
+ public function RFCNumber()
+ {
+ return $this->rfcNumber;
+ }
+
+ public function __toString()
+ {
+ return $this->message() . " rfc: " . $this->rfcNumber . "interal code: " . static::CODE;
+ }
+}
diff --git a/include/swiftmailer/egulias/email-validator/LICENSE b/include/swiftmailer/egulias/email-validator/LICENSE
new file mode 100644
index 0000000..c34d2c1
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2013-2016 Eduardo Gulias Davis
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/include/swiftmailer/egulias/email-validator/README.md b/include/swiftmailer/egulias/email-validator/README.md
new file mode 100644
index 0000000..fc7c89e
--- /dev/null
+++ b/include/swiftmailer/egulias/email-validator/README.md
@@ -0,0 +1,79 @@
+# EmailValidator
+[![Build Status](https://travis-ci.org/egulias/EmailValidator.png?branch=master)](https://travis-ci.org/egulias/EmailValidator) [![Coverage Status](https://coveralls.io/repos/egulias/EmailValidator/badge.png?branch=master)](https://coveralls.io/r/egulias/EmailValidator?branch=master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/egulias/EmailValidator/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/egulias/EmailValidator/?branch=master) [![SensioLabsInsight](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6/small.png)](https://insight.sensiolabs.com/projects/22ba6692-9c02-42e5-a65d-1c5696bfffc6)
+=============================
+With the help of [PHPStorm](https://www.jetbrains.com/phpstorm/)
+
+## Requirements ##
+
+ * [Composer](https://getcomposer.org) is required for installation
+ * [Spoofchecking](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php) validation requires that your PHP system have the [PHP Internationalization Libraries](http://php.net/manual/en/book.intl.php) (also known as PHP Intl)
+
+## Installation ##
+
+Run the command below to install via Composer
+
+```shell
+composer require egulias/email-validator "~2.1"
+```
+
+## Getting Started ##
+`EmailValidator`requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations).
+
+A basic example with the RFC validation
+```php
+isValid("example@example.com", new RFCValidation()); //true
+```
+
+
+### Available validations ###
+
+1. [RFCValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/RFCValidation.php)
+2. [NoRFCWarningsValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/NoRFCWarningsValidation.php)
+3. [DNSCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/DNSCheckValidation.php)
+4. [SpoofCheckValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/SpoofCheckValidation.php)
+5. [MultipleValidationWithAnd](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/MultipleValidationWithAnd.php)
+6. [Your own validation](#how-to-extend)
+
+`MultipleValidationWithAnd`
+
+It is a validation that operates over other validations performing a logical and (&&) over the result of each validation.
+
+```php
+isValid("example@example.com", $multipleValidations); //true
+```
+
+### How to extend ###
+
+It's easy! You just need to extend [EmailValidation](https://github.com/egulias/EmailValidator/blob/master/EmailValidator/Validation/EmailValidation.php) and you can use your own validation.
+
+
+## Other Contributors ##
+(You can find current contributors [here](https://github.com/egulias/EmailValidator/graphs/contributors))
+
+As this is a port from another library and work, here are other people related to the previous one:
+
+* Ricard Clau [@ricardclau](http://github.com/ricardclau): Performance against PHP built-in filter_var
+* Josepf Bielawski [@stloyd](http://github.com/stloyd): For its first re-work of Dominic's lib
+* Dominic Sayers [@dominicsayers](http://github.com/dominicsayers): The original isemail function
+
+## License ##
+Released under the MIT License attached with this code.
+
diff --git a/include/swiftmailer/lexer/LICENSE b/include/swiftmailer/lexer/LICENSE
new file mode 100644
index 0000000..5e781fc
--- /dev/null
+++ b/include/swiftmailer/lexer/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2006-2013 Doctrine Project
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/include/swiftmailer/lexer/README.md b/include/swiftmailer/lexer/README.md
new file mode 100644
index 0000000..66f4430
--- /dev/null
+++ b/include/swiftmailer/lexer/README.md
@@ -0,0 +1,5 @@
+# Doctrine Lexer
+
+Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.
+
+This lexer is used in Doctrine Annotations and in Doctrine ORM (DQL).
diff --git a/include/swiftmailer/lexer/composer.json b/include/swiftmailer/lexer/composer.json
new file mode 100644
index 0000000..8cd694c
--- /dev/null
+++ b/include/swiftmailer/lexer/composer.json
@@ -0,0 +1,24 @@
+{
+ "name": "doctrine/lexer",
+ "type": "library",
+ "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
+ "keywords": ["lexer", "parser"],
+ "homepage": "http://www.doctrine-project.org",
+ "license": "MIT",
+ "authors": [
+ {"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
+ {"name": "Roman Borschel", "email": "roman@code-factory.org"},
+ {"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
+ ],
+ "require": {
+ "php": ">=5.3.2"
+ },
+ "autoload": {
+ "psr-0": { "Doctrine\\Common\\Lexer\\": "lib/" }
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ }
+}
diff --git a/include/swiftmailer/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php b/include/swiftmailer/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php
new file mode 100644
index 0000000..399a552
--- /dev/null
+++ b/include/swiftmailer/lexer/lib/Doctrine/Common/Lexer/AbstractLexer.php
@@ -0,0 +1,327 @@
+.
+ */
+
+namespace Doctrine\Common\Lexer;
+
+/**
+ * Base class for writing simple lexers, i.e. for creating small DSLs.
+ *
+ * @since 2.0
+ * @author Guilherme Blanco
+ * @author Jonathan Wage
+ * @author Roman Borschel
+ */
+abstract class AbstractLexer
+{
+ /**
+ * Lexer original input string.
+ *
+ * @var string
+ */
+ private $input;
+
+ /**
+ * Array of scanned tokens.
+ *
+ * Each token is an associative array containing three items:
+ * - 'value' : the string value of the token in the input string
+ * - 'type' : the type of the token (identifier, numeric, string, input
+ * parameter, none)
+ * - 'position' : the position of the token in the input string
+ *
+ * @var array
+ */
+ private $tokens = array();
+
+ /**
+ * Current lexer position in input string.
+ *
+ * @var integer
+ */
+ private $position = 0;
+
+ /**
+ * Current peek of current lexer position.
+ *
+ * @var integer
+ */
+ private $peek = 0;
+
+ /**
+ * The next token in the input.
+ *
+ * @var array
+ */
+ public $lookahead;
+
+ /**
+ * The last matched/seen token.
+ *
+ * @var array
+ */
+ public $token;
+
+ /**
+ * Sets the input data to be tokenized.
+ *
+ * The Lexer is immediately reset and the new input tokenized.
+ * Any unprocessed tokens from any previous input are lost.
+ *
+ * @param string $input The input to be tokenized.
+ *
+ * @return void
+ */
+ public function setInput($input)
+ {
+ $this->input = $input;
+ $this->tokens = array();
+
+ $this->reset();
+ $this->scan($input);
+ }
+
+ /**
+ * Resets the lexer.
+ *
+ * @return void
+ */
+ public function reset()
+ {
+ $this->lookahead = null;
+ $this->token = null;
+ $this->peek = 0;
+ $this->position = 0;
+ }
+
+ /**
+ * Resets the peek pointer to 0.
+ *
+ * @return void
+ */
+ public function resetPeek()
+ {
+ $this->peek = 0;
+ }
+
+ /**
+ * Resets the lexer position on the input to the given position.
+ *
+ * @param integer $position Position to place the lexical scanner.
+ *
+ * @return void
+ */
+ public function resetPosition($position = 0)
+ {
+ $this->position = $position;
+ }
+
+ /**
+ * Retrieve the original lexer's input until a given position.
+ *
+ * @param integer $position
+ *
+ * @return string
+ */
+ public function getInputUntilPosition($position)
+ {
+ return substr($this->input, 0, $position);
+ }
+
+ /**
+ * Checks whether a given token matches the current lookahead.
+ *
+ * @param integer|string $token
+ *
+ * @return boolean
+ */
+ public function isNextToken($token)
+ {
+ return null !== $this->lookahead && $this->lookahead['type'] === $token;
+ }
+
+ /**
+ * Checks whether any of the given tokens matches the current lookahead.
+ *
+ * @param array $tokens
+ *
+ * @return boolean
+ */
+ public function isNextTokenAny(array $tokens)
+ {
+ return null !== $this->lookahead && in_array($this->lookahead['type'], $tokens, true);
+ }
+
+ /**
+ * Moves to the next token in the input string.
+ *
+ * @return boolean
+ */
+ public function moveNext()
+ {
+ $this->peek = 0;
+ $this->token = $this->lookahead;
+ $this->lookahead = (isset($this->tokens[$this->position]))
+ ? $this->tokens[$this->position++] : null;
+
+ return $this->lookahead !== null;
+ }
+
+ /**
+ * Tells the lexer to skip input tokens until it sees a token with the given value.
+ *
+ * @param string $type The token type to skip until.
+ *
+ * @return void
+ */
+ public function skipUntil($type)
+ {
+ while ($this->lookahead !== null && $this->lookahead['type'] !== $type) {
+ $this->moveNext();
+ }
+ }
+
+ /**
+ * Checks if given value is identical to the given token.
+ *
+ * @param mixed $value
+ * @param integer $token
+ *
+ * @return boolean
+ */
+ public function isA($value, $token)
+ {
+ return $this->getType($value) === $token;
+ }
+
+ /**
+ * Moves the lookahead token forward.
+ *
+ * @return array|null The next token or NULL if there are no more tokens ahead.
+ */
+ public function peek()
+ {
+ if (isset($this->tokens[$this->position + $this->peek])) {
+ return $this->tokens[$this->position + $this->peek++];
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Peeks at the next token, returns it and immediately resets the peek.
+ *
+ * @return array|null The next token or NULL if there are no more tokens ahead.
+ */
+ public function glimpse()
+ {
+ $peek = $this->peek();
+ $this->peek = 0;
+ return $peek;
+ }
+
+ /**
+ * Scans the input string for tokens.
+ *
+ * @param string $input A query string.
+ *
+ * @return void
+ */
+ protected function scan($input)
+ {
+ static $regex;
+
+ if ( ! isset($regex)) {
+ $regex = sprintf(
+ '/(%s)|%s/%s',
+ implode(')|(', $this->getCatchablePatterns()),
+ implode('|', $this->getNonCatchablePatterns()),
+ $this->getModifiers()
+ );
+ }
+
+ $flags = PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_OFFSET_CAPTURE;
+ $matches = preg_split($regex, $input, -1, $flags);
+
+ foreach ($matches as $match) {
+ // Must remain before 'value' assignment since it can change content
+ $type = $this->getType($match[0]);
+
+ $this->tokens[] = array(
+ 'value' => $match[0],
+ 'type' => $type,
+ 'position' => $match[1],
+ );
+ }
+ }
+
+ /**
+ * Gets the literal for a given token.
+ *
+ * @param integer $token
+ *
+ * @return string
+ */
+ public function getLiteral($token)
+ {
+ $className = get_class($this);
+ $reflClass = new \ReflectionClass($className);
+ $constants = $reflClass->getConstants();
+
+ foreach ($constants as $name => $value) {
+ if ($value === $token) {
+ return $className . '::' . $name;
+ }
+ }
+
+ return $token;
+ }
+
+ /**
+ * Regex modifiers
+ *
+ * @return string
+ */
+ protected function getModifiers()
+ {
+ return 'i';
+ }
+
+ /**
+ * Lexical catchable patterns.
+ *
+ * @return array
+ */
+ abstract protected function getCatchablePatterns();
+
+ /**
+ * Lexical non-catchable patterns.
+ *
+ * @return array
+ */
+ abstract protected function getNonCatchablePatterns();
+
+ /**
+ * Retrieve token type. Also processes the token value if necessary.
+ *
+ * @param string $value
+ *
+ * @return integer
+ */
+ abstract protected function getType(&$value);
+}
diff --git a/include/swiftmailer/lib/classes/Swift.php b/include/swiftmailer/lib/classes/Swift.php
new file mode 100644
index 0000000..ffe5a48
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift.php
@@ -0,0 +1,78 @@
+address = $address;
+ }
+
+ public function getAddress(): string
+ {
+ return $this->address;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Attachment.php b/include/swiftmailer/lib/classes/Swift/Attachment.php
new file mode 100644
index 0000000..7a1420f
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Attachment.php
@@ -0,0 +1,54 @@
+createDependenciesFor('mime.attachment')
+ );
+
+ $this->setBody($data, $contentType);
+ $this->setFilename($filename);
+ }
+
+ /**
+ * Create a new Attachment from a filesystem path.
+ *
+ * @param string $path
+ * @param string $contentType optional
+ *
+ * @return self
+ */
+ public static function fromPath($path, $contentType = null)
+ {
+ return (new self())->setFile(
+ new Swift_ByteStream_FileByteStream($path),
+ $contentType
+ );
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php b/include/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php
new file mode 100644
index 0000000..3a69c15
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/ByteStream/AbstractFilterableInputStream.php
@@ -0,0 +1,176 @@
+filters[$key] = $filter;
+ }
+
+ /**
+ * Remove an already present StreamFilter based on its $key.
+ *
+ * @param string $key
+ */
+ public function removeFilter($key)
+ {
+ unset($this->filters[$key]);
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * @param string $bytes
+ *
+ * @throws Swift_IoException
+ *
+ * @return int
+ */
+ public function write($bytes)
+ {
+ $this->writeBuffer .= $bytes;
+ foreach ($this->filters as $filter) {
+ if ($filter->shouldBuffer($this->writeBuffer)) {
+ return;
+ }
+ }
+ $this->doWrite($this->writeBuffer);
+
+ return ++$this->sequence;
+ }
+
+ /**
+ * For any bytes that are currently buffered inside the stream, force them
+ * off the buffer.
+ *
+ * @throws Swift_IoException
+ */
+ public function commit()
+ {
+ $this->doWrite($this->writeBuffer);
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ $this->mirrors[] = $is;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ foreach ($this->mirrors as $k => $stream) {
+ if ($is === $stream) {
+ if ('' !== $this->writeBuffer) {
+ $stream->write($this->writeBuffer);
+ }
+ unset($this->mirrors[$k]);
+ }
+ }
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ *
+ * @throws Swift_IoException
+ */
+ public function flushBuffers()
+ {
+ if ('' !== $this->writeBuffer) {
+ $this->doWrite($this->writeBuffer);
+ }
+ $this->flush();
+
+ foreach ($this->mirrors as $stream) {
+ $stream->flushBuffers();
+ }
+ }
+
+ /** Run $bytes through all filters */
+ private function filter($bytes)
+ {
+ foreach ($this->filters as $filter) {
+ $bytes = $filter->filter($bytes);
+ }
+
+ return $bytes;
+ }
+
+ /** Just write the bytes to the stream */
+ private function doWrite($bytes)
+ {
+ $this->doCommit($this->filter($bytes));
+
+ foreach ($this->mirrors as $stream) {
+ $stream->write($bytes);
+ }
+
+ $this->writeBuffer = '';
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php b/include/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php
new file mode 100644
index 0000000..4f3dcc3
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/ByteStream/ArrayByteStream.php
@@ -0,0 +1,178 @@
+array = $stack;
+ $this->arraySize = \count($stack);
+ } elseif (\is_string($stack)) {
+ $this->write($stack);
+ } else {
+ $this->array = [];
+ }
+ }
+
+ /**
+ * Reads $length bytes from the stream into a string and moves the pointer
+ * through the stream by $length.
+ *
+ * If less bytes exist than are requested the
+ * remaining bytes are given instead. If no bytes are remaining at all, boolean
+ * false is returned.
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ public function read($length)
+ {
+ if ($this->offset == $this->arraySize) {
+ return false;
+ }
+
+ // Don't use array slice
+ $end = $length + $this->offset;
+ $end = $this->arraySize < $end ? $this->arraySize : $end;
+ $ret = '';
+ for (; $this->offset < $end; ++$this->offset) {
+ $ret .= $this->array[$this->offset];
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * @param string $bytes
+ */
+ public function write($bytes)
+ {
+ $to_add = str_split($bytes);
+ foreach ($to_add as $value) {
+ $this->array[] = $value;
+ }
+ $this->arraySize = \count($this->array);
+
+ foreach ($this->mirrors as $stream) {
+ $stream->write($bytes);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function commit()
+ {
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ $this->mirrors[] = $is;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ foreach ($this->mirrors as $k => $stream) {
+ if ($is === $stream) {
+ unset($this->mirrors[$k]);
+ }
+ }
+ }
+
+ /**
+ * Move the internal read pointer to $byteOffset in the stream.
+ *
+ * @param int $byteOffset
+ *
+ * @return bool
+ */
+ public function setReadPointer($byteOffset)
+ {
+ if ($byteOffset > $this->arraySize) {
+ $byteOffset = $this->arraySize;
+ } elseif ($byteOffset < 0) {
+ $byteOffset = 0;
+ }
+
+ $this->offset = $byteOffset;
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ */
+ public function flushBuffers()
+ {
+ $this->offset = 0;
+ $this->array = [];
+ $this->arraySize = 0;
+
+ foreach ($this->mirrors as $stream) {
+ $stream->flushBuffers();
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php b/include/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php
new file mode 100644
index 0000000..f639121
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/ByteStream/FileByteStream.php
@@ -0,0 +1,214 @@
+path = $path;
+ $this->mode = $writable ? 'w+b' : 'rb';
+ }
+
+ /**
+ * Get the complete path to the file.
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Reads $length bytes from the stream into a string and moves the pointer
+ * through the stream by $length.
+ *
+ * If less bytes exist than are requested the
+ * remaining bytes are given instead. If no bytes are remaining at all, boolean
+ * false is returned.
+ *
+ * @param int $length
+ *
+ * @return string|bool
+ *
+ * @throws Swift_IoException
+ */
+ public function read($length)
+ {
+ $fp = $this->getReadHandle();
+ if (!feof($fp)) {
+ $bytes = fread($fp, $length);
+ $this->offset = ftell($fp);
+
+ // If we read one byte after reaching the end of the file
+ // feof() will return false and an empty string is returned
+ if ((false === $bytes || '' === $bytes) && feof($fp)) {
+ $this->resetReadHandle();
+
+ return false;
+ }
+
+ return $bytes;
+ }
+
+ $this->resetReadHandle();
+
+ return false;
+ }
+
+ /**
+ * Move the internal read pointer to $byteOffset in the stream.
+ *
+ * @param int $byteOffset
+ *
+ * @return bool
+ */
+ public function setReadPointer($byteOffset)
+ {
+ if (isset($this->reader)) {
+ $this->seekReadStreamToPosition($byteOffset);
+ }
+ $this->offset = $byteOffset;
+ }
+
+ /** Just write the bytes to the file */
+ protected function doCommit($bytes)
+ {
+ fwrite($this->getWriteHandle(), $bytes);
+ $this->resetReadHandle();
+ }
+
+ /** Not used */
+ protected function flush()
+ {
+ }
+
+ /** Get the resource for reading */
+ private function getReadHandle()
+ {
+ if (!isset($this->reader)) {
+ $pointer = @fopen($this->path, 'rb');
+ if (!$pointer) {
+ throw new Swift_IoException('Unable to open file for reading ['.$this->path.']');
+ }
+ $this->reader = $pointer;
+ if (0 != $this->offset) {
+ $this->getReadStreamSeekableStatus();
+ $this->seekReadStreamToPosition($this->offset);
+ }
+ }
+
+ return $this->reader;
+ }
+
+ /** Get the resource for writing */
+ private function getWriteHandle()
+ {
+ if (!isset($this->writer)) {
+ if (!$this->writer = fopen($this->path, $this->mode)) {
+ throw new Swift_IoException('Unable to open file for writing ['.$this->path.']');
+ }
+ }
+
+ return $this->writer;
+ }
+
+ /** Force a reload of the resource for reading */
+ private function resetReadHandle()
+ {
+ if (isset($this->reader)) {
+ fclose($this->reader);
+ $this->reader = null;
+ }
+ }
+
+ /** Check if ReadOnly Stream is seekable */
+ private function getReadStreamSeekableStatus()
+ {
+ $metas = stream_get_meta_data($this->reader);
+ $this->seekable = $metas['seekable'];
+ }
+
+ /** Streams in a readOnly stream ensuring copy if needed */
+ private function seekReadStreamToPosition($offset)
+ {
+ if (null === $this->seekable) {
+ $this->getReadStreamSeekableStatus();
+ }
+ if (false === $this->seekable) {
+ $currentPos = ftell($this->reader);
+ if ($currentPos < $offset) {
+ $toDiscard = $offset - $currentPos;
+ fread($this->reader, $toDiscard);
+
+ return;
+ }
+ $this->copyReadStream();
+ }
+ fseek($this->reader, $offset, SEEK_SET);
+ }
+
+ /** Copy a readOnly Stream to ensure seekability */
+ private function copyReadStream()
+ {
+ if ($tmpFile = fopen('php://temp/maxmemory:4096', 'w+b')) {
+ /* We have opened a php:// Stream Should work without problem */
+ } elseif (\function_exists('sys_get_temp_dir') && is_writable(sys_get_temp_dir()) && ($tmpFile = tmpfile())) {
+ /* We have opened a tmpfile */
+ } else {
+ throw new Swift_IoException('Unable to copy the file to make it seekable, sys_temp_dir is not writable, php://memory not available');
+ }
+ $currentPos = ftell($this->reader);
+ fclose($this->reader);
+ $source = fopen($this->path, 'rb');
+ if (!$source) {
+ throw new Swift_IoException('Unable to open file for copying ['.$this->path.']');
+ }
+ fseek($tmpFile, 0, SEEK_SET);
+ while (!feof($source)) {
+ fwrite($tmpFile, fread($source, 4096));
+ }
+ fseek($tmpFile, $currentPos, SEEK_SET);
+ fclose($source);
+ $this->reader = $tmpFile;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php b/include/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php
new file mode 100644
index 0000000..0dc6190
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php
@@ -0,0 +1,52 @@
+getPath()))) {
+ throw new Swift_IoException('Failed to get temporary file content.');
+ }
+
+ return $content;
+ }
+
+ public function __destruct()
+ {
+ if (file_exists($this->getPath())) {
+ @unlink($this->getPath());
+ }
+ }
+
+ public function __sleep()
+ {
+ throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
+ }
+
+ public function __wakeup()
+ {
+ throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterReader.php b/include/swiftmailer/lib/classes/Swift/CharacterReader.php
new file mode 100644
index 0000000..4267adb
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterReader.php
@@ -0,0 +1,67 @@
+
+ */
+interface Swift_CharacterReader
+{
+ const MAP_TYPE_INVALID = 0x01;
+ const MAP_TYPE_FIXED_LEN = 0x02;
+ const MAP_TYPE_POSITIONS = 0x03;
+
+ /**
+ * Returns the complete character map.
+ *
+ * @param string $string
+ * @param int $startOffset
+ * @param array $currentMap
+ * @param mixed $ignoredChars
+ *
+ * @return int
+ */
+ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars);
+
+ /**
+ * Returns the mapType, see constants.
+ *
+ * @return int
+ */
+ public function getMapType();
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ *
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param int[] $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size);
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * For fixed width character sets this should be the number of octets-per-character.
+ * For multibyte character sets this will probably be 1.
+ *
+ * @return int
+ */
+ public function getInitialByteSize();
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php b/include/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php
new file mode 100644
index 0000000..3e055af
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterReader/GenericFixedWidthReader.php
@@ -0,0 +1,97 @@
+
+ */
+class Swift_CharacterReader_GenericFixedWidthReader implements Swift_CharacterReader
+{
+ /**
+ * The number of bytes in a single character.
+ *
+ * @var int
+ */
+ private $width;
+
+ /**
+ * Creates a new GenericFixedWidthReader using $width bytes per character.
+ *
+ * @param int $width
+ */
+ public function __construct($width)
+ {
+ $this->width = $width;
+ }
+
+ /**
+ * Returns the complete character map.
+ *
+ * @param string $string
+ * @param int $startOffset
+ * @param array $currentMap
+ * @param mixed $ignoredChars
+ *
+ * @return int
+ */
+ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
+ {
+ $strlen = \strlen($string);
+ // % and / are CPU intensive, so, maybe find a better way
+ $ignored = $strlen % $this->width;
+ $ignoredChars = $ignored ? substr($string, -$ignored) : '';
+ $currentMap = $this->width;
+
+ return ($strlen - $ignored) / $this->width;
+ }
+
+ /**
+ * Returns the mapType.
+ *
+ * @return int
+ */
+ public function getMapType()
+ {
+ return self::MAP_TYPE_FIXED_LEN;
+ }
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ *
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param string $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size)
+ {
+ $needed = $this->width - $size;
+
+ return $needed > -1 ? $needed : -1;
+ }
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * @return int
+ */
+ public function getInitialByteSize()
+ {
+ return $this->width;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php b/include/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php
new file mode 100644
index 0000000..ffc05f7
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterReader/UsAsciiReader.php
@@ -0,0 +1,84 @@
+ "\x07F") {
+ // Invalid char
+ $currentMap[$i + $startOffset] = $string[$i];
+ }
+ }
+
+ return $strlen;
+ }
+
+ /**
+ * Returns mapType.
+ *
+ * @return int mapType
+ */
+ public function getMapType()
+ {
+ return self::MAP_TYPE_INVALID;
+ }
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param string $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size)
+ {
+ $byte = reset($bytes);
+ if (1 == \count($bytes) && $byte >= 0x00 && $byte <= 0x7F) {
+ return 0;
+ }
+
+ return -1;
+ }
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * @return int
+ */
+ public function getInitialByteSize()
+ {
+ return 1;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php b/include/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php
new file mode 100644
index 0000000..da37e0d
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterReader/Utf8Reader.php
@@ -0,0 +1,176 @@
+
+ */
+class Swift_CharacterReader_Utf8Reader implements Swift_CharacterReader
+{
+ /** Pre-computed for optimization */
+ private static $length_map = [
+ // N=0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x0N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x1N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x2N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x3N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x4N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x5N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x6N
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x7N
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x8N
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x9N
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xAN
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xBN
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xCN
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xDN
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEN
+ 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 0, 0, // 0xFN
+ ];
+
+ private static $s_length_map = [
+ "\x00" => 1, "\x01" => 1, "\x02" => 1, "\x03" => 1, "\x04" => 1, "\x05" => 1, "\x06" => 1, "\x07" => 1,
+ "\x08" => 1, "\x09" => 1, "\x0a" => 1, "\x0b" => 1, "\x0c" => 1, "\x0d" => 1, "\x0e" => 1, "\x0f" => 1,
+ "\x10" => 1, "\x11" => 1, "\x12" => 1, "\x13" => 1, "\x14" => 1, "\x15" => 1, "\x16" => 1, "\x17" => 1,
+ "\x18" => 1, "\x19" => 1, "\x1a" => 1, "\x1b" => 1, "\x1c" => 1, "\x1d" => 1, "\x1e" => 1, "\x1f" => 1,
+ "\x20" => 1, "\x21" => 1, "\x22" => 1, "\x23" => 1, "\x24" => 1, "\x25" => 1, "\x26" => 1, "\x27" => 1,
+ "\x28" => 1, "\x29" => 1, "\x2a" => 1, "\x2b" => 1, "\x2c" => 1, "\x2d" => 1, "\x2e" => 1, "\x2f" => 1,
+ "\x30" => 1, "\x31" => 1, "\x32" => 1, "\x33" => 1, "\x34" => 1, "\x35" => 1, "\x36" => 1, "\x37" => 1,
+ "\x38" => 1, "\x39" => 1, "\x3a" => 1, "\x3b" => 1, "\x3c" => 1, "\x3d" => 1, "\x3e" => 1, "\x3f" => 1,
+ "\x40" => 1, "\x41" => 1, "\x42" => 1, "\x43" => 1, "\x44" => 1, "\x45" => 1, "\x46" => 1, "\x47" => 1,
+ "\x48" => 1, "\x49" => 1, "\x4a" => 1, "\x4b" => 1, "\x4c" => 1, "\x4d" => 1, "\x4e" => 1, "\x4f" => 1,
+ "\x50" => 1, "\x51" => 1, "\x52" => 1, "\x53" => 1, "\x54" => 1, "\x55" => 1, "\x56" => 1, "\x57" => 1,
+ "\x58" => 1, "\x59" => 1, "\x5a" => 1, "\x5b" => 1, "\x5c" => 1, "\x5d" => 1, "\x5e" => 1, "\x5f" => 1,
+ "\x60" => 1, "\x61" => 1, "\x62" => 1, "\x63" => 1, "\x64" => 1, "\x65" => 1, "\x66" => 1, "\x67" => 1,
+ "\x68" => 1, "\x69" => 1, "\x6a" => 1, "\x6b" => 1, "\x6c" => 1, "\x6d" => 1, "\x6e" => 1, "\x6f" => 1,
+ "\x70" => 1, "\x71" => 1, "\x72" => 1, "\x73" => 1, "\x74" => 1, "\x75" => 1, "\x76" => 1, "\x77" => 1,
+ "\x78" => 1, "\x79" => 1, "\x7a" => 1, "\x7b" => 1, "\x7c" => 1, "\x7d" => 1, "\x7e" => 1, "\x7f" => 1,
+ "\x80" => 0, "\x81" => 0, "\x82" => 0, "\x83" => 0, "\x84" => 0, "\x85" => 0, "\x86" => 0, "\x87" => 0,
+ "\x88" => 0, "\x89" => 0, "\x8a" => 0, "\x8b" => 0, "\x8c" => 0, "\x8d" => 0, "\x8e" => 0, "\x8f" => 0,
+ "\x90" => 0, "\x91" => 0, "\x92" => 0, "\x93" => 0, "\x94" => 0, "\x95" => 0, "\x96" => 0, "\x97" => 0,
+ "\x98" => 0, "\x99" => 0, "\x9a" => 0, "\x9b" => 0, "\x9c" => 0, "\x9d" => 0, "\x9e" => 0, "\x9f" => 0,
+ "\xa0" => 0, "\xa1" => 0, "\xa2" => 0, "\xa3" => 0, "\xa4" => 0, "\xa5" => 0, "\xa6" => 0, "\xa7" => 0,
+ "\xa8" => 0, "\xa9" => 0, "\xaa" => 0, "\xab" => 0, "\xac" => 0, "\xad" => 0, "\xae" => 0, "\xaf" => 0,
+ "\xb0" => 0, "\xb1" => 0, "\xb2" => 0, "\xb3" => 0, "\xb4" => 0, "\xb5" => 0, "\xb6" => 0, "\xb7" => 0,
+ "\xb8" => 0, "\xb9" => 0, "\xba" => 0, "\xbb" => 0, "\xbc" => 0, "\xbd" => 0, "\xbe" => 0, "\xbf" => 0,
+ "\xc0" => 2, "\xc1" => 2, "\xc2" => 2, "\xc3" => 2, "\xc4" => 2, "\xc5" => 2, "\xc6" => 2, "\xc7" => 2,
+ "\xc8" => 2, "\xc9" => 2, "\xca" => 2, "\xcb" => 2, "\xcc" => 2, "\xcd" => 2, "\xce" => 2, "\xcf" => 2,
+ "\xd0" => 2, "\xd1" => 2, "\xd2" => 2, "\xd3" => 2, "\xd4" => 2, "\xd5" => 2, "\xd6" => 2, "\xd7" => 2,
+ "\xd8" => 2, "\xd9" => 2, "\xda" => 2, "\xdb" => 2, "\xdc" => 2, "\xdd" => 2, "\xde" => 2, "\xdf" => 2,
+ "\xe0" => 3, "\xe1" => 3, "\xe2" => 3, "\xe3" => 3, "\xe4" => 3, "\xe5" => 3, "\xe6" => 3, "\xe7" => 3,
+ "\xe8" => 3, "\xe9" => 3, "\xea" => 3, "\xeb" => 3, "\xec" => 3, "\xed" => 3, "\xee" => 3, "\xef" => 3,
+ "\xf0" => 4, "\xf1" => 4, "\xf2" => 4, "\xf3" => 4, "\xf4" => 4, "\xf5" => 4, "\xf6" => 4, "\xf7" => 4,
+ "\xf8" => 5, "\xf9" => 5, "\xfa" => 5, "\xfb" => 5, "\xfc" => 6, "\xfd" => 6, "\xfe" => 0, "\xff" => 0,
+ ];
+
+ /**
+ * Returns the complete character map.
+ *
+ * @param string $string
+ * @param int $startOffset
+ * @param array $currentMap
+ * @param mixed $ignoredChars
+ *
+ * @return int
+ */
+ public function getCharPositions($string, $startOffset, &$currentMap, &$ignoredChars)
+ {
+ if (!isset($currentMap['i']) || !isset($currentMap['p'])) {
+ $currentMap['p'] = $currentMap['i'] = [];
+ }
+
+ $strlen = \strlen($string);
+ $charPos = \count($currentMap['p']);
+ $foundChars = 0;
+ $invalid = false;
+ for ($i = 0; $i < $strlen; ++$i) {
+ $char = $string[$i];
+ $size = self::$s_length_map[$char];
+ if (0 == $size) {
+ /* char is invalid, we must wait for a resync */
+ $invalid = true;
+ continue;
+ } else {
+ if (true === $invalid) {
+ /* We mark the chars as invalid and start a new char */
+ $currentMap['p'][$charPos + $foundChars] = $startOffset + $i;
+ $currentMap['i'][$charPos + $foundChars] = true;
+ ++$foundChars;
+ $invalid = false;
+ }
+ if (($i + $size) > $strlen) {
+ $ignoredChars = substr($string, $i);
+ break;
+ }
+ for ($j = 1; $j < $size; ++$j) {
+ $char = $string[$i + $j];
+ if ($char > "\x7F" && $char < "\xC0") {
+ // Valid - continue parsing
+ } else {
+ /* char is invalid, we must wait for a resync */
+ $invalid = true;
+ continue 2;
+ }
+ }
+ /* Ok we got a complete char here */
+ $currentMap['p'][$charPos + $foundChars] = $startOffset + $i + $size;
+ $i += $j - 1;
+ ++$foundChars;
+ }
+ }
+
+ return $foundChars;
+ }
+
+ /**
+ * Returns mapType.
+ *
+ * @return int mapType
+ */
+ public function getMapType()
+ {
+ return self::MAP_TYPE_POSITIONS;
+ }
+
+ /**
+ * Returns an integer which specifies how many more bytes to read.
+ *
+ * A positive integer indicates the number of more bytes to fetch before invoking
+ * this method again.
+ * A value of zero means this is already a valid character.
+ * A value of -1 means this cannot possibly be a valid character.
+ *
+ * @param string $bytes
+ * @param int $size
+ *
+ * @return int
+ */
+ public function validateByteSequence($bytes, $size)
+ {
+ if ($size < 1) {
+ return -1;
+ }
+ $needed = self::$length_map[$bytes[0]] - $size;
+
+ return $needed > -1 ? $needed : -1;
+ }
+
+ /**
+ * Returns the number of bytes which should be read to start each character.
+ *
+ * @return int
+ */
+ public function getInitialByteSize()
+ {
+ return 1;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php b/include/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php
new file mode 100644
index 0000000..15b6c69
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterReaderFactory.php
@@ -0,0 +1,26 @@
+init();
+ }
+
+ public function __wakeup()
+ {
+ $this->init();
+ }
+
+ public function init()
+ {
+ if (\count(self::$map) > 0) {
+ return;
+ }
+
+ $prefix = 'Swift_CharacterReader_';
+
+ $singleByte = [
+ 'class' => $prefix.'GenericFixedWidthReader',
+ 'constructor' => [1],
+ ];
+
+ $doubleByte = [
+ 'class' => $prefix.'GenericFixedWidthReader',
+ 'constructor' => [2],
+ ];
+
+ $fourBytes = [
+ 'class' => $prefix.'GenericFixedWidthReader',
+ 'constructor' => [4],
+ ];
+
+ // Utf-8
+ self::$map['utf-?8'] = [
+ 'class' => $prefix.'Utf8Reader',
+ 'constructor' => [],
+ ];
+
+ //7-8 bit charsets
+ self::$map['(us-)?ascii'] = $singleByte;
+ self::$map['(iso|iec)-?8859-?[0-9]+'] = $singleByte;
+ self::$map['windows-?125[0-9]'] = $singleByte;
+ self::$map['cp-?[0-9]+'] = $singleByte;
+ self::$map['ansi'] = $singleByte;
+ self::$map['macintosh'] = $singleByte;
+ self::$map['koi-?7'] = $singleByte;
+ self::$map['koi-?8-?.+'] = $singleByte;
+ self::$map['mik'] = $singleByte;
+ self::$map['(cork|t1)'] = $singleByte;
+ self::$map['v?iscii'] = $singleByte;
+
+ //16 bits
+ self::$map['(ucs-?2|utf-?16)'] = $doubleByte;
+
+ //32 bits
+ self::$map['(ucs-?4|utf-?32)'] = $fourBytes;
+
+ // Fallback
+ self::$map['.*'] = $singleByte;
+ }
+
+ /**
+ * Returns a CharacterReader suitable for the charset applied.
+ *
+ * @param string $charset
+ *
+ * @return Swift_CharacterReader
+ */
+ public function getReaderFor($charset)
+ {
+ $charset = strtolower(trim($charset));
+ foreach (self::$map as $pattern => $spec) {
+ $re = '/^'.$pattern.'$/D';
+ if (preg_match($re, $charset)) {
+ if (!\array_key_exists($pattern, self::$loaded)) {
+ $reflector = new ReflectionClass($spec['class']);
+ if ($reflector->getConstructor()) {
+ $reader = $reflector->newInstanceArgs($spec['constructor']);
+ } else {
+ $reader = $reflector->newInstance();
+ }
+ self::$loaded[$pattern] = $reader;
+ }
+
+ return self::$loaded[$pattern];
+ }
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterStream.php b/include/swiftmailer/lib/classes/Swift/CharacterStream.php
new file mode 100644
index 0000000..c9d8a07
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterStream.php
@@ -0,0 +1,87 @@
+setCharacterReaderFactory($factory);
+ $this->setCharacterSet($charset);
+ }
+
+ /**
+ * Set the character set used in this CharacterStream.
+ *
+ * @param string $charset
+ */
+ public function setCharacterSet($charset)
+ {
+ $this->charset = $charset;
+ $this->charReader = null;
+ }
+
+ /**
+ * Set the CharacterReaderFactory for multi charset support.
+ */
+ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
+ {
+ $this->charReaderFactory = $factory;
+ }
+
+ /**
+ * Overwrite this character stream using the byte sequence in the byte stream.
+ *
+ * @param Swift_OutputByteStream $os output stream to read from
+ */
+ public function importByteStream(Swift_OutputByteStream $os)
+ {
+ if (!isset($this->charReader)) {
+ $this->charReader = $this->charReaderFactory
+ ->getReaderFor($this->charset);
+ }
+
+ $startLength = $this->charReader->getInitialByteSize();
+ while (false !== $bytes = $os->read($startLength)) {
+ $c = [];
+ for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) {
+ $c[] = self::$byteMap[$bytes[$i]];
+ }
+ $size = \count($c);
+ $need = $this->charReader
+ ->validateByteSequence($c, $size);
+ if ($need > 0 &&
+ false !== $bytes = $os->read($need)) {
+ for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) {
+ $c[] = self::$byteMap[$bytes[$i]];
+ }
+ }
+ $this->array[] = $c;
+ ++$this->array_size;
+ }
+ }
+
+ /**
+ * Import a string a bytes into this CharacterStream, overwriting any existing
+ * data in the stream.
+ *
+ * @param string $string
+ */
+ public function importString($string)
+ {
+ $this->flushContents();
+ $this->write($string);
+ }
+
+ /**
+ * Read $length characters from the stream and move the internal pointer
+ * $length further into the stream.
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ public function read($length)
+ {
+ if ($this->offset == $this->array_size) {
+ return false;
+ }
+
+ // Don't use array slice
+ $arrays = [];
+ $end = $length + $this->offset;
+ for ($i = $this->offset; $i < $end; ++$i) {
+ if (!isset($this->array[$i])) {
+ break;
+ }
+ $arrays[] = $this->array[$i];
+ }
+ $this->offset += $i - $this->offset; // Limit function calls
+ $chars = false;
+ foreach ($arrays as $array) {
+ $chars .= implode('', array_map('chr', $array));
+ }
+
+ return $chars;
+ }
+
+ /**
+ * Read $length characters from the stream and return a 1-dimensional array
+ * containing there octet values.
+ *
+ * @param int $length
+ *
+ * @return int[]
+ */
+ public function readBytes($length)
+ {
+ if ($this->offset == $this->array_size) {
+ return false;
+ }
+ $arrays = [];
+ $end = $length + $this->offset;
+ for ($i = $this->offset; $i < $end; ++$i) {
+ if (!isset($this->array[$i])) {
+ break;
+ }
+ $arrays[] = $this->array[$i];
+ }
+ $this->offset += ($i - $this->offset); // Limit function calls
+
+ return array_merge(...$arrays);
+ }
+
+ /**
+ * Write $chars to the end of the stream.
+ *
+ * @param string $chars
+ */
+ public function write($chars)
+ {
+ if (!isset($this->charReader)) {
+ $this->charReader = $this->charReaderFactory->getReaderFor(
+ $this->charset);
+ }
+
+ $startLength = $this->charReader->getInitialByteSize();
+
+ $fp = fopen('php://memory', 'w+b');
+ fwrite($fp, $chars);
+ unset($chars);
+ fseek($fp, 0, SEEK_SET);
+
+ $buffer = [0];
+ $buf_pos = 1;
+ $buf_len = 1;
+ $has_datas = true;
+ do {
+ $bytes = [];
+ // Buffer Filing
+ if ($buf_len - $buf_pos < $startLength) {
+ $buf = array_splice($buffer, $buf_pos);
+ $new = $this->reloadBuffer($fp, 100);
+ if ($new) {
+ $buffer = array_merge($buf, $new);
+ $buf_len = \count($buffer);
+ $buf_pos = 0;
+ } else {
+ $has_datas = false;
+ }
+ }
+ if ($buf_len - $buf_pos > 0) {
+ $size = 0;
+ for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) {
+ ++$size;
+ $bytes[] = $buffer[$buf_pos++];
+ }
+ $need = $this->charReader->validateByteSequence(
+ $bytes, $size);
+ if ($need > 0) {
+ if ($buf_len - $buf_pos < $need) {
+ $new = $this->reloadBuffer($fp, $need);
+
+ if ($new) {
+ $buffer = array_merge($buffer, $new);
+ $buf_len = \count($buffer);
+ }
+ }
+ for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) {
+ $bytes[] = $buffer[$buf_pos++];
+ }
+ }
+ $this->array[] = $bytes;
+ ++$this->array_size;
+ }
+ } while ($has_datas);
+
+ fclose($fp);
+ }
+
+ /**
+ * Move the internal pointer to $charOffset in the stream.
+ *
+ * @param int $charOffset
+ */
+ public function setPointer($charOffset)
+ {
+ if ($charOffset > $this->array_size) {
+ $charOffset = $this->array_size;
+ } elseif ($charOffset < 0) {
+ $charOffset = 0;
+ }
+ $this->offset = $charOffset;
+ }
+
+ /**
+ * Empty the stream and reset the internal pointer.
+ */
+ public function flushContents()
+ {
+ $this->offset = 0;
+ $this->array = [];
+ $this->array_size = 0;
+ }
+
+ private function reloadBuffer($fp, $len)
+ {
+ if (!feof($fp) && false !== ($bytes = fread($fp, $len))) {
+ $buf = [];
+ for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) {
+ $buf[] = self::$byteMap[$bytes[$i]];
+ }
+
+ return $buf;
+ }
+
+ return false;
+ }
+
+ private static function initializeMaps()
+ {
+ if (!isset(self::$charMap)) {
+ self::$charMap = [];
+ for ($byte = 0; $byte < 256; ++$byte) {
+ self::$charMap[$byte] = \chr($byte);
+ }
+ self::$byteMap = array_flip(self::$charMap);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php b/include/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php
new file mode 100644
index 0000000..7578dda
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/CharacterStream/NgCharacterStream.php
@@ -0,0 +1,262 @@
+
+ */
+class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream
+{
+ /**
+ * The char reader (lazy-loaded) for the current charset.
+ *
+ * @var Swift_CharacterReader
+ */
+ private $charReader;
+
+ /**
+ * A factory for creating CharacterReader instances.
+ *
+ * @var Swift_CharacterReaderFactory
+ */
+ private $charReaderFactory;
+
+ /**
+ * The character set this stream is using.
+ *
+ * @var string
+ */
+ private $charset;
+
+ /**
+ * The data's stored as-is.
+ *
+ * @var string
+ */
+ private $datas = '';
+
+ /**
+ * Number of bytes in the stream.
+ *
+ * @var int
+ */
+ private $datasSize = 0;
+
+ /**
+ * Map.
+ *
+ * @var mixed
+ */
+ private $map;
+
+ /**
+ * Map Type.
+ *
+ * @var int
+ */
+ private $mapType = 0;
+
+ /**
+ * Number of characters in the stream.
+ *
+ * @var int
+ */
+ private $charCount = 0;
+
+ /**
+ * Position in the stream.
+ *
+ * @var int
+ */
+ private $currentPos = 0;
+
+ /**
+ * Constructor.
+ *
+ * @param string $charset
+ */
+ public function __construct(Swift_CharacterReaderFactory $factory, $charset)
+ {
+ $this->setCharacterReaderFactory($factory);
+ $this->setCharacterSet($charset);
+ }
+
+ /* -- Changing parameters of the stream -- */
+
+ /**
+ * Set the character set used in this CharacterStream.
+ *
+ * @param string $charset
+ */
+ public function setCharacterSet($charset)
+ {
+ $this->charset = $charset;
+ $this->charReader = null;
+ $this->mapType = 0;
+ }
+
+ /**
+ * Set the CharacterReaderFactory for multi charset support.
+ */
+ public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
+ {
+ $this->charReaderFactory = $factory;
+ }
+
+ /**
+ * @see Swift_CharacterStream::flushContents()
+ */
+ public function flushContents()
+ {
+ $this->datas = null;
+ $this->map = null;
+ $this->charCount = 0;
+ $this->currentPos = 0;
+ $this->datasSize = 0;
+ }
+
+ /**
+ * @see Swift_CharacterStream::importByteStream()
+ */
+ public function importByteStream(Swift_OutputByteStream $os)
+ {
+ $this->flushContents();
+ $blocks = 512;
+ $os->setReadPointer(0);
+ while (false !== ($read = $os->read($blocks))) {
+ $this->write($read);
+ }
+ }
+
+ /**
+ * @see Swift_CharacterStream::importString()
+ *
+ * @param string $string
+ */
+ public function importString($string)
+ {
+ $this->flushContents();
+ $this->write($string);
+ }
+
+ /**
+ * @see Swift_CharacterStream::read()
+ *
+ * @param int $length
+ *
+ * @return string
+ */
+ public function read($length)
+ {
+ if ($this->currentPos >= $this->charCount) {
+ return false;
+ }
+ $ret = false;
+ $length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length;
+ switch ($this->mapType) {
+ case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
+ $len = $length * $this->map;
+ $ret = substr($this->datas,
+ $this->currentPos * $this->map,
+ $len);
+ $this->currentPos += $length;
+ break;
+
+ case Swift_CharacterReader::MAP_TYPE_INVALID:
+ $ret = '';
+ for (; $this->currentPos < $length; ++$this->currentPos) {
+ if (isset($this->map[$this->currentPos])) {
+ $ret .= '?';
+ } else {
+ $ret .= $this->datas[$this->currentPos];
+ }
+ }
+ break;
+
+ case Swift_CharacterReader::MAP_TYPE_POSITIONS:
+ $end = $this->currentPos + $length;
+ $end = $end > $this->charCount ? $this->charCount : $end;
+ $ret = '';
+ $start = 0;
+ if ($this->currentPos > 0) {
+ $start = $this->map['p'][$this->currentPos - 1];
+ }
+ $to = $start;
+ for (; $this->currentPos < $end; ++$this->currentPos) {
+ if (isset($this->map['i'][$this->currentPos])) {
+ $ret .= substr($this->datas, $start, $to - $start).'?';
+ $start = $this->map['p'][$this->currentPos];
+ } else {
+ $to = $this->map['p'][$this->currentPos];
+ }
+ }
+ $ret .= substr($this->datas, $start, $to - $start);
+ break;
+ }
+
+ return $ret;
+ }
+
+ /**
+ * @see Swift_CharacterStream::readBytes()
+ *
+ * @param int $length
+ *
+ * @return int[]
+ */
+ public function readBytes($length)
+ {
+ $read = $this->read($length);
+ if (false !== $read) {
+ $ret = array_map('ord', str_split($read, 1));
+
+ return $ret;
+ }
+
+ return false;
+ }
+
+ /**
+ * @see Swift_CharacterStream::setPointer()
+ *
+ * @param int $charOffset
+ */
+ public function setPointer($charOffset)
+ {
+ if ($this->charCount < $charOffset) {
+ $charOffset = $this->charCount;
+ }
+ $this->currentPos = $charOffset;
+ }
+
+ /**
+ * @see Swift_CharacterStream::write()
+ *
+ * @param string $chars
+ */
+ public function write($chars)
+ {
+ if (!isset($this->charReader)) {
+ $this->charReader = $this->charReaderFactory->getReaderFor(
+ $this->charset);
+ $this->map = [];
+ $this->mapType = $this->charReader->getMapType();
+ }
+ $ignored = '';
+ $this->datas .= $chars;
+ $this->charCount += $this->charReader->getCharPositions(substr($this->datas, $this->datasSize), $this->datasSize, $this->map, $ignored);
+ if (false !== $ignored) {
+ $this->datasSize = \strlen($this->datas) - \strlen($ignored);
+ } else {
+ $this->datasSize = \strlen($this->datas);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/ConfigurableSpool.php b/include/swiftmailer/lib/classes/Swift/ConfigurableSpool.php
new file mode 100644
index 0000000..a711bac
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/ConfigurableSpool.php
@@ -0,0 +1,63 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Base class for Spools (implements time and message limits).
+ *
+ * @author Fabien Potencier
+ */
+abstract class Swift_ConfigurableSpool implements Swift_Spool
+{
+ /** The maximum number of messages to send per flush */
+ private $message_limit;
+
+ /** The time limit per flush */
+ private $time_limit;
+
+ /**
+ * Sets the maximum number of messages to send per flush.
+ *
+ * @param int $limit
+ */
+ public function setMessageLimit($limit)
+ {
+ $this->message_limit = (int) $limit;
+ }
+
+ /**
+ * Gets the maximum number of messages to send per flush.
+ *
+ * @return int The limit
+ */
+ public function getMessageLimit()
+ {
+ return $this->message_limit;
+ }
+
+ /**
+ * Sets the time limit (in seconds) per flush.
+ *
+ * @param int $limit The limit
+ */
+ public function setTimeLimit($limit)
+ {
+ $this->time_limit = (int) $limit;
+ }
+
+ /**
+ * Gets the time limit (in seconds) per flush.
+ *
+ * @return int The limit
+ */
+ public function getTimeLimit()
+ {
+ return $this->time_limit;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/DependencyContainer.php b/include/swiftmailer/lib/classes/Swift/DependencyContainer.php
new file mode 100644
index 0000000..3cc885e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/DependencyContainer.php
@@ -0,0 +1,387 @@
+store);
+ }
+
+ /**
+ * Test if an item is registered in this container with the given name.
+ *
+ * @see register()
+ *
+ * @param string $itemName
+ *
+ * @return bool
+ */
+ public function has($itemName)
+ {
+ return \array_key_exists($itemName, $this->store)
+ && isset($this->store[$itemName]['lookupType']);
+ }
+
+ /**
+ * Lookup the item with the given $itemName.
+ *
+ * @see register()
+ *
+ * @param string $itemName
+ *
+ * @return mixed
+ *
+ * @throws Swift_DependencyException If the dependency is not found
+ */
+ public function lookup($itemName)
+ {
+ if (!$this->has($itemName)) {
+ throw new Swift_DependencyException('Cannot lookup dependency "'.$itemName.'" since it is not registered.');
+ }
+
+ switch ($this->store[$itemName]['lookupType']) {
+ case self::TYPE_ALIAS:
+ return $this->createAlias($itemName);
+ case self::TYPE_VALUE:
+ return $this->getValue($itemName);
+ case self::TYPE_INSTANCE:
+ return $this->createNewInstance($itemName);
+ case self::TYPE_SHARED:
+ return $this->createSharedInstance($itemName);
+ case self::TYPE_ARRAY:
+ return $this->createDependenciesFor($itemName);
+ }
+ }
+
+ /**
+ * Create an array of arguments passed to the constructor of $itemName.
+ *
+ * @param string $itemName
+ *
+ * @return array
+ */
+ public function createDependenciesFor($itemName)
+ {
+ $args = [];
+ if (isset($this->store[$itemName]['args'])) {
+ $args = $this->resolveArgs($this->store[$itemName]['args']);
+ }
+
+ return $args;
+ }
+
+ /**
+ * Register a new dependency with $itemName.
+ *
+ * This method returns the current DependencyContainer instance because it
+ * requires the use of the fluid interface to set the specific details for the
+ * dependency.
+ *
+ * @see asNewInstanceOf(), asSharedInstanceOf(), asValue()
+ *
+ * @param string $itemName
+ *
+ * @return $this
+ */
+ public function register($itemName)
+ {
+ $this->store[$itemName] = [];
+ $this->endPoint = &$this->store[$itemName];
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as a literal value.
+ *
+ * {@link register()} must be called before this will work.
+ *
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ public function asValue($value)
+ {
+ $endPoint = &$this->getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_VALUE;
+ $endPoint['value'] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as an alias of another item.
+ *
+ * @param string $lookup
+ *
+ * @return $this
+ */
+ public function asAliasOf($lookup)
+ {
+ $endPoint = &$this->getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_ALIAS;
+ $endPoint['ref'] = $lookup;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as a new instance of $className.
+ *
+ * {@link register()} must be called before this will work.
+ * Any arguments can be set with {@link withDependencies()},
+ * {@link addConstructorValue()} or {@link addConstructorLookup()}.
+ *
+ * @see withDependencies(), addConstructorValue(), addConstructorLookup()
+ *
+ * @param string $className
+ *
+ * @return $this
+ */
+ public function asNewInstanceOf($className)
+ {
+ $endPoint = &$this->getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_INSTANCE;
+ $endPoint['className'] = $className;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as a shared instance of $className.
+ *
+ * {@link register()} must be called before this will work.
+ *
+ * @param string $className
+ *
+ * @return $this
+ */
+ public function asSharedInstanceOf($className)
+ {
+ $endPoint = &$this->getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_SHARED;
+ $endPoint['className'] = $className;
+
+ return $this;
+ }
+
+ /**
+ * Specify the previously registered item as array of dependencies.
+ *
+ * {@link register()} must be called before this will work.
+ *
+ * @return $this
+ */
+ public function asArray()
+ {
+ $endPoint = &$this->getEndPoint();
+ $endPoint['lookupType'] = self::TYPE_ARRAY;
+
+ return $this;
+ }
+
+ /**
+ * Specify a list of injected dependencies for the previously registered item.
+ *
+ * This method takes an array of lookup names.
+ *
+ * @see addConstructorValue(), addConstructorLookup()
+ *
+ * @return $this
+ */
+ public function withDependencies(array $lookups)
+ {
+ $endPoint = &$this->getEndPoint();
+ $endPoint['args'] = [];
+ foreach ($lookups as $lookup) {
+ $this->addConstructorLookup($lookup);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Specify a literal (non looked up) value for the constructor of the
+ * previously registered item.
+ *
+ * @see withDependencies(), addConstructorLookup()
+ *
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ public function addConstructorValue($value)
+ {
+ $endPoint = &$this->getEndPoint();
+ if (!isset($endPoint['args'])) {
+ $endPoint['args'] = [];
+ }
+ $endPoint['args'][] = ['type' => 'value', 'item' => $value];
+
+ return $this;
+ }
+
+ /**
+ * Specify a dependency lookup for the constructor of the previously
+ * registered item.
+ *
+ * @see withDependencies(), addConstructorValue()
+ *
+ * @param string $lookup
+ *
+ * @return $this
+ */
+ public function addConstructorLookup($lookup)
+ {
+ $endPoint = &$this->getEndPoint();
+ if (!isset($this->endPoint['args'])) {
+ $endPoint['args'] = [];
+ }
+ $endPoint['args'][] = ['type' => 'lookup', 'item' => $lookup];
+
+ return $this;
+ }
+
+ /** Get the literal value with $itemName */
+ private function getValue($itemName)
+ {
+ return $this->store[$itemName]['value'];
+ }
+
+ /** Resolve an alias to another item */
+ private function createAlias($itemName)
+ {
+ return $this->lookup($this->store[$itemName]['ref']);
+ }
+
+ /** Create a fresh instance of $itemName */
+ private function createNewInstance($itemName)
+ {
+ $reflector = new ReflectionClass($this->store[$itemName]['className']);
+ if ($reflector->getConstructor()) {
+ return $reflector->newInstanceArgs(
+ $this->createDependenciesFor($itemName)
+ );
+ }
+
+ return $reflector->newInstance();
+ }
+
+ /** Create and register a shared instance of $itemName */
+ private function createSharedInstance($itemName)
+ {
+ if (!isset($this->store[$itemName]['instance'])) {
+ $this->store[$itemName]['instance'] = $this->createNewInstance($itemName);
+ }
+
+ return $this->store[$itemName]['instance'];
+ }
+
+ /** Get the current endpoint in the store */
+ private function &getEndPoint()
+ {
+ if (!isset($this->endPoint)) {
+ throw new BadMethodCallException('Component must first be registered by calling register()');
+ }
+
+ return $this->endPoint;
+ }
+
+ /** Get an argument list with dependencies resolved */
+ private function resolveArgs(array $args)
+ {
+ $resolved = [];
+ foreach ($args as $argDefinition) {
+ switch ($argDefinition['type']) {
+ case 'lookup':
+ $resolved[] = $this->lookupRecursive($argDefinition['item']);
+ break;
+ case 'value':
+ $resolved[] = $argDefinition['item'];
+ break;
+ }
+ }
+
+ return $resolved;
+ }
+
+ /** Resolve a single dependency with an collections */
+ private function lookupRecursive($item)
+ {
+ if (\is_array($item)) {
+ $collection = [];
+ foreach ($item as $k => $v) {
+ $collection[$k] = $this->lookupRecursive($v);
+ }
+
+ return $collection;
+ }
+
+ return $this->lookup($item);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/DependencyException.php b/include/swiftmailer/lib/classes/Swift/DependencyException.php
new file mode 100644
index 0000000..799d38d
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/DependencyException.php
@@ -0,0 +1,27 @@
+createDependenciesFor('mime.embeddedfile')
+ );
+
+ $this->setBody($data);
+ $this->setFilename($filename);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+
+ /**
+ * Create a new EmbeddedFile from a filesystem path.
+ *
+ * @param string $path
+ *
+ * @return Swift_Mime_EmbeddedFile
+ */
+ public static function fromPath($path)
+ {
+ return (new self())->setFile(new Swift_ByteStream_FileByteStream($path));
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Encoder.php b/include/swiftmailer/lib/classes/Swift/Encoder.php
new file mode 100644
index 0000000..2073abc
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Encoder.php
@@ -0,0 +1,28 @@
+= $maxLineLength || 76 < $maxLineLength) {
+ $maxLineLength = 76;
+ }
+
+ $encodedString = base64_encode($string);
+ $firstLine = '';
+
+ if (0 != $firstLineOffset) {
+ $firstLine = substr(
+ $encodedString, 0, $maxLineLength - $firstLineOffset
+ )."\r\n";
+ $encodedString = substr(
+ $encodedString, $maxLineLength - $firstLineOffset
+ );
+ }
+
+ return $firstLine.trim(chunk_split($encodedString, $maxLineLength, "\r\n"));
+ }
+
+ /**
+ * Does nothing.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php b/include/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php
new file mode 100644
index 0000000..f078d6d
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Encoder/QpEncoder.php
@@ -0,0 +1,300 @@
+ '=00', 1 => '=01', 2 => '=02', 3 => '=03', 4 => '=04',
+ 5 => '=05', 6 => '=06', 7 => '=07', 8 => '=08', 9 => '=09',
+ 10 => '=0A', 11 => '=0B', 12 => '=0C', 13 => '=0D', 14 => '=0E',
+ 15 => '=0F', 16 => '=10', 17 => '=11', 18 => '=12', 19 => '=13',
+ 20 => '=14', 21 => '=15', 22 => '=16', 23 => '=17', 24 => '=18',
+ 25 => '=19', 26 => '=1A', 27 => '=1B', 28 => '=1C', 29 => '=1D',
+ 30 => '=1E', 31 => '=1F', 32 => '=20', 33 => '=21', 34 => '=22',
+ 35 => '=23', 36 => '=24', 37 => '=25', 38 => '=26', 39 => '=27',
+ 40 => '=28', 41 => '=29', 42 => '=2A', 43 => '=2B', 44 => '=2C',
+ 45 => '=2D', 46 => '=2E', 47 => '=2F', 48 => '=30', 49 => '=31',
+ 50 => '=32', 51 => '=33', 52 => '=34', 53 => '=35', 54 => '=36',
+ 55 => '=37', 56 => '=38', 57 => '=39', 58 => '=3A', 59 => '=3B',
+ 60 => '=3C', 61 => '=3D', 62 => '=3E', 63 => '=3F', 64 => '=40',
+ 65 => '=41', 66 => '=42', 67 => '=43', 68 => '=44', 69 => '=45',
+ 70 => '=46', 71 => '=47', 72 => '=48', 73 => '=49', 74 => '=4A',
+ 75 => '=4B', 76 => '=4C', 77 => '=4D', 78 => '=4E', 79 => '=4F',
+ 80 => '=50', 81 => '=51', 82 => '=52', 83 => '=53', 84 => '=54',
+ 85 => '=55', 86 => '=56', 87 => '=57', 88 => '=58', 89 => '=59',
+ 90 => '=5A', 91 => '=5B', 92 => '=5C', 93 => '=5D', 94 => '=5E',
+ 95 => '=5F', 96 => '=60', 97 => '=61', 98 => '=62', 99 => '=63',
+ 100 => '=64', 101 => '=65', 102 => '=66', 103 => '=67', 104 => '=68',
+ 105 => '=69', 106 => '=6A', 107 => '=6B', 108 => '=6C', 109 => '=6D',
+ 110 => '=6E', 111 => '=6F', 112 => '=70', 113 => '=71', 114 => '=72',
+ 115 => '=73', 116 => '=74', 117 => '=75', 118 => '=76', 119 => '=77',
+ 120 => '=78', 121 => '=79', 122 => '=7A', 123 => '=7B', 124 => '=7C',
+ 125 => '=7D', 126 => '=7E', 127 => '=7F', 128 => '=80', 129 => '=81',
+ 130 => '=82', 131 => '=83', 132 => '=84', 133 => '=85', 134 => '=86',
+ 135 => '=87', 136 => '=88', 137 => '=89', 138 => '=8A', 139 => '=8B',
+ 140 => '=8C', 141 => '=8D', 142 => '=8E', 143 => '=8F', 144 => '=90',
+ 145 => '=91', 146 => '=92', 147 => '=93', 148 => '=94', 149 => '=95',
+ 150 => '=96', 151 => '=97', 152 => '=98', 153 => '=99', 154 => '=9A',
+ 155 => '=9B', 156 => '=9C', 157 => '=9D', 158 => '=9E', 159 => '=9F',
+ 160 => '=A0', 161 => '=A1', 162 => '=A2', 163 => '=A3', 164 => '=A4',
+ 165 => '=A5', 166 => '=A6', 167 => '=A7', 168 => '=A8', 169 => '=A9',
+ 170 => '=AA', 171 => '=AB', 172 => '=AC', 173 => '=AD', 174 => '=AE',
+ 175 => '=AF', 176 => '=B0', 177 => '=B1', 178 => '=B2', 179 => '=B3',
+ 180 => '=B4', 181 => '=B5', 182 => '=B6', 183 => '=B7', 184 => '=B8',
+ 185 => '=B9', 186 => '=BA', 187 => '=BB', 188 => '=BC', 189 => '=BD',
+ 190 => '=BE', 191 => '=BF', 192 => '=C0', 193 => '=C1', 194 => '=C2',
+ 195 => '=C3', 196 => '=C4', 197 => '=C5', 198 => '=C6', 199 => '=C7',
+ 200 => '=C8', 201 => '=C9', 202 => '=CA', 203 => '=CB', 204 => '=CC',
+ 205 => '=CD', 206 => '=CE', 207 => '=CF', 208 => '=D0', 209 => '=D1',
+ 210 => '=D2', 211 => '=D3', 212 => '=D4', 213 => '=D5', 214 => '=D6',
+ 215 => '=D7', 216 => '=D8', 217 => '=D9', 218 => '=DA', 219 => '=DB',
+ 220 => '=DC', 221 => '=DD', 222 => '=DE', 223 => '=DF', 224 => '=E0',
+ 225 => '=E1', 226 => '=E2', 227 => '=E3', 228 => '=E4', 229 => '=E5',
+ 230 => '=E6', 231 => '=E7', 232 => '=E8', 233 => '=E9', 234 => '=EA',
+ 235 => '=EB', 236 => '=EC', 237 => '=ED', 238 => '=EE', 239 => '=EF',
+ 240 => '=F0', 241 => '=F1', 242 => '=F2', 243 => '=F3', 244 => '=F4',
+ 245 => '=F5', 246 => '=F6', 247 => '=F7', 248 => '=F8', 249 => '=F9',
+ 250 => '=FA', 251 => '=FB', 252 => '=FC', 253 => '=FD', 254 => '=FE',
+ 255 => '=FF',
+ ];
+
+ protected static $safeMapShare = [];
+
+ /**
+ * A map of non-encoded ascii characters.
+ *
+ * @var string[]
+ */
+ protected $safeMap = [];
+
+ /**
+ * Creates a new QpEncoder for the given CharacterStream.
+ *
+ * @param Swift_CharacterStream $charStream to use for reading characters
+ * @param Swift_StreamFilter $filter if input should be canonicalized
+ */
+ public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null)
+ {
+ $this->charStream = $charStream;
+ if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) {
+ $this->initSafeMap();
+ self::$safeMapShare[$this->getSafeMapShareId()] = $this->safeMap;
+ } else {
+ $this->safeMap = self::$safeMapShare[$this->getSafeMapShareId()];
+ }
+ $this->filter = $filter;
+ }
+
+ public function __sleep()
+ {
+ return ['charStream', 'filter'];
+ }
+
+ public function __wakeup()
+ {
+ if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) {
+ $this->initSafeMap();
+ self::$safeMapShare[$this->getSafeMapShareId()] = $this->safeMap;
+ } else {
+ $this->safeMap = self::$safeMapShare[$this->getSafeMapShareId()];
+ }
+ }
+
+ protected function getSafeMapShareId()
+ {
+ return static::class;
+ }
+
+ protected function initSafeMap()
+ {
+ foreach (array_merge(
+ [0x09, 0x20], range(0x21, 0x3C), range(0x3E, 0x7E)) as $byte) {
+ $this->safeMap[$byte] = \chr($byte);
+ }
+ }
+
+ /**
+ * Takes an unencoded string and produces a QP encoded string from it.
+ *
+ * QP encoded strings have a maximum line length of 76 characters.
+ * If the first line needs to be shorter, indicate the difference with
+ * $firstLineOffset.
+ *
+ * @param string $string to encode
+ * @param int $firstLineOffset optional
+ * @param int $maxLineLength optional 0 indicates the default of 76 chars
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($maxLineLength > 76 || $maxLineLength <= 0) {
+ $maxLineLength = 76;
+ }
+
+ $thisLineLength = $maxLineLength - $firstLineOffset;
+
+ $lines = [];
+ $lNo = 0;
+ $lines[$lNo] = '';
+ $currentLine = &$lines[$lNo++];
+ $size = $lineLen = 0;
+
+ $this->charStream->flushContents();
+ $this->charStream->importString($string);
+
+ // Fetching more than 4 chars at one is slower, as is fetching fewer bytes
+ // Conveniently 4 chars is the UTF-8 safe number since UTF-8 has up to 6
+ // bytes per char and (6 * 4 * 3 = 72 chars per line) * =NN is 3 bytes
+ while (false !== $bytes = $this->nextSequence()) {
+ // If we're filtering the input
+ if (isset($this->filter)) {
+ // If we can't filter because we need more bytes
+ while ($this->filter->shouldBuffer($bytes)) {
+ // Then collect bytes into the buffer
+ if (false === $moreBytes = $this->nextSequence(1)) {
+ break;
+ }
+
+ foreach ($moreBytes as $b) {
+ $bytes[] = $b;
+ }
+ }
+ // And filter them
+ $bytes = $this->filter->filter($bytes);
+ }
+
+ $enc = $this->encodeByteSequence($bytes, $size);
+
+ $i = strpos($enc, '=0D=0A');
+ $newLineLength = $lineLen + (false === $i ? $size : $i);
+
+ if ($currentLine && $newLineLength >= $thisLineLength) {
+ $lines[$lNo] = '';
+ $currentLine = &$lines[$lNo++];
+ $thisLineLength = $maxLineLength;
+ $lineLen = 0;
+ }
+
+ $currentLine .= $enc;
+
+ if (false === $i) {
+ $lineLen += $size;
+ } else {
+ // 6 is the length of '=0D=0A'.
+ $lineLen = $size - strrpos($enc, '=0D=0A') - 6;
+ }
+ }
+
+ return $this->standardize(implode("=\r\n", $lines));
+ }
+
+ /**
+ * Updates the charset used.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charStream->setCharacterSet($charset);
+ }
+
+ /**
+ * Encode the given byte array into a verbatim QP form.
+ *
+ * @param int[] $bytes
+ * @param int $size
+ *
+ * @return string
+ */
+ protected function encodeByteSequence(array $bytes, &$size)
+ {
+ $ret = '';
+ $size = 0;
+ foreach ($bytes as $b) {
+ if (isset($this->safeMap[$b])) {
+ $ret .= $this->safeMap[$b];
+ ++$size;
+ } else {
+ $ret .= self::$qpMap[$b];
+ $size += 3;
+ }
+ }
+
+ return $ret;
+ }
+
+ /**
+ * Get the next sequence of bytes to read from the char stream.
+ *
+ * @param int $size number of bytes to read
+ *
+ * @return int[]
+ */
+ protected function nextSequence($size = 4)
+ {
+ return $this->charStream->readBytes($size);
+ }
+
+ /**
+ * Make sure CRLF is correct and HT/SPACE are in valid places.
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ protected function standardize($string)
+ {
+ $string = str_replace(["\t=0D=0A", ' =0D=0A', '=0D=0A'],
+ ["=09\r\n", "=20\r\n", "\r\n"], $string
+ );
+ switch ($end = \ord(substr($string, -1))) {
+ case 0x09:
+ case 0x20:
+ $string = substr_replace($string, self::$qpMap[$end], -1);
+ }
+
+ return $string;
+ }
+
+ /**
+ * Make a deep copy of object.
+ */
+ public function __clone()
+ {
+ $this->charStream = clone $this->charStream;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php b/include/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php
new file mode 100644
index 0000000..7eac368
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Encoder/Rfc2231Encoder.php
@@ -0,0 +1,90 @@
+charStream = $charStream;
+ }
+
+ /**
+ * Takes an unencoded string and produces a string encoded according to
+ * RFC 2231 from it.
+ *
+ * @param string $string
+ * @param int $firstLineOffset
+ * @param int $maxLineLength optional, 0 indicates the default of 75 bytes
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ $lines = [];
+ $lineCount = 0;
+ $lines[] = '';
+ $currentLine = &$lines[$lineCount++];
+
+ if (0 >= $maxLineLength) {
+ $maxLineLength = 75;
+ }
+
+ $this->charStream->flushContents();
+ $this->charStream->importString($string);
+
+ $thisLineLength = $maxLineLength - $firstLineOffset;
+
+ while (false !== $char = $this->charStream->read(4)) {
+ $encodedChar = rawurlencode($char);
+ if (0 != \strlen($currentLine)
+ && \strlen($currentLine.$encodedChar) > $thisLineLength) {
+ $lines[] = '';
+ $currentLine = &$lines[$lineCount++];
+ $thisLineLength = $maxLineLength;
+ }
+ $currentLine .= $encodedChar;
+ }
+
+ return implode("\r\n", $lines);
+ }
+
+ /**
+ * Updates the charset used.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charStream->setCharacterSet($charset);
+ }
+
+ /**
+ * Make a deep copy of object.
+ */
+ public function __clone()
+ {
+ $this->charStream = clone $this->charStream;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/CommandEvent.php b/include/swiftmailer/lib/classes/Swift/Events/CommandEvent.php
new file mode 100644
index 0000000..18994c1
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/CommandEvent.php
@@ -0,0 +1,64 @@
+command = $command;
+ $this->successCodes = $successCodes;
+ }
+
+ /**
+ * Get the command which was sent to the server.
+ *
+ * @return string
+ */
+ public function getCommand()
+ {
+ return $this->command;
+ }
+
+ /**
+ * Get the numeric response codes which indicate success for this command.
+ *
+ * @return int[]
+ */
+ public function getSuccessCodes()
+ {
+ return $this->successCodes;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/CommandListener.php b/include/swiftmailer/lib/classes/Swift/Events/CommandListener.php
new file mode 100644
index 0000000..b158eab
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/CommandListener.php
@@ -0,0 +1,22 @@
+source = $source;
+ }
+
+ /**
+ * Get the source object of this event.
+ *
+ * @return object
+ */
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+ /**
+ * Prevent this Event from bubbling any further up the stack.
+ */
+ public function cancelBubble($cancel = true)
+ {
+ $this->bubbleCancelled = $cancel;
+ }
+
+ /**
+ * Returns true if this Event will not bubble any further up the stack.
+ *
+ * @return bool
+ */
+ public function bubbleCancelled()
+ {
+ return $this->bubbleCancelled;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php b/include/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php
new file mode 100644
index 0000000..ff7c371
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/ResponseEvent.php
@@ -0,0 +1,64 @@
+response = $response;
+ $this->valid = $valid;
+ }
+
+ /**
+ * Get the response which was received from the server.
+ *
+ * @return string
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Get the success status of this Event.
+ *
+ * @return bool
+ */
+ public function isValid()
+ {
+ return $this->valid;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/ResponseListener.php b/include/swiftmailer/lib/classes/Swift/Events/ResponseListener.php
new file mode 100644
index 0000000..85115a3
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/ResponseListener.php
@@ -0,0 +1,22 @@
+message = $message;
+ $this->result = self::RESULT_PENDING;
+ }
+
+ /**
+ * Get the Transport used to send the Message.
+ *
+ * @return Swift_Transport
+ */
+ public function getTransport()
+ {
+ return $this->getSource();
+ }
+
+ /**
+ * Get the Message being sent.
+ *
+ * @return Swift_Mime_SimpleMessage
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * Set the array of addresses that failed in sending.
+ *
+ * @param array $recipients
+ */
+ public function setFailedRecipients($recipients)
+ {
+ $this->failedRecipients = $recipients;
+ }
+
+ /**
+ * Get an recipient addresses which were not accepted for delivery.
+ *
+ * @return string[]
+ */
+ public function getFailedRecipients()
+ {
+ return $this->failedRecipients;
+ }
+
+ /**
+ * Set the result of sending.
+ *
+ * @param int $result
+ */
+ public function setResult($result)
+ {
+ $this->result = $result;
+ }
+
+ /**
+ * Get the result of this Event.
+ *
+ * The return value is a bitmask from
+ * {@see RESULT_PENDING, RESULT_SUCCESS, RESULT_TENTATIVE, RESULT_FAILED}
+ *
+ * @return int
+ */
+ public function getResult()
+ {
+ return $this->result;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/SendListener.php b/include/swiftmailer/lib/classes/Swift/Events/SendListener.php
new file mode 100644
index 0000000..f7bf55e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/SendListener.php
@@ -0,0 +1,27 @@
+eventMap = [
+ 'Swift_Events_CommandEvent' => 'Swift_Events_CommandListener',
+ 'Swift_Events_ResponseEvent' => 'Swift_Events_ResponseListener',
+ 'Swift_Events_SendEvent' => 'Swift_Events_SendListener',
+ 'Swift_Events_TransportChangeEvent' => 'Swift_Events_TransportChangeListener',
+ 'Swift_Events_TransportExceptionEvent' => 'Swift_Events_TransportExceptionListener',
+ ];
+ }
+
+ /**
+ * Create a new SendEvent for $source and $message.
+ *
+ * @return Swift_Events_SendEvent
+ */
+ public function createSendEvent(Swift_Transport $source, Swift_Mime_SimpleMessage $message)
+ {
+ return new Swift_Events_SendEvent($source, $message);
+ }
+
+ /**
+ * Create a new CommandEvent for $source and $command.
+ *
+ * @param string $command That will be executed
+ * @param array $successCodes That are needed
+ *
+ * @return Swift_Events_CommandEvent
+ */
+ public function createCommandEvent(Swift_Transport $source, $command, $successCodes = [])
+ {
+ return new Swift_Events_CommandEvent($source, $command, $successCodes);
+ }
+
+ /**
+ * Create a new ResponseEvent for $source and $response.
+ *
+ * @param string $response
+ * @param bool $valid If the response is valid
+ *
+ * @return Swift_Events_ResponseEvent
+ */
+ public function createResponseEvent(Swift_Transport $source, $response, $valid)
+ {
+ return new Swift_Events_ResponseEvent($source, $response, $valid);
+ }
+
+ /**
+ * Create a new TransportChangeEvent for $source.
+ *
+ * @return Swift_Events_TransportChangeEvent
+ */
+ public function createTransportChangeEvent(Swift_Transport $source)
+ {
+ return new Swift_Events_TransportChangeEvent($source);
+ }
+
+ /**
+ * Create a new TransportExceptionEvent for $source.
+ *
+ * @return Swift_Events_TransportExceptionEvent
+ */
+ public function createTransportExceptionEvent(Swift_Transport $source, Swift_TransportException $ex)
+ {
+ return new Swift_Events_TransportExceptionEvent($source, $ex);
+ }
+
+ /**
+ * Bind an event listener to this dispatcher.
+ */
+ public function bindEventListener(Swift_Events_EventListener $listener)
+ {
+ foreach ($this->listeners as $l) {
+ // Already loaded
+ if ($l === $listener) {
+ return;
+ }
+ }
+ $this->listeners[] = $listener;
+ }
+
+ /**
+ * Dispatch the given Event to all suitable listeners.
+ *
+ * @param string $target method
+ */
+ public function dispatchEvent(Swift_Events_EventObject $evt, $target)
+ {
+ $bubbleQueue = $this->prepareBubbleQueue($evt);
+ $this->bubble($bubbleQueue, $evt, $target);
+ }
+
+ /** Queue listeners on a stack ready for $evt to be bubbled up it */
+ private function prepareBubbleQueue(Swift_Events_EventObject $evt)
+ {
+ $bubbleQueue = [];
+ $evtClass = \get_class($evt);
+ foreach ($this->listeners as $listener) {
+ if (\array_key_exists($evtClass, $this->eventMap)
+ && ($listener instanceof $this->eventMap[$evtClass])) {
+ $bubbleQueue[] = $listener;
+ }
+ }
+
+ return $bubbleQueue;
+ }
+
+ /** Bubble $evt up the stack calling $target() on each listener */
+ private function bubble(array &$bubbleQueue, Swift_Events_EventObject $evt, $target)
+ {
+ if (!$evt->bubbleCancelled() && $listener = array_shift($bubbleQueue)) {
+ $listener->$target($evt);
+ $this->bubble($bubbleQueue, $evt, $target);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php b/include/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php
new file mode 100644
index 0000000..a8972fd
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/TransportChangeEvent.php
@@ -0,0 +1,27 @@
+getSource();
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php b/include/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php
new file mode 100644
index 0000000..4a7492b
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/TransportChangeListener.php
@@ -0,0 +1,37 @@
+exception = $ex;
+ }
+
+ /**
+ * Get the TransportException thrown.
+ *
+ * @return Swift_TransportException
+ */
+ public function getException()
+ {
+ return $this->exception;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php b/include/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php
new file mode 100644
index 0000000..ad80eb0
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Events/TransportExceptionListener.php
@@ -0,0 +1,22 @@
+createDependenciesFor('transport.failover')
+ );
+
+ $this->setTransports($transports);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/FileSpool.php b/include/swiftmailer/lib/classes/Swift/FileSpool.php
new file mode 100644
index 0000000..7af8471
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/FileSpool.php
@@ -0,0 +1,208 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages on the filesystem.
+ *
+ * @author Fabien Potencier
+ * @author Xavier De Cock
+ */
+class Swift_FileSpool extends Swift_ConfigurableSpool
+{
+ /** The spool directory */
+ private $path;
+
+ /**
+ * File WriteRetry Limit.
+ *
+ * @var int
+ */
+ private $retryLimit = 10;
+
+ /**
+ * Create a new FileSpool.
+ *
+ * @param string $path
+ *
+ * @throws Swift_IoException
+ */
+ public function __construct($path)
+ {
+ $this->path = $path;
+
+ if (!file_exists($this->path)) {
+ if (!mkdir($this->path, 0777, true)) {
+ throw new Swift_IoException(sprintf('Unable to create path "%s".', $this->path));
+ }
+ }
+ }
+
+ /**
+ * Tests if this Spool mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Spool mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Spool mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * Allow to manage the enqueuing retry limit.
+ *
+ * Default, is ten and allows over 64^20 different fileNames
+ *
+ * @param int $limit
+ */
+ public function setRetryLimit($limit)
+ {
+ $this->retryLimit = $limit;
+ }
+
+ /**
+ * Queues a message.
+ *
+ * @param Swift_Mime_SimpleMessage $message The message to store
+ *
+ * @throws Swift_IoException
+ *
+ * @return bool
+ */
+ public function queueMessage(Swift_Mime_SimpleMessage $message)
+ {
+ $ser = serialize($message);
+ $fileName = $this->path.'/'.$this->getRandomString(10);
+ for ($i = 0; $i < $this->retryLimit; ++$i) {
+ /* We try an exclusive creation of the file. This is an atomic operation, it avoid locking mechanism */
+ $fp = @fopen($fileName.'.message', 'xb');
+ if (false !== $fp) {
+ if (false === fwrite($fp, $ser)) {
+ return false;
+ }
+
+ return fclose($fp);
+ } else {
+ /* The file already exists, we try a longer fileName */
+ $fileName .= $this->getRandomString(1);
+ }
+ }
+
+ throw new Swift_IoException(sprintf('Unable to create a file for enqueuing Message in "%s".', $this->path));
+ }
+
+ /**
+ * Execute a recovery if for any reason a process is sending for too long.
+ *
+ * @param int $timeout in second Defaults is for very slow smtp responses
+ */
+ public function recover($timeout = 900)
+ {
+ foreach (new DirectoryIterator($this->path) as $file) {
+ $file = $file->getRealPath();
+
+ if ('.message.sending' == substr($file, -16)) {
+ $lockedtime = filectime($file);
+ if ((time() - $lockedtime) > $timeout) {
+ rename($file, substr($file, 0, -8));
+ }
+ }
+ }
+ }
+
+ /**
+ * Sends messages using the given transport instance.
+ *
+ * @param Swift_Transport $transport A transport instance
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent e-mail's
+ */
+ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
+ {
+ $directoryIterator = new DirectoryIterator($this->path);
+
+ /* Start the transport only if there are queued files to send */
+ if (!$transport->isStarted()) {
+ foreach ($directoryIterator as $file) {
+ if ('.message' == substr($file->getRealPath(), -8)) {
+ $transport->start();
+ break;
+ }
+ }
+ }
+
+ $failedRecipients = (array) $failedRecipients;
+ $count = 0;
+ $time = time();
+ foreach ($directoryIterator as $file) {
+ $file = $file->getRealPath();
+
+ if ('.message' != substr($file, -8)) {
+ continue;
+ }
+
+ /* We try a rename, it's an atomic operation, and avoid locking the file */
+ if (rename($file, $file.'.sending')) {
+ $message = unserialize(file_get_contents($file.'.sending'));
+
+ $count += $transport->send($message, $failedRecipients);
+
+ unlink($file.'.sending');
+ } else {
+ /* This message has just been catched by another process */
+ continue;
+ }
+
+ if ($this->getMessageLimit() && $count >= $this->getMessageLimit()) {
+ break;
+ }
+
+ if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit()) {
+ break;
+ }
+ }
+
+ return $count;
+ }
+
+ /**
+ * Returns a random string needed to generate a fileName for the queue.
+ *
+ * @param int $count
+ *
+ * @return string
+ */
+ protected function getRandomString($count)
+ {
+ // This string MUST stay FS safe, avoid special chars
+ $base = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-';
+ $ret = '';
+ $strlen = \strlen($base);
+ for ($i = 0; $i < $count; ++$i) {
+ $ret .= $base[random_int(0, $strlen - 1)];
+ }
+
+ return $ret;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/FileStream.php b/include/swiftmailer/lib/classes/Swift/FileStream.php
new file mode 100644
index 0000000..0b24db1
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/FileStream.php
@@ -0,0 +1,24 @@
+setFile(new Swift_ByteStream_FileByteStream($path));
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/InputByteStream.php b/include/swiftmailer/lib/classes/Swift/InputByteStream.php
new file mode 100644
index 0000000..379a5a1
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/InputByteStream.php
@@ -0,0 +1,75 @@
+stream = $stream;
+ }
+
+ /**
+ * Set a string into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param string $string
+ * @param int $mode
+ */
+ public function setString($nsKey, $itemKey, $string, $mode)
+ {
+ $this->prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $this->contents[$nsKey][$itemKey] = $string;
+ break;
+ case self::MODE_APPEND:
+ if (!$this->hasKey($nsKey, $itemKey)) {
+ $this->contents[$nsKey][$itemKey] = '';
+ }
+ $this->contents[$nsKey][$itemKey] .= $string;
+ break;
+ default:
+ throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey);
+ }
+ }
+
+ /**
+ * Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param int $mode
+ */
+ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
+ {
+ $this->prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $this->clearKey($nsKey, $itemKey);
+ // no break
+ case self::MODE_APPEND:
+ if (!$this->hasKey($nsKey, $itemKey)) {
+ $this->contents[$nsKey][$itemKey] = '';
+ }
+ while (false !== $bytes = $os->read(8192)) {
+ $this->contents[$nsKey][$itemKey] .= $bytes;
+ }
+ break;
+ default:
+ throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey);
+ }
+ }
+
+ /**
+ * Provides a ByteStream which when written to, writes data to $itemKey.
+ *
+ * NOTE: The stream will always write in append mode.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return Swift_InputByteStream
+ */
+ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
+ {
+ $is = clone $this->stream;
+ $is->setKeyCache($this);
+ $is->setNsKey($nsKey);
+ $is->setItemKey($itemKey);
+ if (isset($writeThrough)) {
+ $is->setWriteThroughStream($writeThrough);
+ }
+
+ return $is;
+ }
+
+ /**
+ * Get data back out of the cache as a string.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return string
+ */
+ public function getString($nsKey, $itemKey)
+ {
+ $this->prepareCache($nsKey);
+ if ($this->hasKey($nsKey, $itemKey)) {
+ return $this->contents[$nsKey][$itemKey];
+ }
+ }
+
+ /**
+ * Get data back out of the cache as a ByteStream.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_InputByteStream $is to write the data to
+ */
+ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
+ {
+ $this->prepareCache($nsKey);
+ $is->write($this->getString($nsKey, $itemKey));
+ }
+
+ /**
+ * Check if the given $itemKey exists in the namespace $nsKey.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return bool
+ */
+ public function hasKey($nsKey, $itemKey)
+ {
+ $this->prepareCache($nsKey);
+
+ return \array_key_exists($itemKey, $this->contents[$nsKey]);
+ }
+
+ /**
+ * Clear data for $itemKey in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ */
+ public function clearKey($nsKey, $itemKey)
+ {
+ unset($this->contents[$nsKey][$itemKey]);
+ }
+
+ /**
+ * Clear all data in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ */
+ public function clearAll($nsKey)
+ {
+ unset($this->contents[$nsKey]);
+ }
+
+ /**
+ * Initialize the namespace of $nsKey if needed.
+ *
+ * @param string $nsKey
+ */
+ private function prepareCache($nsKey)
+ {
+ if (!\array_key_exists($nsKey, $this->contents)) {
+ $this->contents[$nsKey] = [];
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php b/include/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php
new file mode 100644
index 0000000..33b6367
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php
@@ -0,0 +1,294 @@
+stream = $stream;
+ $this->path = $path;
+ }
+
+ /**
+ * Set a string into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param string $string
+ * @param int $mode
+ *
+ * @throws Swift_IoException
+ */
+ public function setString($nsKey, $itemKey, $string, $mode)
+ {
+ $this->prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START);
+ break;
+ case self::MODE_APPEND:
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_END);
+ break;
+ default:
+ throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey);
+ break;
+ }
+ fwrite($fp, $string);
+ $this->freeHandle($nsKey, $itemKey);
+ }
+
+ /**
+ * Set a ByteStream into the cache under $itemKey for the namespace $nsKey.
+ *
+ * @see MODE_WRITE, MODE_APPEND
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param int $mode
+ *
+ * @throws Swift_IoException
+ */
+ public function importFromByteStream($nsKey, $itemKey, Swift_OutputByteStream $os, $mode)
+ {
+ $this->prepareCache($nsKey);
+ switch ($mode) {
+ case self::MODE_WRITE:
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START);
+ break;
+ case self::MODE_APPEND:
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_END);
+ break;
+ default:
+ throw new Swift_SwiftException('Invalid mode ['.$mode.'] used to set nsKey='.$nsKey.', itemKey='.$itemKey);
+ break;
+ }
+ while (false !== $bytes = $os->read(8192)) {
+ fwrite($fp, $bytes);
+ }
+ $this->freeHandle($nsKey, $itemKey);
+ }
+
+ /**
+ * Provides a ByteStream which when written to, writes data to $itemKey.
+ *
+ * NOTE: The stream will always write in append mode.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return Swift_InputByteStream
+ */
+ public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null)
+ {
+ $is = clone $this->stream;
+ $is->setKeyCache($this);
+ $is->setNsKey($nsKey);
+ $is->setItemKey($itemKey);
+ if (isset($writeThrough)) {
+ $is->setWriteThroughStream($writeThrough);
+ }
+
+ return $is;
+ }
+
+ /**
+ * Get data back out of the cache as a string.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @throws Swift_IoException
+ *
+ * @return string
+ */
+ public function getString($nsKey, $itemKey)
+ {
+ $this->prepareCache($nsKey);
+ if ($this->hasKey($nsKey, $itemKey)) {
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START);
+ $str = '';
+ while (!feof($fp) && false !== $bytes = fread($fp, 8192)) {
+ $str .= $bytes;
+ }
+ $this->freeHandle($nsKey, $itemKey);
+
+ return $str;
+ }
+ }
+
+ /**
+ * Get data back out of the cache as a ByteStream.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param Swift_InputByteStream $is to write the data to
+ */
+ public function exportToByteStream($nsKey, $itemKey, Swift_InputByteStream $is)
+ {
+ if ($this->hasKey($nsKey, $itemKey)) {
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_START);
+ while (!feof($fp) && false !== $bytes = fread($fp, 8192)) {
+ $is->write($bytes);
+ }
+ $this->freeHandle($nsKey, $itemKey);
+ }
+ }
+
+ /**
+ * Check if the given $itemKey exists in the namespace $nsKey.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ *
+ * @return bool
+ */
+ public function hasKey($nsKey, $itemKey)
+ {
+ return is_file($this->path.'/'.$nsKey.'/'.$itemKey);
+ }
+
+ /**
+ * Clear data for $itemKey in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ */
+ public function clearKey($nsKey, $itemKey)
+ {
+ if ($this->hasKey($nsKey, $itemKey)) {
+ $this->freeHandle($nsKey, $itemKey);
+ unlink($this->path.'/'.$nsKey.'/'.$itemKey);
+ }
+ }
+
+ /**
+ * Clear all data in the namespace $nsKey if it exists.
+ *
+ * @param string $nsKey
+ */
+ public function clearAll($nsKey)
+ {
+ if (\array_key_exists($nsKey, $this->keys)) {
+ foreach ($this->keys[$nsKey] as $itemKey => $null) {
+ $this->clearKey($nsKey, $itemKey);
+ }
+ if (is_dir($this->path.'/'.$nsKey)) {
+ rmdir($this->path.'/'.$nsKey);
+ }
+ unset($this->keys[$nsKey]);
+ }
+ }
+
+ /**
+ * Initialize the namespace of $nsKey if needed.
+ *
+ * @param string $nsKey
+ */
+ private function prepareCache($nsKey)
+ {
+ $cacheDir = $this->path.'/'.$nsKey;
+ if (!is_dir($cacheDir)) {
+ if (!mkdir($cacheDir)) {
+ throw new Swift_IoException('Failed to create cache directory '.$cacheDir);
+ }
+ $this->keys[$nsKey] = [];
+ }
+ }
+
+ /**
+ * Get a file handle on the cache item.
+ *
+ * @param string $nsKey
+ * @param string $itemKey
+ * @param int $position
+ *
+ * @return resource
+ */
+ private function getHandle($nsKey, $itemKey, $position)
+ {
+ if (!isset($this->keys[$nsKey][$itemKey])) {
+ $openMode = $this->hasKey($nsKey, $itemKey) ? 'r+b' : 'w+b';
+ $fp = fopen($this->path.'/'.$nsKey.'/'.$itemKey, $openMode);
+ $this->keys[$nsKey][$itemKey] = $fp;
+ }
+ if (self::POSITION_START == $position) {
+ fseek($this->keys[$nsKey][$itemKey], 0, SEEK_SET);
+ } elseif (self::POSITION_END == $position) {
+ fseek($this->keys[$nsKey][$itemKey], 0, SEEK_END);
+ }
+
+ return $this->keys[$nsKey][$itemKey];
+ }
+
+ private function freeHandle($nsKey, $itemKey)
+ {
+ $fp = $this->getHandle($nsKey, $itemKey, self::POSITION_CURRENT);
+ fclose($fp);
+ $this->keys[$nsKey][$itemKey] = null;
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ foreach ($this->keys as $nsKey => $null) {
+ $this->clearAll($nsKey);
+ }
+ }
+
+ public function __wakeup()
+ {
+ $this->keys = [];
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php b/include/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php
new file mode 100644
index 0000000..be2dbba
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/KeyCache/KeyCacheInputStream.php
@@ -0,0 +1,47 @@
+keyCache = $keyCache;
+ }
+
+ /**
+ * Specify a stream to write through for each write().
+ */
+ public function setWriteThroughStream(Swift_InputByteStream $is)
+ {
+ $this->writeThrough = $is;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * @param string $bytes
+ * @param Swift_InputByteStream $is optional
+ */
+ public function write($bytes, Swift_InputByteStream $is = null)
+ {
+ $this->keyCache->setString(
+ $this->nsKey, $this->itemKey, $bytes, Swift_KeyCache::MODE_APPEND
+ );
+ if (isset($is)) {
+ $is->write($bytes);
+ }
+ if (isset($this->writeThrough)) {
+ $this->writeThrough->write($bytes);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function commit()
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ */
+ public function flushBuffers()
+ {
+ $this->keyCache->clearKey($this->nsKey, $this->itemKey);
+ }
+
+ /**
+ * Set the nsKey which will be written to.
+ *
+ * @param string $nsKey
+ */
+ public function setNsKey($nsKey)
+ {
+ $this->nsKey = $nsKey;
+ }
+
+ /**
+ * Set the itemKey which will be written to.
+ *
+ * @param string $itemKey
+ */
+ public function setItemKey($itemKey)
+ {
+ $this->itemKey = $itemKey;
+ }
+
+ /**
+ * Any implementation should be cloneable, allowing the clone to access a
+ * separate $nsKey and $itemKey.
+ */
+ public function __clone()
+ {
+ $this->writeThrough = null;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php b/include/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php
new file mode 100644
index 0000000..244b5f6
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/LoadBalancedTransport.php
@@ -0,0 +1,33 @@
+createDependenciesFor('transport.loadbalanced')
+ );
+
+ $this->setTransports($transports);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mailer.php b/include/swiftmailer/lib/classes/Swift/Mailer.php
new file mode 100644
index 0000000..5763007
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mailer.php
@@ -0,0 +1,98 @@
+transport = $transport;
+ }
+
+ /**
+ * Create a new class instance of one of the message services.
+ *
+ * For example 'mimepart' would create a 'message.mimepart' instance
+ *
+ * @param string $service
+ *
+ * @return object
+ */
+ public function createMessage($service = 'message')
+ {
+ return Swift_DependencyContainer::getInstance()
+ ->lookup('message.'.$service);
+ }
+
+ /**
+ * Send the given Message like it would be sent in a mail client.
+ *
+ * All recipients (with the exception of Bcc) will be able to see the other
+ * recipients this message was sent to.
+ *
+ * Recipient/sender data will be retrieved from the Message object.
+ *
+ * The return value is the number of recipients who were accepted for
+ * delivery.
+ *
+ * @param array $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of successful recipients. Can be 0 which indicates failure
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ $failedRecipients = (array) $failedRecipients;
+
+ // FIXME: to be removed in 7.0 (as transport must now start itself on send)
+ if (!$this->transport->isStarted()) {
+ $this->transport->start();
+ }
+
+ $sent = 0;
+
+ try {
+ $sent = $this->transport->send($message, $failedRecipients);
+ } catch (Swift_RfcComplianceException $e) {
+ foreach ($message->getTo() as $address => $name) {
+ $failedRecipients[] = $address;
+ }
+ }
+
+ return $sent;
+ }
+
+ /**
+ * Register a plugin using a known unique key (e.g. myPlugin).
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->transport->registerPlugin($plugin);
+ }
+
+ /**
+ * The Transport used to send messages.
+ *
+ * @return Swift_Transport
+ */
+ public function getTransport()
+ {
+ return $this->transport;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php b/include/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php
new file mode 100644
index 0000000..19aa82a
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mailer/ArrayRecipientIterator.php
@@ -0,0 +1,53 @@
+recipients = $recipients;
+ }
+
+ /**
+ * Returns true only if there are more recipients to send to.
+ *
+ * @return bool
+ */
+ public function hasNext()
+ {
+ return !empty($this->recipients);
+ }
+
+ /**
+ * Returns an array where the keys are the addresses of recipients and the
+ * values are the names. e.g. ('foo@bar' => 'Foo') or ('foo@bar' => NULL).
+ *
+ * @return array
+ */
+ public function nextRecipient()
+ {
+ return array_splice($this->recipients, 0, 1);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php b/include/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php
new file mode 100644
index 0000000..650f3ec
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mailer/RecipientIterator.php
@@ -0,0 +1,32 @@
+ 'Foo') or ('foo@bar' => NULL).
+ *
+ * @return array
+ */
+ public function nextRecipient();
+}
diff --git a/include/swiftmailer/lib/classes/Swift/MemorySpool.php b/include/swiftmailer/lib/classes/Swift/MemorySpool.php
new file mode 100644
index 0000000..e3b0894
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/MemorySpool.php
@@ -0,0 +1,110 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages in memory.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_MemorySpool implements Swift_Spool
+{
+ protected $messages = [];
+ private $flushRetries = 3;
+
+ /**
+ * Tests if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Transport mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Transport mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * @param int $retries
+ */
+ public function setFlushRetries($retries)
+ {
+ $this->flushRetries = $retries;
+ }
+
+ /**
+ * Stores a message in the queue.
+ *
+ * @param Swift_Mime_SimpleMessage $message The message to store
+ *
+ * @return bool Whether the operation has succeeded
+ */
+ public function queueMessage(Swift_Mime_SimpleMessage $message)
+ {
+ //clone the message to make sure it is not changed while in the queue
+ $this->messages[] = clone $message;
+
+ return true;
+ }
+
+ /**
+ * Sends messages using the given transport instance.
+ *
+ * @param Swift_Transport $transport A transport instance
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent emails
+ */
+ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
+ {
+ if (!$this->messages) {
+ return 0;
+ }
+
+ if (!$transport->isStarted()) {
+ $transport->start();
+ }
+
+ $count = 0;
+ $retries = $this->flushRetries;
+ while ($retries--) {
+ try {
+ while ($message = array_pop($this->messages)) {
+ $count += $transport->send($message, $failedRecipients);
+ }
+ } catch (Swift_TransportException $exception) {
+ if ($retries) {
+ // re-queue the message at the end of the queue to give a chance
+ // to the other messages to be sent, in case the failure was due to
+ // this message and not just the transport failing
+ array_unshift($this->messages, $message);
+
+ // wait half a second before we try again
+ usleep(500000);
+ } else {
+ throw $exception;
+ }
+ }
+ }
+
+ return $count;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Message.php b/include/swiftmailer/lib/classes/Swift/Message.php
new file mode 100644
index 0000000..819ffc3
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Message.php
@@ -0,0 +1,279 @@
+createDependenciesFor('mime.message')
+ );
+
+ if (!isset($charset)) {
+ $charset = Swift_DependencyContainer::getInstance()
+ ->lookup('properties.charset');
+ }
+ $this->setSubject($subject);
+ $this->setBody($body);
+ $this->setCharset($charset);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+
+ /**
+ * Add a MimePart to this Message.
+ *
+ * @param string|Swift_OutputByteStream $body
+ * @param string $contentType
+ * @param string $charset
+ *
+ * @return $this
+ */
+ public function addPart($body, $contentType = null, $charset = null)
+ {
+ return $this->attach((new Swift_MimePart($body, $contentType, $charset))->setEncoder($this->getEncoder()));
+ }
+
+ /**
+ * Attach a new signature handler to the message.
+ *
+ * @return $this
+ */
+ public function attachSigner(Swift_Signer $signer)
+ {
+ if ($signer instanceof Swift_Signers_HeaderSigner) {
+ $this->headerSigners[] = $signer;
+ } elseif ($signer instanceof Swift_Signers_BodySigner) {
+ $this->bodySigners[] = $signer;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Detach a signature handler from a message.
+ *
+ * @return $this
+ */
+ public function detachSigner(Swift_Signer $signer)
+ {
+ if ($signer instanceof Swift_Signers_HeaderSigner) {
+ foreach ($this->headerSigners as $k => $headerSigner) {
+ if ($headerSigner === $signer) {
+ unset($this->headerSigners[$k]);
+
+ return $this;
+ }
+ }
+ } elseif ($signer instanceof Swift_Signers_BodySigner) {
+ foreach ($this->bodySigners as $k => $bodySigner) {
+ if ($bodySigner === $signer) {
+ unset($this->bodySigners[$k]);
+
+ return $this;
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Clear all signature handlers attached to the message.
+ *
+ * @return $this
+ */
+ public function clearSigners()
+ {
+ $this->headerSigners = [];
+ $this->bodySigners = [];
+
+ return $this;
+ }
+
+ /**
+ * Get this message as a complete string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ if (empty($this->headerSigners) && empty($this->bodySigners)) {
+ return parent::toString();
+ }
+
+ $this->saveMessage();
+
+ $this->doSign();
+
+ $string = parent::toString();
+
+ $this->restoreMessage();
+
+ return $string;
+ }
+
+ /**
+ * Write this message to a {@link Swift_InputByteStream}.
+ */
+ public function toByteStream(Swift_InputByteStream $is)
+ {
+ if (empty($this->headerSigners) && empty($this->bodySigners)) {
+ parent::toByteStream($is);
+
+ return;
+ }
+
+ $this->saveMessage();
+
+ $this->doSign();
+
+ parent::toByteStream($is);
+
+ $this->restoreMessage();
+ }
+
+ public function __wakeup()
+ {
+ Swift_DependencyContainer::getInstance()->createDependenciesFor('mime.message');
+ }
+
+ /**
+ * loops through signers and apply the signatures.
+ */
+ protected function doSign()
+ {
+ foreach ($this->bodySigners as $signer) {
+ $altered = $signer->getAlteredHeaders();
+ $this->saveHeaders($altered);
+ $signer->signMessage($this);
+ }
+
+ foreach ($this->headerSigners as $signer) {
+ $altered = $signer->getAlteredHeaders();
+ $this->saveHeaders($altered);
+ $signer->reset();
+
+ $signer->setHeaders($this->getHeaders());
+
+ $signer->startBody();
+ $this->bodyToByteStream($signer);
+ $signer->endBody();
+
+ $signer->addSignature($this->getHeaders());
+ }
+ }
+
+ /**
+ * save the message before any signature is applied.
+ */
+ protected function saveMessage()
+ {
+ $this->savedMessage = ['headers' => []];
+ $this->savedMessage['body'] = $this->getBody();
+ $this->savedMessage['children'] = $this->getChildren();
+ if (\count($this->savedMessage['children']) > 0 && '' != $this->getBody()) {
+ $this->setChildren(array_merge([$this->becomeMimePart()], $this->savedMessage['children']));
+ $this->setBody('');
+ }
+ }
+
+ /**
+ * save the original headers.
+ */
+ protected function saveHeaders(array $altered)
+ {
+ foreach ($altered as $head) {
+ $lc = strtolower($head);
+
+ if (!isset($this->savedMessage['headers'][$lc])) {
+ $this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head);
+ }
+ }
+ }
+
+ /**
+ * Remove or restore altered headers.
+ */
+ protected function restoreHeaders()
+ {
+ foreach ($this->savedMessage['headers'] as $name => $savedValue) {
+ $headers = $this->getHeaders()->getAll($name);
+
+ foreach ($headers as $key => $value) {
+ if (!isset($savedValue[$key])) {
+ $this->getHeaders()->remove($name, $key);
+ }
+ }
+ }
+ }
+
+ /**
+ * Restore message body.
+ */
+ protected function restoreMessage()
+ {
+ $this->setBody($this->savedMessage['body']);
+ $this->setChildren($this->savedMessage['children']);
+
+ $this->restoreHeaders();
+ $this->savedMessage = [];
+ }
+
+ /**
+ * Clone Message Signers.
+ *
+ * @see Swift_Mime_SimpleMimeEntity::__clone()
+ */
+ public function __clone()
+ {
+ parent::__clone();
+ foreach ($this->bodySigners as $key => $bodySigner) {
+ $this->bodySigners[$key] = clone $bodySigner;
+ }
+
+ foreach ($this->headerSigners as $key => $headerSigner) {
+ $this->headerSigners[$key] = clone $headerSigner;
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Attachment.php b/include/swiftmailer/lib/classes/Swift/Mime/Attachment.php
new file mode 100644
index 0000000..d994373
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Attachment.php
@@ -0,0 +1,144 @@
+setDisposition('attachment');
+ $this->setContentType('application/octet-stream');
+ $this->mimeTypes = $mimeTypes;
+ }
+
+ /**
+ * Get the nesting level used for this attachment.
+ *
+ * Always returns {@link LEVEL_MIXED}.
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return self::LEVEL_MIXED;
+ }
+
+ /**
+ * Get the Content-Disposition of this attachment.
+ *
+ * By default attachments have a disposition of "attachment".
+ *
+ * @return string
+ */
+ public function getDisposition()
+ {
+ return $this->getHeaderFieldModel('Content-Disposition');
+ }
+
+ /**
+ * Set the Content-Disposition of this attachment.
+ *
+ * @param string $disposition
+ *
+ * @return $this
+ */
+ public function setDisposition($disposition)
+ {
+ if (!$this->setHeaderFieldModel('Content-Disposition', $disposition)) {
+ $this->getHeaders()->addParameterizedHeader('Content-Disposition', $disposition);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the filename of this attachment when downloaded.
+ *
+ * @return string
+ */
+ public function getFilename()
+ {
+ return $this->getHeaderParameter('Content-Disposition', 'filename');
+ }
+
+ /**
+ * Set the filename of this attachment.
+ *
+ * @param string $filename
+ *
+ * @return $this
+ */
+ public function setFilename($filename)
+ {
+ $this->setHeaderParameter('Content-Disposition', 'filename', $filename);
+ $this->setHeaderParameter('Content-Type', 'name', $filename);
+
+ return $this;
+ }
+
+ /**
+ * Get the file size of this attachment.
+ *
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->getHeaderParameter('Content-Disposition', 'size');
+ }
+
+ /**
+ * Set the file size of this attachment.
+ *
+ * @param int $size
+ *
+ * @return $this
+ */
+ public function setSize($size)
+ {
+ $this->setHeaderParameter('Content-Disposition', 'size', $size);
+
+ return $this;
+ }
+
+ /**
+ * Set the file that this attachment is for.
+ *
+ * @param string $contentType optional
+ *
+ * @return $this
+ */
+ public function setFile(Swift_FileStream $file, $contentType = null)
+ {
+ $this->setFilename(basename($file->getPath()));
+ $this->setBody($file, $contentType);
+ if (!isset($contentType)) {
+ $extension = strtolower(substr($file->getPath(), strrpos($file->getPath(), '.') + 1));
+
+ if (\array_key_exists($extension, $this->mimeTypes)) {
+ $this->setContentType($this->mimeTypes[$extension]);
+ }
+ }
+
+ return $this;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php b/include/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php
new file mode 100644
index 0000000..b49c3a8
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/CharsetObserver.php
@@ -0,0 +1,24 @@
+= $maxLineLength || 76 < $maxLineLength) {
+ $maxLineLength = 76;
+ }
+
+ $remainder = 0;
+ $base64ReadBufferRemainderBytes = null;
+
+ // To reduce memory usage, the output buffer is streamed to the input buffer like so:
+ // Output Stream => base64encode => wrap line length => Input Stream
+ // HOWEVER it's important to note that base64_encode() should only be passed whole triplets of data (except for the final chunk of data)
+ // otherwise it will assume the input data has *ended* and it will incorrectly pad/terminate the base64 data mid-stream.
+ // We use $base64ReadBufferRemainderBytes to carry over 1-2 "remainder" bytes from the each chunk from OutputStream and pre-pend those onto the
+ // chunk of bytes read in the next iteration.
+ // When the OutputStream is empty, we must flush any remainder bytes.
+ while (true) {
+ $readBytes = $os->read(8192);
+ $atEOF = (false === $readBytes);
+
+ if ($atEOF) {
+ $streamTheseBytes = $base64ReadBufferRemainderBytes;
+ } else {
+ $streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes;
+ }
+ $base64ReadBufferRemainderBytes = null;
+ $bytesLength = \strlen($streamTheseBytes);
+
+ if (0 === $bytesLength) { // no data left to encode
+ break;
+ }
+
+ // if we're not on the last block of the ouput stream, make sure $streamTheseBytes ends with a complete triplet of data
+ // and carry over remainder 1-2 bytes to the next loop iteration
+ if (!$atEOF) {
+ $excessBytes = $bytesLength % 3;
+ if (0 !== $excessBytes) {
+ $base64ReadBufferRemainderBytes = substr($streamTheseBytes, -$excessBytes);
+ $streamTheseBytes = substr($streamTheseBytes, 0, $bytesLength - $excessBytes);
+ }
+ }
+
+ $encoded = base64_encode($streamTheseBytes);
+ $encodedTransformed = '';
+ $thisMaxLineLength = $maxLineLength - $remainder - $firstLineOffset;
+
+ while ($thisMaxLineLength < \strlen($encoded)) {
+ $encodedTransformed .= substr($encoded, 0, $thisMaxLineLength)."\r\n";
+ $firstLineOffset = 0;
+ $encoded = substr($encoded, $thisMaxLineLength);
+ $thisMaxLineLength = $maxLineLength;
+ $remainder = 0;
+ }
+
+ if (0 < $remainingLength = \strlen($encoded)) {
+ $remainder += $remainingLength;
+ $encodedTransformed .= $encoded;
+ $encoded = null;
+ }
+
+ $is->write($encodedTransformed);
+
+ if ($atEOF) {
+ break;
+ }
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ * Returns the string 'base64'.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'base64';
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php
new file mode 100644
index 0000000..8dfea60
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/NativeQpContentEncoder.php
@@ -0,0 +1,121 @@
+charset = $charset ?: 'utf-8';
+ }
+
+ /**
+ * Notify this observer that the entity's charset has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charset = $charset;
+ }
+
+ /**
+ * Encode $in to $out.
+ *
+ * @param Swift_OutputByteStream $os to read from
+ * @param Swift_InputByteStream $is to write to
+ * @param int $firstLineOffset
+ * @param int $maxLineLength 0 indicates the default length for this encoding
+ *
+ * @throws RuntimeException
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ('utf-8' !== $this->charset) {
+ throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset));
+ }
+
+ $string = '';
+
+ while (false !== $bytes = $os->read(8192)) {
+ $string .= $bytes;
+ }
+
+ $is->write($this->encodeString($string));
+ }
+
+ /**
+ * Get the MIME name of this content encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'quoted-printable';
+ }
+
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset if first line needs to be shorter
+ * @param int $maxLineLength 0 indicates the default length for this encoding
+ *
+ * @throws RuntimeException
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ('utf-8' !== $this->charset) {
+ throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset));
+ }
+
+ return $this->standardize(quoted_printable_encode($string));
+ }
+
+ /**
+ * Make sure CRLF is correct and HT/SPACE are in valid places.
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ protected function standardize($string)
+ {
+ // transform CR or LF to CRLF
+ $string = preg_replace('~=0D(?!=0A)|(?
+ */
+class Swift_Mime_ContentEncoder_NullContentEncoder implements Swift_Mime_ContentEncoder
+{
+ /**
+ * The name of this encoding scheme (probably 7bit or 8bit).
+ *
+ * @var string
+ */
+ private $name;
+
+ /**
+ * Creates a new NullContentEncoder with $name (probably 7bit or 8bit).
+ *
+ * @param string $name
+ */
+ public function __construct($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength ignored
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return $string;
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength ignored
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ while (false !== ($bytes = $os->read(8192))) {
+ $is->write($bytes);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Not used.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php
new file mode 100644
index 0000000..72592fc
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/PlainContentEncoder.php
@@ -0,0 +1,164 @@
+name = $name;
+ $this->canonical = $canonical;
+ }
+
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength - 0 means no wrapping will occur
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($this->canonical) {
+ $string = $this->canonicalize($string);
+ }
+
+ return $this->safeWordwrap($string, $maxLineLength, "\r\n");
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength optional, 0 means no wrapping will occur
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ $leftOver = '';
+ while (false !== $bytes = $os->read(8192)) {
+ $toencode = $leftOver.$bytes;
+ if ($this->canonical) {
+ $toencode = $this->canonicalize($toencode);
+ }
+ $wrapped = $this->safeWordwrap($toencode, $maxLineLength, "\r\n");
+ $lastLinePos = strrpos($wrapped, "\r\n");
+ $leftOver = substr($wrapped, $lastLinePos);
+ $wrapped = substr($wrapped, 0, $lastLinePos);
+
+ $is->write($wrapped);
+ }
+ if (\strlen($leftOver)) {
+ $is->write($leftOver);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Not used.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+
+ /**
+ * A safer (but weaker) wordwrap for unicode.
+ *
+ * @param string $string
+ * @param int $length
+ * @param string $le
+ *
+ * @return string
+ */
+ private function safeWordwrap($string, $length = 75, $le = "\r\n")
+ {
+ if (0 >= $length) {
+ return $string;
+ }
+
+ $originalLines = explode($le, $string);
+
+ $lines = [];
+ $lineCount = 0;
+
+ foreach ($originalLines as $originalLine) {
+ $lines[] = '';
+ $currentLine = &$lines[$lineCount++];
+
+ //$chunks = preg_split('/(?<=[\ \t,\.!\?\-&\+\/])/', $originalLine);
+ $chunks = preg_split('/(?<=\s)/', $originalLine);
+
+ foreach ($chunks as $chunk) {
+ if (0 != \strlen($currentLine)
+ && \strlen($currentLine.$chunk) > $length) {
+ $lines[] = '';
+ $currentLine = &$lines[$lineCount++];
+ }
+ $currentLine .= $chunk;
+ }
+ }
+
+ return implode("\r\n", $lines);
+ }
+
+ /**
+ * Canonicalize string input (fix CRLF).
+ *
+ * @param string $string
+ *
+ * @return string
+ */
+ private function canonicalize($string)
+ {
+ return str_replace(
+ ["\r\n", "\r", "\n"],
+ ["\n", "\n", "\r\n"],
+ $string
+ );
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
new file mode 100644
index 0000000..465ffd8
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoder.php
@@ -0,0 +1,134 @@
+dotEscape = $dotEscape;
+ parent::__construct($charStream, $filter);
+ }
+
+ public function __sleep()
+ {
+ return ['charStream', 'filter', 'dotEscape'];
+ }
+
+ protected function getSafeMapShareId()
+ {
+ return static::class.($this->dotEscape ? '.dotEscape' : '');
+ }
+
+ protected function initSafeMap()
+ {
+ parent::initSafeMap();
+ if ($this->dotEscape) {
+ /* Encode . as =2e for buggy remote servers */
+ unset($this->safeMap[0x2e]);
+ }
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * QP encoded strings have a maximum line length of 76 characters.
+ * If the first line needs to be shorter, indicate the difference with
+ * $firstLineOffset.
+ *
+ * @param Swift_OutputByteStream $os output stream
+ * @param Swift_InputByteStream $is input stream
+ * @param int $firstLineOffset
+ * @param int $maxLineLength
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ if ($maxLineLength > 76 || $maxLineLength <= 0) {
+ $maxLineLength = 76;
+ }
+
+ $thisLineLength = $maxLineLength - $firstLineOffset;
+
+ $this->charStream->flushContents();
+ $this->charStream->importByteStream($os);
+
+ $currentLine = '';
+ $prepend = '';
+ $size = $lineLen = 0;
+
+ while (false !== $bytes = $this->nextSequence()) {
+ // If we're filtering the input
+ if (isset($this->filter)) {
+ // If we can't filter because we need more bytes
+ while ($this->filter->shouldBuffer($bytes)) {
+ // Then collect bytes into the buffer
+ if (false === $moreBytes = $this->nextSequence(1)) {
+ break;
+ }
+
+ foreach ($moreBytes as $b) {
+ $bytes[] = $b;
+ }
+ }
+ // And filter them
+ $bytes = $this->filter->filter($bytes);
+ }
+
+ $enc = $this->encodeByteSequence($bytes, $size);
+
+ $i = strpos($enc, '=0D=0A');
+ $newLineLength = $lineLen + (false === $i ? $size : $i);
+
+ if ($currentLine && $newLineLength >= $thisLineLength) {
+ $is->write($prepend.$this->standardize($currentLine));
+ $currentLine = '';
+ $prepend = "=\r\n";
+ $thisLineLength = $maxLineLength;
+ $lineLen = 0;
+ }
+
+ $currentLine .= $enc;
+
+ if (false === $i) {
+ $lineLen += $size;
+ } else {
+ // 6 is the length of '=0D=0A'.
+ $lineLen = $size - strrpos($enc, '=0D=0A') - 6;
+ }
+ }
+ if (\strlen($currentLine)) {
+ $is->write($prepend.$this->standardize($currentLine));
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ * Returns the string 'quoted-printable'.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'quoted-printable';
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php
new file mode 100644
index 0000000..f3ece43
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/QpContentEncoderProxy.php
@@ -0,0 +1,96 @@
+
+ */
+class Swift_Mime_ContentEncoder_QpContentEncoderProxy implements Swift_Mime_ContentEncoder
+{
+ /**
+ * @var Swift_Mime_ContentEncoder_QpContentEncoder
+ */
+ private $safeEncoder;
+
+ /**
+ * @var Swift_Mime_ContentEncoder_NativeQpContentEncoder
+ */
+ private $nativeEncoder;
+
+ /**
+ * @var string|null
+ */
+ private $charset;
+
+ /**
+ * Constructor.
+ *
+ * @param string|null $charset
+ */
+ public function __construct(Swift_Mime_ContentEncoder_QpContentEncoder $safeEncoder, Swift_Mime_ContentEncoder_NativeQpContentEncoder $nativeEncoder, $charset)
+ {
+ $this->safeEncoder = $safeEncoder;
+ $this->nativeEncoder = $nativeEncoder;
+ $this->charset = $charset;
+ }
+
+ /**
+ * Make a deep copy of object.
+ */
+ public function __clone()
+ {
+ $this->safeEncoder = clone $this->safeEncoder;
+ $this->nativeEncoder = clone $this->nativeEncoder;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charset = $charset;
+ $this->safeEncoder->charsetChanged($charset);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ $this->getEncoder()->encodeByteStream($os, $is, $firstLineOffset, $maxLineLength);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'quoted-printable';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return $this->getEncoder()->encodeString($string, $firstLineOffset, $maxLineLength);
+ }
+
+ /**
+ * @return Swift_Mime_ContentEncoder
+ */
+ private function getEncoder()
+ {
+ return 'utf-8' === $this->charset ? $this->nativeEncoder : $this->safeEncoder;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php
new file mode 100644
index 0000000..870e7f4
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/ContentEncoder/RawContentEncoder.php
@@ -0,0 +1,65 @@
+
+ */
+class Swift_Mime_ContentEncoder_RawContentEncoder implements Swift_Mime_ContentEncoder
+{
+ /**
+ * Encode a given string to produce an encoded string.
+ *
+ * @param string $string
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength ignored
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return $string;
+ }
+
+ /**
+ * Encode stream $in to stream $out.
+ *
+ * @param int $firstLineOffset ignored
+ * @param int $maxLineLength ignored
+ */
+ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStream $is, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ while (false !== ($bytes = $os->read(8192))) {
+ $is->write($bytes);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'raw';
+ }
+
+ /**
+ * Not used.
+ */
+ public function charsetChanged($charset)
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php b/include/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php
new file mode 100644
index 0000000..42a5177
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/EmbeddedFile.php
@@ -0,0 +1,41 @@
+setDisposition('inline');
+ $this->setId($this->getId());
+ }
+
+ /**
+ * Get the nesting level of this EmbeddedFile.
+ *
+ * Returns {@see LEVEL_RELATED}.
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return self::LEVEL_RELATED;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php b/include/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php
new file mode 100644
index 0000000..1a952ec
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/EncodingObserver.php
@@ -0,0 +1,22 @@
+getName(), "\r\n");
+ mb_internal_encoding($old);
+
+ return $newstring;
+ }
+
+ return parent::encodeString($string, $firstLineOffset, $maxLineLength);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php b/include/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php
new file mode 100644
index 0000000..378c480
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/HeaderEncoder/QpHeaderEncoder.php
@@ -0,0 +1,65 @@
+safeMap[$byte] = \chr($byte);
+ }
+ }
+
+ /**
+ * Get the name of this encoding scheme.
+ *
+ * Returns the string 'Q'.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return 'Q';
+ }
+
+ /**
+ * Takes an unencoded string and produces a QP encoded string from it.
+ *
+ * @param string $string string to encode
+ * @param int $firstLineOffset optional
+ * @param int $maxLineLength optional, 0 indicates the default of 76 chars
+ *
+ * @return string
+ */
+ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
+ {
+ return str_replace([' ', '=20', "=\r\n"], ['_', '_', "\r\n"],
+ parent::encodeString($string, $firstLineOffset, $maxLineLength)
+ );
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php
new file mode 100644
index 0000000..22caeb2
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/AbstractHeader.php
@@ -0,0 +1,476 @@
+clearCachedValueIf($charset != $this->charset);
+ $this->charset = $charset;
+ if (isset($this->encoder)) {
+ $this->encoder->charsetChanged($charset);
+ }
+ }
+
+ /**
+ * Get the character set used in this Header.
+ *
+ * @return string
+ */
+ public function getCharset()
+ {
+ return $this->charset;
+ }
+
+ /**
+ * Set the language used in this Header.
+ *
+ * For example, for US English, 'en-us'.
+ * This can be unspecified.
+ *
+ * @param string $lang
+ */
+ public function setLanguage($lang)
+ {
+ $this->clearCachedValueIf($this->lang != $lang);
+ $this->lang = $lang;
+ }
+
+ /**
+ * Get the language used in this Header.
+ *
+ * @return string
+ */
+ public function getLanguage()
+ {
+ return $this->lang;
+ }
+
+ /**
+ * Set the encoder used for encoding the header.
+ */
+ public function setEncoder(Swift_Mime_HeaderEncoder $encoder)
+ {
+ $this->encoder = $encoder;
+ $this->setCachedValue(null);
+ }
+
+ /**
+ * Get the encoder used for encoding this Header.
+ *
+ * @return Swift_Mime_HeaderEncoder
+ */
+ public function getEncoder()
+ {
+ return $this->encoder;
+ }
+
+ /**
+ * Get the name of this header (e.g. charset).
+ *
+ * @return string
+ */
+ public function getFieldName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Set the maximum length of lines in the header (excluding EOL).
+ *
+ * @param int $lineLength
+ */
+ public function setMaxLineLength($lineLength)
+ {
+ $this->clearCachedValueIf($this->lineLength != $lineLength);
+ $this->lineLength = $lineLength;
+ }
+
+ /**
+ * Get the maximum permitted length of lines in this Header.
+ *
+ * @return int
+ */
+ public function getMaxLineLength()
+ {
+ return $this->lineLength;
+ }
+
+ /**
+ * Get this Header rendered as a RFC 2822 compliant string.
+ *
+ * @return string
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function toString()
+ {
+ return $this->tokensToString($this->toTokens());
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return string
+ *
+ * @see toString()
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Set the name of this Header field.
+ *
+ * @param string $name
+ */
+ protected function setFieldName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Produces a compliant, formatted RFC 2822 'phrase' based on the string given.
+ *
+ * @param string $string as displayed
+ * @param string $charset of the text
+ * @param bool $shorten the first line to make remove for header name
+ *
+ * @return string
+ */
+ protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false)
+ {
+ // Treat token as exactly what was given
+ $phraseStr = $string;
+ // If it's not valid
+
+ if (!preg_match('/^'.self::PHRASE_PATTERN.'$/D', $phraseStr)) {
+ // .. but it is just ascii text, try escaping some characters
+ // and make it a quoted-string
+ if (preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $phraseStr)) {
+ $phraseStr = $this->escapeSpecials($phraseStr, ['"']);
+ $phraseStr = '"'.$phraseStr.'"';
+ } else {
+ // ... otherwise it needs encoding
+ // Determine space remaining on line if first line
+ if ($shorten) {
+ $usedLength = \strlen($header->getFieldName().': ');
+ } else {
+ $usedLength = 0;
+ }
+ $phraseStr = $this->encodeWords($header, $string, $usedLength);
+ }
+ }
+
+ return $phraseStr;
+ }
+
+ /**
+ * Escape special characters in a string (convert to quoted-pairs).
+ *
+ * @param string $token
+ * @param string[] $include additional chars to escape
+ *
+ * @return string
+ */
+ private function escapeSpecials($token, $include = [])
+ {
+ foreach (array_merge(['\\'], $include) as $char) {
+ $token = str_replace($char, '\\'.$char, $token);
+ }
+
+ return $token;
+ }
+
+ /**
+ * Encode needed word tokens within a string of input.
+ *
+ * @param string $input
+ * @param string $usedLength optional
+ *
+ * @return string
+ */
+ protected function encodeWords(Swift_Mime_Header $header, $input, $usedLength = -1)
+ {
+ $value = '';
+
+ $tokens = $this->getEncodableWordTokens($input);
+
+ foreach ($tokens as $token) {
+ // See RFC 2822, Sect 2.2 (really 2.2 ??)
+ if ($this->tokenNeedsEncoding($token)) {
+ // Don't encode starting WSP
+ $firstChar = substr($token, 0, 1);
+ switch ($firstChar) {
+ case ' ':
+ case "\t":
+ $value .= $firstChar;
+ $token = substr($token, 1);
+ }
+
+ if (-1 == $usedLength) {
+ $usedLength = \strlen($header->getFieldName().': ') + \strlen($value);
+ }
+ $value .= $this->getTokenAsEncodedWord($token, $usedLength);
+
+ $header->setMaxLineLength(76); // Forcefully override
+ } else {
+ $value .= $token;
+ }
+ }
+
+ return $value;
+ }
+
+ /**
+ * Test if a token needs to be encoded or not.
+ *
+ * @param string $token
+ *
+ * @return bool
+ */
+ protected function tokenNeedsEncoding($token)
+ {
+ return preg_match('~[\x00-\x08\x10-\x19\x7F-\xFF\r\n]~', $token);
+ }
+
+ /**
+ * Splits a string into tokens in blocks of words which can be encoded quickly.
+ *
+ * @param string $string
+ *
+ * @return string[]
+ */
+ protected function getEncodableWordTokens($string)
+ {
+ $tokens = [];
+
+ $encodedToken = '';
+ // Split at all whitespace boundaries
+ foreach (preg_split('~(?=[\t ])~', $string) as $token) {
+ if ($this->tokenNeedsEncoding($token)) {
+ $encodedToken .= $token;
+ } else {
+ if (\strlen($encodedToken) > 0) {
+ $tokens[] = $encodedToken;
+ $encodedToken = '';
+ }
+ $tokens[] = $token;
+ }
+ }
+ if (\strlen($encodedToken)) {
+ $tokens[] = $encodedToken;
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Get a token as an encoded word for safe insertion into headers.
+ *
+ * @param string $token token to encode
+ * @param int $firstLineOffset optional
+ *
+ * @return string
+ */
+ protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
+ {
+ // Adjust $firstLineOffset to account for space needed for syntax
+ $charsetDecl = $this->charset;
+ if (isset($this->lang)) {
+ $charsetDecl .= '*'.$this->lang;
+ }
+ $encodingWrapperLength = \strlen(
+ '=?'.$charsetDecl.'?'.$this->encoder->getName().'??='
+ );
+
+ if ($firstLineOffset >= 75) {
+ //Does this logic need to be here?
+ $firstLineOffset = 0;
+ }
+
+ $encodedTextLines = explode("\r\n",
+ $this->encoder->encodeString(
+ $token, $firstLineOffset, 75 - $encodingWrapperLength, $this->charset
+ )
+ );
+
+ if ('iso-2022-jp' !== strtolower($this->charset)) {
+ // special encoding for iso-2022-jp using mb_encode_mimeheader
+ foreach ($encodedTextLines as $lineNum => $line) {
+ $encodedTextLines[$lineNum] = '=?'.$charsetDecl.
+ '?'.$this->encoder->getName().
+ '?'.$line.'?=';
+ }
+ }
+
+ return implode("\r\n ", $encodedTextLines);
+ }
+
+ /**
+ * Generates tokens from the given string which include CRLF as individual tokens.
+ *
+ * @param string $token
+ *
+ * @return string[]
+ */
+ protected function generateTokenLines($token)
+ {
+ return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
+ }
+
+ /**
+ * Set a value into the cache.
+ *
+ * @param string $value
+ */
+ protected function setCachedValue($value)
+ {
+ $this->cachedValue = $value;
+ }
+
+ /**
+ * Get the value in the cache.
+ *
+ * @return string
+ */
+ protected function getCachedValue()
+ {
+ return $this->cachedValue;
+ }
+
+ /**
+ * Clear the cached value if $condition is met.
+ *
+ * @param bool $condition
+ */
+ protected function clearCachedValueIf($condition)
+ {
+ if ($condition) {
+ $this->setCachedValue(null);
+ }
+ }
+
+ /**
+ * Generate a list of all tokens in the final header.
+ *
+ * @param string $string The string to tokenize
+ *
+ * @return array An array of tokens as strings
+ */
+ protected function toTokens($string = null)
+ {
+ if (null === $string) {
+ $string = $this->getFieldBody();
+ }
+
+ $tokens = [];
+
+ // Generate atoms; split at all invisible boundaries followed by WSP
+ foreach (preg_split('~(?=[ \t])~', $string) as $token) {
+ $newTokens = $this->generateTokenLines($token);
+ foreach ($newTokens as $newToken) {
+ $tokens[] = $newToken;
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Takes an array of tokens which appear in the header and turns them into
+ * an RFC 2822 compliant string, adding FWSP where needed.
+ *
+ * @param string[] $tokens
+ *
+ * @return string
+ */
+ private function tokensToString(array $tokens)
+ {
+ $lineCount = 0;
+ $headerLines = [];
+ $headerLines[] = $this->name.': ';
+ $currentLine = &$headerLines[$lineCount++];
+
+ // Build all tokens back into compliant header
+ foreach ($tokens as $i => $token) {
+ // Line longer than specified maximum or token was just a new line
+ if (("\r\n" == $token) ||
+ ($i > 0 && \strlen($currentLine.$token) > $this->lineLength)
+ && 0 < \strlen($currentLine)) {
+ $headerLines[] = '';
+ $currentLine = &$headerLines[$lineCount++];
+ }
+
+ // Append token to the line
+ if ("\r\n" != $token) {
+ $currentLine .= $token;
+ }
+ }
+
+ // Implode with FWS (RFC 2822, 2.2.3)
+ return implode("\r\n", $headerLines)."\r\n";
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php
new file mode 100644
index 0000000..efe1dad
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/DateHeader.php
@@ -0,0 +1,113 @@
+setFieldName($name);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_DATE;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * @param DateTimeInterface $model
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setDateTime($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * @return DateTimeImmutable
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getDateTime();
+ }
+
+ /**
+ * Get the date-time representing the Date in this Header.
+ *
+ * @return DateTimeImmutable
+ */
+ public function getDateTime()
+ {
+ return $this->dateTime;
+ }
+
+ /**
+ * Set the date-time of the Date in this Header.
+ *
+ * If a DateTime instance is provided, it is converted to DateTimeImmutable.
+ */
+ public function setDateTime(DateTimeInterface $dateTime)
+ {
+ $this->clearCachedValueIf($this->getCachedValue() != $dateTime->format(DateTime::RFC2822));
+ if ($dateTime instanceof DateTime) {
+ $immutable = new DateTimeImmutable('@'.$dateTime->getTimestamp());
+ $dateTime = $immutable->setTimezone($dateTime->getTimezone());
+ }
+ $this->dateTime = $dateTime;
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@link toString()} for that).
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ if (isset($this->dateTime)) {
+ $this->setCachedValue($this->dateTime->format(DateTime::RFC2822));
+ }
+ }
+
+ return $this->getCachedValue();
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php
new file mode 100644
index 0000000..4fcdff4
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/IdentificationHeader.php
@@ -0,0 +1,189 @@
+setFieldName($name);
+ $this->emailValidator = $emailValidator;
+ $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder();
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_ID;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string ID, or an array of IDs.
+ *
+ * @param mixed $model
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setId($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns an array of IDs
+ *
+ * @return array
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getIds();
+ }
+
+ /**
+ * Set the ID used in the value of this header.
+ *
+ * @param string|array $id
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setId($id)
+ {
+ $this->setIds(\is_array($id) ? $id : [$id]);
+ }
+
+ /**
+ * Get the ID used in the value of this Header.
+ *
+ * If multiple IDs are set only the first is returned.
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ if (\count($this->ids) > 0) {
+ return $this->ids[0];
+ }
+ }
+
+ /**
+ * Set a collection of IDs to use in the value of this Header.
+ *
+ * @param string[] $ids
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setIds(array $ids)
+ {
+ $actualIds = [];
+
+ foreach ($ids as $id) {
+ $this->assertValidId($id);
+ $actualIds[] = $id;
+ }
+
+ $this->clearCachedValueIf($this->ids != $actualIds);
+ $this->ids = $actualIds;
+ }
+
+ /**
+ * Get the list of IDs used in this Header.
+ *
+ * @return string[]
+ */
+ public function getIds()
+ {
+ return $this->ids;
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@see toString()} for that).
+ *
+ * @see toString()
+ *
+ * @throws Swift_RfcComplianceException
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ $angleAddrs = [];
+
+ foreach ($this->ids as $id) {
+ $angleAddrs[] = '<'.$this->addressEncoder->encodeString($id).'>';
+ }
+
+ $this->setCachedValue(implode(' ', $angleAddrs));
+ }
+
+ return $this->getCachedValue();
+ }
+
+ /**
+ * Throws an Exception if the id passed does not comply with RFC 2822.
+ *
+ * @param string $id
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ private function assertValidId($id)
+ {
+ $emailValidation = class_exists(MessageIDValidation::class) ? new MessageIDValidation() : new RFCValidation();
+
+ if (!$this->emailValidator->isValid($id, $emailValidation)) {
+ throw new Swift_RfcComplianceException('Invalid ID given <'.$id.'>');
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php
new file mode 100644
index 0000000..ddd5e8c
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/MailboxHeader.php
@@ -0,0 +1,358 @@
+setFieldName($name);
+ $this->setEncoder($encoder);
+ $this->emailValidator = $emailValidator;
+ $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder();
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_MAILBOX;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string, or an array of addresses.
+ *
+ * @param mixed $model
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setNameAddresses($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns an associative array like {@link getNameAddresses()}
+ *
+ * @throws Swift_RfcComplianceException
+ *
+ * @return array
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getNameAddresses();
+ }
+
+ /**
+ * Set a list of mailboxes to be shown in this Header.
+ *
+ * The mailboxes can be a simple array of addresses, or an array of
+ * key=>value pairs where (email => personalName).
+ * Example:
+ *
+ * setNameAddresses(array(
+ * 'chris@swiftmailer.org' => 'Chris Corbyn',
+ * 'mark@swiftmailer.org' //No associated personal name
+ * ));
+ * ?>
+ *
+ *
+ * @see __construct()
+ * @see setAddresses()
+ * @see setValue()
+ *
+ * @param string|string[] $mailboxes
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setNameAddresses($mailboxes)
+ {
+ $this->mailboxes = $this->normalizeMailboxes((array) $mailboxes);
+ $this->setCachedValue(null); //Clear any cached value
+ }
+
+ /**
+ * Get the full mailbox list of this Header as an array of valid RFC 2822 strings.
+ *
+ * Example:
+ *
+ * 'Chris Corbyn',
+ * 'mark@swiftmailer.org' => 'Mark Corbyn')
+ * );
+ * print_r($header->getNameAddressStrings());
+ * // array (
+ * // 0 => Chris Corbyn ,
+ * // 1 => Mark Corbyn
+ * // )
+ * ?>
+ *
+ *
+ * @see getNameAddresses()
+ * @see toString()
+ *
+ * @throws Swift_RfcComplianceException
+ *
+ * @return string[]
+ */
+ public function getNameAddressStrings()
+ {
+ return $this->createNameAddressStrings($this->getNameAddresses());
+ }
+
+ /**
+ * Get all mailboxes in this Header as key=>value pairs.
+ *
+ * The key is the address and the value is the name (or null if none set).
+ * Example:
+ *
+ * 'Chris Corbyn',
+ * 'mark@swiftmailer.org' => 'Mark Corbyn')
+ * );
+ * print_r($header->getNameAddresses());
+ * // array (
+ * // chris@swiftmailer.org => Chris Corbyn,
+ * // mark@swiftmailer.org => Mark Corbyn
+ * // )
+ * ?>
+ *
+ *
+ * @see getAddresses()
+ * @see getNameAddressStrings()
+ *
+ * @return string[]
+ */
+ public function getNameAddresses()
+ {
+ return $this->mailboxes;
+ }
+
+ /**
+ * Makes this Header represent a list of plain email addresses with no names.
+ *
+ * Example:
+ *
+ * setAddresses(
+ * array('one@domain.tld', 'two@domain.tld', 'three@domain.tld')
+ * );
+ * ?>
+ *
+ *
+ * @see setNameAddresses()
+ * @see setValue()
+ *
+ * @param string[] $addresses
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setAddresses($addresses)
+ {
+ $this->setNameAddresses(array_values((array) $addresses));
+ }
+
+ /**
+ * Get all email addresses in this Header.
+ *
+ * @see getNameAddresses()
+ *
+ * @return string[]
+ */
+ public function getAddresses()
+ {
+ return array_keys($this->mailboxes);
+ }
+
+ /**
+ * Remove one or more addresses from this Header.
+ *
+ * @param string|string[] $addresses
+ */
+ public function removeAddresses($addresses)
+ {
+ $this->setCachedValue(null);
+ foreach ((array) $addresses as $address) {
+ unset($this->mailboxes[$address]);
+ }
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@link toString()} for that).
+ *
+ * @see toString()
+ *
+ * @throws Swift_RfcComplianceException
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ // Compute the string value of the header only if needed
+ if (null === $this->getCachedValue()) {
+ $this->setCachedValue($this->createMailboxListString($this->mailboxes));
+ }
+
+ return $this->getCachedValue();
+ }
+
+ /**
+ * Normalizes a user-input list of mailboxes into consistent key=>value pairs.
+ *
+ * @param string[] $mailboxes
+ *
+ * @return string[]
+ */
+ protected function normalizeMailboxes(array $mailboxes)
+ {
+ $actualMailboxes = [];
+
+ foreach ($mailboxes as $key => $value) {
+ if (\is_string($key)) {
+ //key is email addr
+ $address = $key;
+ $name = $value;
+ } else {
+ $address = $value;
+ $name = null;
+ }
+ $this->assertValidAddress($address);
+ $actualMailboxes[$address] = $name;
+ }
+
+ return $actualMailboxes;
+ }
+
+ /**
+ * Produces a compliant, formatted display-name based on the string given.
+ *
+ * @param string $displayName as displayed
+ * @param bool $shorten the first line to make remove for header name
+ *
+ * @return string
+ */
+ protected function createDisplayNameString($displayName, $shorten = false)
+ {
+ return $this->createPhrase($this, $displayName, $this->getCharset(), $this->getEncoder(), $shorten);
+ }
+
+ /**
+ * Creates a string form of all the mailboxes in the passed array.
+ *
+ * @param string[] $mailboxes
+ *
+ * @throws Swift_RfcComplianceException
+ *
+ * @return string
+ */
+ protected function createMailboxListString(array $mailboxes)
+ {
+ return implode(', ', $this->createNameAddressStrings($mailboxes));
+ }
+
+ /**
+ * Redefine the encoding requirements for mailboxes.
+ *
+ * All "specials" must be encoded as the full header value will not be quoted
+ *
+ * @see RFC 2822 3.2.1
+ *
+ * @param string $token
+ *
+ * @return bool
+ */
+ protected function tokenNeedsEncoding($token)
+ {
+ return preg_match('/[()<>\[\]:;@\,."]/', $token) || parent::tokenNeedsEncoding($token);
+ }
+
+ /**
+ * Return an array of strings conforming the the name-addr spec of RFC 2822.
+ *
+ * @param string[] $mailboxes
+ *
+ * @return string[]
+ */
+ private function createNameAddressStrings(array $mailboxes)
+ {
+ $strings = [];
+
+ foreach ($mailboxes as $email => $name) {
+ $mailboxStr = $this->addressEncoder->encodeString($email);
+ if (null !== $name) {
+ $nameStr = $this->createDisplayNameString($name, empty($strings));
+ $mailboxStr = $nameStr.' <'.$mailboxStr.'>';
+ }
+ $strings[] = $mailboxStr;
+ }
+
+ return $strings;
+ }
+
+ /**
+ * Throws an Exception if the address passed does not comply with RFC 2822.
+ *
+ * @param string $address
+ *
+ * @throws Swift_RfcComplianceException if invalid
+ */
+ private function assertValidAddress($address)
+ {
+ if (!$this->emailValidator->isValid($address, new RFCValidation())) {
+ throw new Swift_RfcComplianceException('Address in mailbox given ['.$address.'] does not comply with RFC 2822, 3.6.2.');
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php
new file mode 100644
index 0000000..fafb5ba
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/OpenDKIMHeader.php
@@ -0,0 +1,135 @@
+
+ *
+ * @deprecated since SwiftMailer 6.1.0; use Swift_Signers_DKIMSigner instead.
+ */
+class Swift_Mime_Headers_OpenDKIMHeader implements Swift_Mime_Header
+{
+ /**
+ * The value of this Header.
+ *
+ * @var string
+ */
+ private $value;
+
+ /**
+ * The name of this Header.
+ *
+ * @var string
+ */
+ private $fieldName;
+
+ /**
+ * @param string $name
+ */
+ public function __construct($name)
+ {
+ $this->fieldName = $name;
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_TEXT;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string for the field value.
+ *
+ * @param string $model
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setValue($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns a string.
+ *
+ * @return string
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Get the (unencoded) value of this header.
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Set the (unencoded) value of this header.
+ *
+ * @param string $value
+ */
+ public function setValue($value)
+ {
+ $this->value = $value;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Get this Header rendered as a RFC 2822 compliant string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ return $this->fieldName.': '.$this->value."\r\n";
+ }
+
+ /**
+ * Set the Header FieldName.
+ *
+ * @see Swift_Mime_Header::getFieldName()
+ */
+ public function getFieldName()
+ {
+ return $this->fieldName;
+ }
+
+ /**
+ * Ignored.
+ */
+ public function setCharset($charset)
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php
new file mode 100644
index 0000000..47c15e6
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/ParameterizedHeader.php
@@ -0,0 +1,255 @@
+paramEncoder = $paramEncoder;
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_PARAMETERIZED;
+ }
+
+ /**
+ * Set the character set used in this Header.
+ *
+ * @param string $charset
+ */
+ public function setCharset($charset)
+ {
+ parent::setCharset($charset);
+ if (isset($this->paramEncoder)) {
+ $this->paramEncoder->charsetChanged($charset);
+ }
+ }
+
+ /**
+ * Set the value of $parameter.
+ *
+ * @param string $parameter
+ * @param string $value
+ */
+ public function setParameter($parameter, $value)
+ {
+ $this->setParameters(array_merge($this->getParameters(), [$parameter => $value]));
+ }
+
+ /**
+ * Get the value of $parameter.
+ *
+ * @param string $parameter
+ *
+ * @return string
+ */
+ public function getParameter($parameter)
+ {
+ $params = $this->getParameters();
+
+ return $params[$parameter] ?? null;
+ }
+
+ /**
+ * Set an associative array of parameter names mapped to values.
+ *
+ * @param string[] $parameters
+ */
+ public function setParameters(array $parameters)
+ {
+ $this->clearCachedValueIf($this->params != $parameters);
+ $this->params = $parameters;
+ }
+
+ /**
+ * Returns an associative array of parameter names mapped to values.
+ *
+ * @return string[]
+ */
+ public function getParameters()
+ {
+ return $this->params;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ *
+ * @return string
+ */
+ public function getFieldBody() //TODO: Check caching here
+ {
+ $body = parent::getFieldBody();
+ foreach ($this->params as $name => $value) {
+ if (null !== $value) {
+ // Add the parameter
+ $body .= '; '.$this->createParameter($name, $value);
+ }
+ }
+
+ return $body;
+ }
+
+ /**
+ * Generate a list of all tokens in the final header.
+ *
+ * This doesn't need to be overridden in theory, but it is for implementation
+ * reasons to prevent potential breakage of attributes.
+ *
+ * @param string $string The string to tokenize
+ *
+ * @return array An array of tokens as strings
+ */
+ protected function toTokens($string = null)
+ {
+ $tokens = parent::toTokens(parent::getFieldBody());
+
+ // Try creating any parameters
+ foreach ($this->params as $name => $value) {
+ if (null !== $value) {
+ // Add the semi-colon separator
+ $tokens[\count($tokens) - 1] .= ';';
+ $tokens = array_merge($tokens, $this->generateTokenLines(
+ ' '.$this->createParameter($name, $value)
+ ));
+ }
+ }
+
+ return $tokens;
+ }
+
+ /**
+ * Render a RFC 2047 compliant header parameter from the $name and $value.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @return string
+ */
+ private function createParameter($name, $value)
+ {
+ $origValue = $value;
+
+ $encoded = false;
+ // Allow room for parameter name, indices, "=" and DQUOTEs
+ $maxValueLength = $this->getMaxLineLength() - \strlen($name.'=*N"";') - 1;
+ $firstLineOffset = 0;
+
+ // If it's not already a valid parameter value...
+ if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
+ // TODO: text, or something else??
+ // ... and it's not ascii
+ if (!preg_match('/^[\x00-\x08\x0B\x0C\x0E-\x7F]*$/D', $value)) {
+ $encoded = true;
+ // Allow space for the indices, charset and language
+ $maxValueLength = $this->getMaxLineLength() - \strlen($name.'*N*="";') - 1;
+ $firstLineOffset = \strlen(
+ $this->getCharset()."'".$this->getLanguage()."'"
+ );
+ }
+ }
+
+ // Encode if we need to
+ if ($encoded || \strlen($value) > $maxValueLength) {
+ if (isset($this->paramEncoder)) {
+ $value = $this->paramEncoder->encodeString(
+ $origValue, $firstLineOffset, $maxValueLength, $this->getCharset()
+ );
+ } else {
+ // We have to go against RFC 2183/2231 in some areas for interoperability
+ $value = $this->getTokenAsEncodedWord($origValue);
+ $encoded = false;
+ }
+ }
+
+ $valueLines = isset($this->paramEncoder) ? explode("\r\n", $value) : [$value];
+
+ // Need to add indices
+ if (\count($valueLines) > 1) {
+ $paramLines = [];
+ foreach ($valueLines as $i => $line) {
+ $paramLines[] = $name.'*'.$i.
+ $this->getEndOfParameterValue($line, true, 0 == $i);
+ }
+
+ return implode(";\r\n ", $paramLines);
+ } else {
+ return $name.$this->getEndOfParameterValue(
+ $valueLines[0], $encoded, true
+ );
+ }
+ }
+
+ /**
+ * Returns the parameter value from the "=" and beyond.
+ *
+ * @param string $value to append
+ * @param bool $encoded
+ * @param bool $firstLine
+ *
+ * @return string
+ */
+ private function getEndOfParameterValue($value, $encoded = false, $firstLine = false)
+ {
+ if (!preg_match('/^'.self::TOKEN_REGEX.'$/D', $value)) {
+ $value = '"'.$value.'"';
+ }
+ $prepend = '=';
+ if ($encoded) {
+ $prepend = '*=';
+ if ($firstLine) {
+ $prepend = '*='.$this->getCharset()."'".$this->getLanguage().
+ "'";
+ }
+ }
+
+ return $prepend.$value;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php
new file mode 100644
index 0000000..81b421e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/PathHeader.php
@@ -0,0 +1,153 @@
+setFieldName($name);
+ $this->emailValidator = $emailValidator;
+ $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder();
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_PATH;
+ }
+
+ /**
+ * Set the model for the field body.
+ * This method takes a string for an address.
+ *
+ * @param string $model
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setAddress($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ * This method returns a string email address.
+ *
+ * @return mixed
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getAddress();
+ }
+
+ /**
+ * Set the Address which should appear in this Header.
+ *
+ * @param string $address
+ *
+ * @throws Swift_RfcComplianceException
+ */
+ public function setAddress($address)
+ {
+ if (null === $address) {
+ $this->address = null;
+ } elseif ('' == $address) {
+ $this->address = '';
+ } else {
+ $this->assertValidAddress($address);
+ $this->address = $address;
+ }
+ $this->setCachedValue(null);
+ }
+
+ /**
+ * Get the address which is used in this Header (if any).
+ *
+ * Null is returned if no address is set.
+ *
+ * @return string
+ */
+ public function getAddress()
+ {
+ return $this->address;
+ }
+
+ /**
+ * Get the string value of the body in this Header.
+ *
+ * This is not necessarily RFC 2822 compliant since folding white space will
+ * not be added at this stage (see {@link toString()} for that).
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ if (isset($this->address)) {
+ $address = $this->addressEncoder->encodeString($this->address);
+ $this->setCachedValue('<'.$address.'>');
+ }
+ }
+
+ return $this->getCachedValue();
+ }
+
+ /**
+ * Throws an Exception if the address passed does not comply with RFC 2822.
+ *
+ * @param string $address
+ *
+ * @throws Swift_RfcComplianceException If address is invalid
+ */
+ private function assertValidAddress($address)
+ {
+ if (!$this->emailValidator->isValid($address, new RFCValidation())) {
+ throw new Swift_RfcComplianceException('Address set in PathHeader does not comply with addr-spec of RFC 2822.');
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php b/include/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php
new file mode 100644
index 0000000..64f160d
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/Headers/UnstructuredHeader.php
@@ -0,0 +1,109 @@
+setFieldName($name);
+ $this->setEncoder($encoder);
+ }
+
+ /**
+ * Get the type of Header that this instance represents.
+ *
+ * @see TYPE_TEXT, TYPE_PARAMETERIZED, TYPE_MAILBOX
+ * @see TYPE_DATE, TYPE_ID, TYPE_PATH
+ *
+ * @return int
+ */
+ public function getFieldType()
+ {
+ return self::TYPE_TEXT;
+ }
+
+ /**
+ * Set the model for the field body.
+ *
+ * This method takes a string for the field value.
+ *
+ * @param string $model
+ */
+ public function setFieldBodyModel($model)
+ {
+ $this->setValue($model);
+ }
+
+ /**
+ * Get the model for the field body.
+ *
+ * This method returns a string.
+ *
+ * @return string
+ */
+ public function getFieldBodyModel()
+ {
+ return $this->getValue();
+ }
+
+ /**
+ * Get the (unencoded) value of this header.
+ *
+ * @return string
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Set the (unencoded) value of this header.
+ *
+ * @param string $value
+ */
+ public function setValue($value)
+ {
+ $this->clearCachedValueIf($this->value != $value);
+ $this->value = $value;
+ }
+
+ /**
+ * Get the value of this header prepared for rendering.
+ *
+ * @return string
+ */
+ public function getFieldBody()
+ {
+ if (!$this->getCachedValue()) {
+ $this->setCachedValue(
+ $this->encodeWords($this, $this->value)
+ );
+ }
+
+ return $this->getCachedValue();
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php b/include/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php
new file mode 100644
index 0000000..3ce35f2
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/IdGenerator.php
@@ -0,0 +1,54 @@
+idRight = $idRight;
+ }
+
+ /**
+ * Returns the right-hand side of the "@" used in all generated IDs.
+ *
+ * @return string
+ */
+ public function getIdRight()
+ {
+ return $this->idRight;
+ }
+
+ /**
+ * Sets the right-hand side of the "@" to use in all generated IDs.
+ *
+ * @param string $idRight
+ */
+ public function setIdRight($idRight)
+ {
+ $this->idRight = $idRight;
+ }
+
+ /**
+ * @return string
+ */
+ public function generateId()
+ {
+ // 32 hex values for the left part
+ return bin2hex(random_bytes(16)).'@'.$this->idRight;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/MimePart.php b/include/swiftmailer/lib/classes/Swift/Mime/MimePart.php
new file mode 100644
index 0000000..fa0726a
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/MimePart.php
@@ -0,0 +1,199 @@
+setContentType('text/plain');
+ if (null !== $charset) {
+ $this->setCharset($charset);
+ }
+ }
+
+ /**
+ * Set the body of this entity, either as a string, or as an instance of
+ * {@link Swift_OutputByteStream}.
+ *
+ * @param mixed $body
+ * @param string $contentType optional
+ * @param string $charset optional
+ *
+ * @return $this
+ */
+ public function setBody($body, $contentType = null, $charset = null)
+ {
+ if (isset($charset)) {
+ $this->setCharset($charset);
+ }
+ $body = $this->convertString($body);
+
+ parent::setBody($body, $contentType);
+
+ return $this;
+ }
+
+ /**
+ * Get the character set of this entity.
+ *
+ * @return string
+ */
+ public function getCharset()
+ {
+ return $this->getHeaderParameter('Content-Type', 'charset');
+ }
+
+ /**
+ * Set the character set of this entity.
+ *
+ * @param string $charset
+ *
+ * @return $this
+ */
+ public function setCharset($charset)
+ {
+ $this->setHeaderParameter('Content-Type', 'charset', $charset);
+ if ($charset !== $this->userCharset) {
+ $this->clearCache();
+ }
+ $this->userCharset = $charset;
+ parent::charsetChanged($charset);
+
+ return $this;
+ }
+
+ /**
+ * Get the format of this entity (i.e. flowed or fixed).
+ *
+ * @return string
+ */
+ public function getFormat()
+ {
+ return $this->getHeaderParameter('Content-Type', 'format');
+ }
+
+ /**
+ * Set the format of this entity (flowed or fixed).
+ *
+ * @param string $format
+ *
+ * @return $this
+ */
+ public function setFormat($format)
+ {
+ $this->setHeaderParameter('Content-Type', 'format', $format);
+ $this->userFormat = $format;
+
+ return $this;
+ }
+
+ /**
+ * Test if delsp is being used for this entity.
+ *
+ * @return bool
+ */
+ public function getDelSp()
+ {
+ return 'yes' === $this->getHeaderParameter('Content-Type', 'delsp');
+ }
+
+ /**
+ * Turn delsp on or off for this entity.
+ *
+ * @param bool $delsp
+ *
+ * @return $this
+ */
+ public function setDelSp($delsp = true)
+ {
+ $this->setHeaderParameter('Content-Type', 'delsp', $delsp ? 'yes' : null);
+ $this->userDelSp = $delsp;
+
+ return $this;
+ }
+
+ /**
+ * Get the nesting level of this entity.
+ *
+ * @see LEVEL_TOP, LEVEL_ALTERNATIVE, LEVEL_MIXED, LEVEL_RELATED
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return $this->nestingLevel;
+ }
+
+ /**
+ * Receive notification that the charset has changed on this document, or a
+ * parent document.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->setCharset($charset);
+ }
+
+ /** Fix the content-type and encoding of this entity */
+ protected function fixHeaders()
+ {
+ parent::fixHeaders();
+ if (\count($this->getChildren())) {
+ $this->setHeaderParameter('Content-Type', 'charset', null);
+ $this->setHeaderParameter('Content-Type', 'format', null);
+ $this->setHeaderParameter('Content-Type', 'delsp', null);
+ } else {
+ $this->setCharset($this->userCharset);
+ $this->setFormat($this->userFormat);
+ $this->setDelSp($this->userDelSp);
+ }
+ }
+
+ /** Set the nesting level of this entity */
+ protected function setNestingLevel($level)
+ {
+ $this->nestingLevel = $level;
+ }
+
+ /** Encode charset when charset is not utf-8 */
+ protected function convertString($string)
+ {
+ $charset = strtolower($this->getCharset());
+ if (!\in_array($charset, ['utf-8', 'iso-8859-1', 'iso-8859-15', ''])) {
+ return mb_convert_encoding($string, $charset, 'utf-8');
+ }
+
+ return $string;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php b/include/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php
new file mode 100644
index 0000000..b4345f4
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderFactory.php
@@ -0,0 +1,194 @@
+encoder = $encoder;
+ $this->paramEncoder = $paramEncoder;
+ $this->emailValidator = $emailValidator;
+ $this->charset = $charset;
+ $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder();
+ }
+
+ /**
+ * Create a new Mailbox Header with a list of $addresses.
+ *
+ * @param string $name
+ * @param array|string|null $addresses
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createMailboxHeader($name, $addresses = null)
+ {
+ $header = new Swift_Mime_Headers_MailboxHeader($name, $this->encoder, $this->emailValidator, $this->addressEncoder);
+ if (isset($addresses)) {
+ $header->setFieldBodyModel($addresses);
+ }
+ $this->setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new Date header using $dateTime.
+ *
+ * @param string $name
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createDateHeader($name, DateTimeInterface $dateTime = null)
+ {
+ $header = new Swift_Mime_Headers_DateHeader($name);
+ if (isset($dateTime)) {
+ $header->setFieldBodyModel($dateTime);
+ }
+ $this->setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new basic text header with $name and $value.
+ *
+ * @param string $name
+ * @param string $value
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createTextHeader($name, $value = null)
+ {
+ $header = new Swift_Mime_Headers_UnstructuredHeader($name, $this->encoder);
+ if (isset($value)) {
+ $header->setFieldBodyModel($value);
+ }
+ $this->setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new ParameterizedHeader with $name, $value and $params.
+ *
+ * @param string $name
+ * @param string $value
+ * @param array $params
+ *
+ * @return Swift_Mime_Headers_ParameterizedHeader
+ */
+ public function createParameterizedHeader($name, $value = null, $params = [])
+ {
+ $header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->encoder, ('content-disposition' == strtolower($name)) ? $this->paramEncoder : null);
+ if (isset($value)) {
+ $header->setFieldBodyModel($value);
+ }
+ foreach ($params as $k => $v) {
+ $header->setParameter($k, $v);
+ }
+ $this->setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new ID header for Message-ID or Content-ID.
+ *
+ * @param string $name
+ * @param string|array $ids
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createIdHeader($name, $ids = null)
+ {
+ $header = new Swift_Mime_Headers_IdentificationHeader($name, $this->emailValidator);
+ if (isset($ids)) {
+ $header->setFieldBodyModel($ids);
+ }
+ $this->setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Create a new Path header with an address (path) in it.
+ *
+ * @param string $name
+ * @param string $path
+ *
+ * @return Swift_Mime_Header
+ */
+ public function createPathHeader($name, $path = null)
+ {
+ $header = new Swift_Mime_Headers_PathHeader($name, $this->emailValidator);
+ if (isset($path)) {
+ $header->setFieldBodyModel($path);
+ }
+ $this->setHeaderCharset($header);
+
+ return $header;
+ }
+
+ /**
+ * Notify this observer that the entity's charset has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->charset = $charset;
+ $this->encoder->charsetChanged($charset);
+ $this->paramEncoder->charsetChanged($charset);
+ }
+
+ /**
+ * Make a deep copy of object.
+ */
+ public function __clone()
+ {
+ $this->encoder = clone $this->encoder;
+ $this->paramEncoder = clone $this->paramEncoder;
+ }
+
+ /** Apply the charset to the Header */
+ private function setHeaderCharset(Swift_Mime_Header $header)
+ {
+ if (isset($this->charset)) {
+ $header->setCharset($this->charset);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php b/include/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php
new file mode 100644
index 0000000..3eed551
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/SimpleHeaderSet.php
@@ -0,0 +1,399 @@
+factory = $factory;
+ if (isset($charset)) {
+ $this->setCharset($charset);
+ }
+ }
+
+ public function newInstance()
+ {
+ return new self($this->factory);
+ }
+
+ /**
+ * Set the charset used by these headers.
+ *
+ * @param string $charset
+ */
+ public function setCharset($charset)
+ {
+ $this->charset = $charset;
+ $this->factory->charsetChanged($charset);
+ $this->notifyHeadersOfCharset($charset);
+ }
+
+ /**
+ * Add a new Mailbox Header with a list of $addresses.
+ *
+ * @param string $name
+ * @param array|string $addresses
+ */
+ public function addMailboxHeader($name, $addresses = null)
+ {
+ $this->storeHeader($name, $this->factory->createMailboxHeader($name, $addresses));
+ }
+
+ /**
+ * Add a new Date header using $dateTime.
+ *
+ * @param string $name
+ */
+ public function addDateHeader($name, DateTimeInterface $dateTime = null)
+ {
+ $this->storeHeader($name, $this->factory->createDateHeader($name, $dateTime));
+ }
+
+ /**
+ * Add a new basic text header with $name and $value.
+ *
+ * @param string $name
+ * @param string $value
+ */
+ public function addTextHeader($name, $value = null)
+ {
+ $this->storeHeader($name, $this->factory->createTextHeader($name, $value));
+ }
+
+ /**
+ * Add a new ParameterizedHeader with $name, $value and $params.
+ *
+ * @param string $name
+ * @param string $value
+ * @param array $params
+ */
+ public function addParameterizedHeader($name, $value = null, $params = [])
+ {
+ $this->storeHeader($name, $this->factory->createParameterizedHeader($name, $value, $params));
+ }
+
+ /**
+ * Add a new ID header for Message-ID or Content-ID.
+ *
+ * @param string $name
+ * @param string|array $ids
+ */
+ public function addIdHeader($name, $ids = null)
+ {
+ $this->storeHeader($name, $this->factory->createIdHeader($name, $ids));
+ }
+
+ /**
+ * Add a new Path header with an address (path) in it.
+ *
+ * @param string $name
+ * @param string $path
+ */
+ public function addPathHeader($name, $path = null)
+ {
+ $this->storeHeader($name, $this->factory->createPathHeader($name, $path));
+ }
+
+ /**
+ * Returns true if at least one header with the given $name exists.
+ *
+ * If multiple headers match, the actual one may be specified by $index.
+ *
+ * @param string $name
+ * @param int $index
+ *
+ * @return bool
+ */
+ public function has($name, $index = 0)
+ {
+ $lowerName = strtolower($name);
+
+ if (!\array_key_exists($lowerName, $this->headers)) {
+ return false;
+ }
+
+ if (\func_num_args() < 2) {
+ // index was not specified, so we only need to check that there is at least one header value set
+ return (bool) \count($this->headers[$lowerName]);
+ }
+
+ return \array_key_exists($index, $this->headers[$lowerName]);
+ }
+
+ /**
+ * Set a header in the HeaderSet.
+ *
+ * The header may be a previously fetched header via {@link get()} or it may
+ * be one that has been created separately.
+ *
+ * If $index is specified, the header will be inserted into the set at this
+ * offset.
+ *
+ * @param int $index
+ */
+ public function set(Swift_Mime_Header $header, $index = 0)
+ {
+ $this->storeHeader($header->getFieldName(), $header, $index);
+ }
+
+ /**
+ * Get the header with the given $name.
+ *
+ * If multiple headers match, the actual one may be specified by $index.
+ * Returns NULL if none present.
+ *
+ * @param string $name
+ * @param int $index
+ *
+ * @return Swift_Mime_Header|null
+ */
+ public function get($name, $index = 0)
+ {
+ $name = strtolower($name);
+
+ if (\func_num_args() < 2) {
+ if ($this->has($name)) {
+ $values = array_values($this->headers[$name]);
+
+ return array_shift($values);
+ }
+ } else {
+ if ($this->has($name, $index)) {
+ return $this->headers[$name][$index];
+ }
+ }
+ }
+
+ /**
+ * Get all headers with the given $name.
+ *
+ * @param string $name
+ *
+ * @return array
+ */
+ public function getAll($name = null)
+ {
+ if (!isset($name)) {
+ $headers = [];
+ foreach ($this->headers as $collection) {
+ $headers = array_merge($headers, $collection);
+ }
+
+ return $headers;
+ }
+
+ $lowerName = strtolower($name);
+ if (!\array_key_exists($lowerName, $this->headers)) {
+ return [];
+ }
+
+ return $this->headers[$lowerName];
+ }
+
+ /**
+ * Return the name of all Headers.
+ *
+ * @return array
+ */
+ public function listAll()
+ {
+ $headers = $this->headers;
+ if ($this->canSort()) {
+ uksort($headers, [$this, 'sortHeaders']);
+ }
+
+ return array_keys($headers);
+ }
+
+ /**
+ * Remove the header with the given $name if it's set.
+ *
+ * If multiple headers match, the actual one may be specified by $index.
+ *
+ * @param string $name
+ * @param int $index
+ */
+ public function remove($name, $index = 0)
+ {
+ $lowerName = strtolower($name);
+ unset($this->headers[$lowerName][$index]);
+ }
+
+ /**
+ * Remove all headers with the given $name.
+ *
+ * @param string $name
+ */
+ public function removeAll($name)
+ {
+ $lowerName = strtolower($name);
+ unset($this->headers[$lowerName]);
+ }
+
+ /**
+ * Define a list of Header names as an array in the correct order.
+ *
+ * These Headers will be output in the given order where present.
+ */
+ public function defineOrdering(array $sequence)
+ {
+ $this->order = array_flip(array_map('strtolower', $sequence));
+ }
+
+ /**
+ * Set a list of header names which must always be displayed when set.
+ *
+ * Usually headers without a field value won't be output unless set here.
+ */
+ public function setAlwaysDisplayed(array $names)
+ {
+ $this->required = array_flip(array_map('strtolower', $names));
+ }
+
+ /**
+ * Notify this observer that the entity's charset has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->setCharset($charset);
+ }
+
+ /**
+ * Returns a string with a representation of all headers.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ $string = '';
+ $headers = $this->headers;
+ if ($this->canSort()) {
+ uksort($headers, [$this, 'sortHeaders']);
+ }
+ foreach ($headers as $collection) {
+ foreach ($collection as $header) {
+ if ($this->isDisplayed($header) || '' != $header->getFieldBody()) {
+ $string .= $header->toString();
+ }
+ }
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return string
+ *
+ * @see toString()
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /** Save a Header to the internal collection */
+ private function storeHeader($name, Swift_Mime_Header $header, $offset = null)
+ {
+ if (!isset($this->headers[strtolower($name)])) {
+ $this->headers[strtolower($name)] = [];
+ }
+ if (!isset($offset)) {
+ $this->headers[strtolower($name)][] = $header;
+ } else {
+ $this->headers[strtolower($name)][$offset] = $header;
+ }
+ }
+
+ /** Test if the headers can be sorted */
+ private function canSort()
+ {
+ return \count($this->order) > 0;
+ }
+
+ /** uksort() algorithm for Header ordering */
+ private function sortHeaders($a, $b)
+ {
+ $lowerA = strtolower($a);
+ $lowerB = strtolower($b);
+ $aPos = \array_key_exists($lowerA, $this->order) ? $this->order[$lowerA] : -1;
+ $bPos = \array_key_exists($lowerB, $this->order) ? $this->order[$lowerB] : -1;
+
+ if (-1 === $aPos && -1 === $bPos) {
+ // just be sure to be determinist here
+ return $a > $b ? -1 : 1;
+ }
+
+ if (-1 == $aPos) {
+ return 1;
+ } elseif (-1 == $bPos) {
+ return -1;
+ }
+
+ return $aPos < $bPos ? -1 : 1;
+ }
+
+ /** Test if the given Header is always displayed */
+ private function isDisplayed(Swift_Mime_Header $header)
+ {
+ return \array_key_exists(strtolower($header->getFieldName()), $this->required);
+ }
+
+ /** Notify all Headers of the new charset */
+ private function notifyHeadersOfCharset($charset)
+ {
+ foreach ($this->headers as $headerGroup) {
+ foreach ($headerGroup as $header) {
+ $header->setCharset($charset);
+ }
+ }
+ }
+
+ /**
+ * Make a deep copy of object.
+ */
+ public function __clone()
+ {
+ $this->factory = clone $this->factory;
+ foreach ($this->headers as $groupKey => $headerGroup) {
+ foreach ($headerGroup as $key => $header) {
+ $this->headers[$groupKey][$key] = clone $header;
+ }
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php b/include/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php
new file mode 100644
index 0000000..62da165
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/SimpleMessage.php
@@ -0,0 +1,642 @@
+getHeaders()->defineOrdering([
+ 'Return-Path',
+ 'Received',
+ 'DKIM-Signature',
+ 'DomainKey-Signature',
+ 'Sender',
+ 'Message-ID',
+ 'Date',
+ 'Subject',
+ 'From',
+ 'Reply-To',
+ 'To',
+ 'Cc',
+ 'Bcc',
+ 'MIME-Version',
+ 'Content-Type',
+ 'Content-Transfer-Encoding',
+ ]);
+ $this->getHeaders()->setAlwaysDisplayed(['Date', 'Message-ID', 'From']);
+ $this->getHeaders()->addTextHeader('MIME-Version', '1.0');
+ $this->setDate(new DateTimeImmutable());
+ $this->setId($this->getId());
+ $this->getHeaders()->addMailboxHeader('From');
+ }
+
+ /**
+ * Always returns {@link LEVEL_TOP} for a message instance.
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return self::LEVEL_TOP;
+ }
+
+ /**
+ * Set the subject of this message.
+ *
+ * @param string $subject
+ *
+ * @return $this
+ */
+ public function setSubject($subject)
+ {
+ if (!$this->setHeaderFieldModel('Subject', $subject)) {
+ $this->getHeaders()->addTextHeader('Subject', $subject);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the subject of this message.
+ *
+ * @return string
+ */
+ public function getSubject()
+ {
+ return $this->getHeaderFieldModel('Subject');
+ }
+
+ /**
+ * Set the date at which this message was created.
+ *
+ * @return $this
+ */
+ public function setDate(DateTimeInterface $dateTime)
+ {
+ if (!$this->setHeaderFieldModel('Date', $dateTime)) {
+ $this->getHeaders()->addDateHeader('Date', $dateTime);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the date at which this message was created.
+ *
+ * @return DateTimeInterface
+ */
+ public function getDate()
+ {
+ return $this->getHeaderFieldModel('Date');
+ }
+
+ /**
+ * Set the return-path (the bounce address) of this message.
+ *
+ * @param string $address
+ *
+ * @return $this
+ */
+ public function setReturnPath($address)
+ {
+ if (!$this->setHeaderFieldModel('Return-Path', $address)) {
+ $this->getHeaders()->addPathHeader('Return-Path', $address);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the return-path (bounce address) of this message.
+ *
+ * @return string
+ */
+ public function getReturnPath()
+ {
+ return $this->getHeaderFieldModel('Return-Path');
+ }
+
+ /**
+ * Set the sender of this message.
+ *
+ * This does not override the From field, but it has a higher significance.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function setSender($address, $name = null)
+ {
+ if (!\is_array($address) && isset($name)) {
+ $address = [$address => $name];
+ }
+
+ if (!$this->setHeaderFieldModel('Sender', (array) $address)) {
+ $this->getHeaders()->addMailboxHeader('Sender', (array) $address);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the sender of this message.
+ *
+ * @return string
+ */
+ public function getSender()
+ {
+ return $this->getHeaderFieldModel('Sender');
+ }
+
+ /**
+ * Add a From: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function addFrom($address, $name = null)
+ {
+ $current = $this->getFrom();
+ $current[$address] = $name;
+
+ return $this->setFrom($current);
+ }
+
+ /**
+ * Set the from address of this message.
+ *
+ * You may pass an array of addresses if this message is from multiple people.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param string|array $addresses
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function setFrom($addresses, $name = null)
+ {
+ if (!\is_array($addresses) && isset($name)) {
+ $addresses = [$addresses => $name];
+ }
+
+ if (!$this->setHeaderFieldModel('From', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('From', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the from address of this message.
+ *
+ * @return mixed
+ */
+ public function getFrom()
+ {
+ return $this->getHeaderFieldModel('From');
+ }
+
+ /**
+ * Add a Reply-To: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function addReplyTo($address, $name = null)
+ {
+ $current = $this->getReplyTo();
+ $current[$address] = $name;
+
+ return $this->setReplyTo($current);
+ }
+
+ /**
+ * Set the reply-to address of this message.
+ *
+ * You may pass an array of addresses if replies will go to multiple people.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function setReplyTo($addresses, $name = null)
+ {
+ if (!\is_array($addresses) && isset($name)) {
+ $addresses = [$addresses => $name];
+ }
+
+ if (!$this->setHeaderFieldModel('Reply-To', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('Reply-To', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the reply-to address of this message.
+ *
+ * @return string
+ */
+ public function getReplyTo()
+ {
+ return $this->getHeaderFieldModel('Reply-To');
+ }
+
+ /**
+ * Add a To: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function addTo($address, $name = null)
+ {
+ $current = $this->getTo();
+ $current[$address] = $name;
+
+ return $this->setTo($current);
+ }
+
+ /**
+ * Set the to addresses of this message.
+ *
+ * If multiple recipients will receive the message an array should be used.
+ * Example: array('receiver@domain.org', 'other@domain.org' => 'A name')
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function setTo($addresses, $name = null)
+ {
+ if (!\is_array($addresses) && isset($name)) {
+ $addresses = [$addresses => $name];
+ }
+
+ if (!$this->setHeaderFieldModel('To', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('To', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the To addresses of this message.
+ *
+ * @return array
+ */
+ public function getTo()
+ {
+ return $this->getHeaderFieldModel('To');
+ }
+
+ /**
+ * Add a Cc: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function addCc($address, $name = null)
+ {
+ $current = $this->getCc();
+ $current[$address] = $name;
+
+ return $this->setCc($current);
+ }
+
+ /**
+ * Set the Cc addresses of this message.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function setCc($addresses, $name = null)
+ {
+ if (!\is_array($addresses) && isset($name)) {
+ $addresses = [$addresses => $name];
+ }
+
+ if (!$this->setHeaderFieldModel('Cc', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('Cc', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the Cc address of this message.
+ *
+ * @return array
+ */
+ public function getCc()
+ {
+ return $this->getHeaderFieldModel('Cc');
+ }
+
+ /**
+ * Add a Bcc: address to this message.
+ *
+ * If $name is passed this name will be associated with the address.
+ *
+ * @param string $address
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function addBcc($address, $name = null)
+ {
+ $current = $this->getBcc();
+ $current[$address] = $name;
+
+ return $this->setBcc($current);
+ }
+
+ /**
+ * Set the Bcc addresses of this message.
+ *
+ * If $name is passed and the first parameter is a string, this name will be
+ * associated with the address.
+ *
+ * @param mixed $addresses
+ * @param string $name optional
+ *
+ * @return $this
+ */
+ public function setBcc($addresses, $name = null)
+ {
+ if (!\is_array($addresses) && isset($name)) {
+ $addresses = [$addresses => $name];
+ }
+
+ if (!$this->setHeaderFieldModel('Bcc', (array) $addresses)) {
+ $this->getHeaders()->addMailboxHeader('Bcc', (array) $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the Bcc addresses of this message.
+ *
+ * @return array
+ */
+ public function getBcc()
+ {
+ return $this->getHeaderFieldModel('Bcc');
+ }
+
+ /**
+ * Set the priority of this message.
+ *
+ * The value is an integer where 1 is the highest priority and 5 is the lowest.
+ *
+ * @param int $priority
+ *
+ * @return $this
+ */
+ public function setPriority($priority)
+ {
+ $priorityMap = [
+ self::PRIORITY_HIGHEST => 'Highest',
+ self::PRIORITY_HIGH => 'High',
+ self::PRIORITY_NORMAL => 'Normal',
+ self::PRIORITY_LOW => 'Low',
+ self::PRIORITY_LOWEST => 'Lowest',
+ ];
+ $pMapKeys = array_keys($priorityMap);
+ if ($priority > max($pMapKeys)) {
+ $priority = max($pMapKeys);
+ } elseif ($priority < min($pMapKeys)) {
+ $priority = min($pMapKeys);
+ }
+ if (!$this->setHeaderFieldModel('X-Priority',
+ sprintf('%d (%s)', $priority, $priorityMap[$priority]))) {
+ $this->getHeaders()->addTextHeader('X-Priority',
+ sprintf('%d (%s)', $priority, $priorityMap[$priority]));
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the priority of this message.
+ *
+ * The returned value is an integer where 1 is the highest priority and 5
+ * is the lowest.
+ *
+ * @return int
+ */
+ public function getPriority()
+ {
+ list($priority) = sscanf($this->getHeaderFieldModel('X-Priority'),
+ '%[1-5]'
+ );
+
+ return $priority ?? 3;
+ }
+
+ /**
+ * Ask for a delivery receipt from the recipient to be sent to $addresses.
+ *
+ * @param array $addresses
+ *
+ * @return $this
+ */
+ public function setReadReceiptTo($addresses)
+ {
+ if (!$this->setHeaderFieldModel('Disposition-Notification-To', $addresses)) {
+ $this->getHeaders()
+ ->addMailboxHeader('Disposition-Notification-To', $addresses);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the addresses to which a read-receipt will be sent.
+ *
+ * @return string
+ */
+ public function getReadReceiptTo()
+ {
+ return $this->getHeaderFieldModel('Disposition-Notification-To');
+ }
+
+ /**
+ * Attach a {@link Swift_Mime_SimpleMimeEntity} such as an Attachment or MimePart.
+ *
+ * @return $this
+ */
+ public function attach(Swift_Mime_SimpleMimeEntity $entity)
+ {
+ $this->setChildren(array_merge($this->getChildren(), [$entity]));
+
+ return $this;
+ }
+
+ /**
+ * Remove an already attached entity.
+ *
+ * @return $this
+ */
+ public function detach(Swift_Mime_SimpleMimeEntity $entity)
+ {
+ $newChildren = [];
+ foreach ($this->getChildren() as $child) {
+ if ($entity !== $child) {
+ $newChildren[] = $child;
+ }
+ }
+ $this->setChildren($newChildren);
+
+ return $this;
+ }
+
+ /**
+ * Attach a {@link Swift_Mime_SimpleMimeEntity} and return it's CID source.
+ *
+ * This method should be used when embedding images or other data in a message.
+ *
+ * @return string
+ */
+ public function embed(Swift_Mime_SimpleMimeEntity $entity)
+ {
+ $this->attach($entity);
+
+ return 'cid:'.$entity->getId();
+ }
+
+ /**
+ * Get this message as a complete string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ if (\count($children = $this->getChildren()) > 0 && '' != $this->getBody()) {
+ $this->setChildren(array_merge([$this->becomeMimePart()], $children));
+ $string = parent::toString();
+ $this->setChildren($children);
+ } else {
+ $string = parent::toString();
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Write this message to a {@link Swift_InputByteStream}.
+ */
+ public function toByteStream(Swift_InputByteStream $is)
+ {
+ if (\count($children = $this->getChildren()) > 0 && '' != $this->getBody()) {
+ $this->setChildren(array_merge([$this->becomeMimePart()], $children));
+ parent::toByteStream($is);
+ $this->setChildren($children);
+ } else {
+ parent::toByteStream($is);
+ }
+ }
+
+ /** @see Swift_Mime_SimpleMimeEntity::getIdField() */
+ protected function getIdField()
+ {
+ return 'Message-ID';
+ }
+
+ /** Turn the body of this message into a child of itself if needed */
+ protected function becomeMimePart()
+ {
+ $part = new parent($this->getHeaders()->newInstance(), $this->getEncoder(),
+ $this->getCache(), $this->getIdGenerator(), $this->userCharset
+ );
+ $part->setContentType($this->userContentType);
+ $part->setBody($this->getBody());
+ $part->setFormat($this->userFormat);
+ $part->setDelSp($this->userDelSp);
+ $part->setNestingLevel($this->getTopNestingLevel());
+
+ return $part;
+ }
+
+ /** Get the highest nesting level nested inside this message */
+ private function getTopNestingLevel()
+ {
+ $highestLevel = $this->getNestingLevel();
+ foreach ($this->getChildren() as $child) {
+ $childLevel = $child->getNestingLevel();
+ if ($highestLevel < $childLevel) {
+ $highestLevel = $childLevel;
+ }
+ }
+
+ return $highestLevel;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php b/include/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php
new file mode 100644
index 0000000..fa18aa8
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Mime/SimpleMimeEntity.php
@@ -0,0 +1,826 @@
+ [self::LEVEL_TOP, self::LEVEL_MIXED],
+ 'multipart/alternative' => [self::LEVEL_MIXED, self::LEVEL_ALTERNATIVE],
+ 'multipart/related' => [self::LEVEL_ALTERNATIVE, self::LEVEL_RELATED],
+ ];
+
+ /** A set of filter rules to define what level an entity should be nested at */
+ private $compoundLevelFilters = [];
+
+ /** The nesting level of this entity */
+ private $nestingLevel = self::LEVEL_ALTERNATIVE;
+
+ /** A KeyCache instance used during encoding and streaming */
+ private $cache;
+
+ /** Direct descendants of this entity */
+ private $immediateChildren = [];
+
+ /** All descendants of this entity */
+ private $children = [];
+
+ /** The maximum line length of the body of this entity */
+ private $maxLineLength = 78;
+
+ /** The order in which alternative mime types should appear */
+ private $alternativePartOrder = [
+ 'text/plain' => 1,
+ 'text/html' => 2,
+ 'multipart/related' => 3,
+ ];
+
+ /** The CID of this entity */
+ private $id;
+
+ /** The key used for accessing the cache */
+ private $cacheKey;
+
+ protected $userContentType;
+
+ /**
+ * Create a new SimpleMimeEntity with $headers, $encoder and $cache.
+ */
+ public function __construct(Swift_Mime_SimpleHeaderSet $headers, Swift_Mime_ContentEncoder $encoder, Swift_KeyCache $cache, Swift_IdGenerator $idGenerator)
+ {
+ $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values
+ $this->cache = $cache;
+ $this->headers = $headers;
+ $this->idGenerator = $idGenerator;
+ $this->setEncoder($encoder);
+ $this->headers->defineOrdering(['Content-Type', 'Content-Transfer-Encoding']);
+
+ // This array specifies that, when the entire MIME document contains
+ // $compoundLevel, then for each child within $level, if its Content-Type
+ // is $contentType then it should be treated as if it's level is
+ // $neededLevel instead. I tried to write that unambiguously! :-\
+ // Data Structure:
+ // array (
+ // $compoundLevel => array(
+ // $level => array(
+ // $contentType => $neededLevel
+ // )
+ // )
+ // )
+
+ $this->compoundLevelFilters = [
+ (self::LEVEL_ALTERNATIVE + self::LEVEL_RELATED) => [
+ self::LEVEL_ALTERNATIVE => [
+ 'text/plain' => self::LEVEL_ALTERNATIVE,
+ 'text/html' => self::LEVEL_RELATED,
+ ],
+ ],
+ ];
+
+ $this->id = $this->idGenerator->generateId();
+ }
+
+ /**
+ * Generate a new Content-ID or Message-ID for this MIME entity.
+ *
+ * @return string
+ */
+ public function generateId()
+ {
+ $this->setId($this->idGenerator->generateId());
+
+ return $this->id;
+ }
+
+ /**
+ * Get the {@link Swift_Mime_SimpleHeaderSet} for this entity.
+ *
+ * @return Swift_Mime_SimpleHeaderSet
+ */
+ public function getHeaders()
+ {
+ return $this->headers;
+ }
+
+ /**
+ * Get the nesting level of this entity.
+ *
+ * @see LEVEL_TOP, LEVEL_MIXED, LEVEL_RELATED, LEVEL_ALTERNATIVE
+ *
+ * @return int
+ */
+ public function getNestingLevel()
+ {
+ return $this->nestingLevel;
+ }
+
+ /**
+ * Get the Content-type of this entity.
+ *
+ * @return string
+ */
+ public function getContentType()
+ {
+ return $this->getHeaderFieldModel('Content-Type');
+ }
+
+ /**
+ * Get the Body Content-type of this entity.
+ *
+ * @return string
+ */
+ public function getBodyContentType()
+ {
+ return $this->userContentType;
+ }
+
+ /**
+ * Set the Content-type of this entity.
+ *
+ * @param string $type
+ *
+ * @return $this
+ */
+ public function setContentType($type)
+ {
+ $this->setContentTypeInHeaders($type);
+ // Keep track of the value so that if the content-type changes automatically
+ // due to added child entities, it can be restored if they are later removed
+ $this->userContentType = $type;
+
+ return $this;
+ }
+
+ /**
+ * Get the CID of this entity.
+ *
+ * The CID will only be present in headers if a Content-ID header is present.
+ *
+ * @return string
+ */
+ public function getId()
+ {
+ $tmp = (array) $this->getHeaderFieldModel($this->getIdField());
+
+ return $this->headers->has($this->getIdField()) ? current($tmp) : $this->id;
+ }
+
+ /**
+ * Set the CID of this entity.
+ *
+ * @param string $id
+ *
+ * @return $this
+ */
+ public function setId($id)
+ {
+ if (!$this->setHeaderFieldModel($this->getIdField(), $id)) {
+ $this->headers->addIdHeader($this->getIdField(), $id);
+ }
+ $this->id = $id;
+
+ return $this;
+ }
+
+ /**
+ * Get the description of this entity.
+ *
+ * This value comes from the Content-Description header if set.
+ *
+ * @return string
+ */
+ public function getDescription()
+ {
+ return $this->getHeaderFieldModel('Content-Description');
+ }
+
+ /**
+ * Set the description of this entity.
+ *
+ * This method sets a value in the Content-ID header.
+ *
+ * @param string $description
+ *
+ * @return $this
+ */
+ public function setDescription($description)
+ {
+ if (!$this->setHeaderFieldModel('Content-Description', $description)) {
+ $this->headers->addTextHeader('Content-Description', $description);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the maximum line length of the body of this entity.
+ *
+ * @return int
+ */
+ public function getMaxLineLength()
+ {
+ return $this->maxLineLength;
+ }
+
+ /**
+ * Set the maximum line length of lines in this body.
+ *
+ * Though not enforced by the library, lines should not exceed 1000 chars.
+ *
+ * @param int $length
+ *
+ * @return $this
+ */
+ public function setMaxLineLength($length)
+ {
+ $this->maxLineLength = $length;
+
+ return $this;
+ }
+
+ /**
+ * Get all children added to this entity.
+ *
+ * @return Swift_Mime_SimpleMimeEntity[]
+ */
+ public function getChildren()
+ {
+ return $this->children;
+ }
+
+ /**
+ * Set all children of this entity.
+ *
+ * @param Swift_Mime_SimpleMimeEntity[] $children
+ * @param int $compoundLevel For internal use only
+ *
+ * @return $this
+ */
+ public function setChildren(array $children, $compoundLevel = null)
+ {
+ // TODO: Try to refactor this logic
+ $compoundLevel = $compoundLevel ?? $this->getCompoundLevel($children);
+ $immediateChildren = [];
+ $grandchildren = [];
+ $newContentType = $this->userContentType;
+
+ foreach ($children as $child) {
+ $level = $this->getNeededChildLevel($child, $compoundLevel);
+ if (empty($immediateChildren)) {
+ //first iteration
+ $immediateChildren = [$child];
+ } else {
+ $nextLevel = $this->getNeededChildLevel($immediateChildren[0], $compoundLevel);
+ if ($nextLevel == $level) {
+ $immediateChildren[] = $child;
+ } elseif ($level < $nextLevel) {
+ // Re-assign immediateChildren to grandchildren
+ $grandchildren = array_merge($grandchildren, $immediateChildren);
+ // Set new children
+ $immediateChildren = [$child];
+ } else {
+ $grandchildren[] = $child;
+ }
+ }
+ }
+
+ if ($immediateChildren) {
+ $lowestLevel = $this->getNeededChildLevel($immediateChildren[0], $compoundLevel);
+
+ // Determine which composite media type is needed to accommodate the
+ // immediate children
+ foreach ($this->compositeRanges as $mediaType => $range) {
+ if ($lowestLevel > $range[0] && $lowestLevel <= $range[1]) {
+ $newContentType = $mediaType;
+
+ break;
+ }
+ }
+
+ // Put any grandchildren in a subpart
+ if (!empty($grandchildren)) {
+ $subentity = $this->createChild();
+ $subentity->setNestingLevel($lowestLevel);
+ $subentity->setChildren($grandchildren, $compoundLevel);
+ array_unshift($immediateChildren, $subentity);
+ }
+ }
+
+ $this->immediateChildren = $immediateChildren;
+ $this->children = $children;
+ $this->setContentTypeInHeaders($newContentType);
+ $this->fixHeaders();
+ $this->sortChildren();
+
+ return $this;
+ }
+
+ /**
+ * Get the body of this entity as a string.
+ *
+ * @return string
+ */
+ public function getBody()
+ {
+ return $this->body instanceof Swift_OutputByteStream ? $this->readStream($this->body) : $this->body;
+ }
+
+ /**
+ * Set the body of this entity, either as a string, or as an instance of
+ * {@link Swift_OutputByteStream}.
+ *
+ * @param mixed $body
+ * @param string $contentType optional
+ *
+ * @return $this
+ */
+ public function setBody($body, $contentType = null)
+ {
+ if ($body !== $this->body) {
+ $this->clearCache();
+ }
+
+ $this->body = $body;
+ if (null !== $contentType) {
+ $this->setContentType($contentType);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the encoder used for the body of this entity.
+ *
+ * @return Swift_Mime_ContentEncoder
+ */
+ public function getEncoder()
+ {
+ return $this->encoder;
+ }
+
+ /**
+ * Set the encoder used for the body of this entity.
+ *
+ * @return $this
+ */
+ public function setEncoder(Swift_Mime_ContentEncoder $encoder)
+ {
+ if ($encoder !== $this->encoder) {
+ $this->clearCache();
+ }
+
+ $this->encoder = $encoder;
+ $this->setEncoding($encoder->getName());
+ $this->notifyEncoderChanged($encoder);
+
+ return $this;
+ }
+
+ /**
+ * Get the boundary used to separate children in this entity.
+ *
+ * @return string
+ */
+ public function getBoundary()
+ {
+ if (!isset($this->boundary)) {
+ $this->boundary = '_=_swift_'.time().'_'.bin2hex(random_bytes(16)).'_=_';
+ }
+
+ return $this->boundary;
+ }
+
+ /**
+ * Set the boundary used to separate children in this entity.
+ *
+ * @param string $boundary
+ *
+ * @throws Swift_RfcComplianceException
+ *
+ * @return $this
+ */
+ public function setBoundary($boundary)
+ {
+ $this->assertValidBoundary($boundary);
+ $this->boundary = $boundary;
+
+ return $this;
+ }
+
+ /**
+ * Receive notification that the charset of this entity, or a parent entity
+ * has changed.
+ *
+ * @param string $charset
+ */
+ public function charsetChanged($charset)
+ {
+ $this->notifyCharsetChanged($charset);
+ }
+
+ /**
+ * Receive notification that the encoder of this entity or a parent entity
+ * has changed.
+ */
+ public function encoderChanged(Swift_Mime_ContentEncoder $encoder)
+ {
+ $this->notifyEncoderChanged($encoder);
+ }
+
+ /**
+ * Get this entire entity as a string.
+ *
+ * @return string
+ */
+ public function toString()
+ {
+ $string = $this->headers->toString();
+ $string .= $this->bodyToString();
+
+ return $string;
+ }
+
+ /**
+ * Get this entire entity as a string.
+ *
+ * @return string
+ */
+ protected function bodyToString()
+ {
+ $string = '';
+
+ if (isset($this->body) && empty($this->immediateChildren)) {
+ if ($this->cache->hasKey($this->cacheKey, 'body')) {
+ $body = $this->cache->getString($this->cacheKey, 'body');
+ } else {
+ $body = "\r\n".$this->encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength());
+ $this->cache->setString($this->cacheKey, 'body', $body, Swift_KeyCache::MODE_WRITE);
+ }
+ $string .= $body;
+ }
+
+ if (!empty($this->immediateChildren)) {
+ foreach ($this->immediateChildren as $child) {
+ $string .= "\r\n\r\n--".$this->getBoundary()."\r\n";
+ $string .= $child->toString();
+ }
+ $string .= "\r\n\r\n--".$this->getBoundary()."--\r\n";
+ }
+
+ return $string;
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @see toString()
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->toString();
+ }
+
+ /**
+ * Write this entire entity to a {@see Swift_InputByteStream}.
+ */
+ public function toByteStream(Swift_InputByteStream $is)
+ {
+ $is->write($this->headers->toString());
+ $is->commit();
+
+ $this->bodyToByteStream($is);
+ }
+
+ /**
+ * Write this entire entity to a {@link Swift_InputByteStream}.
+ */
+ protected function bodyToByteStream(Swift_InputByteStream $is)
+ {
+ if (empty($this->immediateChildren)) {
+ if (isset($this->body)) {
+ if ($this->cache->hasKey($this->cacheKey, 'body')) {
+ $this->cache->exportToByteStream($this->cacheKey, 'body', $is);
+ } else {
+ $cacheIs = $this->cache->getInputByteStream($this->cacheKey, 'body');
+ if ($cacheIs) {
+ $is->bind($cacheIs);
+ }
+
+ $is->write("\r\n");
+
+ if ($this->body instanceof Swift_OutputByteStream) {
+ $this->body->setReadPointer(0);
+
+ $this->encoder->encodeByteStream($this->body, $is, 0, $this->getMaxLineLength());
+ } else {
+ $is->write($this->encoder->encodeString($this->getBody(), 0, $this->getMaxLineLength()));
+ }
+
+ if ($cacheIs) {
+ $is->unbind($cacheIs);
+ }
+ }
+ }
+ }
+
+ if (!empty($this->immediateChildren)) {
+ foreach ($this->immediateChildren as $child) {
+ $is->write("\r\n\r\n--".$this->getBoundary()."\r\n");
+ $child->toByteStream($is);
+ }
+ $is->write("\r\n\r\n--".$this->getBoundary()."--\r\n");
+ }
+ }
+
+ /**
+ * Get the name of the header that provides the ID of this entity.
+ */
+ protected function getIdField()
+ {
+ return 'Content-ID';
+ }
+
+ /**
+ * Get the model data (usually an array or a string) for $field.
+ */
+ protected function getHeaderFieldModel($field)
+ {
+ if ($this->headers->has($field)) {
+ return $this->headers->get($field)->getFieldBodyModel();
+ }
+ }
+
+ /**
+ * Set the model data for $field.
+ */
+ protected function setHeaderFieldModel($field, $model)
+ {
+ if ($this->headers->has($field)) {
+ $this->headers->get($field)->setFieldBodyModel($model);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the parameter value of $parameter on $field header.
+ */
+ protected function getHeaderParameter($field, $parameter)
+ {
+ if ($this->headers->has($field)) {
+ return $this->headers->get($field)->getParameter($parameter);
+ }
+ }
+
+ /**
+ * Set the parameter value of $parameter on $field header.
+ */
+ protected function setHeaderParameter($field, $parameter, $value)
+ {
+ if ($this->headers->has($field)) {
+ $this->headers->get($field)->setParameter($parameter, $value);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Re-evaluate what content type and encoding should be used on this entity.
+ */
+ protected function fixHeaders()
+ {
+ if (\count($this->immediateChildren)) {
+ $this->setHeaderParameter('Content-Type', 'boundary',
+ $this->getBoundary()
+ );
+ $this->headers->remove('Content-Transfer-Encoding');
+ } else {
+ $this->setHeaderParameter('Content-Type', 'boundary', null);
+ $this->setEncoding($this->encoder->getName());
+ }
+ }
+
+ /**
+ * Get the KeyCache used in this entity.
+ *
+ * @return Swift_KeyCache
+ */
+ protected function getCache()
+ {
+ return $this->cache;
+ }
+
+ /**
+ * Get the ID generator.
+ *
+ * @return Swift_IdGenerator
+ */
+ protected function getIdGenerator()
+ {
+ return $this->idGenerator;
+ }
+
+ /**
+ * Empty the KeyCache for this entity.
+ */
+ protected function clearCache()
+ {
+ $this->cache->clearKey($this->cacheKey, 'body');
+ }
+
+ private function readStream(Swift_OutputByteStream $os)
+ {
+ $string = '';
+ while (false !== $bytes = $os->read(8192)) {
+ $string .= $bytes;
+ }
+
+ $os->setReadPointer(0);
+
+ return $string;
+ }
+
+ private function setEncoding($encoding)
+ {
+ if (!$this->setHeaderFieldModel('Content-Transfer-Encoding', $encoding)) {
+ $this->headers->addTextHeader('Content-Transfer-Encoding', $encoding);
+ }
+ }
+
+ private function assertValidBoundary($boundary)
+ {
+ if (!preg_match('/^[a-z0-9\'\(\)\+_\-,\.\/:=\?\ ]{0,69}[a-z0-9\'\(\)\+_\-,\.\/:=\?]$/Di', $boundary)) {
+ throw new Swift_RfcComplianceException('Mime boundary set is not RFC 2046 compliant.');
+ }
+ }
+
+ private function setContentTypeInHeaders($type)
+ {
+ if (!$this->setHeaderFieldModel('Content-Type', $type)) {
+ $this->headers->addParameterizedHeader('Content-Type', $type);
+ }
+ }
+
+ private function setNestingLevel($level)
+ {
+ $this->nestingLevel = $level;
+ }
+
+ private function getCompoundLevel($children)
+ {
+ $level = 0;
+ foreach ($children as $child) {
+ $level |= $child->getNestingLevel();
+ }
+
+ return $level;
+ }
+
+ private function getNeededChildLevel($child, $compoundLevel)
+ {
+ $filter = [];
+ foreach ($this->compoundLevelFilters as $bitmask => $rules) {
+ if (($compoundLevel & $bitmask) === $bitmask) {
+ $filter = $rules + $filter;
+ }
+ }
+
+ $realLevel = $child->getNestingLevel();
+ $lowercaseType = strtolower($child->getContentType());
+
+ if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) {
+ return $filter[$realLevel][$lowercaseType];
+ }
+
+ return $realLevel;
+ }
+
+ private function createChild()
+ {
+ return new self($this->headers->newInstance(), $this->encoder, $this->cache, $this->idGenerator);
+ }
+
+ private function notifyEncoderChanged(Swift_Mime_ContentEncoder $encoder)
+ {
+ foreach ($this->immediateChildren as $child) {
+ $child->encoderChanged($encoder);
+ }
+ }
+
+ private function notifyCharsetChanged($charset)
+ {
+ $this->encoder->charsetChanged($charset);
+ $this->headers->charsetChanged($charset);
+ foreach ($this->immediateChildren as $child) {
+ $child->charsetChanged($charset);
+ }
+ }
+
+ private function sortChildren()
+ {
+ $shouldSort = false;
+ foreach ($this->immediateChildren as $child) {
+ // NOTE: This include alternative parts moved into a related part
+ if (self::LEVEL_ALTERNATIVE == $child->getNestingLevel()) {
+ $shouldSort = true;
+ break;
+ }
+ }
+
+ // Sort in order of preference, if there is one
+ if ($shouldSort) {
+ // Group the messages by order of preference
+ $sorted = [];
+ foreach ($this->immediateChildren as $child) {
+ $type = $child->getContentType();
+ $level = \array_key_exists($type, $this->alternativePartOrder) ? $this->alternativePartOrder[$type] : max($this->alternativePartOrder) + 1;
+
+ if (empty($sorted[$level])) {
+ $sorted[$level] = [];
+ }
+
+ $sorted[$level][] = $child;
+ }
+
+ ksort($sorted);
+
+ $this->immediateChildren = array_reduce($sorted, 'array_merge', []);
+ }
+ }
+
+ /**
+ * Empties it's own contents from the cache.
+ */
+ public function __destruct()
+ {
+ if ($this->cache instanceof Swift_KeyCache) {
+ $this->cache->clearAll($this->cacheKey);
+ }
+ }
+
+ /**
+ * Make a deep copy of object.
+ */
+ public function __clone()
+ {
+ $this->headers = clone $this->headers;
+ $this->encoder = clone $this->encoder;
+ $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values
+ $children = [];
+ foreach ($this->children as $pos => $child) {
+ $children[$pos] = clone $child;
+ }
+ $this->setChildren($children);
+ }
+
+ public function __wakeup()
+ {
+ $this->cacheKey = bin2hex(random_bytes(16)); // set 32 hex values
+ $this->cache = new Swift_KeyCache_ArrayKeyCache(new Swift_KeyCache_SimpleKeyCacheInputStream());
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/MimePart.php b/include/swiftmailer/lib/classes/Swift/MimePart.php
new file mode 100644
index 0000000..ea97619
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/MimePart.php
@@ -0,0 +1,45 @@
+createDependenciesFor('mime.part')
+ );
+
+ if (!isset($charset)) {
+ $charset = Swift_DependencyContainer::getInstance()
+ ->lookup('properties.charset');
+ }
+ $this->setBody($body);
+ $this->setCharset($charset);
+ if ($contentType) {
+ $this->setContentType($contentType);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/NullTransport.php b/include/swiftmailer/lib/classes/Swift/NullTransport.php
new file mode 100644
index 0000000..e44b7af
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/NullTransport.php
@@ -0,0 +1,26 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Pretends messages have been sent, but just ignores them.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_NullTransport extends Swift_Transport_NullTransport
+{
+ public function __construct()
+ {
+ \call_user_func_array(
+ [$this, 'Swift_Transport_NullTransport::__construct'],
+ Swift_DependencyContainer::getInstance()
+ ->createDependenciesFor('transport.null')
+ );
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/OutputByteStream.php b/include/swiftmailer/lib/classes/Swift/OutputByteStream.php
new file mode 100644
index 0000000..1f26f9b
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/OutputByteStream.php
@@ -0,0 +1,46 @@
+setThreshold($threshold);
+ $this->setSleepTime($sleep);
+ $this->sleeper = $sleeper;
+ }
+
+ /**
+ * Set the number of emails to send before restarting.
+ *
+ * @param int $threshold
+ */
+ public function setThreshold($threshold)
+ {
+ $this->threshold = $threshold;
+ }
+
+ /**
+ * Get the number of emails to send before restarting.
+ *
+ * @return int
+ */
+ public function getThreshold()
+ {
+ return $this->threshold;
+ }
+
+ /**
+ * Set the number of seconds to sleep for during a restart.
+ *
+ * @param int $sleep time
+ */
+ public function setSleepTime($sleep)
+ {
+ $this->sleep = $sleep;
+ }
+
+ /**
+ * Get the number of seconds to sleep for during a restart.
+ *
+ * @return int
+ */
+ public function getSleepTime()
+ {
+ return $this->sleep;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ ++$this->counter;
+ if ($this->counter >= $this->threshold) {
+ $transport = $evt->getTransport();
+ $transport->stop();
+ if ($this->sleep) {
+ $this->sleep($this->sleep);
+ }
+ $transport->start();
+ $this->counter = 0;
+ }
+ }
+
+ /**
+ * Sleep for $seconds.
+ *
+ * @param int $seconds
+ */
+ public function sleep($seconds)
+ {
+ if (isset($this->sleeper)) {
+ $this->sleeper->sleep($seconds);
+ } else {
+ sleep($seconds);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php b/include/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php
new file mode 100644
index 0000000..36451f4
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/BandwidthMonitorPlugin.php
@@ -0,0 +1,154 @@
+getMessage();
+ $message->toByteStream($this);
+ }
+
+ /**
+ * Invoked immediately following a command being sent.
+ */
+ public function commandSent(Swift_Events_CommandEvent $evt)
+ {
+ $command = $evt->getCommand();
+ $this->out += \strlen($command);
+ }
+
+ /**
+ * Invoked immediately following a response coming back.
+ */
+ public function responseReceived(Swift_Events_ResponseEvent $evt)
+ {
+ $response = $evt->getResponse();
+ $this->in += \strlen($response);
+ }
+
+ /**
+ * Called when a message is sent so that the outgoing counter can be increased.
+ *
+ * @param string $bytes
+ */
+ public function write($bytes)
+ {
+ $this->out += \strlen($bytes);
+ foreach ($this->mirrors as $stream) {
+ $stream->write($bytes);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function commit()
+ {
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ $this->mirrors[] = $is;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ foreach ($this->mirrors as $k => $stream) {
+ if ($is === $stream) {
+ unset($this->mirrors[$k]);
+ }
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function flushBuffers()
+ {
+ foreach ($this->mirrors as $stream) {
+ $stream->flushBuffers();
+ }
+ }
+
+ /**
+ * Get the total number of bytes sent to the server.
+ *
+ * @return int
+ */
+ public function getBytesOut()
+ {
+ return $this->out;
+ }
+
+ /**
+ * Get the total number of bytes received from the server.
+ *
+ * @return int
+ */
+ public function getBytesIn()
+ {
+ return $this->in;
+ }
+
+ /**
+ * Reset the internal counters to zero.
+ */
+ public function reset()
+ {
+ $this->out = 0;
+ $this->in = 0;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php b/include/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php
new file mode 100644
index 0000000..9f9f08b
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Decorator/Replacements.php
@@ -0,0 +1,31 @@
+
+ * $replacements = array(
+ * "address1@domain.tld" => array("{a}" => "b", "{c}" => "d"),
+ * "address2@domain.tld" => array("{a}" => "x", "{c}" => "y")
+ * )
+ *
+ *
+ * When using an instance of {@link Swift_Plugins_Decorator_Replacements},
+ * the object should return just the array of replacements for the address
+ * given to {@link Swift_Plugins_Decorator_Replacements::getReplacementsFor()}.
+ *
+ * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements
+ */
+ public function __construct($replacements)
+ {
+ $this->setReplacements($replacements);
+ }
+
+ /**
+ * Sets replacements.
+ *
+ * @param mixed $replacements Array or Swift_Plugins_Decorator_Replacements
+ *
+ * @see __construct()
+ */
+ public function setReplacements($replacements)
+ {
+ if (!($replacements instanceof Swift_Plugins_Decorator_Replacements)) {
+ $this->replacements = (array) $replacements;
+ } else {
+ $this->replacements = $replacements;
+ }
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $this->restoreMessage($message);
+ $to = array_keys($message->getTo());
+ $address = array_shift($to);
+ if ($replacements = $this->getReplacementsFor($address)) {
+ $body = $message->getBody();
+ $search = array_keys($replacements);
+ $replace = array_values($replacements);
+ $bodyReplaced = str_replace(
+ $search, $replace, $body
+ );
+ if ($body != $bodyReplaced) {
+ $this->originalBody = $body;
+ $message->setBody($bodyReplaced);
+ }
+
+ foreach ($message->getHeaders()->getAll() as $header) {
+ $body = $header->getFieldBodyModel();
+ $count = 0;
+ if (\is_array($body)) {
+ $bodyReplaced = [];
+ foreach ($body as $key => $value) {
+ $count1 = 0;
+ $count2 = 0;
+ $key = \is_string($key) ? str_replace($search, $replace, $key, $count1) : $key;
+ $value = \is_string($value) ? str_replace($search, $replace, $value, $count2) : $value;
+ $bodyReplaced[$key] = $value;
+
+ if (!$count && ($count1 || $count2)) {
+ $count = 1;
+ }
+ }
+ } elseif (\is_string($body)) {
+ $bodyReplaced = str_replace($search, $replace, $body, $count);
+ }
+
+ if ($count) {
+ $this->originalHeaders[$header->getFieldName()] = $body;
+ $header->setFieldBodyModel($bodyReplaced);
+ }
+ }
+
+ $children = (array) $message->getChildren();
+ foreach ($children as $child) {
+ list($type) = sscanf($child->getContentType(), '%[^/]/%s');
+ if ('text' == $type) {
+ $body = $child->getBody();
+ $bodyReplaced = str_replace(
+ $search, $replace, $body
+ );
+ if ($body != $bodyReplaced) {
+ $child->setBody($bodyReplaced);
+ $this->originalChildBodies[$child->getId()] = $body;
+ }
+ }
+ }
+ $this->lastMessage = $message;
+ }
+ }
+
+ /**
+ * Find a map of replacements for the address.
+ *
+ * If this plugin was provided with a delegate instance of
+ * {@link Swift_Plugins_Decorator_Replacements} then the call will be
+ * delegated to it. Otherwise, it will attempt to find the replacements
+ * from the array provided in the constructor.
+ *
+ * If no replacements can be found, an empty value (NULL) is returned.
+ *
+ * @param string $address
+ *
+ * @return array
+ */
+ public function getReplacementsFor($address)
+ {
+ if ($this->replacements instanceof Swift_Plugins_Decorator_Replacements) {
+ return $this->replacements->getReplacementsFor($address);
+ }
+
+ return $this->replacements[$address] ?? null;
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $this->restoreMessage($evt->getMessage());
+ }
+
+ /** Restore a changed message back to its original state */
+ private function restoreMessage(Swift_Mime_SimpleMessage $message)
+ {
+ if ($this->lastMessage === $message) {
+ if (isset($this->originalBody)) {
+ $message->setBody($this->originalBody);
+ $this->originalBody = null;
+ }
+ if (!empty($this->originalHeaders)) {
+ foreach ($message->getHeaders()->getAll() as $header) {
+ if (\array_key_exists($header->getFieldName(), $this->originalHeaders)) {
+ $header->setFieldBodyModel($this->originalHeaders[$header->getFieldName()]);
+ }
+ }
+ $this->originalHeaders = [];
+ }
+ if (!empty($this->originalChildBodies)) {
+ $children = (array) $message->getChildren();
+ foreach ($children as $child) {
+ $id = $child->getId();
+ if (\array_key_exists($id, $this->originalChildBodies)) {
+ $child->setBody($this->originalChildBodies[$id]);
+ }
+ }
+ $this->originalChildBodies = [];
+ }
+ $this->lastMessage = null;
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php b/include/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php
new file mode 100644
index 0000000..3f4dbbf
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/ImpersonatePlugin.php
@@ -0,0 +1,65 @@
+sender = $sender;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $headers = $message->getHeaders();
+
+ // save current recipients
+ $headers->addPathHeader('X-Swift-Return-Path', $message->getReturnPath());
+
+ // replace them with the one to send to
+ $message->setReturnPath($this->sender);
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+
+ // restore original headers
+ $headers = $message->getHeaders();
+
+ if ($headers->has('X-Swift-Return-Path')) {
+ $message->setReturnPath($headers->get('X-Swift-Return-Path')->getAddress());
+ $headers->removeAll('X-Swift-Return-Path');
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Logger.php b/include/swiftmailer/lib/classes/Swift/Plugins/Logger.php
new file mode 100644
index 0000000..d9bce89
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Logger.php
@@ -0,0 +1,36 @@
+logger = $logger;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $entry
+ */
+ public function add($entry)
+ {
+ $this->logger->add($entry);
+ }
+
+ /**
+ * Clear the log contents.
+ */
+ public function clear()
+ {
+ $this->logger->clear();
+ }
+
+ /**
+ * Get this log as a string.
+ *
+ * @return string
+ */
+ public function dump()
+ {
+ return $this->logger->dump();
+ }
+
+ /**
+ * Invoked immediately following a command being sent.
+ */
+ public function commandSent(Swift_Events_CommandEvent $evt)
+ {
+ $command = $evt->getCommand();
+ $this->logger->add(sprintf('>> %s', $command));
+ }
+
+ /**
+ * Invoked immediately following a response coming back.
+ */
+ public function responseReceived(Swift_Events_ResponseEvent $evt)
+ {
+ $response = $evt->getResponse();
+ $this->logger->add(sprintf('<< %s', $response));
+ }
+
+ /**
+ * Invoked just before a Transport is started.
+ */
+ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = \get_class($evt->getSource());
+ $this->logger->add(sprintf('++ Starting %s', $transportName));
+ }
+
+ /**
+ * Invoked immediately after the Transport is started.
+ */
+ public function transportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = \get_class($evt->getSource());
+ $this->logger->add(sprintf('++ %s started', $transportName));
+ }
+
+ /**
+ * Invoked just before a Transport is stopped.
+ */
+ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = \get_class($evt->getSource());
+ $this->logger->add(sprintf('++ Stopping %s', $transportName));
+ }
+
+ /**
+ * Invoked immediately after the Transport is stopped.
+ */
+ public function transportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ $transportName = \get_class($evt->getSource());
+ $this->logger->add(sprintf('++ %s stopped', $transportName));
+ }
+
+ /**
+ * Invoked as a TransportException is thrown in the Transport system.
+ */
+ public function exceptionThrown(Swift_Events_TransportExceptionEvent $evt)
+ {
+ $e = $evt->getException();
+ $message = $e->getMessage();
+ $code = $e->getCode();
+ $this->logger->add(sprintf('!! %s (code: %s)', $message, $code));
+ $message .= PHP_EOL;
+ $message .= 'Log data:'.PHP_EOL;
+ $message .= $this->logger->dump();
+ $evt->cancelBubble();
+ throw new Swift_TransportException($message, $code, $e->getPrevious());
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php b/include/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php
new file mode 100644
index 0000000..6f595ad
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Loggers/ArrayLogger.php
@@ -0,0 +1,72 @@
+size = $size;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $entry
+ */
+ public function add($entry)
+ {
+ $this->log[] = $entry;
+ while (\count($this->log) > $this->size) {
+ array_shift($this->log);
+ }
+ }
+
+ /**
+ * Clear the log contents.
+ */
+ public function clear()
+ {
+ $this->log = [];
+ }
+
+ /**
+ * Get this log as a string.
+ *
+ * @return string
+ */
+ public function dump()
+ {
+ return implode(PHP_EOL, $this->log);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php b/include/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php
new file mode 100644
index 0000000..40a53d2
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Loggers/EchoLogger.php
@@ -0,0 +1,58 @@
+isHtml = $isHtml;
+ }
+
+ /**
+ * Add a log entry.
+ *
+ * @param string $entry
+ */
+ public function add($entry)
+ {
+ if ($this->isHtml) {
+ printf('%s%s%s', htmlspecialchars($entry, ENT_QUOTES), '
', PHP_EOL);
+ } else {
+ printf('%s%s', $entry, PHP_EOL);
+ }
+ }
+
+ /**
+ * Not implemented.
+ */
+ public function clear()
+ {
+ }
+
+ /**
+ * Not implemented.
+ */
+ public function dump()
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php b/include/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php
new file mode 100644
index 0000000..39c48ed
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/MessageLogger.php
@@ -0,0 +1,70 @@
+messages = [];
+ }
+
+ /**
+ * Get the message list.
+ *
+ * @return Swift_Mime_SimpleMessage[]
+ */
+ public function getMessages()
+ {
+ return $this->messages;
+ }
+
+ /**
+ * Get the message count.
+ *
+ * @return int count
+ */
+ public function countMessages()
+ {
+ return \count($this->messages);
+ }
+
+ /**
+ * Empty the message list.
+ */
+ public function clear()
+ {
+ $this->messages = [];
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $this->messages[] = clone $evt->getMessage();
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php b/include/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php
new file mode 100644
index 0000000..fb99e4c
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Pop/Pop3Connection.php
@@ -0,0 +1,31 @@
+host = $host;
+ $this->port = $port;
+ $this->crypto = $crypto;
+ }
+
+ /**
+ * Set a Pop3Connection to delegate to instead of connecting directly.
+ *
+ * @return $this
+ */
+ public function setConnection(Swift_Plugins_Pop_Pop3Connection $connection)
+ {
+ $this->connection = $connection;
+
+ return $this;
+ }
+
+ /**
+ * Bind this plugin to a specific SMTP transport instance.
+ */
+ public function bindSmtp(Swift_Transport $smtp)
+ {
+ $this->transport = $smtp;
+ }
+
+ /**
+ * Set the connection timeout in seconds (default 10).
+ *
+ * @param int $timeout
+ *
+ * @return $this
+ */
+ public function setTimeout($timeout)
+ {
+ $this->timeout = (int) $timeout;
+
+ return $this;
+ }
+
+ /**
+ * Set the username to use when connecting (if needed).
+ *
+ * @param string $username
+ *
+ * @return $this
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+
+ return $this;
+ }
+
+ /**
+ * Set the password to use when connecting (if needed).
+ *
+ * @param string $password
+ *
+ * @return $this
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+
+ return $this;
+ }
+
+ /**
+ * Connect to the POP3 host and authenticate.
+ *
+ * @throws Swift_Plugins_Pop_Pop3Exception if connection fails
+ */
+ public function connect()
+ {
+ if (isset($this->connection)) {
+ $this->connection->connect();
+ } else {
+ if (!isset($this->socket)) {
+ if (!$socket = fsockopen(
+ $this->getHostString(), $this->port, $errno, $errstr, $this->timeout)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]: %s', $this->host, $errstr));
+ }
+ $this->socket = $socket;
+
+ if (false === $greeting = fgets($this->socket)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]', trim($greeting)));
+ }
+
+ $this->assertOk($greeting);
+
+ if ($this->username) {
+ $this->command(sprintf("USER %s\r\n", $this->username));
+ $this->command(sprintf("PASS %s\r\n", $this->password));
+ }
+ }
+ }
+ }
+
+ /**
+ * Disconnect from the POP3 host.
+ */
+ public function disconnect()
+ {
+ if (isset($this->connection)) {
+ $this->connection->disconnect();
+ } else {
+ $this->command("QUIT\r\n");
+ if (!fclose($this->socket)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 host [%s] connection could not be stopped', $this->host));
+ }
+ $this->socket = null;
+ }
+ }
+
+ /**
+ * Invoked just before a Transport is started.
+ */
+ public function beforeTransportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ if (isset($this->transport)) {
+ if ($this->transport !== $evt->getTransport()) {
+ return;
+ }
+ }
+
+ $this->connect();
+ $this->disconnect();
+ }
+
+ /**
+ * Not used.
+ */
+ public function transportStarted(Swift_Events_TransportChangeEvent $evt)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function beforeTransportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function transportStopped(Swift_Events_TransportChangeEvent $evt)
+ {
+ }
+
+ private function command($command)
+ {
+ if (!fwrite($this->socket, $command)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to write command [%s] to POP3 host', trim($command)));
+ }
+
+ if (false === $response = fgets($this->socket)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to read from POP3 host after command [%s]', trim($command)));
+ }
+
+ $this->assertOk($response);
+
+ return $response;
+ }
+
+ private function assertOk($response)
+ {
+ if ('+OK' != substr($response, 0, 3)) {
+ throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 command failed [%s]', trim($response)));
+ }
+ }
+
+ private function getHostString()
+ {
+ $host = $this->host;
+ switch (strtolower($this->crypto)) {
+ case 'ssl':
+ $host = 'ssl://'.$host;
+ break;
+
+ case 'tls':
+ $host = 'tls://'.$host;
+ break;
+ }
+
+ return $host;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php b/include/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php
new file mode 100644
index 0000000..f7373b2
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/RedirectingPlugin.php
@@ -0,0 +1,201 @@
+recipient = $recipient;
+ $this->whitelist = $whitelist;
+ }
+
+ /**
+ * Set the recipient of all messages.
+ *
+ * @param mixed $recipient
+ */
+ public function setRecipient($recipient)
+ {
+ $this->recipient = $recipient;
+ }
+
+ /**
+ * Get the recipient of all messages.
+ *
+ * @return mixed
+ */
+ public function getRecipient()
+ {
+ return $this->recipient;
+ }
+
+ /**
+ * Set a list of regular expressions to whitelist certain recipients.
+ */
+ public function setWhitelist(array $whitelist)
+ {
+ $this->whitelist = $whitelist;
+ }
+
+ /**
+ * Get the whitelist.
+ *
+ * @return array
+ */
+ public function getWhitelist()
+ {
+ return $this->whitelist;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $headers = $message->getHeaders();
+
+ // conditionally save current recipients
+
+ if ($headers->has('to')) {
+ $headers->addMailboxHeader('X-Swift-To', $message->getTo());
+ }
+
+ if ($headers->has('cc')) {
+ $headers->addMailboxHeader('X-Swift-Cc', $message->getCc());
+ }
+
+ if ($headers->has('bcc')) {
+ $headers->addMailboxHeader('X-Swift-Bcc', $message->getBcc());
+ }
+
+ // Filter remaining headers against whitelist
+ $this->filterHeaderSet($headers, 'To');
+ $this->filterHeaderSet($headers, 'Cc');
+ $this->filterHeaderSet($headers, 'Bcc');
+
+ // Add each hard coded recipient
+ $to = $message->getTo();
+ if (null === $to) {
+ $to = [];
+ }
+
+ foreach ((array) $this->recipient as $recipient) {
+ if (!\array_key_exists($recipient, $to)) {
+ $message->addTo($recipient);
+ }
+ }
+ }
+
+ /**
+ * Filter header set against a whitelist of regular expressions.
+ *
+ * @param string $type
+ */
+ private function filterHeaderSet(Swift_Mime_SimpleHeaderSet $headerSet, $type)
+ {
+ foreach ($headerSet->getAll($type) as $headers) {
+ $headers->setNameAddresses($this->filterNameAddresses($headers->getNameAddresses()));
+ }
+ }
+
+ /**
+ * Filtered list of addresses => name pairs.
+ *
+ * @return array
+ */
+ private function filterNameAddresses(array $recipients)
+ {
+ $filtered = [];
+
+ foreach ($recipients as $address => $name) {
+ if ($this->isWhitelisted($address)) {
+ $filtered[$address] = $name;
+ }
+ }
+
+ return $filtered;
+ }
+
+ /**
+ * Matches address against whitelist of regular expressions.
+ *
+ * @return bool
+ */
+ protected function isWhitelisted($recipient)
+ {
+ if (\in_array($recipient, (array) $this->recipient)) {
+ return true;
+ }
+
+ foreach ($this->whitelist as $pattern) {
+ if (preg_match($pattern, $recipient)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $this->restoreMessage($evt->getMessage());
+ }
+
+ private function restoreMessage(Swift_Mime_SimpleMessage $message)
+ {
+ // restore original headers
+ $headers = $message->getHeaders();
+
+ if ($headers->has('X-Swift-To')) {
+ $message->setTo($headers->get('X-Swift-To')->getNameAddresses());
+ $headers->removeAll('X-Swift-To');
+ } else {
+ $message->setTo(null);
+ }
+
+ if ($headers->has('X-Swift-Cc')) {
+ $message->setCc($headers->get('X-Swift-Cc')->getNameAddresses());
+ $headers->removeAll('X-Swift-Cc');
+ }
+
+ if ($headers->has('X-Swift-Bcc')) {
+ $message->setBcc($headers->get('X-Swift-Bcc')->getNameAddresses());
+ $headers->removeAll('X-Swift-Bcc');
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Reporter.php b/include/swiftmailer/lib/classes/Swift/Plugins/Reporter.php
new file mode 100644
index 0000000..b881833
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Reporter.php
@@ -0,0 +1,31 @@
+reporter = $reporter;
+ }
+
+ /**
+ * Not used.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ }
+
+ /**
+ * Invoked immediately after the Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $message = $evt->getMessage();
+ $failures = array_flip($evt->getFailedRecipients());
+ foreach ((array) $message->getTo() as $address => $null) {
+ $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS));
+ }
+ foreach ((array) $message->getCc() as $address => $null) {
+ $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS));
+ }
+ foreach ((array) $message->getBcc() as $address => $null) {
+ $this->reporter->notify($message, $address, (\array_key_exists($address, $failures) ? Swift_Plugins_Reporter::RESULT_FAIL : Swift_Plugins_Reporter::RESULT_PASS));
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php b/include/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php
new file mode 100644
index 0000000..249cffb
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Reporters/HitReporter.php
@@ -0,0 +1,58 @@
+failures_cache[$address])) {
+ $this->failures[] = $address;
+ $this->failures_cache[$address] = true;
+ }
+ }
+
+ /**
+ * Get an array of addresses for which delivery failed.
+ *
+ * @return array
+ */
+ public function getFailedRecipients()
+ {
+ return $this->failures;
+ }
+
+ /**
+ * Clear the buffer (empty the list).
+ */
+ public function clear()
+ {
+ $this->failures = $this->failures_cache = [];
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php b/include/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php
new file mode 100644
index 0000000..1cfc3f9
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Reporters/HtmlReporter.php
@@ -0,0 +1,38 @@
+'.PHP_EOL;
+ echo 'PASS '.$address.PHP_EOL;
+ echo ''.PHP_EOL;
+ flush();
+ } else {
+ echo ''.PHP_EOL;
+ echo 'FAIL '.$address.PHP_EOL;
+ echo '
'.PHP_EOL;
+ flush();
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php b/include/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php
new file mode 100644
index 0000000..595c0f6
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Sleeper.php
@@ -0,0 +1,24 @@
+rate = $rate;
+ $this->mode = $mode;
+ $this->sleeper = $sleeper;
+ $this->timer = $timer;
+ }
+
+ /**
+ * Invoked immediately before the Message is sent.
+ */
+ public function beforeSendPerformed(Swift_Events_SendEvent $evt)
+ {
+ $time = $this->getTimestamp();
+ if (!isset($this->start)) {
+ $this->start = $time;
+ }
+ $duration = $time - $this->start;
+
+ switch ($this->mode) {
+ case self::BYTES_PER_MINUTE:
+ $sleep = $this->throttleBytesPerMinute($duration);
+ break;
+ case self::MESSAGES_PER_SECOND:
+ $sleep = $this->throttleMessagesPerSecond($duration);
+ break;
+ case self::MESSAGES_PER_MINUTE:
+ $sleep = $this->throttleMessagesPerMinute($duration);
+ break;
+ default:
+ $sleep = 0;
+ break;
+ }
+
+ if ($sleep > 0) {
+ $this->sleep($sleep);
+ }
+ }
+
+ /**
+ * Invoked when a Message is sent.
+ */
+ public function sendPerformed(Swift_Events_SendEvent $evt)
+ {
+ parent::sendPerformed($evt);
+ ++$this->messages;
+ }
+
+ /**
+ * Sleep for $seconds.
+ *
+ * @param int $seconds
+ */
+ public function sleep($seconds)
+ {
+ if (isset($this->sleeper)) {
+ $this->sleeper->sleep($seconds);
+ } else {
+ sleep($seconds);
+ }
+ }
+
+ /**
+ * Get the current UNIX timestamp.
+ *
+ * @return int
+ */
+ public function getTimestamp()
+ {
+ if (isset($this->timer)) {
+ return $this->timer->getTimestamp();
+ }
+
+ return time();
+ }
+
+ /**
+ * Get a number of seconds to sleep for.
+ *
+ * @param int $timePassed
+ *
+ * @return int
+ */
+ private function throttleBytesPerMinute($timePassed)
+ {
+ $expectedDuration = $this->getBytesOut() / ($this->rate / 60);
+
+ return (int) ceil($expectedDuration - $timePassed);
+ }
+
+ /**
+ * Get a number of seconds to sleep for.
+ *
+ * @param int $timePassed
+ *
+ * @return int
+ */
+ private function throttleMessagesPerSecond($timePassed)
+ {
+ $expectedDuration = $this->messages / $this->rate;
+
+ return (int) ceil($expectedDuration - $timePassed);
+ }
+
+ /**
+ * Get a number of seconds to sleep for.
+ *
+ * @param int $timePassed
+ *
+ * @return int
+ */
+ private function throttleMessagesPerMinute($timePassed)
+ {
+ $expectedDuration = $this->messages / ($this->rate / 60);
+
+ return (int) ceil($expectedDuration - $timePassed);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Plugins/Timer.php b/include/swiftmailer/lib/classes/Swift/Plugins/Timer.php
new file mode 100644
index 0000000..9c8deb3
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Plugins/Timer.php
@@ -0,0 +1,24 @@
+register('properties.charset')->asValue($charset);
+
+ return $this;
+ }
+
+ /**
+ * Set the directory where temporary files can be saved.
+ *
+ * @param string $dir
+ *
+ * @return $this
+ */
+ public function setTempDir($dir)
+ {
+ Swift_DependencyContainer::getInstance()->register('tempdir')->asValue($dir);
+
+ return $this;
+ }
+
+ /**
+ * Set the type of cache to use (i.e. "disk" or "array").
+ *
+ * @param string $type
+ *
+ * @return $this
+ */
+ public function setCacheType($type)
+ {
+ Swift_DependencyContainer::getInstance()->register('cache')->asAliasOf(sprintf('cache.%s', $type));
+
+ return $this;
+ }
+
+ /**
+ * Set the QuotedPrintable dot escaper preference.
+ *
+ * @param bool $dotEscape
+ *
+ * @return $this
+ */
+ public function setQPDotEscape($dotEscape)
+ {
+ $dotEscape = !empty($dotEscape);
+ Swift_DependencyContainer::getInstance()
+ ->register('mime.qpcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder')
+ ->withDependencies(['mime.charstream', 'mime.bytecanonicalizer'])
+ ->addConstructorValue($dotEscape);
+
+ return $this;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php b/include/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php
new file mode 100644
index 0000000..2897474
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/ReplacementFilterFactory.php
@@ -0,0 +1,27 @@
+createDependenciesFor('transport.sendmail')
+ );
+
+ $this->setCommand($command);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signer.php b/include/swiftmailer/lib/classes/Swift/Signer.php
new file mode 100644
index 0000000..26c5e28
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signer.php
@@ -0,0 +1,19 @@
+
+ */
+interface Swift_Signer
+{
+ public function reset();
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signers/BodySigner.php b/include/swiftmailer/lib/classes/Swift/Signers/BodySigner.php
new file mode 100644
index 0000000..b25c427
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signers/BodySigner.php
@@ -0,0 +1,31 @@
+
+ */
+interface Swift_Signers_BodySigner extends Swift_Signer
+{
+ /**
+ * Change the Swift_Signed_Message to apply the singing.
+ *
+ * @return self
+ */
+ public function signMessage(Swift_Message $message);
+
+ /**
+ * Return the list of header a signer might tamper.
+ *
+ * @return array
+ */
+ public function getAlteredHeaders();
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php b/include/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php
new file mode 100644
index 0000000..9a26abd
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signers/DKIMSigner.php
@@ -0,0 +1,682 @@
+
+ */
+class Swift_Signers_DKIMSigner implements Swift_Signers_HeaderSigner
+{
+ /**
+ * PrivateKey.
+ *
+ * @var string
+ */
+ protected $privateKey;
+
+ /**
+ * DomainName.
+ *
+ * @var string
+ */
+ protected $domainName;
+
+ /**
+ * Selector.
+ *
+ * @var string
+ */
+ protected $selector;
+
+ private $passphrase = '';
+
+ /**
+ * Hash algorithm used.
+ *
+ * @see RFC6376 3.3: Signers MUST implement and SHOULD sign using rsa-sha256.
+ *
+ * @var string
+ */
+ protected $hashAlgorithm = 'rsa-sha256';
+
+ /**
+ * Body canon method.
+ *
+ * @var string
+ */
+ protected $bodyCanon = 'simple';
+
+ /**
+ * Header canon method.
+ *
+ * @var string
+ */
+ protected $headerCanon = 'simple';
+
+ /**
+ * Headers not being signed.
+ *
+ * @var array
+ */
+ protected $ignoredHeaders = ['return-path' => true];
+
+ /**
+ * Signer identity.
+ *
+ * @var string
+ */
+ protected $signerIdentity;
+
+ /**
+ * BodyLength.
+ *
+ * @var int
+ */
+ protected $bodyLen = 0;
+
+ /**
+ * Maximum signedLen.
+ *
+ * @var int
+ */
+ protected $maxLen = PHP_INT_MAX;
+
+ /**
+ * Embbed bodyLen in signature.
+ *
+ * @var bool
+ */
+ protected $showLen = false;
+
+ /**
+ * When the signature has been applied (true means time()), false means not embedded.
+ *
+ * @var mixed
+ */
+ protected $signatureTimestamp = true;
+
+ /**
+ * When will the signature expires false means not embedded, if sigTimestamp is auto
+ * Expiration is relative, otherwise it's absolute.
+ *
+ * @var int
+ */
+ protected $signatureExpiration = false;
+
+ /**
+ * Must we embed signed headers?
+ *
+ * @var bool
+ */
+ protected $debugHeaders = false;
+
+ // work variables
+ /**
+ * Headers used to generate hash.
+ *
+ * @var array
+ */
+ protected $signedHeaders = [];
+
+ /**
+ * If debugHeaders is set store debugData here.
+ *
+ * @var string[]
+ */
+ private $debugHeadersData = [];
+
+ /**
+ * Stores the bodyHash.
+ *
+ * @var string
+ */
+ private $bodyHash = '';
+
+ /**
+ * Stores the signature header.
+ *
+ * @var Swift_Mime_Headers_ParameterizedHeader
+ */
+ protected $dkimHeader;
+
+ private $bodyHashHandler;
+
+ private $headerHash;
+
+ private $headerCanonData = '';
+
+ private $bodyCanonEmptyCounter = 0;
+
+ private $bodyCanonIgnoreStart = 2;
+
+ private $bodyCanonSpace = false;
+
+ private $bodyCanonLastChar = null;
+
+ private $bodyCanonLine = '';
+
+ private $bound = [];
+
+ /**
+ * Constructor.
+ *
+ * @param string $privateKey
+ * @param string $domainName
+ * @param string $selector
+ * @param string $passphrase
+ */
+ public function __construct($privateKey, $domainName, $selector, $passphrase = '')
+ {
+ $this->privateKey = $privateKey;
+ $this->domainName = $domainName;
+ $this->signerIdentity = '@'.$domainName;
+ $this->selector = $selector;
+ $this->passphrase = $passphrase;
+ }
+
+ /**
+ * Reset the Signer.
+ *
+ * @see Swift_Signer::reset()
+ */
+ public function reset()
+ {
+ $this->headerHash = null;
+ $this->signedHeaders = [];
+ $this->bodyHash = null;
+ $this->bodyHashHandler = null;
+ $this->bodyCanonIgnoreStart = 2;
+ $this->bodyCanonEmptyCounter = 0;
+ $this->bodyCanonLastChar = null;
+ $this->bodyCanonSpace = false;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * Writing may not happen immediately if the stream chooses to buffer. If
+ * you want to write these bytes with immediate effect, call {@link commit()}
+ * after calling write().
+ *
+ * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
+ * second, etc etc).
+ *
+ * @param string $bytes
+ *
+ * @return int
+ *
+ * @throws Swift_IoException
+ */
+ // TODO fix return
+ public function write($bytes)
+ {
+ $this->canonicalizeBody($bytes);
+ foreach ($this->bound as $is) {
+ $is->write($bytes);
+ }
+ }
+
+ /**
+ * For any bytes that are currently buffered inside the stream, force them
+ * off the buffer.
+ */
+ public function commit()
+ {
+ // Nothing to do
+ return;
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ $this->bound[] = $is;
+
+ return;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ foreach ($this->bound as $k => $stream) {
+ if ($stream === $is) {
+ unset($this->bound[$k]);
+
+ return;
+ }
+ }
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ *
+ * @throws Swift_IoException
+ */
+ public function flushBuffers()
+ {
+ $this->reset();
+ }
+
+ /**
+ * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1.
+ *
+ * @param string $hash 'rsa-sha1' or 'rsa-sha256'
+ *
+ * @throws Swift_SwiftException
+ *
+ * @return $this
+ */
+ public function setHashAlgorithm($hash)
+ {
+ switch ($hash) {
+ case 'rsa-sha1':
+ $this->hashAlgorithm = 'rsa-sha1';
+ break;
+ case 'rsa-sha256':
+ $this->hashAlgorithm = 'rsa-sha256';
+ if (!\defined('OPENSSL_ALGO_SHA256')) {
+ throw new Swift_SwiftException('Unable to set sha256 as it is not supported by OpenSSL.');
+ }
+ break;
+ default:
+ throw new Swift_SwiftException('Unable to set the hash algorithm, must be one of rsa-sha1 or rsa-sha256 (%s given).', $hash);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the body canonicalization algorithm.
+ *
+ * @param string $canon
+ *
+ * @return $this
+ */
+ public function setBodyCanon($canon)
+ {
+ if ('relaxed' == $canon) {
+ $this->bodyCanon = 'relaxed';
+ } else {
+ $this->bodyCanon = 'simple';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the header canonicalization algorithm.
+ *
+ * @param string $canon
+ *
+ * @return $this
+ */
+ public function setHeaderCanon($canon)
+ {
+ if ('relaxed' == $canon) {
+ $this->headerCanon = 'relaxed';
+ } else {
+ $this->headerCanon = 'simple';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the signer identity.
+ *
+ * @param string $identity
+ *
+ * @return $this
+ */
+ public function setSignerIdentity($identity)
+ {
+ $this->signerIdentity = $identity;
+
+ return $this;
+ }
+
+ /**
+ * Set the length of the body to sign.
+ *
+ * @param mixed $len (bool or int)
+ *
+ * @return $this
+ */
+ public function setBodySignedLen($len)
+ {
+ if (true === $len) {
+ $this->showLen = true;
+ $this->maxLen = PHP_INT_MAX;
+ } elseif (false === $len) {
+ $this->showLen = false;
+ $this->maxLen = PHP_INT_MAX;
+ } else {
+ $this->showLen = true;
+ $this->maxLen = (int) $len;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the signature timestamp.
+ *
+ * @param int $time A timestamp
+ *
+ * @return $this
+ */
+ public function setSignatureTimestamp($time)
+ {
+ $this->signatureTimestamp = $time;
+
+ return $this;
+ }
+
+ /**
+ * Set the signature expiration timestamp.
+ *
+ * @param int $time A timestamp
+ *
+ * @return $this
+ */
+ public function setSignatureExpiration($time)
+ {
+ $this->signatureExpiration = $time;
+
+ return $this;
+ }
+
+ /**
+ * Enable / disable the DebugHeaders.
+ *
+ * @param bool $debug
+ *
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setDebugHeaders($debug)
+ {
+ $this->debugHeaders = (bool) $debug;
+
+ return $this;
+ }
+
+ /**
+ * Start Body.
+ */
+ public function startBody()
+ {
+ // Init
+ switch ($this->hashAlgorithm) {
+ case 'rsa-sha256':
+ $this->bodyHashHandler = hash_init('sha256');
+ break;
+ case 'rsa-sha1':
+ $this->bodyHashHandler = hash_init('sha1');
+ break;
+ }
+ $this->bodyCanonLine = '';
+ }
+
+ /**
+ * End Body.
+ */
+ public function endBody()
+ {
+ $this->endOfBody();
+ }
+
+ /**
+ * Returns the list of Headers Tampered by this plugin.
+ *
+ * @return array
+ */
+ public function getAlteredHeaders()
+ {
+ if ($this->debugHeaders) {
+ return ['DKIM-Signature', 'X-DebugHash'];
+ } else {
+ return ['DKIM-Signature'];
+ }
+ }
+
+ /**
+ * Adds an ignored Header.
+ *
+ * @param string $header_name
+ *
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function ignoreHeader($header_name)
+ {
+ $this->ignoredHeaders[strtolower($header_name)] = true;
+
+ return $this;
+ }
+
+ /**
+ * Set the headers to sign.
+ *
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers)
+ {
+ $this->headerCanonData = '';
+ // Loop through Headers
+ $listHeaders = $headers->listAll();
+ foreach ($listHeaders as $hName) {
+ // Check if we need to ignore Header
+ if (!isset($this->ignoredHeaders[strtolower($hName)])) {
+ if ($headers->has($hName)) {
+ $tmp = $headers->getAll($hName);
+ foreach ($tmp as $header) {
+ if ('' != $header->getFieldBody()) {
+ $this->addHeader($header->toString());
+ $this->signedHeaders[] = $header->getFieldName();
+ }
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add the signature to the given Headers.
+ *
+ * @return Swift_Signers_DKIMSigner
+ */
+ public function addSignature(Swift_Mime_SimpleHeaderSet $headers)
+ {
+ // Prepare the DKIM-Signature
+ $params = ['v' => '1', 'a' => $this->hashAlgorithm, 'bh' => base64_encode($this->bodyHash), 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'i' => $this->signerIdentity, 's' => $this->selector];
+ if ('simple' != $this->bodyCanon) {
+ $params['c'] = $this->headerCanon.'/'.$this->bodyCanon;
+ } elseif ('simple' != $this->headerCanon) {
+ $params['c'] = $this->headerCanon;
+ }
+ if ($this->showLen) {
+ $params['l'] = $this->bodyLen;
+ }
+ if (true === $this->signatureTimestamp) {
+ $params['t'] = time();
+ if (false !== $this->signatureExpiration) {
+ $params['x'] = $params['t'] + $this->signatureExpiration;
+ }
+ } else {
+ if (false !== $this->signatureTimestamp) {
+ $params['t'] = $this->signatureTimestamp;
+ }
+ if (false !== $this->signatureExpiration) {
+ $params['x'] = $this->signatureExpiration;
+ }
+ }
+ if ($this->debugHeaders) {
+ $params['z'] = implode('|', $this->debugHeadersData);
+ }
+ $string = '';
+ foreach ($params as $k => $v) {
+ $string .= $k.'='.$v.'; ';
+ }
+ $string = trim($string);
+ $headers->addTextHeader('DKIM-Signature', $string);
+ // Add the last DKIM-Signature
+ $tmp = $headers->getAll('DKIM-Signature');
+ $this->dkimHeader = end($tmp);
+ $this->addHeader(trim($this->dkimHeader->toString())."\r\n b=", true);
+ if ($this->debugHeaders) {
+ $headers->addTextHeader('X-DebugHash', base64_encode($this->headerHash));
+ }
+ $this->dkimHeader->setValue($string.' b='.trim(chunk_split(base64_encode($this->getEncryptedHash()), 73, ' ')));
+
+ return $this;
+ }
+
+ /* Private helpers */
+
+ protected function addHeader($header, $is_sig = false)
+ {
+ switch ($this->headerCanon) {
+ case 'relaxed':
+ // Prepare Header and cascade
+ $exploded = explode(':', $header, 2);
+ $name = strtolower(trim($exploded[0]));
+ $value = str_replace("\r\n", '', $exploded[1]);
+ $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
+ $header = $name.':'.trim($value).($is_sig ? '' : "\r\n");
+ // no break
+ case 'simple':
+ // Nothing to do
+ }
+ $this->addToHeaderHash($header);
+ }
+
+ protected function canonicalizeBody($string)
+ {
+ $len = \strlen($string);
+ $canon = '';
+ $method = ('relaxed' == $this->bodyCanon);
+ for ($i = 0; $i < $len; ++$i) {
+ if ($this->bodyCanonIgnoreStart > 0) {
+ --$this->bodyCanonIgnoreStart;
+ continue;
+ }
+ switch ($string[$i]) {
+ case "\r":
+ $this->bodyCanonLastChar = "\r";
+ break;
+ case "\n":
+ if ("\r" == $this->bodyCanonLastChar) {
+ if ($method) {
+ $this->bodyCanonSpace = false;
+ }
+ if ('' == $this->bodyCanonLine) {
+ ++$this->bodyCanonEmptyCounter;
+ } else {
+ $this->bodyCanonLine = '';
+ $canon .= "\r\n";
+ }
+ } else {
+ // Wooops Error
+ // todo handle it but should never happen
+ }
+ break;
+ case ' ':
+ case "\t":
+ if ($method) {
+ $this->bodyCanonSpace = true;
+ break;
+ }
+ // no break
+ default:
+ if ($this->bodyCanonEmptyCounter > 0) {
+ $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter);
+ $this->bodyCanonEmptyCounter = 0;
+ }
+ if ($this->bodyCanonSpace) {
+ $this->bodyCanonLine .= ' ';
+ $canon .= ' ';
+ $this->bodyCanonSpace = false;
+ }
+ $this->bodyCanonLine .= $string[$i];
+ $canon .= $string[$i];
+ }
+ }
+ $this->addToBodyHash($canon);
+ }
+
+ protected function endOfBody()
+ {
+ // Add trailing Line return if last line is non empty
+ if (\strlen($this->bodyCanonLine) > 0) {
+ $this->addToBodyHash("\r\n");
+ }
+ $this->bodyHash = hash_final($this->bodyHashHandler, true);
+ }
+
+ private function addToBodyHash($string)
+ {
+ $len = \strlen($string);
+ if ($len > ($new_len = ($this->maxLen - $this->bodyLen))) {
+ $string = substr($string, 0, $new_len);
+ $len = $new_len;
+ }
+ hash_update($this->bodyHashHandler, $string);
+ $this->bodyLen += $len;
+ }
+
+ private function addToHeaderHash($header)
+ {
+ if ($this->debugHeaders) {
+ $this->debugHeadersData[] = trim($header);
+ }
+ $this->headerCanonData .= $header;
+ }
+
+ /**
+ * @throws Swift_SwiftException
+ *
+ * @return string
+ */
+ private function getEncryptedHash()
+ {
+ $signature = '';
+ switch ($this->hashAlgorithm) {
+ case 'rsa-sha1':
+ $algorithm = OPENSSL_ALGO_SHA1;
+ break;
+ case 'rsa-sha256':
+ $algorithm = OPENSSL_ALGO_SHA256;
+ break;
+ }
+ $pkeyId = openssl_get_privatekey($this->privateKey, $this->passphrase);
+ if (!$pkeyId) {
+ throw new Swift_SwiftException('Unable to load DKIM Private Key ['.openssl_error_string().']');
+ }
+ if (openssl_sign($this->headerCanonData, $signature, $pkeyId, $algorithm)) {
+ return $signature;
+ }
+ throw new Swift_SwiftException('Unable to sign DKIM Hash ['.openssl_error_string().']');
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php b/include/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php
new file mode 100644
index 0000000..8833765
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signers/DomainKeySigner.php
@@ -0,0 +1,504 @@
+
+ */
+class Swift_Signers_DomainKeySigner implements Swift_Signers_HeaderSigner
+{
+ /**
+ * PrivateKey.
+ *
+ * @var string
+ */
+ protected $privateKey;
+
+ /**
+ * DomainName.
+ *
+ * @var string
+ */
+ protected $domainName;
+
+ /**
+ * Selector.
+ *
+ * @var string
+ */
+ protected $selector;
+
+ /**
+ * Hash algorithm used.
+ *
+ * @var string
+ */
+ protected $hashAlgorithm = 'rsa-sha1';
+
+ /**
+ * Canonisation method.
+ *
+ * @var string
+ */
+ protected $canon = 'simple';
+
+ /**
+ * Headers not being signed.
+ *
+ * @var array
+ */
+ protected $ignoredHeaders = [];
+
+ /**
+ * Signer identity.
+ *
+ * @var string
+ */
+ protected $signerIdentity;
+
+ /**
+ * Must we embed signed headers?
+ *
+ * @var bool
+ */
+ protected $debugHeaders = false;
+
+ // work variables
+ /**
+ * Headers used to generate hash.
+ *
+ * @var array
+ */
+ private $signedHeaders = [];
+
+ /**
+ * Stores the signature header.
+ *
+ * @var Swift_Mime_Headers_ParameterizedHeader
+ */
+ protected $domainKeyHeader;
+
+ /**
+ * Hash Handler.
+ *
+ * @var resource|null
+ */
+ private $hashHandler;
+
+ private $canonData = '';
+
+ private $bodyCanonEmptyCounter = 0;
+
+ private $bodyCanonIgnoreStart = 2;
+
+ private $bodyCanonSpace = false;
+
+ private $bodyCanonLastChar = null;
+
+ private $bodyCanonLine = '';
+
+ private $bound = [];
+
+ /**
+ * Constructor.
+ *
+ * @param string $privateKey
+ * @param string $domainName
+ * @param string $selector
+ */
+ public function __construct($privateKey, $domainName, $selector)
+ {
+ $this->privateKey = $privateKey;
+ $this->domainName = $domainName;
+ $this->signerIdentity = '@'.$domainName;
+ $this->selector = $selector;
+ }
+
+ /**
+ * Resets internal states.
+ *
+ * @return $this
+ */
+ public function reset()
+ {
+ $this->hashHandler = null;
+ $this->bodyCanonIgnoreStart = 2;
+ $this->bodyCanonEmptyCounter = 0;
+ $this->bodyCanonLastChar = null;
+ $this->bodyCanonSpace = false;
+
+ return $this;
+ }
+
+ /**
+ * Writes $bytes to the end of the stream.
+ *
+ * Writing may not happen immediately if the stream chooses to buffer. If
+ * you want to write these bytes with immediate effect, call {@link commit()}
+ * after calling write().
+ *
+ * This method returns the sequence ID of the write (i.e. 1 for first, 2 for
+ * second, etc etc).
+ *
+ * @param string $bytes
+ *
+ * @return int
+ *
+ * @throws Swift_IoException
+ *
+ * @return $this
+ */
+ public function write($bytes)
+ {
+ $this->canonicalizeBody($bytes);
+ foreach ($this->bound as $is) {
+ $is->write($bytes);
+ }
+
+ return $this;
+ }
+
+ /**
+ * For any bytes that are currently buffered inside the stream, force them
+ * off the buffer.
+ *
+ * @throws Swift_IoException
+ *
+ * @return $this
+ */
+ public function commit()
+ {
+ // Nothing to do
+ return $this;
+ }
+
+ /**
+ * Attach $is to this stream.
+ *
+ * The stream acts as an observer, receiving all data that is written.
+ * All {@link write()} and {@link flushBuffers()} operations will be mirrored.
+ *
+ * @return $this
+ */
+ public function bind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ $this->bound[] = $is;
+
+ return $this;
+ }
+
+ /**
+ * Remove an already bound stream.
+ *
+ * If $is is not bound, no errors will be raised.
+ * If the stream currently has any buffered data it will be written to $is
+ * before unbinding occurs.
+ *
+ * @return $this
+ */
+ public function unbind(Swift_InputByteStream $is)
+ {
+ // Don't have to mirror anything
+ foreach ($this->bound as $k => $stream) {
+ if ($stream === $is) {
+ unset($this->bound[$k]);
+
+ break;
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Flush the contents of the stream (empty it) and set the internal pointer
+ * to the beginning.
+ *
+ * @throws Swift_IoException
+ *
+ * @return $this
+ */
+ public function flushBuffers()
+ {
+ $this->reset();
+
+ return $this;
+ }
+
+ /**
+ * Set hash_algorithm, must be one of rsa-sha256 | rsa-sha1 defaults to rsa-sha256.
+ *
+ * @param string $hash
+ *
+ * @return $this
+ */
+ public function setHashAlgorithm($hash)
+ {
+ $this->hashAlgorithm = 'rsa-sha1';
+
+ return $this;
+ }
+
+ /**
+ * Set the canonicalization algorithm.
+ *
+ * @param string $canon simple | nofws defaults to simple
+ *
+ * @return $this
+ */
+ public function setCanon($canon)
+ {
+ if ('nofws' == $canon) {
+ $this->canon = 'nofws';
+ } else {
+ $this->canon = 'simple';
+ }
+
+ return $this;
+ }
+
+ /**
+ * Set the signer identity.
+ *
+ * @param string $identity
+ *
+ * @return $this
+ */
+ public function setSignerIdentity($identity)
+ {
+ $this->signerIdentity = $identity;
+
+ return $this;
+ }
+
+ /**
+ * Enable / disable the DebugHeaders.
+ *
+ * @param bool $debug
+ *
+ * @return $this
+ */
+ public function setDebugHeaders($debug)
+ {
+ $this->debugHeaders = (bool) $debug;
+
+ return $this;
+ }
+
+ /**
+ * Start Body.
+ */
+ public function startBody()
+ {
+ }
+
+ /**
+ * End Body.
+ */
+ public function endBody()
+ {
+ $this->endOfBody();
+ }
+
+ /**
+ * Returns the list of Headers Tampered by this plugin.
+ *
+ * @return array
+ */
+ public function getAlteredHeaders()
+ {
+ if ($this->debugHeaders) {
+ return ['DomainKey-Signature', 'X-DebugHash'];
+ }
+
+ return ['DomainKey-Signature'];
+ }
+
+ /**
+ * Adds an ignored Header.
+ *
+ * @param string $header_name
+ *
+ * @return $this
+ */
+ public function ignoreHeader($header_name)
+ {
+ $this->ignoredHeaders[strtolower($header_name)] = true;
+
+ return $this;
+ }
+
+ /**
+ * Set the headers to sign.
+ *
+ * @return $this
+ */
+ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers)
+ {
+ $this->startHash();
+ $this->canonData = '';
+ // Loop through Headers
+ $listHeaders = $headers->listAll();
+ foreach ($listHeaders as $hName) {
+ // Check if we need to ignore Header
+ if (!isset($this->ignoredHeaders[strtolower($hName)])) {
+ if ($headers->has($hName)) {
+ $tmp = $headers->getAll($hName);
+ foreach ($tmp as $header) {
+ if ('' != $header->getFieldBody()) {
+ $this->addHeader($header->toString());
+ $this->signedHeaders[] = $header->getFieldName();
+ }
+ }
+ }
+ }
+ }
+ $this->endOfHeaders();
+
+ return $this;
+ }
+
+ /**
+ * Add the signature to the given Headers.
+ *
+ * @return $this
+ */
+ public function addSignature(Swift_Mime_SimpleHeaderSet $headers)
+ {
+ // Prepare the DomainKey-Signature Header
+ $params = ['a' => $this->hashAlgorithm, 'b' => chunk_split(base64_encode($this->getEncryptedHash()), 73, ' '), 'c' => $this->canon, 'd' => $this->domainName, 'h' => implode(': ', $this->signedHeaders), 'q' => 'dns', 's' => $this->selector];
+ $string = '';
+ foreach ($params as $k => $v) {
+ $string .= $k.'='.$v.'; ';
+ }
+ $string = trim($string);
+ $headers->addTextHeader('DomainKey-Signature', $string);
+
+ return $this;
+ }
+
+ /* Private helpers */
+
+ protected function addHeader($header)
+ {
+ switch ($this->canon) {
+ case 'nofws':
+ // Prepare Header and cascade
+ $exploded = explode(':', $header, 2);
+ $name = strtolower(trim($exploded[0]));
+ $value = str_replace("\r\n", '', $exploded[1]);
+ $value = preg_replace("/[ \t][ \t]+/", ' ', $value);
+ $header = $name.':'.trim($value)."\r\n";
+ // no break
+ case 'simple':
+ // Nothing to do
+ }
+ $this->addToHash($header);
+ }
+
+ protected function endOfHeaders()
+ {
+ $this->bodyCanonEmptyCounter = 1;
+ }
+
+ protected function canonicalizeBody($string)
+ {
+ $len = \strlen($string);
+ $canon = '';
+ $nofws = ('nofws' == $this->canon);
+ for ($i = 0; $i < $len; ++$i) {
+ if ($this->bodyCanonIgnoreStart > 0) {
+ --$this->bodyCanonIgnoreStart;
+ continue;
+ }
+ switch ($string[$i]) {
+ case "\r":
+ $this->bodyCanonLastChar = "\r";
+ break;
+ case "\n":
+ if ("\r" == $this->bodyCanonLastChar) {
+ if ($nofws) {
+ $this->bodyCanonSpace = false;
+ }
+ if ('' == $this->bodyCanonLine) {
+ ++$this->bodyCanonEmptyCounter;
+ } else {
+ $this->bodyCanonLine = '';
+ $canon .= "\r\n";
+ }
+ } else {
+ // Wooops Error
+ throw new Swift_SwiftException('Invalid new line sequence in mail found \n without preceding \r');
+ }
+ break;
+ case ' ':
+ case "\t":
+ case "\x09": //HTAB
+ if ($nofws) {
+ $this->bodyCanonSpace = true;
+ break;
+ }
+ // no break
+ default:
+ if ($this->bodyCanonEmptyCounter > 0) {
+ $canon .= str_repeat("\r\n", $this->bodyCanonEmptyCounter);
+ $this->bodyCanonEmptyCounter = 0;
+ }
+ $this->bodyCanonLine .= $string[$i];
+ $canon .= $string[$i];
+ }
+ }
+ $this->addToHash($canon);
+ }
+
+ protected function endOfBody()
+ {
+ if (\strlen($this->bodyCanonLine) > 0) {
+ $this->addToHash("\r\n");
+ }
+ }
+
+ private function addToHash($string)
+ {
+ $this->canonData .= $string;
+ hash_update($this->hashHandler, $string);
+ }
+
+ private function startHash()
+ {
+ // Init
+ switch ($this->hashAlgorithm) {
+ case 'rsa-sha1':
+ $this->hashHandler = hash_init('sha1');
+ break;
+ }
+ $this->bodyCanonLine = '';
+ }
+
+ /**
+ * @throws Swift_SwiftException
+ *
+ * @return string
+ */
+ private function getEncryptedHash()
+ {
+ $signature = '';
+ $pkeyId = openssl_get_privatekey($this->privateKey);
+ if (!$pkeyId) {
+ throw new Swift_SwiftException('Unable to load DomainKey Private Key ['.openssl_error_string().']');
+ }
+ if (openssl_sign($this->canonData, $signature, $pkeyId, OPENSSL_ALGO_SHA1)) {
+ return $signature;
+ }
+ throw new Swift_SwiftException('Unable to sign DomainKey Hash ['.openssl_error_string().']');
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php b/include/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php
new file mode 100644
index 0000000..6f5c209
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signers/HeaderSigner.php
@@ -0,0 +1,61 @@
+
+ */
+interface Swift_Signers_HeaderSigner extends Swift_Signer, Swift_InputByteStream
+{
+ /**
+ * Exclude an header from the signed headers.
+ *
+ * @param string $header_name
+ *
+ * @return self
+ */
+ public function ignoreHeader($header_name);
+
+ /**
+ * Prepare the Signer to get a new Body.
+ *
+ * @return self
+ */
+ public function startBody();
+
+ /**
+ * Give the signal that the body has finished streaming.
+ *
+ * @return self
+ */
+ public function endBody();
+
+ /**
+ * Give the headers already given.
+ *
+ * @return self
+ */
+ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers);
+
+ /**
+ * Add the header(s) to the headerSet.
+ *
+ * @return self
+ */
+ public function addSignature(Swift_Mime_SimpleHeaderSet $headers);
+
+ /**
+ * Return the list of header a signer might tamper.
+ *
+ * @return array
+ */
+ public function getAlteredHeaders();
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php b/include/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php
new file mode 100644
index 0000000..6d7b589
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signers/OpenDKIMSigner.php
@@ -0,0 +1,183 @@
+
+ *
+ * @deprecated since SwiftMailer 6.1.0; use Swift_Signers_DKIMSigner instead.
+ */
+class Swift_Signers_OpenDKIMSigner extends Swift_Signers_DKIMSigner
+{
+ private $peclLoaded = false;
+
+ private $dkimHandler = null;
+
+ private $dropFirstLF = true;
+
+ const CANON_RELAXED = 1;
+ const CANON_SIMPLE = 2;
+ const SIG_RSA_SHA1 = 3;
+ const SIG_RSA_SHA256 = 4;
+
+ public function __construct($privateKey, $domainName, $selector)
+ {
+ if (!\extension_loaded('opendkim')) {
+ throw new Swift_SwiftException('php-opendkim extension not found');
+ }
+
+ $this->peclLoaded = true;
+
+ parent::__construct($privateKey, $domainName, $selector);
+ }
+
+ public function addSignature(Swift_Mime_SimpleHeaderSet $headers)
+ {
+ $header = new Swift_Mime_Headers_OpenDKIMHeader('DKIM-Signature');
+ $headerVal = $this->dkimHandler->getSignatureHeader();
+ if (false === $headerVal || \is_int($headerVal)) {
+ throw new Swift_SwiftException('OpenDKIM Error: '.$this->dkimHandler->getError());
+ }
+ $header->setValue($headerVal);
+ $headers->set($header);
+
+ return $this;
+ }
+
+ public function setHeaders(Swift_Mime_SimpleHeaderSet $headers)
+ {
+ $hash = 'rsa-sha1' == $this->hashAlgorithm ? OpenDKIMSign::ALG_RSASHA1 : OpenDKIMSign::ALG_RSASHA256;
+ $bodyCanon = 'simple' == $this->bodyCanon ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED;
+ $headerCanon = 'simple' == $this->headerCanon ? OpenDKIMSign::CANON_SIMPLE : OpenDKIMSign::CANON_RELAXED;
+ $this->dkimHandler = new OpenDKIMSign($this->privateKey, $this->selector, $this->domainName, $headerCanon, $bodyCanon, $hash, -1);
+ // Hardcode signature Margin for now
+ $this->dkimHandler->setMargin(78);
+
+ if (!is_numeric($this->signatureTimestamp)) {
+ OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, time());
+ } else {
+ if (!OpenDKIM::setOption(OpenDKIM::OPTS_FIXEDTIME, $this->signatureTimestamp)) {
+ throw new Swift_SwiftException('Unable to force signature timestamp ['.openssl_error_string().']');
+ }
+ }
+ if (isset($this->signerIdentity)) {
+ $this->dkimHandler->setSigner($this->signerIdentity);
+ }
+ $listHeaders = $headers->listAll();
+ foreach ($listHeaders as $hName) {
+ // Check if we need to ignore Header
+ if (!isset($this->ignoredHeaders[strtolower($hName)])) {
+ $tmp = $headers->getAll($hName);
+ if ($headers->has($hName)) {
+ foreach ($tmp as $header) {
+ if ('' != $header->getFieldBody()) {
+ $htosign = $header->toString();
+ $this->dkimHandler->header($htosign);
+ $this->signedHeaders[] = $header->getFieldName();
+ }
+ }
+ }
+ }
+ }
+
+ return $this;
+ }
+
+ public function startBody()
+ {
+ if (!$this->peclLoaded) {
+ return parent::startBody();
+ }
+ $this->dropFirstLF = true;
+ $this->dkimHandler->eoh();
+
+ return $this;
+ }
+
+ public function endBody()
+ {
+ if (!$this->peclLoaded) {
+ return parent::endBody();
+ }
+ $this->dkimHandler->eom();
+
+ return $this;
+ }
+
+ public function reset()
+ {
+ $this->dkimHandler = null;
+ parent::reset();
+
+ return $this;
+ }
+
+ /**
+ * Set the signature timestamp.
+ *
+ * @param int $time
+ *
+ * @return $this
+ */
+ public function setSignatureTimestamp($time)
+ {
+ $this->signatureTimestamp = $time;
+
+ return $this;
+ }
+
+ /**
+ * Set the signature expiration timestamp.
+ *
+ * @param int $time
+ *
+ * @return $this
+ */
+ public function setSignatureExpiration($time)
+ {
+ $this->signatureExpiration = $time;
+
+ return $this;
+ }
+
+ /**
+ * Enable / disable the DebugHeaders.
+ *
+ * @param bool $debug
+ *
+ * @return $this
+ */
+ public function setDebugHeaders($debug)
+ {
+ $this->debugHeaders = (bool) $debug;
+
+ return $this;
+ }
+
+ // Protected
+
+ protected function canonicalizeBody($string)
+ {
+ if (!$this->peclLoaded) {
+ return parent::canonicalizeBody($string);
+ }
+ if (true === $this->dropFirstLF) {
+ if ("\r" == $string[0] && "\n" == $string[1]) {
+ $string = substr($string, 2);
+ }
+ }
+ $this->dropFirstLF = false;
+ if (\strlen($string)) {
+ $this->dkimHandler->body($string);
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php b/include/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php
new file mode 100644
index 0000000..30f3cbd
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Signers/SMimeSigner.php
@@ -0,0 +1,542 @@
+
+ * @author Jan Flora
+ */
+class Swift_Signers_SMimeSigner implements Swift_Signers_BodySigner
+{
+ protected $signCertificate;
+ protected $signPrivateKey;
+ protected $encryptCert;
+ protected $signThenEncrypt = true;
+ protected $signLevel;
+ protected $encryptLevel;
+ protected $signOptions;
+ protected $encryptOptions;
+ protected $encryptCipher;
+ protected $extraCerts = null;
+ protected $wrapFullMessage = false;
+
+ /**
+ * @var Swift_StreamFilters_StringReplacementFilterFactory
+ */
+ protected $replacementFactory;
+
+ /**
+ * @var Swift_Mime_SimpleHeaderFactory
+ */
+ protected $headerFactory;
+
+ /**
+ * Constructor.
+ *
+ * @param string|null $signCertificate
+ * @param string|null $signPrivateKey
+ * @param string|null $encryptCertificate
+ */
+ public function __construct($signCertificate = null, $signPrivateKey = null, $encryptCertificate = null)
+ {
+ if (null !== $signPrivateKey) {
+ $this->setSignCertificate($signCertificate, $signPrivateKey);
+ }
+
+ if (null !== $encryptCertificate) {
+ $this->setEncryptCertificate($encryptCertificate);
+ }
+
+ $this->replacementFactory = Swift_DependencyContainer::getInstance()
+ ->lookup('transport.replacementfactory');
+
+ $this->signOptions = PKCS7_DETACHED;
+ $this->encryptCipher = OPENSSL_CIPHER_AES_128_CBC;
+ }
+
+ /**
+ * Set the certificate location to use for signing.
+ *
+ * @see https://secure.php.net/manual/en/openssl.pkcs7.flags.php
+ *
+ * @param string $certificate
+ * @param string|array $privateKey If the key needs an passphrase use array('file-location', 'passphrase') instead
+ * @param int $signOptions Bitwise operator options for openssl_pkcs7_sign()
+ * @param string $extraCerts A file containing intermediate certificates needed by the signing certificate
+ *
+ * @return $this
+ */
+ public function setSignCertificate($certificate, $privateKey = null, $signOptions = PKCS7_DETACHED, $extraCerts = null)
+ {
+ $this->signCertificate = 'file://'.str_replace('\\', '/', realpath($certificate));
+
+ if (null !== $privateKey) {
+ if (\is_array($privateKey)) {
+ $this->signPrivateKey = $privateKey;
+ $this->signPrivateKey[0] = 'file://'.str_replace('\\', '/', realpath($privateKey[0]));
+ } else {
+ $this->signPrivateKey = 'file://'.str_replace('\\', '/', realpath($privateKey));
+ }
+ }
+
+ $this->signOptions = $signOptions;
+ $this->extraCerts = $extraCerts ? realpath($extraCerts) : null;
+
+ return $this;
+ }
+
+ /**
+ * Set the certificate location to use for encryption.
+ *
+ * @see https://secure.php.net/manual/en/openssl.pkcs7.flags.php
+ * @see https://secure.php.net/manual/en/openssl.ciphers.php
+ *
+ * @param string|array $recipientCerts Either an single X.509 certificate, or an assoc array of X.509 certificates.
+ * @param int $cipher
+ *
+ * @return $this
+ */
+ public function setEncryptCertificate($recipientCerts, $cipher = null)
+ {
+ if (\is_array($recipientCerts)) {
+ $this->encryptCert = [];
+
+ foreach ($recipientCerts as $cert) {
+ $this->encryptCert[] = 'file://'.str_replace('\\', '/', realpath($cert));
+ }
+ } else {
+ $this->encryptCert = 'file://'.str_replace('\\', '/', realpath($recipientCerts));
+ }
+
+ if (null !== $cipher) {
+ $this->encryptCipher = $cipher;
+ }
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSignCertificate()
+ {
+ return $this->signCertificate;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSignPrivateKey()
+ {
+ return $this->signPrivateKey;
+ }
+
+ /**
+ * Set perform signing before encryption.
+ *
+ * The default is to first sign the message and then encrypt.
+ * But some older mail clients, namely Microsoft Outlook 2000 will work when the message first encrypted.
+ * As this goes against the official specs, its recommended to only use 'encryption -> signing' when specifically targeting these 'broken' clients.
+ *
+ * @param bool $signThenEncrypt
+ *
+ * @return $this
+ */
+ public function setSignThenEncrypt($signThenEncrypt = true)
+ {
+ $this->signThenEncrypt = $signThenEncrypt;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isSignThenEncrypt()
+ {
+ return $this->signThenEncrypt;
+ }
+
+ /**
+ * Resets internal states.
+ *
+ * @return $this
+ */
+ public function reset()
+ {
+ return $this;
+ }
+
+ /**
+ * Specify whether to wrap the entire MIME message in the S/MIME message.
+ *
+ * According to RFC5751 section 3.1:
+ * In order to protect outer, non-content-related message header fields
+ * (for instance, the "Subject", "To", "From", and "Cc" fields), the
+ * sending client MAY wrap a full MIME message in a message/rfc822
+ * wrapper in order to apply S/MIME security services to these header
+ * fields. It is up to the receiving client to decide how to present
+ * this "inner" header along with the unprotected "outer" header.
+ *
+ * @param bool $wrap
+ *
+ * @return $this
+ */
+ public function setWrapFullMessage($wrap)
+ {
+ $this->wrapFullMessage = $wrap;
+ }
+
+ /**
+ * Change the Swift_Message to apply the signing.
+ *
+ * @return $this
+ */
+ public function signMessage(Swift_Message $message)
+ {
+ if (null === $this->signCertificate && null === $this->encryptCert) {
+ return $this;
+ }
+
+ if ($this->signThenEncrypt) {
+ $this->smimeSignMessage($message);
+ $this->smimeEncryptMessage($message);
+ } else {
+ $this->smimeEncryptMessage($message);
+ $this->smimeSignMessage($message);
+ }
+ }
+
+ /**
+ * Return the list of header a signer might tamper.
+ *
+ * @return array
+ */
+ public function getAlteredHeaders()
+ {
+ return ['Content-Type', 'Content-Transfer-Encoding', 'Content-Disposition'];
+ }
+
+ /**
+ * Sign a Swift message.
+ */
+ protected function smimeSignMessage(Swift_Message $message)
+ {
+ // If we don't have a certificate we can't sign the message
+ if (null === $this->signCertificate) {
+ return;
+ }
+
+ // Work on a clone of the original message
+ $signMessage = clone $message;
+ $signMessage->clearSigners();
+
+ if ($this->wrapFullMessage) {
+ // The original message essentially becomes the body of the new
+ // wrapped message
+ $signMessage = $this->wrapMimeMessage($signMessage);
+ } else {
+ // Only keep header needed to parse the body correctly
+ $this->clearAllHeaders($signMessage);
+ $this->copyHeaders(
+ $message,
+ $signMessage,
+ [
+ 'Content-Type',
+ 'Content-Transfer-Encoding',
+ 'Content-Disposition',
+ ]
+ );
+ }
+
+ // Copy the cloned message into a temporary file stream
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $signMessage->toByteStream($messageStream);
+ $messageStream->commit();
+ $signedMessageStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ // Sign the message using openssl
+ if (!openssl_pkcs7_sign(
+ $messageStream->getPath(),
+ $signedMessageStream->getPath(),
+ $this->signCertificate,
+ $this->signPrivateKey,
+ [],
+ $this->signOptions,
+ $this->extraCerts
+ )
+ ) {
+ throw new Swift_IoException(sprintf('Failed to sign S/Mime message. Error: "%s".', openssl_error_string()));
+ }
+
+ // Parse the resulting signed message content back into the Swift message
+ // preserving the original headers
+ $this->parseSSLOutput($signedMessageStream, $message);
+ }
+
+ /**
+ * Encrypt a Swift message.
+ */
+ protected function smimeEncryptMessage(Swift_Message $message)
+ {
+ // If we don't have a certificate we can't encrypt the message
+ if (null === $this->encryptCert) {
+ return;
+ }
+
+ // Work on a clone of the original message
+ $encryptMessage = clone $message;
+ $encryptMessage->clearSigners();
+
+ if ($this->wrapFullMessage) {
+ // The original message essentially becomes the body of the new
+ // wrapped message
+ $encryptMessage = $this->wrapMimeMessage($encryptMessage);
+ } else {
+ // Only keep header needed to parse the body correctly
+ $this->clearAllHeaders($encryptMessage);
+ $this->copyHeaders(
+ $message,
+ $encryptMessage,
+ [
+ 'Content-Type',
+ 'Content-Transfer-Encoding',
+ 'Content-Disposition',
+ ]
+ );
+ }
+
+ // Convert the message content (including headers) to a string
+ // and place it in a temporary file
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $encryptMessage->toByteStream($messageStream);
+ $messageStream->commit();
+ $encryptedMessageStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ // Encrypt the message
+ if (!openssl_pkcs7_encrypt(
+ $messageStream->getPath(),
+ $encryptedMessageStream->getPath(),
+ $this->encryptCert,
+ [],
+ 0,
+ $this->encryptCipher
+ )
+ ) {
+ throw new Swift_IoException(sprintf('Failed to encrypt S/Mime message. Error: "%s".', openssl_error_string()));
+ }
+
+ // Parse the resulting signed message content back into the Swift message
+ // preserving the original headers
+ $this->parseSSLOutput($encryptedMessageStream, $message);
+ }
+
+ /**
+ * Copy named headers from one Swift message to another.
+ */
+ protected function copyHeaders(
+ Swift_Message $fromMessage,
+ Swift_Message $toMessage,
+ array $headers = []
+ ) {
+ foreach ($headers as $header) {
+ $this->copyHeader($fromMessage, $toMessage, $header);
+ }
+ }
+
+ /**
+ * Copy a single header from one Swift message to another.
+ *
+ * @param string $headerName
+ */
+ protected function copyHeader(Swift_Message $fromMessage, Swift_Message $toMessage, $headerName)
+ {
+ $header = $fromMessage->getHeaders()->get($headerName);
+ if (!$header) {
+ return;
+ }
+ $headers = $toMessage->getHeaders();
+ switch ($header->getFieldType()) {
+ case Swift_Mime_Header::TYPE_TEXT:
+ $headers->addTextHeader($header->getFieldName(), $header->getValue());
+ break;
+ case Swift_Mime_Header::TYPE_PARAMETERIZED:
+ $headers->addParameterizedHeader(
+ $header->getFieldName(),
+ $header->getValue(),
+ $header->getParameters()
+ );
+ break;
+ }
+ }
+
+ /**
+ * Remove all headers from a Swift message.
+ */
+ protected function clearAllHeaders(Swift_Message $message)
+ {
+ $headers = $message->getHeaders();
+ foreach ($headers->listAll() as $header) {
+ $headers->removeAll($header);
+ }
+ }
+
+ /**
+ * Wraps a Swift_Message in a message/rfc822 MIME part.
+ *
+ * @return Swift_MimePart
+ */
+ protected function wrapMimeMessage(Swift_Message $message)
+ {
+ // Start by copying the original message into a message stream
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $message->toByteStream($messageStream);
+ $messageStream->commit();
+
+ // Create a new MIME part that wraps the original stream
+ $wrappedMessage = new Swift_MimePart($messageStream, 'message/rfc822');
+ $wrappedMessage->setEncoder(new Swift_Mime_ContentEncoder_PlainContentEncoder('7bit'));
+
+ return $wrappedMessage;
+ }
+
+ protected function parseSSLOutput(Swift_InputByteStream $inputStream, Swift_Message $message)
+ {
+ $messageStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $this->copyFromOpenSSLOutput($inputStream, $messageStream);
+
+ $this->streamToMime($messageStream, $message);
+ }
+
+ /**
+ * Merges an OutputByteStream from OpenSSL to a Swift_Message.
+ */
+ protected function streamToMime(Swift_OutputByteStream $fromStream, Swift_Message $message)
+ {
+ // Parse the stream into headers and body
+ list($headers, $messageStream) = $this->parseStream($fromStream);
+
+ // Get the original message headers
+ $messageHeaders = $message->getHeaders();
+
+ // Let the stream determine the headers describing the body content,
+ // since the body of the original message is overwritten by the body
+ // coming from the stream.
+ // These are all content-* headers.
+
+ // Default transfer encoding is 7bit if not set
+ $encoding = '';
+ // Remove all existing transfer encoding headers
+ $messageHeaders->removeAll('Content-Transfer-Encoding');
+ // See whether the stream sets the transfer encoding
+ if (isset($headers['content-transfer-encoding'])) {
+ $encoding = $headers['content-transfer-encoding'];
+ }
+
+ // We use the null content encoder, since the body is already encoded
+ // according to the transfer encoding specified in the stream
+ $message->setEncoder(new Swift_Mime_ContentEncoder_NullContentEncoder($encoding));
+
+ // Set the disposition, if present
+ if (isset($headers['content-disposition'])) {
+ $messageHeaders->addTextHeader('Content-Disposition', $headers['content-disposition']);
+ }
+
+ // Copy over the body from the stream using the content type dictated
+ // by the stream content
+ $message->setChildren([]);
+ $message->setBody($messageStream, $headers['content-type']);
+ }
+
+ /**
+ * This message will parse the headers of a MIME email byte stream
+ * and return an array that contains the headers as an associative
+ * array and the email body as a string.
+ *
+ * @return array
+ */
+ protected function parseStream(Swift_OutputByteStream $emailStream)
+ {
+ $bufferLength = 78;
+ $headerData = '';
+ $headerBodySeparator = "\r\n\r\n";
+
+ $emailStream->setReadPointer(0);
+
+ // Read out the headers section from the stream to a string
+ while (false !== ($buffer = $emailStream->read($bufferLength))) {
+ $headerData .= $buffer;
+
+ $headersPosEnd = strpos($headerData, $headerBodySeparator);
+
+ // Stop reading if we found the end of the headers
+ if (false !== $headersPosEnd) {
+ break;
+ }
+ }
+
+ // Split the header data into lines
+ $headerData = trim(substr($headerData, 0, $headersPosEnd));
+ $headerLines = explode("\r\n", $headerData);
+ unset($headerData);
+
+ $headers = [];
+ $currentHeaderName = '';
+
+ // Transform header lines into an associative array
+ foreach ($headerLines as $headerLine) {
+ // Handle headers that span multiple lines
+ if (false === strpos($headerLine, ':')) {
+ $headers[$currentHeaderName] .= ' '.trim($headerLine);
+ continue;
+ }
+
+ $header = explode(':', $headerLine, 2);
+ $currentHeaderName = strtolower($header[0]);
+ $headers[$currentHeaderName] = trim($header[1]);
+ }
+
+ // Read the entire email body into a byte stream
+ $bodyStream = new Swift_ByteStream_TemporaryFileByteStream();
+
+ // Skip the header and separator and point to the body
+ $emailStream->setReadPointer($headersPosEnd + \strlen($headerBodySeparator));
+
+ while (false !== ($buffer = $emailStream->read($bufferLength))) {
+ $bodyStream->write($buffer);
+ }
+
+ $bodyStream->commit();
+
+ return [$headers, $bodyStream];
+ }
+
+ protected function copyFromOpenSSLOutput(Swift_OutputByteStream $fromStream, Swift_InputByteStream $toStream)
+ {
+ $bufferLength = 4096;
+ $filteredStream = new Swift_ByteStream_TemporaryFileByteStream();
+ $filteredStream->addFilter($this->replacementFactory->createFilter("\r\n", "\n"), 'CRLF to LF');
+ $filteredStream->addFilter($this->replacementFactory->createFilter("\n", "\r\n"), 'LF to CRLF');
+
+ while (false !== ($buffer = $fromStream->read($bufferLength))) {
+ $filteredStream->write($buffer);
+ }
+
+ $filteredStream->flushBuffers();
+
+ while (false !== ($buffer = $filteredStream->read($bufferLength))) {
+ $toStream->write($buffer);
+ }
+
+ $toStream->commit();
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/SmtpTransport.php b/include/swiftmailer/lib/classes/Swift/SmtpTransport.php
new file mode 100644
index 0000000..ff4d7fa
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/SmtpTransport.php
@@ -0,0 +1,45 @@
+createDependenciesFor('transport.smtp')
+ );
+
+ $this->setHost($host);
+ $this->setPort($port);
+ $this->setEncryption($encryption);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Spool.php b/include/swiftmailer/lib/classes/Swift/Spool.php
new file mode 100644
index 0000000..9d0e8fe
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Spool.php
@@ -0,0 +1,53 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Interface for spools.
+ *
+ * @author Fabien Potencier
+ */
+interface Swift_Spool
+{
+ /**
+ * Starts this Spool mechanism.
+ */
+ public function start();
+
+ /**
+ * Stops this Spool mechanism.
+ */
+ public function stop();
+
+ /**
+ * Tests if this Spool mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted();
+
+ /**
+ * Queues a message.
+ *
+ * @param Swift_Mime_SimpleMessage $message The message to store
+ *
+ * @return bool Whether the operation has succeeded
+ */
+ public function queueMessage(Swift_Mime_SimpleMessage $message);
+
+ /**
+ * Sends messages using the given transport instance.
+ *
+ * @param Swift_Transport $transport A transport instance
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent emails
+ */
+ public function flushQueue(Swift_Transport $transport, &$failedRecipients = null);
+}
diff --git a/include/swiftmailer/lib/classes/Swift/SpoolTransport.php b/include/swiftmailer/lib/classes/Swift/SpoolTransport.php
new file mode 100644
index 0000000..c08e0fb
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/SpoolTransport.php
@@ -0,0 +1,33 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages in a queue.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_SpoolTransport extends Swift_Transport_SpoolTransport
+{
+ /**
+ * Create a new SpoolTransport.
+ */
+ public function __construct(Swift_Spool $spool)
+ {
+ $arguments = Swift_DependencyContainer::getInstance()
+ ->createDependenciesFor('transport.spool');
+
+ $arguments[] = $spool;
+
+ \call_user_func_array(
+ [$this, 'Swift_Transport_SpoolTransport::__construct'],
+ $arguments
+ );
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/StreamFilter.php b/include/swiftmailer/lib/classes/Swift/StreamFilter.php
new file mode 100644
index 0000000..362be2e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/StreamFilter.php
@@ -0,0 +1,35 @@
+index = [];
+ $this->tree = [];
+ $this->replace = [];
+ $this->repSize = [];
+
+ $tree = null;
+ $i = null;
+ $last_size = $size = 0;
+ foreach ($search as $i => $search_element) {
+ if (null !== $tree) {
+ $tree[-1] = min(\count($replace) - 1, $i - 1);
+ $tree[-2] = $last_size;
+ }
+ $tree = &$this->tree;
+ if (\is_array($search_element)) {
+ foreach ($search_element as $k => $char) {
+ $this->index[$char] = true;
+ if (!isset($tree[$char])) {
+ $tree[$char] = [];
+ }
+ $tree = &$tree[$char];
+ }
+ $last_size = $k + 1;
+ $size = max($size, $last_size);
+ } else {
+ $last_size = 1;
+ if (!isset($tree[$search_element])) {
+ $tree[$search_element] = [];
+ }
+ $tree = &$tree[$search_element];
+ $size = max($last_size, $size);
+ $this->index[$search_element] = true;
+ }
+ }
+ if (null !== $i) {
+ $tree[-1] = min(\count($replace) - 1, $i);
+ $tree[-2] = $last_size;
+ $this->treeMaxLen = $size;
+ }
+ foreach ($replace as $rep) {
+ if (!\is_array($rep)) {
+ $rep = [$rep];
+ }
+ $this->replace[] = $rep;
+ }
+ for ($i = \count($this->replace) - 1; $i >= 0; --$i) {
+ $this->replace[$i] = $rep = $this->filter($this->replace[$i], $i);
+ $this->repSize[$i] = \count($rep);
+ }
+ }
+
+ /**
+ * Returns true if based on the buffer passed more bytes should be buffered.
+ *
+ * @param array $buffer
+ *
+ * @return bool
+ */
+ public function shouldBuffer($buffer)
+ {
+ $endOfBuffer = end($buffer);
+
+ return isset($this->index[$endOfBuffer]);
+ }
+
+ /**
+ * Perform the actual replacements on $buffer and return the result.
+ *
+ * @param array $buffer
+ * @param int $minReplaces
+ *
+ * @return array
+ */
+ public function filter($buffer, $minReplaces = -1)
+ {
+ if (0 == $this->treeMaxLen) {
+ return $buffer;
+ }
+
+ $newBuffer = [];
+ $buf_size = \count($buffer);
+ $last_size = 0;
+ for ($i = 0; $i < $buf_size; ++$i) {
+ $search_pos = $this->tree;
+ $last_found = PHP_INT_MAX;
+ // We try to find if the next byte is part of a search pattern
+ for ($j = 0; $j <= $this->treeMaxLen; ++$j) {
+ // We have a new byte for a search pattern
+ if (isset($buffer[$p = $i + $j]) && isset($search_pos[$buffer[$p]])) {
+ $search_pos = $search_pos[$buffer[$p]];
+ // We have a complete pattern, save, in case we don't find a better match later
+ if (isset($search_pos[-1]) && $search_pos[-1] < $last_found
+ && $search_pos[-1] > $minReplaces) {
+ $last_found = $search_pos[-1];
+ $last_size = $search_pos[-2];
+ }
+ }
+ // We got a complete pattern
+ elseif (PHP_INT_MAX !== $last_found) {
+ // Adding replacement datas to output buffer
+ $rep_size = $this->repSize[$last_found];
+ for ($j = 0; $j < $rep_size; ++$j) {
+ $newBuffer[] = $this->replace[$last_found][$j];
+ }
+ // We Move cursor forward
+ $i += $last_size - 1;
+ // Edge Case, last position in buffer
+ if ($i >= $buf_size) {
+ $newBuffer[] = $buffer[$i];
+ }
+
+ // We start the next loop
+ continue 2;
+ } else {
+ // this byte is not in a pattern and we haven't found another pattern
+ break;
+ }
+ }
+ // Normal byte, move it to output buffer
+ $newBuffer[] = $buffer[$i];
+ }
+
+ return $newBuffer;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php b/include/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php
new file mode 100644
index 0000000..50a63f1
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilter.php
@@ -0,0 +1,70 @@
+search = $search;
+ $this->replace = $replace;
+ }
+
+ /**
+ * Returns true if based on the buffer passed more bytes should be buffered.
+ *
+ * @param string $buffer
+ *
+ * @return bool
+ */
+ public function shouldBuffer($buffer)
+ {
+ if ('' === $buffer) {
+ return false;
+ }
+
+ $endOfBuffer = substr($buffer, -1);
+ foreach ((array) $this->search as $needle) {
+ if (false !== strpos($needle, $endOfBuffer)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Perform the actual replacements on $buffer and return the result.
+ *
+ * @param string $buffer
+ *
+ * @return string
+ */
+ public function filter($buffer)
+ {
+ return str_replace($this->search, $this->replace, $buffer);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php b/include/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php
new file mode 100644
index 0000000..783b889
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/StreamFilters/StringReplacementFilterFactory.php
@@ -0,0 +1,45 @@
+filters[$search][$replace])) {
+ if (!isset($this->filters[$search])) {
+ $this->filters[$search] = [];
+ }
+
+ if (!isset($this->filters[$search][$replace])) {
+ $this->filters[$search][$replace] = [];
+ }
+
+ $this->filters[$search][$replace] = new Swift_StreamFilters_StringReplacementFilter($search, $replace);
+ }
+
+ return $this->filters[$search][$replace];
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/SwiftException.php b/include/swiftmailer/lib/classes/Swift/SwiftException.php
new file mode 100644
index 0000000..15e68b1
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/SwiftException.php
@@ -0,0 +1,28 @@
+ping()) {
+ * $transport->stop();
+ * $transport->start();
+ * }
+ *
+ * The Transport mechanism will be started, if it is not already.
+ *
+ * It is undefined if the Transport mechanism attempts to restart as long as
+ * the return value reflects whether the mechanism is now functional.
+ *
+ * @return bool TRUE if the transport is alive
+ */
+ public function ping();
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * This is the responsibility of the send method to start the transport if needed.
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null);
+
+ /**
+ * Register a plugin in the Transport.
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin);
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php b/include/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php
new file mode 100644
index 0000000..d2dbd7a
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/AbstractSmtpTransport.php
@@ -0,0 +1,541 @@
+buffer = $buf;
+ $this->eventDispatcher = $dispatcher;
+ $this->addressEncoder = $addressEncoder ?? new Swift_AddressEncoder_IdnAddressEncoder();
+ $this->setLocalDomain($localDomain);
+ }
+
+ /**
+ * Set the name of the local domain which Swift will identify itself as.
+ *
+ * This should be a fully-qualified domain name and should be truly the domain
+ * you're using.
+ *
+ * If your server does not have a domain name, use the IP address. This will
+ * automatically be wrapped in square brackets as described in RFC 5321,
+ * section 4.1.3.
+ *
+ * @param string $domain
+ *
+ * @return $this
+ */
+ public function setLocalDomain($domain)
+ {
+ if ('[' !== substr($domain, 0, 1)) {
+ if (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
+ $domain = '['.$domain.']';
+ } elseif (filter_var($domain, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
+ $domain = '[IPv6:'.$domain.']';
+ }
+ }
+
+ $this->domain = $domain;
+
+ return $this;
+ }
+
+ /**
+ * Get the name of the domain Swift will identify as.
+ *
+ * If an IP address was specified, this will be returned wrapped in square
+ * brackets as described in RFC 5321, section 4.1.3.
+ *
+ * @return string
+ */
+ public function getLocalDomain()
+ {
+ return $this->domain;
+ }
+
+ /**
+ * Sets the source IP.
+ *
+ * @param string $source
+ */
+ public function setSourceIp($source)
+ {
+ $this->sourceIp = $source;
+ }
+
+ /**
+ * Returns the IP used to connect to the destination.
+ *
+ * @return string
+ */
+ public function getSourceIp()
+ {
+ return $this->sourceIp;
+ }
+
+ public function setAddressEncoder(Swift_AddressEncoder $addressEncoder)
+ {
+ $this->addressEncoder = $addressEncoder;
+ }
+
+ public function getAddressEncoder()
+ {
+ return $this->addressEncoder;
+ }
+
+ /**
+ * Start the SMTP connection.
+ */
+ public function start()
+ {
+ if (!$this->started) {
+ if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStarted');
+ if ($evt->bubbleCancelled()) {
+ return;
+ }
+ }
+
+ try {
+ $this->buffer->initialize($this->getBufferParams());
+ } catch (Swift_TransportException $e) {
+ $this->throwException($e);
+ }
+ $this->readGreeting();
+ $this->doHeloCommand();
+
+ if ($evt) {
+ $this->eventDispatcher->dispatchEvent($evt, 'transportStarted');
+ }
+
+ $this->started = true;
+ }
+ }
+
+ /**
+ * Test if an SMTP connection has been established.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return $this->started;
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ if (!$this->isStarted()) {
+ $this->start();
+ }
+
+ $sent = 0;
+ $failedRecipients = (array) $failedRecipients;
+
+ if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ if (!$reversePath = $this->getReversePath($message)) {
+ $this->throwException(new Swift_TransportException('Cannot send message without a sender address'));
+ }
+
+ $to = (array) $message->getTo();
+ $cc = (array) $message->getCc();
+ $bcc = (array) $message->getBcc();
+ $tos = array_merge($to, $cc, $bcc);
+
+ $message->setBcc([]);
+
+ try {
+ $sent += $this->sendTo($message, $reversePath, $tos, $failedRecipients);
+ } finally {
+ $message->setBcc($bcc);
+ }
+
+ if ($evt) {
+ if ($sent == \count($to) + \count($cc) + \count($bcc)) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ } elseif ($sent > 0) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_TENTATIVE);
+ } else {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_FAILED);
+ }
+ $evt->setFailedRecipients($failedRecipients);
+ $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $message->generateId(); //Make sure a new Message ID is used
+
+ return $sent;
+ }
+
+ /**
+ * Stop the SMTP connection.
+ */
+ public function stop()
+ {
+ if ($this->started) {
+ if ($evt = $this->eventDispatcher->createTransportChangeEvent($this)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'beforeTransportStopped');
+ if ($evt->bubbleCancelled()) {
+ return;
+ }
+ }
+
+ try {
+ $this->executeCommand("QUIT\r\n", [221]);
+ } catch (Swift_TransportException $e) {
+ }
+
+ try {
+ $this->buffer->terminate();
+
+ if ($evt) {
+ $this->eventDispatcher->dispatchEvent($evt, 'transportStopped');
+ }
+ } catch (Swift_TransportException $e) {
+ $this->throwException($e);
+ }
+ }
+ $this->started = false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ping()
+ {
+ try {
+ if (!$this->isStarted()) {
+ $this->start();
+ }
+
+ $this->executeCommand("NOOP\r\n", [250]);
+ } catch (Swift_TransportException $e) {
+ try {
+ $this->stop();
+ } catch (Swift_TransportException $e) {
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Register a plugin.
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->eventDispatcher->bindEventListener($plugin);
+ }
+
+ /**
+ * Reset the current mail transaction.
+ */
+ public function reset()
+ {
+ $this->executeCommand("RSET\r\n", [250], $failures, true);
+ }
+
+ /**
+ * Get the IoBuffer where read/writes are occurring.
+ *
+ * @return Swift_Transport_IoBuffer
+ */
+ public function getBuffer()
+ {
+ return $this->buffer;
+ }
+
+ /**
+ * Run a command against the buffer, expecting the given response codes.
+ *
+ * If no response codes are given, the response will not be validated.
+ * If codes are given, an exception will be thrown on an invalid response.
+ * If the command is RCPT TO, and the pipeline is non-empty, no exception
+ * will be thrown; instead the failing address is added to $failures.
+ *
+ * @param string $command
+ * @param int[] $codes
+ * @param string[] $failures An array of failures by-reference
+ * @param bool $pipeline Do not wait for response
+ * @param string $address the address, if command is RCPT TO
+ *
+ * @return string|null The server response, or null if pipelining is enabled
+ */
+ public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null)
+ {
+ $failures = (array) $failures;
+ $seq = $this->buffer->write($command);
+ if ($evt = $this->eventDispatcher->createCommandEvent($this, $command, $codes)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'commandSent');
+ }
+
+ $this->pipeline[] = [$command, $seq, $codes, $address];
+
+ if ($pipeline && $this->pipelining) {
+ return null;
+ }
+
+ $response = null;
+
+ while ($this->pipeline) {
+ list($command, $seq, $codes, $address) = array_shift($this->pipeline);
+ $response = $this->getFullResponse($seq);
+ try {
+ $this->assertResponseCode($response, $codes);
+ } catch (Swift_TransportException $e) {
+ if ($this->pipeline && $address) {
+ $failures[] = $address;
+ } else {
+ $this->throwException($e);
+ }
+ }
+ }
+
+ return $response;
+ }
+
+ /** Read the opening SMTP greeting */
+ protected function readGreeting()
+ {
+ $this->assertResponseCode($this->getFullResponse(0), [220]);
+ }
+
+ /** Send the HELO welcome */
+ protected function doHeloCommand()
+ {
+ $this->executeCommand(
+ sprintf("HELO %s\r\n", $this->domain), [250]
+ );
+ }
+
+ /** Send the MAIL FROM command */
+ protected function doMailFromCommand($address)
+ {
+ $address = $this->addressEncoder->encodeString($address);
+ $this->executeCommand(
+ sprintf("MAIL FROM:<%s>\r\n", $address), [250], $failures, true
+ );
+ }
+
+ /** Send the RCPT TO command */
+ protected function doRcptToCommand($address)
+ {
+ $address = $this->addressEncoder->encodeString($address);
+ $this->executeCommand(
+ sprintf("RCPT TO:<%s>\r\n", $address), [250, 251, 252], $failures, true, $address
+ );
+ }
+
+ /** Send the DATA command */
+ protected function doDataCommand(&$failedRecipients)
+ {
+ $this->executeCommand("DATA\r\n", [354], $failedRecipients);
+ }
+
+ /** Stream the contents of the message over the buffer */
+ protected function streamMessage(Swift_Mime_SimpleMessage $message)
+ {
+ $this->buffer->setWriteTranslations(["\r\n." => "\r\n.."]);
+ try {
+ $message->toByteStream($this->buffer);
+ $this->buffer->flushBuffers();
+ } catch (Swift_TransportException $e) {
+ $this->throwException($e);
+ }
+ $this->buffer->setWriteTranslations([]);
+ $this->executeCommand("\r\n.\r\n", [250]);
+ }
+
+ /** Determine the best-use reverse path for this message */
+ protected function getReversePath(Swift_Mime_SimpleMessage $message)
+ {
+ $return = $message->getReturnPath();
+ $sender = $message->getSender();
+ $from = $message->getFrom();
+ $path = null;
+ if (!empty($return)) {
+ $path = $return;
+ } elseif (!empty($sender)) {
+ // Don't use array_keys
+ reset($sender); // Reset Pointer to first pos
+ $path = key($sender); // Get key
+ } elseif (!empty($from)) {
+ reset($from); // Reset Pointer to first pos
+ $path = key($from); // Get key
+ }
+
+ return $path;
+ }
+
+ /** Throw a TransportException, first sending it to any listeners */
+ protected function throwException(Swift_TransportException $e)
+ {
+ if ($evt = $this->eventDispatcher->createTransportExceptionEvent($this, $e)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'exceptionThrown');
+ if (!$evt->bubbleCancelled()) {
+ throw $e;
+ }
+ } else {
+ throw $e;
+ }
+ }
+
+ /** Throws an Exception if a response code is incorrect */
+ protected function assertResponseCode($response, $wanted)
+ {
+ if (!$response) {
+ $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got an empty response'));
+ }
+
+ list($code) = sscanf($response, '%3d');
+ $valid = (empty($wanted) || \in_array($code, $wanted));
+
+ if ($evt = $this->eventDispatcher->createResponseEvent($this, $response,
+ $valid)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'responseReceived');
+ }
+
+ if (!$valid) {
+ $this->throwException(new Swift_TransportException('Expected response code '.implode('/', $wanted).' but got code "'.$code.'", with message "'.$response.'"', $code));
+ }
+ }
+
+ /** Get an entire multi-line response using its sequence number */
+ protected function getFullResponse($seq)
+ {
+ $response = '';
+ try {
+ do {
+ $line = $this->buffer->readLine($seq);
+ $response .= $line;
+ } while (null !== $line && false !== $line && ' ' != $line[3]);
+ } catch (Swift_TransportException $e) {
+ $this->throwException($e);
+ } catch (Swift_IoException $e) {
+ $this->throwException(new Swift_TransportException($e->getMessage(), 0, $e));
+ }
+
+ return $response;
+ }
+
+ /** Send an email to the given recipients from the given reverse path */
+ private function doMailTransaction($message, $reversePath, array $recipients, array &$failedRecipients)
+ {
+ $sent = 0;
+ $this->doMailFromCommand($reversePath);
+ foreach ($recipients as $forwardPath) {
+ try {
+ $this->doRcptToCommand($forwardPath);
+ ++$sent;
+ } catch (Swift_TransportException $e) {
+ $failedRecipients[] = $forwardPath;
+ } catch (Swift_AddressEncoderException $e) {
+ $failedRecipients[] = $forwardPath;
+ }
+ }
+
+ if (0 != $sent) {
+ $sent += \count($failedRecipients);
+ $this->doDataCommand($failedRecipients);
+ $sent -= \count($failedRecipients);
+
+ $this->streamMessage($message);
+ } else {
+ $this->reset();
+ }
+
+ return $sent;
+ }
+
+ /** Send a message to the given To: recipients */
+ private function sendTo(Swift_Mime_SimpleMessage $message, $reversePath, array $to, array &$failedRecipients)
+ {
+ if (empty($to)) {
+ return 0;
+ }
+
+ return $this->doMailTransaction($message, $reversePath, array_keys($to),
+ $failedRecipients);
+ }
+
+ /**
+ * Destructor.
+ */
+ public function __destruct()
+ {
+ try {
+ $this->stop();
+ } catch (Exception $e) {
+ }
+ }
+
+ public function __sleep()
+ {
+ throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
+ }
+
+ public function __wakeup()
+ {
+ throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php
new file mode 100644
index 0000000..e7ccf6d
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/CramMd5Authenticator.php
@@ -0,0 +1,75 @@
+executeCommand("AUTH CRAM-MD5\r\n", [334]);
+ $challenge = base64_decode(substr($challenge, 4));
+ $message = base64_encode(
+ $username.' '.$this->getResponse($password, $challenge)
+ );
+ $agent->executeCommand(sprintf("%s\r\n", $message), [235]);
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", [250]);
+
+ throw $e;
+ }
+ }
+
+ /**
+ * Generate a CRAM-MD5 response from a server challenge.
+ *
+ * @param string $secret
+ * @param string $challenge
+ *
+ * @return string
+ */
+ private function getResponse($secret, $challenge)
+ {
+ if (\strlen($secret) > 64) {
+ $secret = pack('H32', md5($secret));
+ }
+
+ if (\strlen($secret) < 64) {
+ $secret = str_pad($secret, 64, \chr(0));
+ }
+
+ $k_ipad = substr($secret, 0, 64) ^ str_repeat(\chr(0x36), 64);
+ $k_opad = substr($secret, 0, 64) ^ str_repeat(\chr(0x5C), 64);
+
+ $inner = pack('H32', md5($k_ipad.$challenge));
+ $digest = md5($k_opad.$inner);
+
+ return $digest;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php
new file mode 100644
index 0000000..458c038
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/LoginAuthenticator.php
@@ -0,0 +1,45 @@
+executeCommand("AUTH LOGIN\r\n", [334]);
+ $agent->executeCommand(sprintf("%s\r\n", base64_encode($username)), [334]);
+ $agent->executeCommand(sprintf("%s\r\n", base64_encode($password)), [235]);
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", [250]);
+
+ throw $e;
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php
new file mode 100644
index 0000000..21c070e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/NTLMAuthenticator.php
@@ -0,0 +1,681 @@
+
+ */
+class Swift_Transport_Esmtp_Auth_NTLMAuthenticator implements Swift_Transport_Esmtp_Authenticator
+{
+ const NTLMSIG = "NTLMSSP\x00";
+ const DESCONST = 'KGS!@#$%';
+
+ /**
+ * Get the name of the AUTH mechanism this Authenticator handles.
+ *
+ * @return string
+ */
+ public function getAuthKeyword()
+ {
+ return 'NTLM';
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @throws \LogicException
+ */
+ public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
+ {
+ if (!\function_exists('openssl_encrypt')) {
+ throw new LogicException('The OpenSSL extension must be enabled to use the NTLM authenticator.');
+ }
+
+ if (!\function_exists('bcmul')) {
+ throw new LogicException('The BCMath functions must be enabled to use the NTLM authenticator.');
+ }
+
+ try {
+ // execute AUTH command and filter out the code at the beginning
+ // AUTH NTLM xxxx
+ $response = base64_decode(substr(trim($this->sendMessage1($agent)), 4));
+
+ // extra parameters for our unit cases
+ $timestamp = \func_num_args() > 3 ? func_get_arg(3) : $this->getCorrectTimestamp(bcmul(microtime(true), '1000'));
+ $client = \func_num_args() > 4 ? func_get_arg(4) : random_bytes(8);
+
+ // Message 3 response
+ $this->sendMessage3($response, $username, $password, $timestamp, $client, $agent);
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", [250]);
+
+ throw $e;
+ }
+ }
+
+ protected function si2bin($si, $bits = 32)
+ {
+ $bin = null;
+ if ($si >= -2 ** ($bits - 1) && ($si <= 2 ** ($bits - 1))) {
+ // positive or zero
+ if ($si >= 0) {
+ $bin = base_convert($si, 10, 2);
+ // pad to $bits bit
+ $bin_length = \strlen($bin);
+ if ($bin_length < $bits) {
+ $bin = str_repeat('0', $bits - $bin_length).$bin;
+ }
+ } else {
+ // negative
+ $si = -$si - 2 ** $bits;
+ $bin = base_convert($si, 10, 2);
+ $bin_length = \strlen($bin);
+ if ($bin_length > $bits) {
+ $bin = str_repeat('1', $bits - $bin_length).$bin;
+ }
+ }
+ }
+
+ return $bin;
+ }
+
+ /**
+ * Send our auth message and returns the response.
+ *
+ * @return string SMTP Response
+ */
+ protected function sendMessage1(Swift_Transport_SmtpAgent $agent)
+ {
+ $message = $this->createMessage1();
+
+ return $agent->executeCommand(sprintf("AUTH %s %s\r\n", $this->getAuthKeyword(), base64_encode($message)), [334]);
+ }
+
+ /**
+ * Fetch all details of our response (message 2).
+ *
+ * @param string $response
+ *
+ * @return array our response parsed
+ */
+ protected function parseMessage2($response)
+ {
+ $responseHex = bin2hex($response);
+ $length = floor(hexdec(substr($responseHex, 28, 4)) / 256) * 2;
+ $offset = floor(hexdec(substr($responseHex, 32, 4)) / 256) * 2;
+ $challenge = hex2bin(substr($responseHex, 48, 16));
+ $context = hex2bin(substr($responseHex, 64, 16));
+ $targetInfoH = hex2bin(substr($responseHex, 80, 16));
+ $targetName = hex2bin(substr($responseHex, $offset, $length));
+ $offset = floor(hexdec(substr($responseHex, 88, 4)) / 256) * 2;
+ $targetInfoBlock = substr($responseHex, $offset);
+ list($domainName, $serverName, $DNSDomainName, $DNSServerName, $terminatorByte) = $this->readSubBlock($targetInfoBlock);
+
+ return [
+ $challenge,
+ $context,
+ $targetInfoH,
+ $targetName,
+ $domainName,
+ $serverName,
+ $DNSDomainName,
+ $DNSServerName,
+ hex2bin($targetInfoBlock),
+ $terminatorByte,
+ ];
+ }
+
+ /**
+ * Read the blob information in from message2.
+ *
+ * @return array
+ */
+ protected function readSubBlock($block)
+ {
+ // remove terminatorByte cause it's always the same
+ $block = substr($block, 0, -8);
+
+ $length = \strlen($block);
+ $offset = 0;
+ $data = [];
+ while ($offset < $length) {
+ $blockLength = hexdec(substr(substr($block, $offset, 8), -4)) / 256;
+ $offset += 8;
+ $data[] = hex2bin(substr($block, $offset, $blockLength * 2));
+ $offset += $blockLength * 2;
+ }
+
+ if (3 == \count($data)) {
+ $data[] = $data[2];
+ $data[2] = '';
+ }
+
+ $data[] = $this->createByte('00');
+
+ return $data;
+ }
+
+ /**
+ * Send our final message with all our data.
+ *
+ * @param string $response Message 1 response (message 2)
+ * @param string $username
+ * @param string $password
+ * @param string $timestamp
+ * @param string $client
+ * @param bool $v2 Use version2 of the protocol
+ *
+ * @return string
+ */
+ protected function sendMessage3($response, $username, $password, $timestamp, $client, Swift_Transport_SmtpAgent $agent, $v2 = true)
+ {
+ list($domain, $username) = $this->getDomainAndUsername($username);
+ //$challenge, $context, $targetInfoH, $targetName, $domainName, $workstation, $DNSDomainName, $DNSServerName, $blob, $ter
+ list($challenge, , , , , $workstation, , , $blob) = $this->parseMessage2($response);
+
+ if (!$v2) {
+ // LMv1
+ $lmResponse = $this->createLMPassword($password, $challenge);
+ // NTLMv1
+ $ntlmResponse = $this->createNTLMPassword($password, $challenge);
+ } else {
+ // LMv2
+ $lmResponse = $this->createLMv2Password($password, $username, $domain, $challenge, $client);
+ // NTLMv2
+ $ntlmResponse = $this->createNTLMv2Hash($password, $username, $domain, $challenge, $blob, $timestamp, $client);
+ }
+
+ $message = $this->createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse);
+
+ return $agent->executeCommand(sprintf("%s\r\n", base64_encode($message)), [235]);
+ }
+
+ /**
+ * Create our message 1.
+ *
+ * @return string
+ */
+ protected function createMessage1()
+ {
+ return self::NTLMSIG
+ .$this->createByte('01') // Message 1
+.$this->createByte('0702'); // Flags
+ }
+
+ /**
+ * Create our message 3.
+ *
+ * @param string $domain
+ * @param string $username
+ * @param string $workstation
+ * @param string $lmResponse
+ * @param string $ntlmResponse
+ *
+ * @return string
+ */
+ protected function createMessage3($domain, $username, $workstation, $lmResponse, $ntlmResponse)
+ {
+ // Create security buffers
+ $domainSec = $this->createSecurityBuffer($domain, 64);
+ $domainInfo = $this->readSecurityBuffer(bin2hex($domainSec));
+ $userSec = $this->createSecurityBuffer($username, ($domainInfo[0] + $domainInfo[1]) / 2);
+ $userInfo = $this->readSecurityBuffer(bin2hex($userSec));
+ $workSec = $this->createSecurityBuffer($workstation, ($userInfo[0] + $userInfo[1]) / 2);
+ $workInfo = $this->readSecurityBuffer(bin2hex($workSec));
+ $lmSec = $this->createSecurityBuffer($lmResponse, ($workInfo[0] + $workInfo[1]) / 2, true);
+ $lmInfo = $this->readSecurityBuffer(bin2hex($lmSec));
+ $ntlmSec = $this->createSecurityBuffer($ntlmResponse, ($lmInfo[0] + $lmInfo[1]) / 2, true);
+
+ return self::NTLMSIG
+ .$this->createByte('03') // TYPE 3 message
+.$lmSec // LM response header
+.$ntlmSec // NTLM response header
+.$domainSec // Domain header
+.$userSec // User header
+.$workSec // Workstation header
+.$this->createByte('000000009a', 8) // session key header (empty)
+.$this->createByte('01020000') // FLAGS
+.$this->convertTo16bit($domain) // domain name
+.$this->convertTo16bit($username) // username
+.$this->convertTo16bit($workstation) // workstation
+.$lmResponse
+ .$ntlmResponse;
+ }
+
+ /**
+ * @param string $timestamp Epoch timestamp in microseconds
+ * @param string $client Random bytes
+ * @param string $targetInfo
+ *
+ * @return string
+ */
+ protected function createBlob($timestamp, $client, $targetInfo)
+ {
+ return $this->createByte('0101')
+ .$this->createByte('00')
+ .$timestamp
+ .$client
+ .$this->createByte('00')
+ .$targetInfo
+ .$this->createByte('00');
+ }
+
+ /**
+ * Get domain and username from our username.
+ *
+ * @example DOMAIN\username
+ *
+ * @param string $name
+ *
+ * @return array
+ */
+ protected function getDomainAndUsername($name)
+ {
+ if (false !== strpos($name, '\\')) {
+ return explode('\\', $name);
+ }
+
+ if (false !== strpos($name, '@')) {
+ list($user, $domain) = explode('@', $name);
+
+ return [$domain, $user];
+ }
+
+ // no domain passed
+ return ['', $name];
+ }
+
+ /**
+ * Create LMv1 response.
+ *
+ * @param string $password
+ * @param string $challenge
+ *
+ * @return string
+ */
+ protected function createLMPassword($password, $challenge)
+ {
+ // FIRST PART
+ $password = $this->createByte(strtoupper($password), 14, false);
+ list($key1, $key2) = str_split($password, 7);
+
+ $desKey1 = $this->createDesKey($key1);
+ $desKey2 = $this->createDesKey($key2);
+
+ $constantDecrypt = $this->createByte($this->desEncrypt(self::DESCONST, $desKey1).$this->desEncrypt(self::DESCONST, $desKey2), 21, false);
+
+ // SECOND PART
+ list($key1, $key2, $key3) = str_split($constantDecrypt, 7);
+
+ $desKey1 = $this->createDesKey($key1);
+ $desKey2 = $this->createDesKey($key2);
+ $desKey3 = $this->createDesKey($key3);
+
+ return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
+ }
+
+ /**
+ * Create NTLMv1 response.
+ *
+ * @param string $password
+ * @param string $challenge
+ *
+ * @return string
+ */
+ protected function createNTLMPassword($password, $challenge)
+ {
+ // FIRST PART
+ $ntlmHash = $this->createByte($this->md4Encrypt($password), 21, false);
+ list($key1, $key2, $key3) = str_split($ntlmHash, 7);
+
+ $desKey1 = $this->createDesKey($key1);
+ $desKey2 = $this->createDesKey($key2);
+ $desKey3 = $this->createDesKey($key3);
+
+ return $this->desEncrypt($challenge, $desKey1).$this->desEncrypt($challenge, $desKey2).$this->desEncrypt($challenge, $desKey3);
+ }
+
+ /**
+ * Convert a normal timestamp to a tenth of a microtime epoch time.
+ *
+ * @param string $time
+ *
+ * @return string
+ */
+ protected function getCorrectTimestamp($time)
+ {
+ // Get our timestamp (tricky!)
+ $time = number_format($time, 0, '.', ''); // save microtime to string
+ $time = bcadd($time, '11644473600000', 0); // add epoch time
+ $time = bcmul($time, 10000, 0); // tenths of a microsecond.
+
+ $binary = $this->si2bin($time, 64); // create 64 bit binary string
+ $timestamp = '';
+ for ($i = 0; $i < 8; ++$i) {
+ $timestamp .= \chr(bindec(substr($binary, -(($i + 1) * 8), 8)));
+ }
+
+ return $timestamp;
+ }
+
+ /**
+ * Create LMv2 response.
+ *
+ * @param string $password
+ * @param string $username
+ * @param string $domain
+ * @param string $challenge NTLM Challenge
+ * @param string $client Random string
+ *
+ * @return string
+ */
+ protected function createLMv2Password($password, $username, $domain, $challenge, $client)
+ {
+ $lmPass = '00'; // by default 00
+ // if $password > 15 than we can't use this method
+ if (\strlen($password) <= 15) {
+ $ntlmHash = $this->md4Encrypt($password);
+ $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain));
+
+ $lmPass = bin2hex($this->md5Encrypt($ntml2Hash, $challenge.$client).$client);
+ }
+
+ return $this->createByte($lmPass, 24);
+ }
+
+ /**
+ * Create NTLMv2 response.
+ *
+ * @param string $password
+ * @param string $username
+ * @param string $domain
+ * @param string $challenge Hex values
+ * @param string $targetInfo Hex values
+ * @param string $timestamp
+ * @param string $client Random bytes
+ *
+ * @return string
+ *
+ * @see http://davenport.sourceforge.net/ntlm.html#theNtlmResponse
+ */
+ protected function createNTLMv2Hash($password, $username, $domain, $challenge, $targetInfo, $timestamp, $client)
+ {
+ $ntlmHash = $this->md4Encrypt($password);
+ $ntml2Hash = $this->md5Encrypt($ntlmHash, $this->convertTo16bit(strtoupper($username).$domain));
+
+ // create blob
+ $blob = $this->createBlob($timestamp, $client, $targetInfo);
+
+ $ntlmv2Response = $this->md5Encrypt($ntml2Hash, $challenge.$blob);
+
+ return $ntlmv2Response.$blob;
+ }
+
+ protected function createDesKey($key)
+ {
+ $material = [bin2hex($key[0])];
+ $len = \strlen($key);
+ for ($i = 1; $i < $len; ++$i) {
+ list($high, $low) = str_split(bin2hex($key[$i]));
+ $v = $this->castToByte(\ord($key[$i - 1]) << (7 + 1 - $i) | $this->uRShift(hexdec(dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xf)), $i));
+ $material[] = str_pad(substr(dechex($v), -2), 2, '0', STR_PAD_LEFT); // cast to byte
+ }
+ $material[] = str_pad(substr(dechex($this->castToByte(\ord($key[6]) << 1)), -2), 2, '0');
+
+ // odd parity
+ foreach ($material as $k => $v) {
+ $b = $this->castToByte(hexdec($v));
+ $needsParity = 0 == (($this->uRShift($b, 7) ^ $this->uRShift($b, 6) ^ $this->uRShift($b, 5)
+ ^ $this->uRShift($b, 4) ^ $this->uRShift($b, 3) ^ $this->uRShift($b, 2)
+ ^ $this->uRShift($b, 1)) & 0x01);
+
+ list($high, $low) = str_split($v);
+ if ($needsParity) {
+ $material[$k] = dechex(hexdec($high) | 0x0).dechex(hexdec($low) | 0x1);
+ } else {
+ $material[$k] = dechex(hexdec($high) & 0xf).dechex(hexdec($low) & 0xe);
+ }
+ }
+
+ return hex2bin(implode('', $material));
+ }
+
+ /** HELPER FUNCTIONS */
+
+ /**
+ * Create our security buffer depending on length and offset.
+ *
+ * @param string $value Value we want to put in
+ * @param int $offset start of value
+ * @param bool $is16 Do we 16bit string or not?
+ *
+ * @return string
+ */
+ protected function createSecurityBuffer($value, $offset, $is16 = false)
+ {
+ $length = \strlen(bin2hex($value));
+ $length = $is16 ? $length / 2 : $length;
+ $length = $this->createByte(str_pad(dechex($length), 2, '0', STR_PAD_LEFT), 2);
+
+ return $length.$length.$this->createByte(dechex($offset), 4);
+ }
+
+ /**
+ * Read our security buffer to fetch length and offset of our value.
+ *
+ * @param string $value Securitybuffer in hex
+ *
+ * @return array array with length and offset
+ */
+ protected function readSecurityBuffer($value)
+ {
+ $length = floor(hexdec(substr($value, 0, 4)) / 256) * 2;
+ $offset = floor(hexdec(substr($value, 8, 4)) / 256) * 2;
+
+ return [$length, $offset];
+ }
+
+ /**
+ * Cast to byte java equivalent to (byte).
+ *
+ * @param int $v
+ *
+ * @return int
+ */
+ protected function castToByte($v)
+ {
+ return (($v + 128) % 256) - 128;
+ }
+
+ /**
+ * Java unsigned right bitwise
+ * $a >>> $b.
+ *
+ * @param int $a
+ * @param int $b
+ *
+ * @return int
+ */
+ protected function uRShift($a, $b)
+ {
+ if (0 == $b) {
+ return $a;
+ }
+
+ return ($a >> $b) & ~(1 << (8 * PHP_INT_SIZE - 1) >> ($b - 1));
+ }
+
+ /**
+ * Right padding with 0 to certain length.
+ *
+ * @param string $input
+ * @param int $bytes Length of bytes
+ * @param bool $isHex Did we provided hex value
+ *
+ * @return string
+ */
+ protected function createByte($input, $bytes = 4, $isHex = true)
+ {
+ if ($isHex) {
+ $byte = hex2bin(str_pad($input, $bytes * 2, '00'));
+ } else {
+ $byte = str_pad($input, $bytes, "\x00");
+ }
+
+ return $byte;
+ }
+
+ /** ENCRYPTION ALGORITHMS */
+
+ /**
+ * DES Encryption.
+ *
+ * @param string $value An 8-byte string
+ * @param string $key
+ *
+ * @return string
+ */
+ protected function desEncrypt($value, $key)
+ {
+ return substr(openssl_encrypt($value, 'DES-ECB', $key, \OPENSSL_RAW_DATA), 0, 8);
+ }
+
+ /**
+ * MD5 Encryption.
+ *
+ * @param string $key Encryption key
+ * @param string $msg Message to encrypt
+ *
+ * @return string
+ */
+ protected function md5Encrypt($key, $msg)
+ {
+ $blocksize = 64;
+ if (\strlen($key) > $blocksize) {
+ $key = pack('H*', md5($key));
+ }
+
+ $key = str_pad($key, $blocksize, "\0");
+ $ipadk = $key ^ str_repeat("\x36", $blocksize);
+ $opadk = $key ^ str_repeat("\x5c", $blocksize);
+
+ return pack('H*', md5($opadk.pack('H*', md5($ipadk.$msg))));
+ }
+
+ /**
+ * MD4 Encryption.
+ *
+ * @param string $input
+ *
+ * @return string
+ *
+ * @see https://secure.php.net/manual/en/ref.hash.php
+ */
+ protected function md4Encrypt($input)
+ {
+ $input = $this->convertTo16bit($input);
+
+ return \function_exists('hash') ? hex2bin(hash('md4', $input)) : mhash(MHASH_MD4, $input);
+ }
+
+ /**
+ * Convert UTF-8 to UTF-16.
+ *
+ * @param string $input
+ *
+ * @return string
+ */
+ protected function convertTo16bit($input)
+ {
+ return iconv('UTF-8', 'UTF-16LE', $input);
+ }
+
+ /**
+ * @param string $message
+ */
+ protected function debug($message)
+ {
+ $message = bin2hex($message);
+ $messageId = substr($message, 16, 8);
+ echo substr($message, 0, 16)." NTLMSSP Signature
\n";
+ echo $messageId." Type Indicator
\n";
+
+ if ('02000000' == $messageId) {
+ $map = [
+ 'Challenge',
+ 'Context',
+ 'Target Information Security Buffer',
+ 'Target Name Data',
+ 'NetBIOS Domain Name',
+ 'NetBIOS Server Name',
+ 'DNS Domain Name',
+ 'DNS Server Name',
+ 'BLOB',
+ 'Target Information Terminator',
+ ];
+
+ $data = $this->parseMessage2(hex2bin($message));
+
+ foreach ($map as $key => $value) {
+ echo bin2hex($data[$key]).' - '.$data[$key].' ||| '.$value."
\n";
+ }
+ } elseif ('03000000' == $messageId) {
+ $i = 0;
+ $data[$i++] = substr($message, 24, 16);
+ list($lmLength, $lmOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 40, 16);
+ list($ntmlLength, $ntmlOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 56, 16);
+ list($targetLength, $targetOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 72, 16);
+ list($userLength, $userOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 88, 16);
+ list($workLength, $workOffset) = $this->readSecurityBuffer($data[$i - 1]);
+
+ $data[$i++] = substr($message, 104, 16);
+ $data[$i++] = substr($message, 120, 8);
+ $data[$i++] = substr($message, $targetOffset, $targetLength);
+ $data[$i++] = substr($message, $userOffset, $userLength);
+ $data[$i++] = substr($message, $workOffset, $workLength);
+ $data[$i++] = substr($message, $lmOffset, $lmLength);
+ $data[$i] = substr($message, $ntmlOffset, $ntmlLength);
+
+ $map = [
+ 'LM Response Security Buffer',
+ 'NTLM Response Security Buffer',
+ 'Target Name Security Buffer',
+ 'User Name Security Buffer',
+ 'Workstation Name Security Buffer',
+ 'Session Key Security Buffer',
+ 'Flags',
+ 'Target Name Data',
+ 'User Name Data',
+ 'Workstation Name Data',
+ 'LM Response Data',
+ 'NTLM Response Data',
+ ];
+
+ foreach ($map as $key => $value) {
+ echo $data[$key].' - '.hex2bin($data[$key]).' ||| '.$value."
\n";
+ }
+ }
+
+ echo '
';
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php
new file mode 100644
index 0000000..41d0a50
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/PlainAuthenticator.php
@@ -0,0 +1,44 @@
+executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), [235]);
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", [250]);
+
+ throw $e;
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php
new file mode 100644
index 0000000..859f22f
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Auth/XOAuth2Authenticator.php
@@ -0,0 +1,64 @@
+
+ * $transport = (new Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
+ * ->setAuthMode('XOAUTH2')
+ * ->setUsername('YOUR_EMAIL_ADDRESS')
+ * ->setPassword('YOUR_ACCESS_TOKEN');
+ *
+ *
+ * @author xu.li
+ *
+ * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol
+ */
+class Swift_Transport_Esmtp_Auth_XOAuth2Authenticator implements Swift_Transport_Esmtp_Authenticator
+{
+ /**
+ * Get the name of the AUTH mechanism this Authenticator handles.
+ *
+ * @return string
+ */
+ public function getAuthKeyword()
+ {
+ return 'XOAUTH2';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(Swift_Transport_SmtpAgent $agent, $email, $token)
+ {
+ try {
+ $param = $this->constructXOAuth2Params($email, $token);
+ $agent->executeCommand('AUTH XOAUTH2 '.$param."\r\n", [235]);
+
+ return true;
+ } catch (Swift_TransportException $e) {
+ $agent->executeCommand("RSET\r\n", [250]);
+
+ throw $e;
+ }
+ }
+
+ /**
+ * Construct the auth parameter.
+ *
+ * @see https://developers.google.com/google-apps/gmail/xoauth2_protocol#the_sasl_xoauth2_mechanism
+ */
+ protected function constructXOAuth2Params($email, $token)
+ {
+ return base64_encode("user=$email\1auth=Bearer $token\1\1");
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php
new file mode 100644
index 0000000..dd55913
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/AuthHandler.php
@@ -0,0 +1,268 @@
+setAuthenticators($authenticators);
+ }
+
+ /**
+ * Set the Authenticators which can process a login request.
+ *
+ * @param Swift_Transport_Esmtp_Authenticator[] $authenticators
+ */
+ public function setAuthenticators(array $authenticators)
+ {
+ $this->authenticators = $authenticators;
+ }
+
+ /**
+ * Get the Authenticators which can process a login request.
+ *
+ * @return Swift_Transport_Esmtp_Authenticator[]
+ */
+ public function getAuthenticators()
+ {
+ return $this->authenticators;
+ }
+
+ /**
+ * Set the username to authenticate with.
+ *
+ * @param string $username
+ */
+ public function setUsername($username)
+ {
+ $this->username = $username;
+ }
+
+ /**
+ * Get the username to authenticate with.
+ *
+ * @return string
+ */
+ public function getUsername()
+ {
+ return $this->username;
+ }
+
+ /**
+ * Set the password to authenticate with.
+ *
+ * @param string $password
+ */
+ public function setPassword($password)
+ {
+ $this->password = $password;
+ }
+
+ /**
+ * Get the password to authenticate with.
+ *
+ * @return string
+ */
+ public function getPassword()
+ {
+ return $this->password;
+ }
+
+ /**
+ * Set the auth mode to use to authenticate.
+ *
+ * @param string $mode
+ */
+ public function setAuthMode($mode)
+ {
+ $this->auth_mode = $mode;
+ }
+
+ /**
+ * Get the auth mode to use to authenticate.
+ *
+ * @return string
+ */
+ public function getAuthMode()
+ {
+ return $this->auth_mode;
+ }
+
+ /**
+ * Get the name of the ESMTP extension this handles.
+ *
+ * @return string
+ */
+ public function getHandledKeyword()
+ {
+ return 'AUTH';
+ }
+
+ /**
+ * Set the parameters which the EHLO greeting indicated.
+ *
+ * @param string[] $parameters
+ */
+ public function setKeywordParams(array $parameters)
+ {
+ $this->esmtpParams = $parameters;
+ }
+
+ /**
+ * Runs immediately after a EHLO has been issued.
+ *
+ * @param Swift_Transport_SmtpAgent $agent to read/write
+ */
+ public function afterEhlo(Swift_Transport_SmtpAgent $agent)
+ {
+ if ($this->username) {
+ $count = 0;
+ $errors = [];
+ foreach ($this->getAuthenticatorsForAgent() as $authenticator) {
+ if (\in_array(strtolower($authenticator->getAuthKeyword()), array_map('strtolower', $this->esmtpParams))) {
+ ++$count;
+ try {
+ if ($authenticator->authenticate($agent, $this->username, $this->password)) {
+ return;
+ }
+ } catch (Swift_TransportException $e) {
+ // keep the error message, but tries the other authenticators
+ $errors[] = [$authenticator->getAuthKeyword(), $e->getMessage()];
+ }
+ }
+ }
+
+ $message = 'Failed to authenticate on SMTP server with username "'.$this->username.'" using '.$count.' possible authenticators.';
+ foreach ($errors as $error) {
+ $message .= ' Authenticator '.$error[0].' returned '.$error[1].'.';
+ }
+ throw new Swift_TransportException($message);
+ }
+ }
+
+ /**
+ * Not used.
+ */
+ public function getMailParams()
+ {
+ return [];
+ }
+
+ /**
+ * Not used.
+ */
+ public function getRcptParams()
+ {
+ return [];
+ }
+
+ /**
+ * Not used.
+ */
+ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
+ {
+ }
+
+ /**
+ * Returns +1, -1 or 0 according to the rules for usort().
+ *
+ * This method is called to ensure extensions can be execute in an appropriate order.
+ *
+ * @param string $esmtpKeyword to compare with
+ *
+ * @return int
+ */
+ public function getPriorityOver($esmtpKeyword)
+ {
+ return 0;
+ }
+
+ /**
+ * Returns an array of method names which are exposed to the Esmtp class.
+ *
+ * @return string[]
+ */
+ public function exposeMixinMethods()
+ {
+ return ['setUsername', 'getUsername', 'setPassword', 'getPassword', 'setAuthMode', 'getAuthMode'];
+ }
+
+ /**
+ * Not used.
+ */
+ public function resetState()
+ {
+ }
+
+ /**
+ * Returns the authenticator list for the given agent.
+ *
+ * @return array
+ */
+ protected function getAuthenticatorsForAgent()
+ {
+ if (!$mode = strtolower($this->auth_mode)) {
+ return $this->authenticators;
+ }
+
+ foreach ($this->authenticators as $authenticator) {
+ if (strtolower($authenticator->getAuthKeyword()) == $mode) {
+ return [$authenticator];
+ }
+ }
+
+ throw new Swift_TransportException('Auth mode '.$mode.' is invalid');
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php
new file mode 100644
index 0000000..f692a6f
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/Authenticator.php
@@ -0,0 +1,36 @@
+encoding = $encoding;
+ }
+
+ /**
+ * Get the name of the ESMTP extension this handles.
+ *
+ * @return string
+ */
+ public function getHandledKeyword()
+ {
+ return '8BITMIME';
+ }
+
+ /**
+ * Not used.
+ */
+ public function setKeywordParams(array $parameters)
+ {
+ }
+
+ /**
+ * Not used.
+ */
+ public function afterEhlo(Swift_Transport_SmtpAgent $agent)
+ {
+ }
+
+ /**
+ * Get params which are appended to MAIL FROM:<>.
+ *
+ * @return string[]
+ */
+ public function getMailParams()
+ {
+ return ['BODY='.$this->encoding];
+ }
+
+ /**
+ * Not used.
+ */
+ public function getRcptParams()
+ {
+ return [];
+ }
+
+ /**
+ * Not used.
+ */
+ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
+ {
+ }
+
+ /**
+ * Returns +1, -1 or 0 according to the rules for usort().
+ *
+ * This method is called to ensure extensions can be execute in an appropriate order.
+ *
+ * @param string $esmtpKeyword to compare with
+ *
+ * @return int
+ */
+ public function getPriorityOver($esmtpKeyword)
+ {
+ return 0;
+ }
+
+ /**
+ * Not used.
+ */
+ public function exposeMixinMethods()
+ {
+ return [];
+ }
+
+ /**
+ * Not used.
+ */
+ public function resetState()
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php
new file mode 100644
index 0000000..7d0252a
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/Esmtp/SmtpUtf8Handler.php
@@ -0,0 +1,107 @@
+.
+ *
+ * @return string[]
+ */
+ public function getMailParams()
+ {
+ return ['SMTPUTF8'];
+ }
+
+ /**
+ * Not used.
+ */
+ public function getRcptParams()
+ {
+ return [];
+ }
+
+ /**
+ * Not used.
+ */
+ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false)
+ {
+ }
+
+ /**
+ * Returns +1, -1 or 0 according to the rules for usort().
+ *
+ * This method is called to ensure extensions can be execute in an appropriate order.
+ *
+ * @param string $esmtpKeyword to compare with
+ *
+ * @return int
+ */
+ public function getPriorityOver($esmtpKeyword)
+ {
+ return 0;
+ }
+
+ /**
+ * Not used.
+ */
+ public function exposeMixinMethods()
+ {
+ return [];
+ }
+
+ /**
+ * Not used.
+ */
+ public function resetState()
+ {
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php b/include/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php
new file mode 100644
index 0000000..b8ea36e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/EsmtpHandler.php
@@ -0,0 +1,86 @@
+.
+ *
+ * @return string[]
+ */
+ public function getMailParams();
+
+ /**
+ * Get params which are appended to RCPT TO:<>.
+ *
+ * @return string[]
+ */
+ public function getRcptParams();
+
+ /**
+ * Runs when a command is due to be sent.
+ *
+ * @param Swift_Transport_SmtpAgent $agent to read/write
+ * @param string $command to send
+ * @param int[] $codes expected in response
+ * @param string[] $failedRecipients to collect failures
+ * @param bool $stop to be set true by-reference if the command is now sent
+ */
+ public function onCommand(Swift_Transport_SmtpAgent $agent, $command, $codes = [], &$failedRecipients = null, &$stop = false);
+
+ /**
+ * Returns +1, -1 or 0 according to the rules for usort().
+ *
+ * This method is called to ensure extensions can be execute in an appropriate order.
+ *
+ * @param string $esmtpKeyword to compare with
+ *
+ * @return int
+ */
+ public function getPriorityOver($esmtpKeyword);
+
+ /**
+ * Returns an array of method names which are exposed to the Esmtp class.
+ *
+ * @return string[]
+ */
+ public function exposeMixinMethods();
+
+ /**
+ * Tells this handler to clear any buffers and reset its state.
+ */
+ public function resetState();
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php b/include/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php
new file mode 100644
index 0000000..bce0cdd
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/EsmtpTransport.php
@@ -0,0 +1,446 @@
+ 'tcp',
+ 'host' => 'localhost',
+ 'port' => 25,
+ 'timeout' => 30,
+ 'blocking' => 1,
+ 'tls' => false,
+ 'type' => Swift_Transport_IoBuffer::TYPE_SOCKET,
+ 'stream_context_options' => [],
+ ];
+
+ /**
+ * Creates a new EsmtpTransport using the given I/O buffer.
+ *
+ * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
+ * @param string $localDomain
+ */
+ public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null)
+ {
+ parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder);
+ $this->setExtensionHandlers($extensionHandlers);
+ }
+
+ /**
+ * Set the host to connect to.
+ *
+ * Literal IPv6 addresses should be wrapped in square brackets.
+ *
+ * @param string $host
+ *
+ * @return $this
+ */
+ public function setHost($host)
+ {
+ $this->params['host'] = $host;
+
+ return $this;
+ }
+
+ /**
+ * Get the host to connect to.
+ *
+ * @return string
+ */
+ public function getHost()
+ {
+ return $this->params['host'];
+ }
+
+ /**
+ * Set the port to connect to.
+ *
+ * @param int $port
+ *
+ * @return $this
+ */
+ public function setPort($port)
+ {
+ $this->params['port'] = (int) $port;
+
+ return $this;
+ }
+
+ /**
+ * Get the port to connect to.
+ *
+ * @return int
+ */
+ public function getPort()
+ {
+ return $this->params['port'];
+ }
+
+ /**
+ * Set the connection timeout.
+ *
+ * @param int $timeout seconds
+ *
+ * @return $this
+ */
+ public function setTimeout($timeout)
+ {
+ $this->params['timeout'] = (int) $timeout;
+ $this->buffer->setParam('timeout', (int) $timeout);
+
+ return $this;
+ }
+
+ /**
+ * Get the connection timeout.
+ *
+ * @return int
+ */
+ public function getTimeout()
+ {
+ return $this->params['timeout'];
+ }
+
+ /**
+ * Set the encryption type (tls or ssl).
+ *
+ * @param string $encryption
+ *
+ * @return $this
+ */
+ public function setEncryption($encryption)
+ {
+ $encryption = strtolower($encryption);
+ if ('tls' == $encryption) {
+ $this->params['protocol'] = 'tcp';
+ $this->params['tls'] = true;
+ } else {
+ $this->params['protocol'] = $encryption;
+ $this->params['tls'] = false;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Get the encryption type.
+ *
+ * @return string
+ */
+ public function getEncryption()
+ {
+ return $this->params['tls'] ? 'tls' : $this->params['protocol'];
+ }
+
+ /**
+ * Sets the stream context options.
+ *
+ * @param array $options
+ *
+ * @return $this
+ */
+ public function setStreamOptions($options)
+ {
+ $this->params['stream_context_options'] = $options;
+
+ return $this;
+ }
+
+ /**
+ * Returns the stream context options.
+ *
+ * @return array
+ */
+ public function getStreamOptions()
+ {
+ return $this->params['stream_context_options'];
+ }
+
+ /**
+ * Sets the source IP.
+ *
+ * IPv6 addresses should be wrapped in square brackets.
+ *
+ * @param string $source
+ *
+ * @return $this
+ */
+ public function setSourceIp($source)
+ {
+ $this->params['sourceIp'] = $source;
+
+ return $this;
+ }
+
+ /**
+ * Returns the IP used to connect to the destination.
+ *
+ * @return string
+ */
+ public function getSourceIp()
+ {
+ return $this->params['sourceIp'] ?? null;
+ }
+
+ /**
+ * Sets whether SMTP pipelining is enabled.
+ *
+ * By default, support is auto-detected using the PIPELINING SMTP extension.
+ * Use this function to override that in the unlikely event of compatibility
+ * issues.
+ *
+ * @param bool $enabled
+ *
+ * @return $this
+ */
+ public function setPipelining($enabled)
+ {
+ $this->pipelining = $enabled;
+
+ return $this;
+ }
+
+ /**
+ * Returns whether SMTP pipelining is enabled.
+ *
+ * @return bool|null a boolean if pipelining is explicitly enabled or disabled,
+ * or null if support is auto-detected
+ */
+ public function getPipelining()
+ {
+ return $this->pipelining;
+ }
+
+ /**
+ * Set ESMTP extension handlers.
+ *
+ * @param Swift_Transport_EsmtpHandler[] $handlers
+ *
+ * @return $this
+ */
+ public function setExtensionHandlers(array $handlers)
+ {
+ $assoc = [];
+ foreach ($handlers as $handler) {
+ $assoc[$handler->getHandledKeyword()] = $handler;
+ }
+ uasort($assoc, function ($a, $b) {
+ return $a->getPriorityOver($b->getHandledKeyword());
+ });
+ $this->handlers = $assoc;
+ $this->setHandlerParams();
+
+ return $this;
+ }
+
+ /**
+ * Get ESMTP extension handlers.
+ *
+ * @return Swift_Transport_EsmtpHandler[]
+ */
+ public function getExtensionHandlers()
+ {
+ return array_values($this->handlers);
+ }
+
+ /**
+ * Run a command against the buffer, expecting the given response codes.
+ *
+ * If no response codes are given, the response will not be validated.
+ * If codes are given, an exception will be thrown on an invalid response.
+ *
+ * @param string $command
+ * @param int[] $codes
+ * @param string[] $failures An array of failures by-reference
+ * @param bool $pipeline Do not wait for response
+ * @param string $address the address, if command is RCPT TO
+ *
+ * @return string|null The server response, or null if pipelining is enabled
+ */
+ public function executeCommand($command, $codes = [], &$failures = null, $pipeline = false, $address = null)
+ {
+ $failures = (array) $failures;
+ $stopSignal = false;
+ $response = null;
+ foreach ($this->getActiveHandlers() as $handler) {
+ $response = $handler->onCommand(
+ $this, $command, $codes, $failures, $stopSignal
+ );
+ if ($stopSignal) {
+ return $response;
+ }
+ }
+
+ return parent::executeCommand($command, $codes, $failures, $pipeline, $address);
+ }
+
+ /** Mixin handling method for ESMTP handlers */
+ public function __call($method, $args)
+ {
+ foreach ($this->handlers as $handler) {
+ if (\in_array(strtolower($method),
+ array_map('strtolower', (array) $handler->exposeMixinMethods())
+ )) {
+ $return = \call_user_func_array([$handler, $method], $args);
+ // Allow fluid method calls
+ if (null === $return && 'set' == substr($method, 0, 3)) {
+ return $this;
+ } else {
+ return $return;
+ }
+ }
+ }
+ trigger_error('Call to undefined method '.$method, E_USER_ERROR);
+ }
+
+ /** Get the params to initialize the buffer */
+ protected function getBufferParams()
+ {
+ return $this->params;
+ }
+
+ /** Overridden to perform EHLO instead */
+ protected function doHeloCommand()
+ {
+ try {
+ $response = $this->executeCommand(
+ sprintf("EHLO %s\r\n", $this->domain), [250]
+ );
+ } catch (Swift_TransportException $e) {
+ return parent::doHeloCommand();
+ }
+
+ if ($this->params['tls']) {
+ try {
+ $this->executeCommand("STARTTLS\r\n", [220]);
+
+ if (!$this->buffer->startTLS()) {
+ throw new Swift_TransportException('Unable to connect with TLS encryption');
+ }
+
+ try {
+ $response = $this->executeCommand(
+ sprintf("EHLO %s\r\n", $this->domain), [250]
+ );
+ } catch (Swift_TransportException $e) {
+ return parent::doHeloCommand();
+ }
+ } catch (Swift_TransportException $e) {
+ $this->throwException($e);
+ }
+ }
+
+ $this->capabilities = $this->getCapabilities($response);
+ if (!isset($this->pipelining)) {
+ $this->pipelining = isset($this->capabilities['PIPELINING']);
+ }
+
+ $this->setHandlerParams();
+ foreach ($this->getActiveHandlers() as $handler) {
+ $handler->afterEhlo($this);
+ }
+ }
+
+ /** Overridden to add Extension support */
+ protected function doMailFromCommand($address)
+ {
+ $address = $this->addressEncoder->encodeString($address);
+ $handlers = $this->getActiveHandlers();
+ $params = [];
+ foreach ($handlers as $handler) {
+ $params = array_merge($params, (array) $handler->getMailParams());
+ }
+ $paramStr = !empty($params) ? ' '.implode(' ', $params) : '';
+ $this->executeCommand(
+ sprintf("MAIL FROM:<%s>%s\r\n", $address, $paramStr), [250], $failures, true
+ );
+ }
+
+ /** Overridden to add Extension support */
+ protected function doRcptToCommand($address)
+ {
+ $address = $this->addressEncoder->encodeString($address);
+ $handlers = $this->getActiveHandlers();
+ $params = [];
+ foreach ($handlers as $handler) {
+ $params = array_merge($params, (array) $handler->getRcptParams());
+ }
+ $paramStr = !empty($params) ? ' '.implode(' ', $params) : '';
+ $this->executeCommand(
+ sprintf("RCPT TO:<%s>%s\r\n", $address, $paramStr), [250, 251, 252], $failures, true, $address
+ );
+ }
+
+ /** Determine ESMTP capabilities by function group */
+ private function getCapabilities($ehloResponse)
+ {
+ $capabilities = [];
+ $ehloResponse = trim($ehloResponse);
+ $lines = explode("\r\n", $ehloResponse);
+ array_shift($lines);
+ foreach ($lines as $line) {
+ if (preg_match('/^[0-9]{3}[ -]([A-Z0-9-]+)((?:[ =].*)?)$/Di', $line, $matches)) {
+ $keyword = strtoupper($matches[1]);
+ $paramStr = strtoupper(ltrim($matches[2], ' ='));
+ $params = !empty($paramStr) ? explode(' ', $paramStr) : [];
+ $capabilities[$keyword] = $params;
+ }
+ }
+
+ return $capabilities;
+ }
+
+ /** Set parameters which are used by each extension handler */
+ private function setHandlerParams()
+ {
+ foreach ($this->handlers as $keyword => $handler) {
+ if (\array_key_exists($keyword, $this->capabilities)) {
+ $handler->setKeywordParams($this->capabilities[$keyword]);
+ }
+ }
+ }
+
+ /** Get ESMTP handlers which are currently ok to use */
+ private function getActiveHandlers()
+ {
+ $handlers = [];
+ foreach ($this->handlers as $keyword => $handler) {
+ if (\array_key_exists($keyword, $this->capabilities)) {
+ $handlers[] = $handler;
+ }
+ }
+
+ return $handlers;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php b/include/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php
new file mode 100644
index 0000000..1a4b475
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/FailoverTransport.php
@@ -0,0 +1,103 @@
+transports);
+ for ($i = 0; $i < $maxTransports
+ && $transport = $this->getNextTransport(); ++$i) {
+ if ($transport->ping()) {
+ return true;
+ } else {
+ $this->killCurrentTransport();
+ }
+ }
+
+ return \count($this->transports) > 0;
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ $maxTransports = \count($this->transports);
+ $sent = 0;
+ $this->lastUsedTransport = null;
+
+ for ($i = 0; $i < $maxTransports
+ && $transport = $this->getNextTransport(); ++$i) {
+ try {
+ if (!$transport->isStarted()) {
+ $transport->start();
+ }
+
+ if ($sent = $transport->send($message, $failedRecipients)) {
+ $this->lastUsedTransport = $transport;
+
+ return $sent;
+ }
+ } catch (Swift_TransportException $e) {
+ $this->killCurrentTransport();
+ }
+ }
+
+ if (0 == \count($this->transports)) {
+ throw new Swift_TransportException('All Transports in FailoverTransport failed, or no Transports available');
+ }
+
+ return $sent;
+ }
+
+ protected function getNextTransport()
+ {
+ if (!isset($this->currentTransport)) {
+ $this->currentTransport = parent::getNextTransport();
+ }
+
+ return $this->currentTransport;
+ }
+
+ protected function killCurrentTransport()
+ {
+ $this->currentTransport = null;
+ parent::killCurrentTransport();
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php b/include/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php
new file mode 100644
index 0000000..50f1e5e
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/IoBuffer.php
@@ -0,0 +1,65 @@
+transports = $transports;
+ $this->deadTransports = [];
+ }
+
+ /**
+ * Get $transports to delegate to.
+ *
+ * @return Swift_Transport[]
+ */
+ public function getTransports()
+ {
+ return array_merge($this->transports, $this->deadTransports);
+ }
+
+ /**
+ * Get the Transport used in the last successful send operation.
+ *
+ * @return Swift_Transport
+ */
+ public function getLastUsedTransport()
+ {
+ return $this->lastUsedTransport;
+ }
+
+ /**
+ * Test if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return \count($this->transports) > 0;
+ }
+
+ /**
+ * Start this Transport mechanism.
+ */
+ public function start()
+ {
+ $this->transports = array_merge($this->transports, $this->deadTransports);
+ }
+
+ /**
+ * Stop this Transport mechanism.
+ */
+ public function stop()
+ {
+ foreach ($this->transports as $transport) {
+ $transport->stop();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ping()
+ {
+ foreach ($this->transports as $transport) {
+ if (!$transport->ping()) {
+ $this->killCurrentTransport();
+ }
+ }
+
+ return \count($this->transports) > 0;
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ * The return value is the number of recipients who were accepted for delivery.
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ $maxTransports = \count($this->transports);
+ $sent = 0;
+ $this->lastUsedTransport = null;
+
+ for ($i = 0; $i < $maxTransports
+ && $transport = $this->getNextTransport(); ++$i) {
+ try {
+ if (!$transport->isStarted()) {
+ $transport->start();
+ }
+ if ($sent = $transport->send($message, $failedRecipients)) {
+ $this->lastUsedTransport = $transport;
+ break;
+ }
+ } catch (Swift_TransportException $e) {
+ $this->killCurrentTransport();
+ }
+ }
+
+ if (0 == \count($this->transports)) {
+ throw new Swift_TransportException('All Transports in LoadBalancedTransport failed, or no Transports available');
+ }
+
+ return $sent;
+ }
+
+ /**
+ * Register a plugin.
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ foreach ($this->transports as $transport) {
+ $transport->registerPlugin($plugin);
+ }
+ }
+
+ /**
+ * Rotates the transport list around and returns the first instance.
+ *
+ * @return Swift_Transport
+ */
+ protected function getNextTransport()
+ {
+ if ($next = array_shift($this->transports)) {
+ $this->transports[] = $next;
+ }
+
+ return $next;
+ }
+
+ /**
+ * Tag the currently used (top of stack) transport as dead/useless.
+ */
+ protected function killCurrentTransport()
+ {
+ if ($transport = array_pop($this->transports)) {
+ try {
+ $transport->stop();
+ } catch (Exception $e) {
+ }
+ $this->deadTransports[] = $transport;
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/NullTransport.php b/include/swiftmailer/lib/classes/Swift/Transport/NullTransport.php
new file mode 100644
index 0000000..7d910db
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/NullTransport.php
@@ -0,0 +1,98 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Pretends messages have been sent, but just ignores them.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_Transport_NullTransport implements Swift_Transport
+{
+ /** The event dispatcher from the plugin API */
+ private $eventDispatcher;
+
+ /**
+ * Constructor.
+ */
+ public function __construct(Swift_Events_EventDispatcher $eventDispatcher)
+ {
+ $this->eventDispatcher = $eventDispatcher;
+ }
+
+ /**
+ * Tests if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Transport mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Transport mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ping()
+ {
+ return true;
+ }
+
+ /**
+ * Sends the given message.
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent emails
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ if ($evt) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $count = (
+ \count((array) $message->getTo())
+ + \count((array) $message->getCc())
+ + \count((array) $message->getBcc())
+ );
+
+ return $count;
+ }
+
+ /**
+ * Register a plugin.
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->eventDispatcher->bindEventListener($plugin);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php b/include/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php
new file mode 100644
index 0000000..72ddae8
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/SendmailTransport.php
@@ -0,0 +1,158 @@
+ 30,
+ 'blocking' => 1,
+ 'command' => '/usr/sbin/sendmail -bs',
+ 'type' => Swift_Transport_IoBuffer::TYPE_PROCESS,
+ ];
+
+ /**
+ * Create a new SendmailTransport with $buf for I/O.
+ *
+ * @param string $localDomain
+ */
+ public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null)
+ {
+ parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder);
+ }
+
+ /**
+ * Start the standalone SMTP session if running in -bs mode.
+ */
+ public function start()
+ {
+ if (false !== strpos($this->getCommand(), ' -bs')) {
+ parent::start();
+ }
+ }
+
+ /**
+ * Set the command to invoke.
+ *
+ * If using -t mode you are strongly advised to include -oi or -i in the flags.
+ * For example: /usr/sbin/sendmail -oi -t
+ * Swift will append a -f flag if one is not present.
+ *
+ * The recommended mode is "-bs" since it is interactive and failure notifications
+ * are hence possible.
+ *
+ * @param string $command
+ *
+ * @return $this
+ */
+ public function setCommand($command)
+ {
+ $this->params['command'] = $command;
+
+ return $this;
+ }
+
+ /**
+ * Get the sendmail command which will be invoked.
+ *
+ * @return string
+ */
+ public function getCommand()
+ {
+ return $this->params['command'];
+ }
+
+ /**
+ * Send the given Message.
+ *
+ * Recipient/sender data will be retrieved from the Message API.
+ *
+ * The return value is the number of recipients who were accepted for delivery.
+ * NOTE: If using 'sendmail -t' you will not be aware of any failures until
+ * they bounce (i.e. send() will always return 100% success).
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ $failedRecipients = (array) $failedRecipients;
+ $command = $this->getCommand();
+ $buffer = $this->getBuffer();
+ $count = 0;
+
+ if (false !== strpos($command, ' -t')) {
+ if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ if (false === strpos($command, ' -f')) {
+ $command .= ' -f'.escapeshellarg($this->getReversePath($message));
+ }
+
+ $buffer->initialize(array_merge($this->params, ['command' => $command]));
+
+ if (false === strpos($command, ' -i') && false === strpos($command, ' -oi')) {
+ $buffer->setWriteTranslations(["\r\n" => "\n", "\n." => "\n.."]);
+ } else {
+ $buffer->setWriteTranslations(["\r\n" => "\n"]);
+ }
+
+ $count = \count((array) $message->getTo())
+ + \count((array) $message->getCc())
+ + \count((array) $message->getBcc())
+ ;
+ $message->toByteStream($buffer);
+ $buffer->flushBuffers();
+ $buffer->setWriteTranslations([]);
+ $buffer->terminate();
+
+ if ($evt) {
+ $evt->setResult(Swift_Events_SendEvent::RESULT_SUCCESS);
+ $evt->setFailedRecipients($failedRecipients);
+ $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ $message->generateId();
+ } elseif (false !== strpos($command, ' -bs')) {
+ $count = parent::send($message, $failedRecipients);
+ } else {
+ $this->throwException(new Swift_TransportException(
+ 'Unsupported sendmail command flags ['.$command.']. '.
+ 'Must be one of "-bs" or "-t" but can include additional flags.'
+ ));
+ }
+
+ return $count;
+ }
+
+ /** Get the params to initialize the buffer */
+ protected function getBufferParams()
+ {
+ return $this->params;
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php b/include/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php
new file mode 100644
index 0000000..e8ce65c
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/SmtpAgent.php
@@ -0,0 +1,36 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+/**
+ * Stores Messages in a queue.
+ *
+ * @author Fabien Potencier
+ */
+class Swift_Transport_SpoolTransport implements Swift_Transport
+{
+ /** The spool instance */
+ private $spool;
+
+ /** The event dispatcher from the plugin API */
+ private $eventDispatcher;
+
+ /**
+ * Constructor.
+ */
+ public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null)
+ {
+ $this->eventDispatcher = $eventDispatcher;
+ $this->spool = $spool;
+ }
+
+ /**
+ * Sets the spool object.
+ *
+ * @return $this
+ */
+ public function setSpool(Swift_Spool $spool)
+ {
+ $this->spool = $spool;
+
+ return $this;
+ }
+
+ /**
+ * Get the spool object.
+ *
+ * @return Swift_Spool
+ */
+ public function getSpool()
+ {
+ return $this->spool;
+ }
+
+ /**
+ * Tests if this Transport mechanism has started.
+ *
+ * @return bool
+ */
+ public function isStarted()
+ {
+ return true;
+ }
+
+ /**
+ * Starts this Transport mechanism.
+ */
+ public function start()
+ {
+ }
+
+ /**
+ * Stops this Transport mechanism.
+ */
+ public function stop()
+ {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function ping()
+ {
+ return true;
+ }
+
+ /**
+ * Sends the given message.
+ *
+ * @param string[] $failedRecipients An array of failures by-reference
+ *
+ * @return int The number of sent e-mail's
+ */
+ public function send(Swift_Mime_SimpleMessage $message, &$failedRecipients = null)
+ {
+ if ($evt = $this->eventDispatcher->createSendEvent($this, $message)) {
+ $this->eventDispatcher->dispatchEvent($evt, 'beforeSendPerformed');
+ if ($evt->bubbleCancelled()) {
+ return 0;
+ }
+ }
+
+ $success = $this->spool->queueMessage($message);
+
+ if ($evt) {
+ $evt->setResult($success ? Swift_Events_SendEvent::RESULT_SPOOLED : Swift_Events_SendEvent::RESULT_FAILED);
+ $this->eventDispatcher->dispatchEvent($evt, 'sendPerformed');
+ }
+
+ return 1;
+ }
+
+ /**
+ * Register a plugin.
+ */
+ public function registerPlugin(Swift_Events_EventListener $plugin)
+ {
+ $this->eventDispatcher->bindEventListener($plugin);
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php b/include/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
new file mode 100644
index 0000000..70782ad
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
@@ -0,0 +1,319 @@
+replacementFactory = $replacementFactory;
+ }
+
+ /**
+ * Perform any initialization needed, using the given $params.
+ *
+ * Parameters will vary depending upon the type of IoBuffer used.
+ */
+ public function initialize(array $params)
+ {
+ $this->params = $params;
+ switch ($params['type']) {
+ case self::TYPE_PROCESS:
+ $this->establishProcessConnection();
+ break;
+ case self::TYPE_SOCKET:
+ default:
+ $this->establishSocketConnection();
+ break;
+ }
+ }
+
+ /**
+ * Set an individual param on the buffer (e.g. switching to SSL).
+ *
+ * @param string $param
+ * @param mixed $value
+ */
+ public function setParam($param, $value)
+ {
+ if (isset($this->stream)) {
+ switch ($param) {
+ case 'timeout':
+ if ($this->stream) {
+ stream_set_timeout($this->stream, $value);
+ }
+ break;
+
+ case 'blocking':
+ if ($this->stream) {
+ stream_set_blocking($this->stream, 1);
+ }
+ }
+ }
+ $this->params[$param] = $value;
+ }
+
+ public function startTLS()
+ {
+ // STREAM_CRYPTO_METHOD_TLS_CLIENT only allow tls1.0 connections (some php versions)
+ // To support modern tls we allow explicit tls1.0, tls1.1, tls1.2
+ // Ssl3 and older are not allowed because they are vulnerable
+ // @TODO make tls arguments configurable
+ return stream_socket_enable_crypto($this->stream, true, STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT);
+ }
+
+ /**
+ * Perform any shutdown logic needed.
+ */
+ public function terminate()
+ {
+ if (isset($this->stream)) {
+ switch ($this->params['type']) {
+ case self::TYPE_PROCESS:
+ fclose($this->in);
+ fclose($this->out);
+ proc_close($this->stream);
+ break;
+ case self::TYPE_SOCKET:
+ default:
+ fclose($this->stream);
+ break;
+ }
+ }
+ $this->stream = null;
+ $this->out = null;
+ $this->in = null;
+ }
+
+ /**
+ * Set an array of string replacements which should be made on data written
+ * to the buffer.
+ *
+ * This could replace LF with CRLF for example.
+ *
+ * @param string[] $replacements
+ */
+ public function setWriteTranslations(array $replacements)
+ {
+ foreach ($this->translations as $search => $replace) {
+ if (!isset($replacements[$search])) {
+ $this->removeFilter($search);
+ unset($this->translations[$search]);
+ }
+ }
+
+ foreach ($replacements as $search => $replace) {
+ if (!isset($this->translations[$search])) {
+ $this->addFilter(
+ $this->replacementFactory->createFilter($search, $replace), $search
+ );
+ $this->translations[$search] = true;
+ }
+ }
+ }
+
+ /**
+ * Get a line of output (including any CRLF).
+ *
+ * The $sequence number comes from any writes and may or may not be used
+ * depending upon the implementation.
+ *
+ * @param int $sequence of last write to scan from
+ *
+ * @return string
+ *
+ * @throws Swift_IoException
+ */
+ public function readLine($sequence)
+ {
+ if (isset($this->out) && !feof($this->out)) {
+ $line = fgets($this->out);
+ if (0 == \strlen($line)) {
+ $metas = stream_get_meta_data($this->out);
+ if ($metas['timed_out']) {
+ throw new Swift_IoException('Connection to '.$this->getReadConnectionDescription().' Timed Out');
+ }
+ }
+
+ return $line;
+ }
+ }
+
+ /**
+ * Reads $length bytes from the stream into a string and moves the pointer
+ * through the stream by $length.
+ *
+ * If less bytes exist than are requested the remaining bytes are given instead.
+ * If no bytes are remaining at all, boolean false is returned.
+ *
+ * @param int $length
+ *
+ * @return string|bool
+ *
+ * @throws Swift_IoException
+ */
+ public function read($length)
+ {
+ if (isset($this->out) && !feof($this->out)) {
+ $ret = fread($this->out, $length);
+ if (0 == \strlen($ret)) {
+ $metas = stream_get_meta_data($this->out);
+ if ($metas['timed_out']) {
+ throw new Swift_IoException('Connection to '.$this->getReadConnectionDescription().' Timed Out');
+ }
+ }
+
+ return $ret;
+ }
+ }
+
+ /** Not implemented */
+ public function setReadPointer($byteOffset)
+ {
+ }
+
+ /** Flush the stream contents */
+ protected function flush()
+ {
+ if (isset($this->in)) {
+ fflush($this->in);
+ }
+ }
+
+ /** Write this bytes to the stream */
+ protected function doCommit($bytes)
+ {
+ if (isset($this->in)) {
+ $bytesToWrite = \strlen($bytes);
+ $totalBytesWritten = 0;
+
+ while ($totalBytesWritten < $bytesToWrite) {
+ $bytesWritten = fwrite($this->in, substr($bytes, $totalBytesWritten));
+ if (false === $bytesWritten || 0 === $bytesWritten) {
+ break;
+ }
+
+ $totalBytesWritten += $bytesWritten;
+ }
+
+ if ($totalBytesWritten > 0) {
+ return ++$this->sequence;
+ }
+ }
+ }
+
+ /**
+ * Establishes a connection to a remote server.
+ */
+ private function establishSocketConnection()
+ {
+ $host = $this->params['host'];
+ if (!empty($this->params['protocol'])) {
+ $host = $this->params['protocol'].'://'.$host;
+ }
+ $timeout = 15;
+ if (!empty($this->params['timeout'])) {
+ $timeout = $this->params['timeout'];
+ }
+ $options = [];
+ if (!empty($this->params['sourceIp'])) {
+ $options['socket']['bindto'] = $this->params['sourceIp'].':0';
+ }
+
+ if (isset($this->params['stream_context_options'])) {
+ $options = array_merge($options, $this->params['stream_context_options']);
+ }
+ $streamContext = stream_context_create($options);
+
+ set_error_handler(function ($type, $msg) {
+ throw new Swift_TransportException('Connection could not be established with host '.$this->params['host'].' :'.$msg);
+ });
+ try {
+ $this->stream = stream_socket_client($host.':'.$this->params['port'], $errno, $errstr, $timeout, STREAM_CLIENT_CONNECT, $streamContext);
+ } finally {
+ restore_error_handler();
+ }
+
+ if (!empty($this->params['blocking'])) {
+ stream_set_blocking($this->stream, 1);
+ } else {
+ stream_set_blocking($this->stream, 0);
+ }
+ stream_set_timeout($this->stream, $timeout);
+ $this->in = &$this->stream;
+ $this->out = &$this->stream;
+ }
+
+ /**
+ * Opens a process for input/output.
+ */
+ private function establishProcessConnection()
+ {
+ $command = $this->params['command'];
+ $descriptorSpec = [
+ 0 => ['pipe', 'r'],
+ 1 => ['pipe', 'w'],
+ 2 => ['pipe', 'w'],
+ ];
+ $pipes = [];
+ $this->stream = proc_open($command, $descriptorSpec, $pipes);
+ stream_set_blocking($pipes[2], 0);
+ if ($err = stream_get_contents($pipes[2])) {
+ throw new Swift_TransportException('Process could not be started ['.$err.']');
+ }
+ $this->in = &$pipes[0];
+ $this->out = &$pipes[1];
+ }
+
+ private function getReadConnectionDescription()
+ {
+ switch ($this->params['type']) {
+ case self::TYPE_PROCESS:
+ return 'Process '.$this->params['command'];
+ break;
+
+ case self::TYPE_SOCKET:
+ default:
+ $host = $this->params['host'];
+ if (!empty($this->params['protocol'])) {
+ $host = $this->params['protocol'].'://'.$host;
+ }
+ $host .= ':'.$this->params['port'];
+
+ return $host;
+ break;
+ }
+ }
+}
diff --git a/include/swiftmailer/lib/classes/Swift/TransportException.php b/include/swiftmailer/lib/classes/Swift/TransportException.php
new file mode 100644
index 0000000..c741745
--- /dev/null
+++ b/include/swiftmailer/lib/classes/Swift/TransportException.php
@@ -0,0 +1,28 @@
+register('cache')
+ ->asAliasOf('cache.array')
+
+ ->register('tempdir')
+ ->asValue('/tmp')
+
+ ->register('cache.null')
+ ->asSharedInstanceOf('Swift_KeyCache_NullKeyCache')
+
+ ->register('cache.array')
+ ->asSharedInstanceOf('Swift_KeyCache_ArrayKeyCache')
+ ->withDependencies(['cache.inputstream'])
+
+ ->register('cache.disk')
+ ->asSharedInstanceOf('Swift_KeyCache_DiskKeyCache')
+ ->withDependencies(['cache.inputstream', 'tempdir'])
+
+ ->register('cache.inputstream')
+ ->asNewInstanceOf('Swift_KeyCache_SimpleKeyCacheInputStream')
+;
diff --git a/include/swiftmailer/lib/dependency_maps/message_deps.php b/include/swiftmailer/lib/dependency_maps/message_deps.php
new file mode 100644
index 0000000..64d69d2
--- /dev/null
+++ b/include/swiftmailer/lib/dependency_maps/message_deps.php
@@ -0,0 +1,9 @@
+register('message.message')
+ ->asNewInstanceOf('Swift_Message')
+
+ ->register('message.mimepart')
+ ->asNewInstanceOf('Swift_MimePart')
+;
diff --git a/include/swiftmailer/lib/dependency_maps/mime_deps.php b/include/swiftmailer/lib/dependency_maps/mime_deps.php
new file mode 100644
index 0000000..307756c
--- /dev/null
+++ b/include/swiftmailer/lib/dependency_maps/mime_deps.php
@@ -0,0 +1,134 @@
+register('properties.charset')
+ ->asValue('utf-8')
+
+ ->register('email.validator')
+ ->asSharedInstanceOf('Egulias\EmailValidator\EmailValidator')
+
+ ->register('mime.idgenerator.idright')
+ // As SERVER_NAME can come from the user in certain configurations, check that
+ // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use
+ // preg_replace() instead of preg_match() to prevent DoS attacks with long host names.
+ ->asValue(!empty($_SERVER['SERVER_NAME']) && '' === preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'swift.generated')
+
+ ->register('mime.idgenerator')
+ ->asSharedInstanceOf('Swift_Mime_IdGenerator')
+ ->withDependencies([
+ 'mime.idgenerator.idright',
+ ])
+
+ ->register('mime.message')
+ ->asNewInstanceOf('Swift_Mime_SimpleMessage')
+ ->withDependencies([
+ 'mime.headerset',
+ 'mime.textcontentencoder',
+ 'cache',
+ 'mime.idgenerator',
+ 'properties.charset',
+ ])
+
+ ->register('mime.part')
+ ->asNewInstanceOf('Swift_Mime_MimePart')
+ ->withDependencies([
+ 'mime.headerset',
+ 'mime.textcontentencoder',
+ 'cache',
+ 'mime.idgenerator',
+ 'properties.charset',
+ ])
+
+ ->register('mime.attachment')
+ ->asNewInstanceOf('Swift_Mime_Attachment')
+ ->withDependencies([
+ 'mime.headerset',
+ 'mime.base64contentencoder',
+ 'cache',
+ 'mime.idgenerator',
+ ])
+ ->addConstructorValue($swift_mime_types)
+
+ ->register('mime.embeddedfile')
+ ->asNewInstanceOf('Swift_Mime_EmbeddedFile')
+ ->withDependencies([
+ 'mime.headerset',
+ 'mime.base64contentencoder',
+ 'cache',
+ 'mime.idgenerator',
+ ])
+ ->addConstructorValue($swift_mime_types)
+
+ ->register('mime.headerfactory')
+ ->asNewInstanceOf('Swift_Mime_SimpleHeaderFactory')
+ ->withDependencies([
+ 'mime.qpheaderencoder',
+ 'mime.rfc2231encoder',
+ 'email.validator',
+ 'properties.charset',
+ 'address.idnaddressencoder',
+ ])
+
+ ->register('mime.headerset')
+ ->asNewInstanceOf('Swift_Mime_SimpleHeaderSet')
+ ->withDependencies(['mime.headerfactory', 'properties.charset'])
+
+ ->register('mime.qpheaderencoder')
+ ->asNewInstanceOf('Swift_Mime_HeaderEncoder_QpHeaderEncoder')
+ ->withDependencies(['mime.charstream'])
+
+ ->register('mime.base64headerencoder')
+ ->asNewInstanceOf('Swift_Mime_HeaderEncoder_Base64HeaderEncoder')
+ ->withDependencies(['mime.charstream'])
+
+ ->register('mime.charstream')
+ ->asNewInstanceOf('Swift_CharacterStream_NgCharacterStream')
+ ->withDependencies(['mime.characterreaderfactory', 'properties.charset'])
+
+ ->register('mime.bytecanonicalizer')
+ ->asSharedInstanceOf('Swift_StreamFilters_ByteArrayReplacementFilter')
+ ->addConstructorValue([[0x0D, 0x0A], [0x0D], [0x0A]])
+ ->addConstructorValue([[0x0A], [0x0A], [0x0D, 0x0A]])
+
+ ->register('mime.characterreaderfactory')
+ ->asSharedInstanceOf('Swift_CharacterReaderFactory_SimpleCharacterReaderFactory')
+
+ ->register('mime.textcontentencoder')
+ ->asAliasOf('mime.qpcontentencoder')
+
+ ->register('mime.safeqpcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoder')
+ ->withDependencies(['mime.charstream', 'mime.bytecanonicalizer'])
+
+ ->register('mime.rawcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_RawContentEncoder')
+
+ ->register('mime.nativeqpcontentencoder')
+ ->withDependencies(['properties.charset'])
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_NativeQpContentEncoder')
+
+ ->register('mime.qpcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_QpContentEncoderProxy')
+ ->withDependencies(['mime.safeqpcontentencoder', 'mime.nativeqpcontentencoder', 'properties.charset'])
+
+ ->register('mime.7bitcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder')
+ ->addConstructorValue('7bit')
+ ->addConstructorValue(true)
+
+ ->register('mime.8bitcontentencoder')
+ ->asNewInstanceOf('Swift_Mime_ContentEncoder_PlainContentEncoder')
+ ->addConstructorValue('8bit')
+ ->addConstructorValue(true)
+
+ ->register('mime.base64contentencoder')
+ ->asSharedInstanceOf('Swift_Mime_ContentEncoder_Base64ContentEncoder')
+
+ ->register('mime.rfc2231encoder')
+ ->asNewInstanceOf('Swift_Encoder_Rfc2231Encoder')
+ ->withDependencies(['mime.charstream'])
+;
+
+unset($swift_mime_types);
diff --git a/include/swiftmailer/lib/dependency_maps/transport_deps.php b/include/swiftmailer/lib/dependency_maps/transport_deps.php
new file mode 100644
index 0000000..34a63c7
--- /dev/null
+++ b/include/swiftmailer/lib/dependency_maps/transport_deps.php
@@ -0,0 +1,97 @@
+register('transport.localdomain')
+ // As SERVER_NAME can come from the user in certain configurations, check that
+ // it does not contain forbidden characters (see RFC 952 and RFC 2181). Use
+ // preg_replace() instead of preg_match() to prevent DoS attacks with long host names.
+ ->asValue(!empty($_SERVER['SERVER_NAME']) && '' === preg_replace('/(?:^\[)?[a-zA-Z0-9-:\]_]+\.?/', '', $_SERVER['SERVER_NAME']) ? trim($_SERVER['SERVER_NAME'], '[]') : '127.0.0.1')
+
+ ->register('transport.smtp')
+ ->asNewInstanceOf('Swift_Transport_EsmtpTransport')
+ ->withDependencies([
+ 'transport.buffer',
+ 'transport.smtphandlers',
+ 'transport.eventdispatcher',
+ 'transport.localdomain',
+ 'address.idnaddressencoder',
+ ])
+
+ ->register('transport.sendmail')
+ ->asNewInstanceOf('Swift_Transport_SendmailTransport')
+ ->withDependencies([
+ 'transport.buffer',
+ 'transport.eventdispatcher',
+ 'transport.localdomain',
+ ])
+
+ ->register('transport.loadbalanced')
+ ->asNewInstanceOf('Swift_Transport_LoadBalancedTransport')
+
+ ->register('transport.failover')
+ ->asNewInstanceOf('Swift_Transport_FailoverTransport')
+
+ ->register('transport.spool')
+ ->asNewInstanceOf('Swift_Transport_SpoolTransport')
+ ->withDependencies(['transport.eventdispatcher'])
+
+ ->register('transport.null')
+ ->asNewInstanceOf('Swift_Transport_NullTransport')
+ ->withDependencies(['transport.eventdispatcher'])
+
+ ->register('transport.buffer')
+ ->asNewInstanceOf('Swift_Transport_StreamBuffer')
+ ->withDependencies(['transport.replacementfactory'])
+
+ ->register('transport.smtphandlers')
+ ->asArray()
+ ->withDependencies(['transport.authhandler'])
+
+ ->register('transport.authhandler')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_AuthHandler')
+ ->withDependencies(['transport.authhandlers'])
+
+ ->register('transport.authhandlers')
+ ->asArray()
+ ->withDependencies([
+ 'transport.crammd5auth',
+ 'transport.loginauth',
+ 'transport.plainauth',
+ 'transport.ntlmauth',
+ 'transport.xoauth2auth',
+ ])
+
+ ->register('transport.smtputf8handler')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_SmtpUtf8Handler')
+
+ ->register('transport.8bitmimehandler')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_EightBitMimeHandler')
+ ->addConstructorValue('8BITMIME')
+
+ ->register('transport.crammd5auth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_CramMd5Authenticator')
+
+ ->register('transport.loginauth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_LoginAuthenticator')
+
+ ->register('transport.plainauth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_PlainAuthenticator')
+
+ ->register('transport.xoauth2auth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_XOAuth2Authenticator')
+
+ ->register('transport.ntlmauth')
+ ->asNewInstanceOf('Swift_Transport_Esmtp_Auth_NTLMAuthenticator')
+
+ ->register('transport.eventdispatcher')
+ ->asNewInstanceOf('Swift_Events_SimpleEventDispatcher')
+
+ ->register('transport.replacementfactory')
+ ->asSharedInstanceOf('Swift_StreamFilters_StringReplacementFilterFactory')
+
+ ->register('address.idnaddressencoder')
+ ->asNewInstanceOf('Swift_AddressEncoder_IdnAddressEncoder')
+
+ ->register('address.utf8addressencoder')
+ ->asNewInstanceOf('Swift_AddressEncoder_Utf8AddressEncoder')
+;
diff --git a/include/swiftmailer/lib/mime_types.php b/include/swiftmailer/lib/mime_types.php
new file mode 100644
index 0000000..72c6fd2
--- /dev/null
+++ b/include/swiftmailer/lib/mime_types.php
@@ -0,0 +1,1007 @@
+ 'text/vnd.in3d.3dml',
+ '3ds' => 'image/x-3ds',
+ '3g2' => 'video/3gpp2',
+ '3gp' => 'video/3gpp',
+ '7z' => 'application/x-7z-compressed',
+ 'aab' => 'application/x-authorware-bin',
+ 'aac' => 'audio/x-aac',
+ 'aam' => 'application/x-authorware-map',
+ 'aas' => 'application/x-authorware-seg',
+ 'abw' => 'application/x-abiword',
+ 'ac' => 'application/pkix-attr-cert',
+ 'acc' => 'application/vnd.americandynamics.acc',
+ 'ace' => 'application/x-ace-compressed',
+ 'acu' => 'application/vnd.acucobol',
+ 'acutc' => 'application/vnd.acucorp',
+ 'adp' => 'audio/adpcm',
+ 'aep' => 'application/vnd.audiograph',
+ 'afm' => 'application/x-font-type1',
+ 'afp' => 'application/vnd.ibm.modcap',
+ 'ahead' => 'application/vnd.ahead.space',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'air' => 'application/vnd.adobe.air-application-installer-package+zip',
+ 'ait' => 'application/vnd.dvb.ait',
+ 'ami' => 'application/vnd.amiga.ami',
+ 'apk' => 'application/vnd.android.package-archive',
+ 'appcache' => 'text/cache-manifest',
+ 'apr' => 'application/vnd.lotus-approach',
+ 'aps' => 'application/postscript',
+ 'arc' => 'application/x-freearc',
+ 'asc' => 'application/pgp-signature',
+ 'asf' => 'video/x-ms-asf',
+ 'asm' => 'text/x-asm',
+ 'aso' => 'application/vnd.accpac.simply.aso',
+ 'asx' => 'video/x-ms-asf',
+ 'atc' => 'application/vnd.acucorp',
+ 'atom' => 'application/atom+xml',
+ 'atomcat' => 'application/atomcat+xml',
+ 'atomsvc' => 'application/atomsvc+xml',
+ 'atx' => 'application/vnd.antix.game-component',
+ 'au' => 'audio/basic',
+ 'avi' => 'video/x-msvideo',
+ 'aw' => 'application/applixware',
+ 'azf' => 'application/vnd.airzip.filesecure.azf',
+ 'azs' => 'application/vnd.airzip.filesecure.azs',
+ 'azw' => 'application/vnd.amazon.ebook',
+ 'bat' => 'application/x-msdownload',
+ 'bcpio' => 'application/x-bcpio',
+ 'bdf' => 'application/x-font-bdf',
+ 'bdm' => 'application/vnd.syncml.dm+wbxml',
+ 'bed' => 'application/vnd.realvnc.bed',
+ 'bh2' => 'application/vnd.fujitsu.oasysprs',
+ 'bin' => 'application/octet-stream',
+ 'blb' => 'application/x-blorb',
+ 'blorb' => 'application/x-blorb',
+ 'bmi' => 'application/vnd.bmi',
+ 'bmp' => 'image/bmp',
+ 'book' => 'application/vnd.framemaker',
+ 'box' => 'application/vnd.previewsystems.box',
+ 'boz' => 'application/x-bzip2',
+ 'bpk' => 'application/octet-stream',
+ 'btif' => 'image/prs.btif',
+ 'bz' => 'application/x-bzip',
+ 'bz2' => 'application/x-bzip2',
+ 'c' => 'text/x-c',
+ 'c11amc' => 'application/vnd.cluetrust.cartomobile-config',
+ 'c11amz' => 'application/vnd.cluetrust.cartomobile-config-pkg',
+ 'c4d' => 'application/vnd.clonk.c4group',
+ 'c4f' => 'application/vnd.clonk.c4group',
+ 'c4g' => 'application/vnd.clonk.c4group',
+ 'c4p' => 'application/vnd.clonk.c4group',
+ 'c4u' => 'application/vnd.clonk.c4group',
+ 'cab' => 'application/vnd.ms-cab-compressed',
+ 'caf' => 'audio/x-caf',
+ 'cap' => 'application/vnd.tcpdump.pcap',
+ 'car' => 'application/vnd.curl.car',
+ 'cat' => 'application/vnd.ms-pki.seccat',
+ 'cb7' => 'application/x-cbr',
+ 'cba' => 'application/x-cbr',
+ 'cbr' => 'application/x-cbr',
+ 'cbt' => 'application/x-cbr',
+ 'cbz' => 'application/x-cbr',
+ 'cc' => 'text/x-c',
+ 'cct' => 'application/x-director',
+ 'ccxml' => 'application/ccxml+xml',
+ 'cdbcmsg' => 'application/vnd.contact.cmsg',
+ 'cdf' => 'application/x-netcdf',
+ 'cdkey' => 'application/vnd.mediastation.cdkey',
+ 'cdmia' => 'application/cdmi-capability',
+ 'cdmic' => 'application/cdmi-container',
+ 'cdmid' => 'application/cdmi-domain',
+ 'cdmio' => 'application/cdmi-object',
+ 'cdmiq' => 'application/cdmi-queue',
+ 'cdx' => 'chemical/x-cdx',
+ 'cdxml' => 'application/vnd.chemdraw+xml',
+ 'cdy' => 'application/vnd.cinderella',
+ 'cer' => 'application/pkix-cert',
+ 'cfs' => 'application/x-cfs-compressed',
+ 'cgm' => 'image/cgm',
+ 'chat' => 'application/x-chat',
+ 'chm' => 'application/vnd.ms-htmlhelp',
+ 'chrt' => 'application/vnd.kde.kchart',
+ 'cif' => 'chemical/x-cif',
+ 'cii' => 'application/vnd.anser-web-certificate-issue-initiation',
+ 'cil' => 'application/vnd.ms-artgalry',
+ 'cla' => 'application/vnd.claymore',
+ 'class' => 'application/java-vm',
+ 'clkk' => 'application/vnd.crick.clicker.keyboard',
+ 'clkp' => 'application/vnd.crick.clicker.palette',
+ 'clkt' => 'application/vnd.crick.clicker.template',
+ 'clkw' => 'application/vnd.crick.clicker.wordbank',
+ 'clkx' => 'application/vnd.crick.clicker',
+ 'clp' => 'application/x-msclip',
+ 'cmc' => 'application/vnd.cosmocaller',
+ 'cmdf' => 'chemical/x-cmdf',
+ 'cml' => 'chemical/x-cml',
+ 'cmp' => 'application/vnd.yellowriver-custom-menu',
+ 'cmx' => 'image/x-cmx',
+ 'cod' => 'application/vnd.rim.cod',
+ 'com' => 'application/x-msdownload',
+ 'conf' => 'text/plain',
+ 'cpio' => 'application/x-cpio',
+ 'cpp' => 'text/x-c',
+ 'cpt' => 'application/mac-compactpro',
+ 'crd' => 'application/x-mscardfile',
+ 'crl' => 'application/pkix-crl',
+ 'crt' => 'application/x-x509-ca-cert',
+ 'csh' => 'application/x-csh',
+ 'csml' => 'chemical/x-csml',
+ 'csp' => 'application/vnd.commonspace',
+ 'css' => 'text/css',
+ 'cst' => 'application/x-director',
+ 'csv' => 'text/csv',
+ 'cu' => 'application/cu-seeme',
+ 'curl' => 'text/vnd.curl',
+ 'cww' => 'application/prs.cww',
+ 'cxt' => 'application/x-director',
+ 'cxx' => 'text/x-c',
+ 'dae' => 'model/vnd.collada+xml',
+ 'daf' => 'application/vnd.mobius.daf',
+ 'dart' => 'application/vnd.dart',
+ 'dataless' => 'application/vnd.fdsn.seed',
+ 'davmount' => 'application/davmount+xml',
+ 'dbk' => 'application/docbook+xml',
+ 'dcr' => 'application/x-director',
+ 'dcurl' => 'text/vnd.curl.dcurl',
+ 'dd2' => 'application/vnd.oma.dd2+xml',
+ 'ddd' => 'application/vnd.fujixerox.ddd',
+ 'deb' => 'application/x-debian-package',
+ 'def' => 'text/plain',
+ 'deploy' => 'application/octet-stream',
+ 'der' => 'application/x-x509-ca-cert',
+ 'dfac' => 'application/vnd.dreamfactory',
+ 'dgc' => 'application/x-dgc-compressed',
+ 'dic' => 'text/x-c',
+ 'dir' => 'application/x-director',
+ 'dis' => 'application/vnd.mobius.dis',
+ 'dist' => 'application/octet-stream',
+ 'distz' => 'application/octet-stream',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'dll' => 'application/x-msdownload',
+ 'dmg' => 'application/x-apple-diskimage',
+ 'dmp' => 'application/vnd.tcpdump.pcap',
+ 'dms' => 'application/octet-stream',
+ 'dna' => 'application/vnd.dna',
+ 'doc' => 'application/msword',
+ 'docm' => 'application/vnd.ms-word.document.macroenabled.12',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dot' => 'application/msword',
+ 'dotm' => 'application/vnd.ms-word.template.macroenabled.12',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'dp' => 'application/vnd.osgi.dp',
+ 'dpg' => 'application/vnd.dpgraph',
+ 'dra' => 'audio/vnd.dra',
+ 'dsc' => 'text/prs.lines.tag',
+ 'dssc' => 'application/dssc+der',
+ 'dtb' => 'application/x-dtbook+xml',
+ 'dtd' => 'application/xml-dtd',
+ 'dts' => 'audio/vnd.dts',
+ 'dtshd' => 'audio/vnd.dts.hd',
+ 'dump' => 'application/octet-stream',
+ 'dvb' => 'video/vnd.dvb.file',
+ 'dvi' => 'application/x-dvi',
+ 'dwf' => 'model/vnd.dwf',
+ 'dwg' => 'image/vnd.dwg',
+ 'dxf' => 'image/vnd.dxf',
+ 'dxp' => 'application/vnd.spotfire.dxp',
+ 'dxr' => 'application/x-director',
+ 'ecelp4800' => 'audio/vnd.nuera.ecelp4800',
+ 'ecelp7470' => 'audio/vnd.nuera.ecelp7470',
+ 'ecelp9600' => 'audio/vnd.nuera.ecelp9600',
+ 'ecma' => 'application/ecmascript',
+ 'edm' => 'application/vnd.novadigm.edm',
+ 'edx' => 'application/vnd.novadigm.edx',
+ 'efif' => 'application/vnd.picsel',
+ 'ei6' => 'application/vnd.pg.osasli',
+ 'elc' => 'application/octet-stream',
+ 'emf' => 'application/x-msmetafile',
+ 'eml' => 'message/rfc822',
+ 'emma' => 'application/emma+xml',
+ 'emz' => 'application/x-msmetafile',
+ 'eol' => 'audio/vnd.digital-winds',
+ 'eot' => 'application/vnd.ms-fontobject',
+ 'eps' => 'application/postscript',
+ 'epub' => 'application/epub+zip',
+ 'es3' => 'application/vnd.eszigno3+xml',
+ 'esa' => 'application/vnd.osgi.subsystem',
+ 'esf' => 'application/vnd.epson.esf',
+ 'et3' => 'application/vnd.eszigno3+xml',
+ 'etx' => 'text/x-setext',
+ 'eva' => 'application/x-eva',
+ 'evy' => 'application/x-envoy',
+ 'exe' => 'application/x-msdownload',
+ 'exi' => 'application/exi',
+ 'ext' => 'application/vnd.novadigm.ext',
+ 'ez' => 'application/andrew-inset',
+ 'ez2' => 'application/vnd.ezpix-album',
+ 'ez3' => 'application/vnd.ezpix-package',
+ 'f' => 'text/x-fortran',
+ 'f4v' => 'video/x-f4v',
+ 'f77' => 'text/x-fortran',
+ 'f90' => 'text/x-fortran',
+ 'fbs' => 'image/vnd.fastbidsheet',
+ 'fcdt' => 'application/vnd.adobe.formscentral.fcdt',
+ 'fcs' => 'application/vnd.isac.fcs',
+ 'fdf' => 'application/vnd.fdf',
+ 'fe_launch' => 'application/vnd.denovo.fcselayout-link',
+ 'fg5' => 'application/vnd.fujitsu.oasysgp',
+ 'fgd' => 'application/x-director',
+ 'fh' => 'image/x-freehand',
+ 'fh4' => 'image/x-freehand',
+ 'fh5' => 'image/x-freehand',
+ 'fh7' => 'image/x-freehand',
+ 'fhc' => 'image/x-freehand',
+ 'fig' => 'application/x-xfig',
+ 'flac' => 'audio/x-flac',
+ 'fli' => 'video/x-fli',
+ 'flo' => 'application/vnd.micrografx.flo',
+ 'flv' => 'video/x-flv',
+ 'flw' => 'application/vnd.kde.kivio',
+ 'flx' => 'text/vnd.fmi.flexstor',
+ 'fly' => 'text/vnd.fly',
+ 'fm' => 'application/vnd.framemaker',
+ 'fnc' => 'application/vnd.frogans.fnc',
+ 'for' => 'text/x-fortran',
+ 'fpx' => 'image/vnd.fpx',
+ 'frame' => 'application/vnd.framemaker',
+ 'fsc' => 'application/vnd.fsc.weblaunch',
+ 'fst' => 'image/vnd.fst',
+ 'ftc' => 'application/vnd.fluxtime.clip',
+ 'fti' => 'application/vnd.anser-web-funds-transfer-initiation',
+ 'fvt' => 'video/vnd.fvt',
+ 'fxp' => 'application/vnd.adobe.fxp',
+ 'fxpl' => 'application/vnd.adobe.fxp',
+ 'fzs' => 'application/vnd.fuzzysheet',
+ 'g2w' => 'application/vnd.geoplan',
+ 'g3' => 'image/g3fax',
+ 'g3w' => 'application/vnd.geospace',
+ 'gac' => 'application/vnd.groove-account',
+ 'gam' => 'application/x-tads',
+ 'gbr' => 'application/rpki-ghostbusters',
+ 'gca' => 'application/x-gca-compressed',
+ 'gdl' => 'model/vnd.gdl',
+ 'geo' => 'application/vnd.dynageo',
+ 'gex' => 'application/vnd.geometry-explorer',
+ 'ggb' => 'application/vnd.geogebra.file',
+ 'ggt' => 'application/vnd.geogebra.tool',
+ 'ghf' => 'application/vnd.groove-help',
+ 'gif' => 'image/gif',
+ 'gim' => 'application/vnd.groove-identity-message',
+ 'gml' => 'application/gml+xml',
+ 'gmx' => 'application/vnd.gmx',
+ 'gnumeric' => 'application/x-gnumeric',
+ 'gph' => 'application/vnd.flographit',
+ 'gpx' => 'application/gpx+xml',
+ 'gqf' => 'application/vnd.grafeq',
+ 'gqs' => 'application/vnd.grafeq',
+ 'gram' => 'application/srgs',
+ 'gramps' => 'application/x-gramps-xml',
+ 'gre' => 'application/vnd.geometry-explorer',
+ 'grv' => 'application/vnd.groove-injector',
+ 'grxml' => 'application/srgs+xml',
+ 'gsf' => 'application/x-font-ghostscript',
+ 'gtar' => 'application/x-gtar',
+ 'gtm' => 'application/vnd.groove-tool-message',
+ 'gtw' => 'model/vnd.gtw',
+ 'gv' => 'text/vnd.graphviz',
+ 'gxf' => 'application/gxf',
+ 'gxt' => 'application/vnd.geonext',
+ 'gz' => 'application/x-gzip',
+ 'h' => 'text/x-c',
+ 'h261' => 'video/h261',
+ 'h263' => 'video/h263',
+ 'h264' => 'video/h264',
+ 'hal' => 'application/vnd.hal+xml',
+ 'hbci' => 'application/vnd.hbci',
+ 'hdf' => 'application/x-hdf',
+ 'hh' => 'text/x-c',
+ 'hlp' => 'application/winhlp',
+ 'hpgl' => 'application/vnd.hp-hpgl',
+ 'hpid' => 'application/vnd.hp-hpid',
+ 'hps' => 'application/vnd.hp-hps',
+ 'hqx' => 'application/mac-binhex40',
+ 'htke' => 'application/vnd.kenameaapp',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'hvd' => 'application/vnd.yamaha.hv-dic',
+ 'hvp' => 'application/vnd.yamaha.hv-voice',
+ 'hvs' => 'application/vnd.yamaha.hv-script',
+ 'i2g' => 'application/vnd.intergeo',
+ 'icc' => 'application/vnd.iccprofile',
+ 'ice' => 'x-conference/x-cooltalk',
+ 'icm' => 'application/vnd.iccprofile',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ief' => 'image/ief',
+ 'ifb' => 'text/calendar',
+ 'ifm' => 'application/vnd.shana.informed.formdata',
+ 'iges' => 'model/iges',
+ 'igl' => 'application/vnd.igloader',
+ 'igm' => 'application/vnd.insors.igm',
+ 'igs' => 'model/iges',
+ 'igx' => 'application/vnd.micrografx.igx',
+ 'iif' => 'application/vnd.shana.informed.interchange',
+ 'imp' => 'application/vnd.accpac.simply.imp',
+ 'ims' => 'application/vnd.ms-ims',
+ 'in' => 'text/plain',
+ 'ink' => 'application/inkml+xml',
+ 'inkml' => 'application/inkml+xml',
+ 'install' => 'application/x-install-instructions',
+ 'iota' => 'application/vnd.astraea-software.iota',
+ 'ipfix' => 'application/ipfix',
+ 'ipk' => 'application/vnd.shana.informed.package',
+ 'irm' => 'application/vnd.ibm.rights-management',
+ 'irp' => 'application/vnd.irepository.package+xml',
+ 'iso' => 'application/x-iso9660-image',
+ 'itp' => 'application/vnd.shana.informed.formtemplate',
+ 'ivp' => 'application/vnd.immervision-ivp',
+ 'ivu' => 'application/vnd.immervision-ivu',
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
+ 'jam' => 'application/vnd.jam',
+ 'jar' => 'application/java-archive',
+ 'java' => 'text/x-java-source',
+ 'jisp' => 'application/vnd.jisp',
+ 'jlt' => 'application/vnd.hp-jlyt',
+ 'jnlp' => 'application/x-java-jnlp-file',
+ 'joda' => 'application/vnd.joost.joda-archive',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'jpgm' => 'video/jpm',
+ 'jpgv' => 'video/jpeg',
+ 'jpm' => 'video/jpm',
+ 'js' => 'application/javascript',
+ 'json' => 'application/json',
+ 'jsonml' => 'application/jsonml+json',
+ 'kar' => 'audio/midi',
+ 'karbon' => 'application/vnd.kde.karbon',
+ 'kfo' => 'application/vnd.kde.kformula',
+ 'kia' => 'application/vnd.kidspiration',
+ 'kml' => 'application/vnd.google-earth.kml+xml',
+ 'kmz' => 'application/vnd.google-earth.kmz',
+ 'kne' => 'application/vnd.kinar',
+ 'knp' => 'application/vnd.kinar',
+ 'kon' => 'application/vnd.kde.kontour',
+ 'kpr' => 'application/vnd.kde.kpresenter',
+ 'kpt' => 'application/vnd.kde.kpresenter',
+ 'kpxx' => 'application/vnd.ds-keypoint',
+ 'ksp' => 'application/vnd.kde.kspread',
+ 'ktr' => 'application/vnd.kahootz',
+ 'ktx' => 'image/ktx',
+ 'ktz' => 'application/vnd.kahootz',
+ 'kwd' => 'application/vnd.kde.kword',
+ 'kwt' => 'application/vnd.kde.kword',
+ 'lasxml' => 'application/vnd.las.las+xml',
+ 'latex' => 'application/x-latex',
+ 'lbd' => 'application/vnd.llamagraphics.life-balance.desktop',
+ 'lbe' => 'application/vnd.llamagraphics.life-balance.exchange+xml',
+ 'les' => 'application/vnd.hhe.lesson-player',
+ 'lha' => 'application/x-lzh-compressed',
+ 'link66' => 'application/vnd.route66.link66+xml',
+ 'list' => 'text/plain',
+ 'list3820' => 'application/vnd.ibm.modcap',
+ 'listafp' => 'application/vnd.ibm.modcap',
+ 'lnk' => 'application/x-ms-shortcut',
+ 'log' => 'text/plain',
+ 'lostxml' => 'application/lost+xml',
+ 'lrf' => 'application/octet-stream',
+ 'lrm' => 'application/vnd.ms-lrm',
+ 'ltf' => 'application/vnd.frogans.ltf',
+ 'lvp' => 'audio/vnd.lucent.voice',
+ 'lwp' => 'application/vnd.lotus-wordpro',
+ 'lzh' => 'application/x-lzh-compressed',
+ 'm13' => 'application/x-msmediaview',
+ 'm14' => 'application/x-msmediaview',
+ 'm1v' => 'video/mpeg',
+ 'm21' => 'application/mp21',
+ 'm2a' => 'audio/mpeg',
+ 'm2v' => 'video/mpeg',
+ 'm3a' => 'audio/mpeg',
+ 'm3u' => 'audio/x-mpegurl',
+ 'm3u8' => 'application/vnd.apple.mpegurl',
+ 'm4a' => 'audio/mp4',
+ 'm4u' => 'video/vnd.mpegurl',
+ 'm4v' => 'video/x-m4v',
+ 'ma' => 'application/mathematica',
+ 'mads' => 'application/mads+xml',
+ 'mag' => 'application/vnd.ecowin.chart',
+ 'maker' => 'application/vnd.framemaker',
+ 'man' => 'text/troff',
+ 'mar' => 'application/octet-stream',
+ 'mathml' => 'application/mathml+xml',
+ 'mb' => 'application/mathematica',
+ 'mbk' => 'application/vnd.mobius.mbk',
+ 'mbox' => 'application/mbox',
+ 'mc1' => 'application/vnd.medcalcdata',
+ 'mcd' => 'application/vnd.mcd',
+ 'mcurl' => 'text/vnd.curl.mcurl',
+ 'mdb' => 'application/x-msaccess',
+ 'mdi' => 'image/vnd.ms-modi',
+ 'me' => 'text/troff',
+ 'mesh' => 'model/mesh',
+ 'meta4' => 'application/metalink4+xml',
+ 'metalink' => 'application/metalink+xml',
+ 'mets' => 'application/mets+xml',
+ 'mfm' => 'application/vnd.mfmp',
+ 'mft' => 'application/rpki-manifest',
+ 'mgp' => 'application/vnd.osgeo.mapguide.package',
+ 'mgz' => 'application/vnd.proteus.magazine',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mie' => 'application/x-mie',
+ 'mif' => 'application/vnd.mif',
+ 'mime' => 'message/rfc822',
+ 'mj2' => 'video/mj2',
+ 'mjp2' => 'video/mj2',
+ 'mk3d' => 'video/x-matroska',
+ 'mka' => 'audio/x-matroska',
+ 'mks' => 'video/x-matroska',
+ 'mkv' => 'video/x-matroska',
+ 'mlp' => 'application/vnd.dolby.mlp',
+ 'mmd' => 'application/vnd.chipnuts.karaoke-mmd',
+ 'mmf' => 'application/vnd.smaf',
+ 'mmr' => 'image/vnd.fujixerox.edmics-mmr',
+ 'mng' => 'video/x-mng',
+ 'mny' => 'application/x-msmoney',
+ 'mobi' => 'application/x-mobipocket-ebook',
+ 'mods' => 'application/mods+xml',
+ 'mov' => 'video/quicktime',
+ 'movie' => 'video/x-sgi-movie',
+ 'mp2' => 'audio/mpeg',
+ 'mp21' => 'application/mp21',
+ 'mp2a' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mp4a' => 'audio/mp4',
+ 'mp4s' => 'application/mp4',
+ 'mp4v' => 'video/mp4',
+ 'mpc' => 'application/vnd.mophun.certificate',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpg4' => 'video/mp4',
+ 'mpga' => 'audio/mpeg',
+ 'mpkg' => 'application/vnd.apple.installer+xml',
+ 'mpm' => 'application/vnd.blueice.multipass',
+ 'mpn' => 'application/vnd.mophun.application',
+ 'mpp' => 'application/vnd.ms-project',
+ 'mpt' => 'application/vnd.ms-project',
+ 'mpy' => 'application/vnd.ibm.minipay',
+ 'mqy' => 'application/vnd.mobius.mqy',
+ 'mrc' => 'application/marc',
+ 'mrcx' => 'application/marcxml+xml',
+ 'ms' => 'text/troff',
+ 'mscml' => 'application/mediaservercontrol+xml',
+ 'mseed' => 'application/vnd.fdsn.mseed',
+ 'mseq' => 'application/vnd.mseq',
+ 'msf' => 'application/vnd.epson.msf',
+ 'msh' => 'model/mesh',
+ 'msi' => 'application/x-msdownload',
+ 'msl' => 'application/vnd.mobius.msl',
+ 'msty' => 'application/vnd.muvee.style',
+ 'mts' => 'model/vnd.mts',
+ 'mus' => 'application/vnd.musician',
+ 'musicxml' => 'application/vnd.recordare.musicxml+xml',
+ 'mvb' => 'application/x-msmediaview',
+ 'mwf' => 'application/vnd.mfer',
+ 'mxf' => 'application/mxf',
+ 'mxl' => 'application/vnd.recordare.musicxml',
+ 'mxml' => 'application/xv+xml',
+ 'mxs' => 'application/vnd.triscape.mxs',
+ 'mxu' => 'video/vnd.mpegurl',
+ 'n-gage' => 'application/vnd.nokia.n-gage.symbian.install',
+ 'n3' => 'text/n3',
+ 'nb' => 'application/mathematica',
+ 'nbp' => 'application/vnd.wolfram.player',
+ 'nc' => 'application/x-netcdf',
+ 'ncx' => 'application/x-dtbncx+xml',
+ 'nfo' => 'text/x-nfo',
+ 'ngdat' => 'application/vnd.nokia.n-gage.data',
+ 'nitf' => 'application/vnd.nitf',
+ 'nlu' => 'application/vnd.neurolanguage.nlu',
+ 'nml' => 'application/vnd.enliven',
+ 'nnd' => 'application/vnd.noblenet-directory',
+ 'nns' => 'application/vnd.noblenet-sealer',
+ 'nnw' => 'application/vnd.noblenet-web',
+ 'npx' => 'image/vnd.net-fpx',
+ 'nsc' => 'application/x-conference',
+ 'nsf' => 'application/vnd.lotus-notes',
+ 'ntf' => 'application/vnd.nitf',
+ 'nzb' => 'application/x-nzb',
+ 'oa2' => 'application/vnd.fujitsu.oasys2',
+ 'oa3' => 'application/vnd.fujitsu.oasys3',
+ 'oas' => 'application/vnd.fujitsu.oasys',
+ 'obd' => 'application/x-msbinder',
+ 'obj' => 'application/x-tgif',
+ 'oda' => 'application/oda',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'odft' => 'application/vnd.oasis.opendocument.formula-template',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'oga' => 'audio/ogg',
+ 'ogg' => 'audio/ogg',
+ 'ogv' => 'video/ogg',
+ 'ogx' => 'application/ogg',
+ 'omdoc' => 'application/omdoc+xml',
+ 'onepkg' => 'application/onenote',
+ 'onetmp' => 'application/onenote',
+ 'onetoc' => 'application/onenote',
+ 'onetoc2' => 'application/onenote',
+ 'opf' => 'application/oebps-package+xml',
+ 'opml' => 'text/x-opml',
+ 'oprc' => 'application/vnd.palm',
+ 'org' => 'application/vnd.lotus-organizer',
+ 'osf' => 'application/vnd.yamaha.openscoreformat',
+ 'osfpvg' => 'application/vnd.yamaha.openscoreformat.osfpvg+xml',
+ 'otc' => 'application/vnd.oasis.opendocument.chart-template',
+ 'otf' => 'application/x-font-otf',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'oti' => 'application/vnd.oasis.opendocument.image-template',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oxps' => 'application/oxps',
+ 'oxt' => 'application/vnd.openofficeorg.extension',
+ 'p' => 'text/x-pascal',
+ 'p10' => 'application/pkcs10',
+ 'p12' => 'application/x-pkcs12',
+ 'p7b' => 'application/x-pkcs7-certificates',
+ 'p7c' => 'application/pkcs7-mime',
+ 'p7m' => 'application/pkcs7-mime',
+ 'p7r' => 'application/x-pkcs7-certreqresp',
+ 'p7s' => 'application/pkcs7-signature',
+ 'p8' => 'application/pkcs8',
+ 'pas' => 'text/x-pascal',
+ 'paw' => 'application/vnd.pawaafile',
+ 'pbd' => 'application/vnd.powerbuilder6',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pcap' => 'application/vnd.tcpdump.pcap',
+ 'pcf' => 'application/x-font-pcf',
+ 'pcl' => 'application/vnd.hp-pcl',
+ 'pclxl' => 'application/vnd.hp-pclxl',
+ 'pct' => 'image/x-pict',
+ 'pcurl' => 'application/vnd.curl.pcurl',
+ 'pcx' => 'image/x-pcx',
+ 'pdb' => 'application/vnd.palm',
+ 'pdf' => 'application/pdf',
+ 'pfa' => 'application/x-font-type1',
+ 'pfb' => 'application/x-font-type1',
+ 'pfm' => 'application/x-font-type1',
+ 'pfr' => 'application/font-tdpfr',
+ 'pfx' => 'application/x-pkcs12',
+ 'pgm' => 'image/x-portable-graymap',
+ 'pgn' => 'application/x-chess-pgn',
+ 'pgp' => 'application/pgp-encrypted',
+ 'php' => 'application/x-php',
+ 'php3' => 'application/x-php',
+ 'php4' => 'application/x-php',
+ 'php5' => 'application/x-php',
+ 'pic' => 'image/x-pict',
+ 'pkg' => 'application/octet-stream',
+ 'pki' => 'application/pkixcmp',
+ 'pkipath' => 'application/pkix-pkipath',
+ 'plb' => 'application/vnd.3gpp.pic-bw-large',
+ 'plc' => 'application/vnd.mobius.plc',
+ 'plf' => 'application/vnd.pocketlearn',
+ 'pls' => 'application/pls+xml',
+ 'pml' => 'application/vnd.ctc-posml',
+ 'png' => 'image/png',
+ 'pnm' => 'image/x-portable-anymap',
+ 'portpkg' => 'application/vnd.macports.portpkg',
+ 'pot' => 'application/vnd.ms-powerpoint',
+ 'potm' => 'application/vnd.ms-powerpoint.template.macroenabled.12',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppam' => 'application/vnd.ms-powerpoint.addin.macroenabled.12',
+ 'ppd' => 'application/vnd.cups-ppd',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'pps' => 'application/vnd.ms-powerpoint',
+ 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroenabled.12',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroenabled.12',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'pqa' => 'application/vnd.palm',
+ 'prc' => 'application/x-mobipocket-ebook',
+ 'pre' => 'application/vnd.lotus-freelance',
+ 'prf' => 'application/pics-rules',
+ 'ps' => 'application/postscript',
+ 'psb' => 'application/vnd.3gpp.pic-bw-small',
+ 'psd' => 'image/vnd.adobe.photoshop',
+ 'psf' => 'application/x-font-linux-psf',
+ 'pskcxml' => 'application/pskc+xml',
+ 'ptid' => 'application/vnd.pvi.ptid1',
+ 'pub' => 'application/x-mspublisher',
+ 'pvb' => 'application/vnd.3gpp.pic-bw-var',
+ 'pwn' => 'application/vnd.3m.post-it-notes',
+ 'pya' => 'audio/vnd.ms-playready.media.pya',
+ 'pyv' => 'video/vnd.ms-playready.media.pyv',
+ 'qam' => 'application/vnd.epson.quickanime',
+ 'qbo' => 'application/vnd.intu.qbo',
+ 'qfx' => 'application/vnd.intu.qfx',
+ 'qps' => 'application/vnd.publishare-delta-tree',
+ 'qt' => 'video/quicktime',
+ 'qwd' => 'application/vnd.quark.quarkxpress',
+ 'qwt' => 'application/vnd.quark.quarkxpress',
+ 'qxb' => 'application/vnd.quark.quarkxpress',
+ 'qxd' => 'application/vnd.quark.quarkxpress',
+ 'qxl' => 'application/vnd.quark.quarkxpress',
+ 'qxt' => 'application/vnd.quark.quarkxpress',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rar' => 'application/x-rar-compressed',
+ 'ras' => 'image/x-cmu-raster',
+ 'rcprofile' => 'application/vnd.ipunplugged.rcprofile',
+ 'rdf' => 'application/rdf+xml',
+ 'rdz' => 'application/vnd.data-vision.rdz',
+ 'rep' => 'application/vnd.businessobjects',
+ 'res' => 'application/x-dtbresource+xml',
+ 'rgb' => 'image/x-rgb',
+ 'rif' => 'application/reginfo+xml',
+ 'rip' => 'audio/vnd.rip',
+ 'ris' => 'application/x-research-info-systems',
+ 'rl' => 'application/resource-lists+xml',
+ 'rlc' => 'image/vnd.fujixerox.edmics-rlc',
+ 'rld' => 'application/resource-lists-diff+xml',
+ 'rm' => 'application/vnd.rn-realmedia',
+ 'rmi' => 'audio/midi',
+ 'rmp' => 'audio/x-pn-realaudio-plugin',
+ 'rms' => 'application/vnd.jcp.javame.midlet-rms',
+ 'rmvb' => 'application/vnd.rn-realmedia-vbr',
+ 'rnc' => 'application/relax-ng-compact-syntax',
+ 'roa' => 'application/rpki-roa',
+ 'roff' => 'text/troff',
+ 'rp9' => 'application/vnd.cloanto.rp9',
+ 'rpss' => 'application/vnd.nokia.radio-presets',
+ 'rpst' => 'application/vnd.nokia.radio-preset',
+ 'rq' => 'application/sparql-query',
+ 'rs' => 'application/rls-services+xml',
+ 'rsd' => 'application/rsd+xml',
+ 'rss' => 'application/rss+xml',
+ 'rtf' => 'application/rtf',
+ 'rtx' => 'text/richtext',
+ 's' => 'text/x-asm',
+ 's3m' => 'audio/s3m',
+ 'saf' => 'application/vnd.yamaha.smaf-audio',
+ 'sbml' => 'application/sbml+xml',
+ 'sc' => 'application/vnd.ibm.secure-container',
+ 'scd' => 'application/x-msschedule',
+ 'scm' => 'application/vnd.lotus-screencam',
+ 'scq' => 'application/scvp-cv-request',
+ 'scs' => 'application/scvp-cv-response',
+ 'scurl' => 'text/vnd.curl.scurl',
+ 'sda' => 'application/vnd.stardivision.draw',
+ 'sdc' => 'application/vnd.stardivision.calc',
+ 'sdd' => 'application/vnd.stardivision.impress',
+ 'sdkd' => 'application/vnd.solent.sdkm+xml',
+ 'sdkm' => 'application/vnd.solent.sdkm+xml',
+ 'sdp' => 'application/sdp',
+ 'sdw' => 'application/vnd.stardivision.writer',
+ 'see' => 'application/vnd.seemail',
+ 'seed' => 'application/vnd.fdsn.seed',
+ 'sema' => 'application/vnd.sema',
+ 'semd' => 'application/vnd.semd',
+ 'semf' => 'application/vnd.semf',
+ 'ser' => 'application/java-serialized-object',
+ 'setpay' => 'application/set-payment-initiation',
+ 'setreg' => 'application/set-registration-initiation',
+ 'sfd-hdstx' => 'application/vnd.hydrostatix.sof-data',
+ 'sfs' => 'application/vnd.spotfire.sfs',
+ 'sfv' => 'text/x-sfv',
+ 'sgi' => 'image/sgi',
+ 'sgl' => 'application/vnd.stardivision.writer-global',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'sh' => 'application/x-sh',
+ 'shar' => 'application/x-shar',
+ 'shf' => 'application/shf+xml',
+ 'sid' => 'image/x-mrsid-image',
+ 'sig' => 'application/pgp-signature',
+ 'sil' => 'audio/silk',
+ 'silo' => 'model/mesh',
+ 'sis' => 'application/vnd.symbian.install',
+ 'sisx' => 'application/vnd.symbian.install',
+ 'sit' => 'application/x-stuffit',
+ 'sitx' => 'application/x-stuffitx',
+ 'skd' => 'application/vnd.koan',
+ 'skm' => 'application/vnd.koan',
+ 'skp' => 'application/vnd.koan',
+ 'skt' => 'application/vnd.koan',
+ 'sldm' => 'application/vnd.ms-powerpoint.slide.macroenabled.12',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'slt' => 'application/vnd.epson.salt',
+ 'sm' => 'application/vnd.stepmania.stepchart',
+ 'smf' => 'application/vnd.stardivision.math',
+ 'smi' => 'application/smil+xml',
+ 'smil' => 'application/smil+xml',
+ 'smv' => 'video/x-smv',
+ 'smzip' => 'application/vnd.stepmania.package',
+ 'snd' => 'audio/basic',
+ 'snf' => 'application/x-font-snf',
+ 'so' => 'application/octet-stream',
+ 'spc' => 'application/x-pkcs7-certificates',
+ 'spf' => 'application/vnd.yamaha.smaf-phrase',
+ 'spl' => 'application/x-futuresplash',
+ 'spot' => 'text/vnd.in3d.spot',
+ 'spp' => 'application/scvp-vp-response',
+ 'spq' => 'application/scvp-vp-request',
+ 'spx' => 'audio/ogg',
+ 'sql' => 'application/x-sql',
+ 'src' => 'application/x-wais-source',
+ 'srt' => 'application/x-subrip',
+ 'sru' => 'application/sru+xml',
+ 'srx' => 'application/sparql-results+xml',
+ 'ssdl' => 'application/ssdl+xml',
+ 'sse' => 'application/vnd.kodak-descriptor',
+ 'ssf' => 'application/vnd.epson.ssf',
+ 'ssml' => 'application/ssml+xml',
+ 'st' => 'application/vnd.sailingtracker.track',
+ 'stc' => 'application/vnd.sun.xml.calc.template',
+ 'std' => 'application/vnd.sun.xml.draw.template',
+ 'stf' => 'application/vnd.wt.stf',
+ 'sti' => 'application/vnd.sun.xml.impress.template',
+ 'stk' => 'application/hyperstudio',
+ 'stl' => 'application/vnd.ms-pki.stl',
+ 'str' => 'application/vnd.pg.format',
+ 'stw' => 'application/vnd.sun.xml.writer.template',
+ 'sub' => 'text/vnd.dvb.subtitle',
+ 'sus' => 'application/vnd.sus-calendar',
+ 'susp' => 'application/vnd.sus-calendar',
+ 'sv4cpio' => 'application/x-sv4cpio',
+ 'sv4crc' => 'application/x-sv4crc',
+ 'svc' => 'application/vnd.dvb.service',
+ 'svd' => 'application/vnd.svd',
+ 'svg' => 'image/svg+xml',
+ 'svgz' => 'image/svg+xml',
+ 'swa' => 'application/x-director',
+ 'swf' => 'application/x-shockwave-flash',
+ 'swi' => 'application/vnd.aristanetworks.swi',
+ 'sxc' => 'application/vnd.sun.xml.calc',
+ 'sxd' => 'application/vnd.sun.xml.draw',
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
+ 'sxi' => 'application/vnd.sun.xml.impress',
+ 'sxm' => 'application/vnd.sun.xml.math',
+ 'sxw' => 'application/vnd.sun.xml.writer',
+ 't' => 'text/troff',
+ 't3' => 'application/x-t3vm-image',
+ 'taglet' => 'application/vnd.mynfc',
+ 'tao' => 'application/vnd.tao.intent-module-archive',
+ 'tar' => 'application/x-tar',
+ 'tcap' => 'application/vnd.3gpp2.tcap',
+ 'tcl' => 'application/x-tcl',
+ 'teacher' => 'application/vnd.smart.teacher',
+ 'tei' => 'application/tei+xml',
+ 'teicorpus' => 'application/tei+xml',
+ 'tex' => 'application/x-tex',
+ 'texi' => 'application/x-texinfo',
+ 'texinfo' => 'application/x-texinfo',
+ 'text' => 'text/plain',
+ 'tfi' => 'application/thraud+xml',
+ 'tfm' => 'application/x-tex-tfm',
+ 'tga' => 'image/x-tga',
+ 'thmx' => 'application/vnd.ms-officetheme',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'tmo' => 'application/vnd.tmobile-livetv',
+ 'torrent' => 'application/x-bittorrent',
+ 'tpl' => 'application/vnd.groove-tool-template',
+ 'tpt' => 'application/vnd.trid.tpt',
+ 'tr' => 'text/troff',
+ 'tra' => 'application/vnd.trueapp',
+ 'trm' => 'application/x-msterminal',
+ 'tsd' => 'application/timestamped-data',
+ 'tsv' => 'text/tab-separated-values',
+ 'ttc' => 'application/x-font-ttf',
+ 'ttf' => 'application/x-font-ttf',
+ 'ttl' => 'text/turtle',
+ 'twd' => 'application/vnd.simtech-mindmapper',
+ 'twds' => 'application/vnd.simtech-mindmapper',
+ 'txd' => 'application/vnd.genomatix.tuxedo',
+ 'txf' => 'application/vnd.mobius.txf',
+ 'txt' => 'text/plain',
+ 'u32' => 'application/x-authorware-bin',
+ 'udeb' => 'application/x-debian-package',
+ 'ufd' => 'application/vnd.ufdl',
+ 'ufdl' => 'application/vnd.ufdl',
+ 'ulx' => 'application/x-glulx',
+ 'umj' => 'application/vnd.umajin',
+ 'unityweb' => 'application/vnd.unity',
+ 'uoml' => 'application/vnd.uoml+xml',
+ 'uri' => 'text/uri-list',
+ 'uris' => 'text/uri-list',
+ 'urls' => 'text/uri-list',
+ 'ustar' => 'application/x-ustar',
+ 'utz' => 'application/vnd.uiq.theme',
+ 'uu' => 'text/x-uuencode',
+ 'uva' => 'audio/vnd.dece.audio',
+ 'uvd' => 'application/vnd.dece.data',
+ 'uvf' => 'application/vnd.dece.data',
+ 'uvg' => 'image/vnd.dece.graphic',
+ 'uvh' => 'video/vnd.dece.hd',
+ 'uvi' => 'image/vnd.dece.graphic',
+ 'uvm' => 'video/vnd.dece.mobile',
+ 'uvp' => 'video/vnd.dece.pd',
+ 'uvs' => 'video/vnd.dece.sd',
+ 'uvt' => 'application/vnd.dece.ttml+xml',
+ 'uvu' => 'video/vnd.uvvu.mp4',
+ 'uvv' => 'video/vnd.dece.video',
+ 'uvva' => 'audio/vnd.dece.audio',
+ 'uvvd' => 'application/vnd.dece.data',
+ 'uvvf' => 'application/vnd.dece.data',
+ 'uvvg' => 'image/vnd.dece.graphic',
+ 'uvvh' => 'video/vnd.dece.hd',
+ 'uvvi' => 'image/vnd.dece.graphic',
+ 'uvvm' => 'video/vnd.dece.mobile',
+ 'uvvp' => 'video/vnd.dece.pd',
+ 'uvvs' => 'video/vnd.dece.sd',
+ 'uvvt' => 'application/vnd.dece.ttml+xml',
+ 'uvvu' => 'video/vnd.uvvu.mp4',
+ 'uvvv' => 'video/vnd.dece.video',
+ 'uvvx' => 'application/vnd.dece.unspecified',
+ 'uvvz' => 'application/vnd.dece.zip',
+ 'uvx' => 'application/vnd.dece.unspecified',
+ 'uvz' => 'application/vnd.dece.zip',
+ 'vcard' => 'text/vcard',
+ 'vcd' => 'application/x-cdlink',
+ 'vcf' => 'text/x-vcard',
+ 'vcg' => 'application/vnd.groove-vcard',
+ 'vcs' => 'text/x-vcalendar',
+ 'vcx' => 'application/vnd.vcx',
+ 'vis' => 'application/vnd.visionary',
+ 'viv' => 'video/vnd.vivo',
+ 'vob' => 'video/x-ms-vob',
+ 'vor' => 'application/vnd.stardivision.writer',
+ 'vox' => 'application/x-authorware-bin',
+ 'vrml' => 'model/vrml',
+ 'vsd' => 'application/vnd.visio',
+ 'vsf' => 'application/vnd.vsf',
+ 'vss' => 'application/vnd.visio',
+ 'vst' => 'application/vnd.visio',
+ 'vsw' => 'application/vnd.visio',
+ 'vtu' => 'model/vnd.vtu',
+ 'vxml' => 'application/voicexml+xml',
+ 'w3d' => 'application/x-director',
+ 'wad' => 'application/x-doom',
+ 'wav' => 'audio/x-wav',
+ 'wax' => 'audio/x-ms-wax',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'wbs' => 'application/vnd.criticaltools.wbs+xml',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wcm' => 'application/vnd.ms-works',
+ 'wdb' => 'application/vnd.ms-works',
+ 'wdp' => 'image/vnd.ms-photo',
+ 'weba' => 'audio/webm',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wg' => 'application/vnd.pmi.widget',
+ 'wgt' => 'application/widget',
+ 'wks' => 'application/vnd.ms-works',
+ 'wm' => 'video/x-ms-wm',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmd' => 'application/x-ms-wmd',
+ 'wmf' => 'application/x-msmetafile',
+ 'wml' => 'text/vnd.wap.wml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'wmls' => 'text/vnd.wap.wmlscript',
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wmz' => 'application/x-msmetafile',
+ 'woff' => 'application/font-woff',
+ 'wpd' => 'application/vnd.wordperfect',
+ 'wpl' => 'application/vnd.ms-wpl',
+ 'wps' => 'application/vnd.ms-works',
+ 'wqd' => 'application/vnd.wqd',
+ 'wri' => 'application/x-mswrite',
+ 'wrl' => 'model/vrml',
+ 'wsdl' => 'application/wsdl+xml',
+ 'wspolicy' => 'application/wspolicy+xml',
+ 'wtb' => 'application/vnd.webturbo',
+ 'wvx' => 'video/x-ms-wvx',
+ 'x32' => 'application/x-authorware-bin',
+ 'x3d' => 'model/x3d+xml',
+ 'x3db' => 'model/x3d+binary',
+ 'x3dbz' => 'model/x3d+binary',
+ 'x3dv' => 'model/x3d+vrml',
+ 'x3dvz' => 'model/x3d+vrml',
+ 'x3dz' => 'model/x3d+xml',
+ 'xaml' => 'application/xaml+xml',
+ 'xap' => 'application/x-silverlight-app',
+ 'xar' => 'application/vnd.xara',
+ 'xbap' => 'application/x-ms-xbap',
+ 'xbd' => 'application/vnd.fujixerox.docuworks.binder',
+ 'xbm' => 'image/x-xbitmap',
+ 'xdf' => 'application/xcap-diff+xml',
+ 'xdm' => 'application/vnd.syncml.dm+xml',
+ 'xdp' => 'application/vnd.adobe.xdp+xml',
+ 'xdssc' => 'application/dssc+xml',
+ 'xdw' => 'application/vnd.fujixerox.docuworks',
+ 'xenc' => 'application/xenc+xml',
+ 'xer' => 'application/patch-ops-error+xml',
+ 'xfdf' => 'application/vnd.adobe.xfdf',
+ 'xfdl' => 'application/vnd.xfdl',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xhvml' => 'application/xv+xml',
+ 'xif' => 'image/vnd.xiff',
+ 'xla' => 'application/vnd.ms-excel',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroenabled.12',
+ 'xlc' => 'application/vnd.ms-excel',
+ 'xlf' => 'application/x-xliff+xml',
+ 'xlm' => 'application/vnd.ms-excel',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroenabled.12',
+ 'xlsm' => 'application/vnd.ms-excel.sheet.macroenabled.12',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xlt' => 'application/vnd.ms-excel',
+ 'xltm' => 'application/vnd.ms-excel.template.macroenabled.12',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'xlw' => 'application/vnd.ms-excel',
+ 'xm' => 'audio/xm',
+ 'xml' => 'application/xml',
+ 'xo' => 'application/vnd.olpc-sugar',
+ 'xop' => 'application/xop+xml',
+ 'xpi' => 'application/x-xpinstall',
+ 'xpl' => 'application/xproc+xml',
+ 'xpm' => 'image/x-xpixmap',
+ 'xpr' => 'application/vnd.is-xpr',
+ 'xps' => 'application/vnd.ms-xpsdocument',
+ 'xpw' => 'application/vnd.intercon.formnet',
+ 'xpx' => 'application/vnd.intercon.formnet',
+ 'xsl' => 'application/xml',
+ 'xslt' => 'application/xslt+xml',
+ 'xsm' => 'application/vnd.syncml+xml',
+ 'xspf' => 'application/xspf+xml',
+ 'xul' => 'application/vnd.mozilla.xul+xml',
+ 'xvm' => 'application/xv+xml',
+ 'xvml' => 'application/xv+xml',
+ 'xwd' => 'image/x-xwindowdump',
+ 'xyz' => 'chemical/x-xyz',
+ 'xz' => 'application/x-xz',
+ 'yang' => 'application/yang',
+ 'yin' => 'application/yin+xml',
+ 'z1' => 'application/x-zmachine',
+ 'z2' => 'application/x-zmachine',
+ 'z3' => 'application/x-zmachine',
+ 'z4' => 'application/x-zmachine',
+ 'z5' => 'application/x-zmachine',
+ 'z6' => 'application/x-zmachine',
+ 'z7' => 'application/x-zmachine',
+ 'z8' => 'application/x-zmachine',
+ 'zaz' => 'application/vnd.zzazz.deck+xml',
+ 'zip' => 'application/zip',
+ 'zir' => 'application/vnd.zul',
+ 'zirz' => 'application/vnd.zul',
+ 'zmm' => 'application/vnd.handheld-entertainment+xml',
+ '123' => 'application/vnd.lotus-1-2-3',
+];
diff --git a/include/swiftmailer/lib/preferences.php b/include/swiftmailer/lib/preferences.php
new file mode 100644
index 0000000..27b7065
--- /dev/null
+++ b/include/swiftmailer/lib/preferences.php
@@ -0,0 +1,19 @@
+setCharset('utf-8');
+
+// Without these lines the default caching mechanism is "array" but this uses a lot of memory.
+// If possible, use a disk cache to enable attaching large attachments etc.
+// You can override the default temporary directory by setting the TMPDIR environment variable.
+if (@is_writable($tmpDir = sys_get_temp_dir())) {
+ $preferences->setTempDir($tmpDir)->setCacheType('disk');
+}
diff --git a/include/swiftmailer/lib/swift_required.php b/include/swiftmailer/lib/swift_required.php
new file mode 100644
index 0000000..d696056
--- /dev/null
+++ b/include/swiftmailer/lib/swift_required.php
@@ -0,0 +1,22 @@
+ 'application/x-php',
+ 'php3' => 'application/x-php',
+ 'php4' => 'application/x-php',
+ 'php5' => 'application/x-php',
+ 'zip' => 'application/zip',
+ 'gif' => 'image/gif',
+ 'png' => 'image/png',
+ 'css' => 'text/css',
+ 'js' => 'text/javascript',
+ 'txt' => 'text/plain',
+ 'aif' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'avi' => 'video/avi',
+ 'bmp' => 'image/bmp',
+ 'bz2' => 'application/x-bz2',
+ 'csv' => 'text/csv',
+ 'dmg' => 'application/x-apple-diskimage',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'eml' => 'message/rfc822',
+ 'aps' => 'application/postscript',
+ 'exe' => 'application/x-ms-dos-executable',
+ 'flv' => 'video/x-flv',
+ 'gz' => 'application/x-gzip',
+ 'hqx' => 'application/stuffit',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'jar' => 'application/x-java-archive',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'm3u' => 'audio/x-mpegurl',
+ 'm4a' => 'audio/mp4',
+ 'mdb' => 'application/x-msaccess',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'odg' => 'vnd.oasis.opendocument.graphics',
+ 'odp' => 'vnd.oasis.opendocument.presentation',
+ 'odt' => 'vnd.oasis.opendocument.text',
+ 'ods' => 'vnd.oasis.opendocument.spreadsheet',
+ 'ogg' => 'audio/ogg',
+ 'pdf' => 'application/pdf',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'ps' => 'application/postscript',
+ 'rar' => 'application/x-rar-compressed',
+ 'rtf' => 'application/rtf',
+ 'tar' => 'application/x-tar',
+ 'sit' => 'application/x-stuffit',
+ 'svg' => 'image/svg+xml',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'ttf' => 'application/x-font-truetype',
+ 'vcf' => 'text/x-vcard',
+ 'wav' => 'audio/wav',
+ 'wma' => 'audio/x-ms-wma',
+ 'wmv' => 'audio/x-ms-wmv',
+ 'xls' => 'application/vnd.ms-excel',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xml' => 'application/xml',
+ ];
+
+ // wrap array for generating file
+ foreach ($valid_mime_types_preset as $extension => $mime_type) {
+ // generate array for mimetype to extension resolver (only first match)
+ $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'";
+ }
+
+ // all extensions from second match
+ foreach ($matches[2] as $i => $extensions) {
+ // explode multiple extensions from string
+ $extensions = explode(' ', strtolower($extensions));
+
+ // force array for foreach
+ if (!\is_array($extensions)) {
+ $extensions = [$extensions];
+ }
+
+ foreach ($extensions as $extension) {
+ // get mime type
+ $mime_type = $matches[1][$i];
+
+ // check if string length lower than 10
+ if (\strlen($extension) < 10) {
+ if (!isset($valid_mime_types[$mime_type])) {
+ // generate array for mimetype to extension resolver (only first match)
+ $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'";
+ }
+ }
+ }
+ }
+ }
+
+ $xml = simplexml_load_string($mime_xml);
+
+ foreach ($xml as $node) {
+ // check if there is no pattern
+ if (!isset($node->glob['pattern'])) {
+ continue;
+ }
+
+ // get all matching extensions from match
+ foreach ((array) $node->glob['pattern'] as $extension) {
+ // skip none glob extensions
+ if (false === strpos($extension, '.')) {
+ continue;
+ }
+
+ // remove get only last part
+ $extension = explode('.', strtolower($extension));
+ $extension = end($extension);
+ }
+
+ if (isset($node->glob['pattern'][0])) {
+ // mime type
+ $mime_type = strtolower((string) $node['type']);
+
+ // get first extension
+ $extension = strtolower(trim($node->glob['ddpattern'][0], '*.'));
+
+ // skip none glob extensions and check if string length between 1 and 10
+ if (false !== strpos($extension, '.') || \strlen($extension) < 1 || \strlen($extension) > 9) {
+ continue;
+ }
+
+ // check if string length lower than 10
+ if (!isset($valid_mime_types[$mime_type])) {
+ // generate array for mimetype to extension resolver (only first match)
+ $valid_mime_types[$extension] = "'{$extension}' => '{$mime_type}'";
+ }
+ }
+ }
+
+ // full list of valid extensions only
+ $valid_mime_types = array_unique($valid_mime_types);
+ ksort($valid_mime_types);
+
+ // combine mime types and extensions array
+ $output = "$preamble\$swift_mime_types = array(\n ".implode(",\n ", $valid_mime_types)."\n);";
+
+ // write mime_types.php config file
+ @file_put_contents('./mime_types.php', $output);
+}
+
+generateUpToDateMimeArray();