first commit
This commit is contained in:
@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles CRAM-MD5 authentication.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Transport_Esmtp_Auth_CramMd5Authenticator implements Swift_Transport_Esmtp_Authenticator
|
||||
{
|
||||
/**
|
||||
* Get the name of the AUTH mechanism this Authenticator handles.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthKeyword()
|
||||
{
|
||||
return 'CRAM-MD5';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
|
||||
{
|
||||
try {
|
||||
$challenge = $agent->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;
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles LOGIN authentication.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Transport_Esmtp_Auth_LoginAuthenticator implements Swift_Transport_Esmtp_Authenticator
|
||||
{
|
||||
/**
|
||||
* Get the name of the AUTH mechanism this Authenticator handles.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthKeyword()
|
||||
{
|
||||
return 'LOGIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
|
||||
{
|
||||
try {
|
||||
$agent->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;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,681 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* This authentication is for Exchange servers. We support version 1 & 2.
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles NTLM authentication.
|
||||
*
|
||||
* @author Ward Peeters <ward@coding-tech.com>
|
||||
*/
|
||||
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<br />\n";
|
||||
echo $messageId." Type Indicator<br />\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."<br />\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."<br />\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo '<br /><br />';
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles PLAIN authentication.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Transport_Esmtp_Auth_PlainAuthenticator implements Swift_Transport_Esmtp_Authenticator
|
||||
{
|
||||
/**
|
||||
* Get the name of the AUTH mechanism this Authenticator handles.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthKeyword()
|
||||
{
|
||||
return 'PLAIN';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password)
|
||||
{
|
||||
try {
|
||||
$message = base64_encode($username.\chr(0).$username.\chr(0).$password);
|
||||
$agent->executeCommand(sprintf("AUTH PLAIN %s\r\n", $message), [235]);
|
||||
|
||||
return true;
|
||||
} catch (Swift_TransportException $e) {
|
||||
$agent->executeCommand("RSET\r\n", [250]);
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Handles XOAUTH2 authentication.
|
||||
*
|
||||
* Example:
|
||||
* <code>
|
||||
* $transport = (new Swift_SmtpTransport('smtp.gmail.com', 587, 'tls'))
|
||||
* ->setAuthMode('XOAUTH2')
|
||||
* ->setUsername('YOUR_EMAIL_ADDRESS')
|
||||
* ->setPassword('YOUR_ACCESS_TOKEN');
|
||||
* </code>
|
||||
*
|
||||
* @author xu.li<AthenaLightenedMyPath@gmail.com>
|
||||
*
|
||||
* @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");
|
||||
}
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An ESMTP handler for AUTH support (RFC 5248).
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
class Swift_Transport_Esmtp_AuthHandler implements Swift_Transport_EsmtpHandler
|
||||
{
|
||||
/**
|
||||
* Authenticators available to process the request.
|
||||
*
|
||||
* @var Swift_Transport_Esmtp_Authenticator[]
|
||||
*/
|
||||
private $authenticators = [];
|
||||
|
||||
/**
|
||||
* The username for authentication.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* The password for authentication.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* The auth mode for authentication.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $auth_mode;
|
||||
|
||||
/**
|
||||
* The ESMTP AUTH parameters available.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
private $esmtpParams = [];
|
||||
|
||||
/**
|
||||
* Create a new AuthHandler with $authenticators for support.
|
||||
*
|
||||
* @param Swift_Transport_Esmtp_Authenticator[] $authenticators
|
||||
*/
|
||||
public function __construct(array $authenticators)
|
||||
{
|
||||
$this->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');
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2004-2009 Chris Corbyn
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An Authentication mechanism.
|
||||
*
|
||||
* @author Chris Corbyn
|
||||
*/
|
||||
interface Swift_Transport_Esmtp_Authenticator
|
||||
{
|
||||
/**
|
||||
* Get the name of the AUTH mechanism this Authenticator handles.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthKeyword();
|
||||
|
||||
/**
|
||||
* Try to authenticate the user with $username and $password.
|
||||
*
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
*
|
||||
* @return bool true if authentication worked (returning false is deprecated, throw a Swift_TransportException instead)
|
||||
*
|
||||
* @throws Swift_TransportException Allows the message to bubble up when authentication was not successful
|
||||
*/
|
||||
public function authenticate(Swift_Transport_SmtpAgent $agent, $username, $password);
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2018 Christian Schmidt
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An ESMTP handler for 8BITMIME support (RFC 6152).
|
||||
*
|
||||
* 8BITMIME is required when sending 8-bit content to over SMTP, e.g. when using
|
||||
* Swift_Mime_ContentEncoder_PlainContentEncoder in "8bit" mode.
|
||||
*
|
||||
* 8BITMIME mode is enabled unconditionally, even when sending ASCII-only
|
||||
* messages, so it should only be used with an outbound SMTP server that will
|
||||
* convert the message to 7-bit MIME if the next hop does not support 8BITMIME.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
class Swift_Transport_Esmtp_EightBitMimeHandler implements Swift_Transport_EsmtpHandler
|
||||
{
|
||||
protected $encoding;
|
||||
|
||||
/**
|
||||
* @param string $encoding The parameter so send with the MAIL FROM command;
|
||||
* either "8BITMIME" or "7BIT"
|
||||
*/
|
||||
public function __construct(string $encoding = '8BITMIME')
|
||||
{
|
||||
$this->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()
|
||||
{
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of SwiftMailer.
|
||||
* (c) 2018 Christian Schmidt
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An ESMTP handler for SMTPUTF8 support (RFC 6531).
|
||||
*
|
||||
* SMTPUTF8 is required when sending to email addresses containing non-ASCII
|
||||
* characters in local-part (the substring before @). This handler should be
|
||||
* used together with Swift_AddressEncoder_Utf8AddressEncoder.
|
||||
*
|
||||
* SMTPUTF8 mode is enabled unconditionally, even when sending to ASCII-only
|
||||
* addresses, so it should only be used with an outbound SMTP server that will
|
||||
* deliver ASCII-only messages even if the next hop does not support SMTPUTF8.
|
||||
*
|
||||
* @author Christian Schmidt
|
||||
*/
|
||||
class Swift_Transport_Esmtp_SmtpUtf8Handler implements Swift_Transport_EsmtpHandler
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of the ESMTP extension this handles.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getHandledKeyword()
|
||||
{
|
||||
return 'SMTPUTF8';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ['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()
|
||||
{
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user