<?php
// Ps: Read "changelog.txt"
/**
Como funciona o sistema de EML?
Trabalha apenas com o body da mensagem.
Exemplo:
->setSubject(assunto)
->setFrom(from)
->setTo(to)
->setBcc(to)
->setEMLFile(eml_file) -- OU -- setHTMLFile(html_file[, auto_images=t/f]) -- OU --
->setMessage(message) -- OU -- importHTML(body[, images_dir])
->send()
Como enviar via SMTP ou MAIL():
->sendThroughMail()
->sendThroughSMTP($smtp_server, $port=25, $user=false, $pass=false, $ssl=[0=nao,1=sim,2=mixed])
Como utilizar CALLBACK():
->send($startInPart, $callBack)
Callback($part=LoopStart|LoopEnd, $loopPart, $totalLoops)
Retornos possíveis:
"STOP" (Força a parada imediata da execução)
Bloqueio de e-mails duplicados:
->allowDupe()
->blockDupe() (Default)
Author: IMAGINACOM
E-mail: contato AT IMAGINACOM.com
**/
class dSendMail2 extends htmlMimeMail{
var $to = '"Destinatario" <nobody@noreply.com.br>';
var $error = false;
var $debug = 0;
var $timeout = 15;
var $delay = 1;
var $groupAmnt = false;
var $sendThrough = false;
var $blockDupe = true;
var $localhost = false;
var $logFolder = false;
var $logFile = false;
static $StaticSendThrough = 'default';
/** Static **/
Function getVersion(){
return "v2.37";
}
/** Public **/
Function __construct(){
$this->htmlMimeMail();
if(self::$StaticSendThrough !== 'default')
$this->sendThrough = self::$StaticSendThrough;
/** Default values: **/
$this->setGroupAmount(20);
$this->setSMTPTimeout(15);
$this->blockDupe();
$this->setPriority(3);
$this->setCrlf("\n");
$this->setCharset('ISO-8859-1');
}
static Function easyMail ($to, $subject, $message, $from=false, $html=false, $attach=false){
$this->setTo($to);
$this->setSubject($subject);
$this->setMessage($message, $html);
if($from) $this->setFrom($from);
if($attach) foreach($attach as $att){
if(!isset($att[1]))
die("Attach precisa ser: Array(Array(filename, filedata), Array(filename, filedata), ...)");
$this->autoAttachFile($att[0], $att[1]);
}
return $this->send();
}
static Function createFromMail($to, $subject, $message, $headers=false){
$m = new dSendMail2;
$m->headers = $headers?self::_convertStrHeaderToArray($headers):Array();
if(!isset($m->headers['From']) || !$m->headers['From']){
if(isset($_SERVER['SERVER_HOST']))
$m->setFrom("nobody@{$_SERVER['SERVER_NAME']}");
elseif(isset($_SERVER['HTTP_HOST']) && preg_match("/^[A-Za-z0-9\-\_\.\:]+$", $_SERVER['HTTP_HOST']))
$m->setFrom("nobody@{$_SERVER['SERVER_HOST']}");
elseif(isset($_SERVER['REMOTE_ADDR']))
$m->setFrom("nobody@{$_SERVER['REMOTE_ADDR']}");
elseif(isset($_SERVER['USERDOMAIN']))
$m->setFrom("nobody@{$_SERVER['USERDOMAIN']}");
else
$m->setFrom('nobody@nowhere.com');
}
$isHTML = (isset($m->headers['Content-Type']) && stripos($m->headers['Content-Type'], "text/html") !== false);
$m->setTo($to);
$m->setSubject($subject);
$m->setMessage($message, $isHTML);
return $m;
}
Function setHTMLFile ($filename, $importImages=true){ // Can receive an HTML File, and auto-attach all images to mass send
$this->error = false;
if(!is_readable($filename)){
$this->error = "Erro lendo o arquivo enviado.";
return false;
}
if($importImages === true){
$importImages = dirname($filename);
}
$this->importHTML(file_get_contents($filename), $importImages);
return true;
}
Function setEMLFile ($filename){ // Can receive an EML File to mass send
$this->error = false;
if(!is_readable($filename)){
$this->error = "Erro lendo o arquivo enviado.";
return false;
}
$this->importEML(file_get_contents($filename));
return true;
}
Function setMessage ($body, $html=true, $nl2br=false){// Defines the message contents
($html)?
$this->html = ($nl2br?nl2br($body):$body):
$this->text = ($body);
}
Function replaceMessage($from, $to){ // Useful if you want to change something after calling importHTML
$this->html = str_replace($from, $to, $this->html);
}
Function setPriority ($priority){ // Defines the message priority (1=High 3=Normal 5=Low, only for Outlook)
if(isset($this->headers['X-Priority']) || in_array($priority, Array(1, 5))){
$this->headers['X-Priority'] = $priority;
}
}
Function setCharset ($charset){ // Defines the charset. ISO-8859-1 is the default.
// Usually: ISO-8859-1 or UTF-8
// Default: ISO-8859-1 (Latin1)
$this->headers['Content-Type'] = $charset;
$this->build_params['html_charset'] = $charset;
$this->build_params['text_charset'] = $charset;
$this->build_params['head_charset'] = $charset;
}
Function setSubject ($subject){
$subject = str_replace(Array("\r", "\n", "\r\n"), "_", $subject);
return parent::setSubject($subject);
}
Function setTo ($to){ // Se the 'To' (Visible)
if(!is_array($to)){
$to = str_replace(";", ",", $to);
$to = explode(",", $to);
}
$to = array_map(Array($this, '_normalizeEmailAddress'), $to);
if($this->blockDupe)
$to = array_unique($to);
$to = implode(",", $to);
$this->to = $to;
}
Function setCc ($to){
if(!is_array($to)){
$to = str_replace(";", ",", $to);
$to = explode(",", $to);
}
$to = array_map(Array($this, '_normalizeEmailAddress'), $to);
if($this->blockDupe)
$to = array_unique($to);
$to = implode(",", $to);
return parent::setCc($to);
}
Function setBcc ($to){
if(!is_array($to)){
$to = str_replace(";", ",", $to);
$to = explode(",", $to);
}
$to = array_map(Array($this, '_normalizeEmailAddress'), $to);
if($this->blockDupe)
$to = array_unique($to);
$to = implode(",", $to);
return parent::setBcc($to);
}
Function setFrom ($from, $nome=false){
if($nome)
$from = "\"{$nome}\" <$from>";
$from = str_replace(Array("\r", "\n", "\r\n"), "_", $from);
return parent::setFrom($from);
}
Function setReplyTo ($email, $nome=false){
if($nome)
$email = "\"{$nome}\" <$email>";
$email = str_replace(Array("\r", "\n", "\r\n"), "_", $email);
$this->headers['Reply-To'] = $email;
}
Function setReturnPath ($email, $nome=false){
if($nome)
$email = "\"{$nome}\" <$email>";
$email = str_replace(Array("\r", "\n", "\r\n"), "_", $email);
$this->headers['Return-Path'] = $email;
}
Function send ($startInPart=1, $callBack=false){ // Send the message, loop if necessary, save to database if necessary
$this->error = false;
if(!$this->is_built)
$this->buildMessage();
$this->output = str_replace("\r\n", "\n", $this->output);
if(!isset($this->headers['From']))
die("Cannot proceed: You must call 'setFrom(email, name)' before sending e-mails.\r\n");
if(!isset($this->to))
die("Cannot proceed: You must call 'setTo(email)' before sending e-mails.\r\n");
// Normaliza campo "From" e "To:"
$this->headers['From'] = $this->_normalizeEmail($this->headers['From']);
$this->to = $this->_normalizeEmail($this->to);
/** Define variáveis importantes para a elaboração dos vários laços **/
$hasCc = !empty($this->headers['Cc']);
$hasBcc = !empty($this->headers['Bcc']);
if($hasBcc){
$parts_bcc = explode(",", $this->headers['Bcc']);
unset($this->headers['Bcc']);
}
$sizeTo = substr_count($this->to, ",")+1;
$sizeCc = $hasCc ?(substr_count($this->headers['Cc'], ",")+1):0;
$sizeBcc= $hasBcc?count($parts_bcc):0;
$loopSize = $this->groupAmnt;
$loopSize -= ($sizeTo+$sizeCc); // Considera os 'destinos' fixos, que são enviados em todos os laços.
$loopPart = $startInPart?$startInPart:1;
$totalLoops = ceil($sizeBcc/$loopSize);
// Prepara variáveis para o padrão
$subject = $this->headers['Subject'];
unset($this->headers['Subject']);
// Get flat representation of headers
foreach ($this->headers as $name => $value)
$headers[] = $name . ': ' . $this->_encodeHeader($value, $this->build_params['head_charset']);
$to = $this->_encodeHeader($this->to, $this->build_params['head_charset']);
$this->_log("Iniciando envio . . .");
$this->_log("From: {$this->headers['From']}");
$this->_log("To: {$this->to}");
$this->_log("Subject: {$subject}");
$this->_log("--------------------------");
$this->_log("Headers:");
$this->_log(print_r($this->headers, true));
$this->_log("Output:");
$this->_log(print_r($this->output, true));
$this->_log("--------------------------");
$this->_log("Delay: {$this->delay}");
$this->_log("sizeTo: {$sizeTo}");
$this->_log("sizeCc: {$sizeCc}");
$this->_log("sizeBcc: {$sizeBcc}");
$this->_log("groupAmnt: {$this->groupAmnt}");
$this->_log("Tamanho do laço: {$loopSize}");
$this->_log("Loop inicial: {$startInPart}");
$this->_log("Loop máximo: {$totalLoops}");
$this->_log("--------------------------");
$orHeaders = $headers;
/** Entra no loop para enviar mensagens **/
do{
$this->_log("Loop #{$loopPart}");
if($callBack){
$cbResult = call_user_func($callBack, 'LoopStart', $loopPart, $totalLoops);
$this->_log("Resultado do callback LoopStart: {$cbResult}");
if(substr($cbResult, 0, 4) == 'STOP')
break;
}
$headers = $orHeaders;
if($hasBcc){
$headbcc = join(",", array_slice($parts_bcc, ($loopPart-1)*$loopSize, $loopSize));
$headers[] = "Bcc: $headbcc";
$this->_log("+ Destinos ocultos: {$headbcc}");
}
if($this->delay && $loopPart > 1){
$this->_log("+ Aguardando {$this->delay} para nao sobrecarregar servidor");
sleep($this->delay);
}
$headersJoined = implode("\n", $headers);
$result = $this->callMail($subject, $headersJoined);
$this->_log("+ Resultado do envio: ".(($result===true)?"Sucesso!":"Falha no envio."));
if(!$result){
$this->_log("FALHA CRÍTICA: O loop #{$loopPart} (total de {$totalLoops}) naão foi entregue com sucesso.");
$this->_log("FALHA CRÍTICA: Loop interrompido.");
$this->error = "Falha no envio do laco $loopPart de $totalLoops. {$this->error}\n";
break;
}
unset($headers, $headersJoined, $result, $headbcc);
if($callBack){
$cbResult = call_user_func($callBack, 'LoopEnd', $loopPart, $totalLoops);
$this->_log("Resultado do callback LoopEnd: {$cbResult}");
if($cbResult == 'STOP')
break;
}
} while($loopPart++ < $totalLoops);
$this->_log("--------------------------");
$this->_log(". . . Concluído!");
// Reset the subject in case mail is resent
if ($subject !== ''){
$this->headers['Subject'] = $subject;
}
return $this->error?false:true;
}
Function autoAttachFile($filename, &$filedata){ // Auto-detect if need to attach or embed the attachment. This need to be called after setMessage()
// $filename = basename($filename);
if($this->html && preg_match('/(?:"|\')'.preg_quote($filename, '/').'(?:"|\')/Ui', $this->html)){
$this->embedFile($filename, $filedata);
$this->_log("Adicionando HTMLImage: $filename (".strlen($filedata)." bytes)");
return 1;
}
else{
$this->attachFile(basename($filename), $filedata);
$this->_log("Adicionando Attachment: $filename (".strlen($filedata)." bytes)");
return 2;
}
}
Function attachFile($filename, &$filedata){
return $this->addAttachment($filedata, basename($filename), $this->_getAutoMimeType($filename));
}
Function embedFile ($filename, &$filedata){
$cid = $this->addHtmlImage($filedata, $filename, $this->_getAutoMimeType($filename));
return $cid?"CID:{$cid}":false;
}
Function allowDupe($yesno=true){ // Default: False
$this->blockDupe = !$yesno;
}
Function blockDupe($yesno=true){ // Default: True
$this->allowDupe(!$yesno);
}
Function setGroupAmount($amount){ // Default: 20
$this->groupAmnt = $amount;
}
Function importHTML($body, $baseDir=false, $importImages=true){// Auto-detect all images inside an HTML body and embed it as attachments.
if(!$baseDir)
$importImages = false;
$this->setMessage($body, true, false); // body, html, force_nl2br
if($importImages){
if($importImages && strpos($baseDir, '/') === null)
die("dSendMail2 - importHTML() - Parâmetro '\$baseDir' deve ter um caminho absoluto, não relativo. Atualmente, '{$baseDir}'.");
$tags = preg_match_all("/<.+?(src|background)=[\"']?(.+?)[\"' ].*?>/is", $body, $out);
if($tags) foreach($out[2] as $addFile){
if(strpos($addFile, "://"))
continue;
$dieCritical = false;
if(file_exists("$baseDir/$addFile")){
$this->autoAttachFile($addFile, file_get_contents("$baseDir/$addFile"));
}
else{
echo "HTML Pediu o arquivo: '{$addFile}', mas este não existe em '{$baseDir}/{$addFile}'<br />\r\n";
$dieCritical = true;
}
if($dieCritical)
die("Arquivos encontrados no HTML mas não foram encontrados na pasta. Cancelando envio.\r\n");
}
}
return true;
}
Function importEML ($fileBody, $importAll=false){
/** Primeiro passo: Separar header/body e importar o header**/
preg_match("/^(.+?)\r?\n\r?\n(.+)$/s", $fileBody, $emlContentsParts);
/** Segundo passo: Definir construção da mensagem **/
$this->setMessage("Esta mensagem foi enviada diretamente em formato EML.\nPara ver seu conteúdo, será necessário fazer o download.");
$this->headers = $this->_convertStrHeaderToArray($emlContentsParts[1]);
$this->output = isset($emlContentsParts[2])?$emlContentsParts[2]:'';
$this->is_built = true;
if(!$importAll){
// Remove headers that will be ignored or overwritted
unset($this->headers["X-Unsent"]);
unset($this->headers["From"]);
unset($this->headers["To"]);
unset($this->headers["Cc"]);
unset($this->headers["Bcc"]);
}
else{
// Import all headers, and parse some of them
$this->setTo($this->headers['To']);
unset($this->headers["To"]);
}
}
Function exportEML($setUnsent=false){
if(!$this->is_built)
$this->buildMessage();
$ret = "";
foreach($this->headers as $key=>$value)
$ret .= "{$key}: ".trim($value)."\n";
if($setUnsent)
$ret .= "X-Unsent: 1\n";
$ret .= "\n";
$ret .= $this->output;
return $ret;
}
Function setSMTPTimeout($timeout){ // Default: 15 (seconds)
$this->timeout = $timeout;
}
Function sendThroughSMTP($smtp_server, $port=25, $user=false, $pass=false, $ssl=false){
$this->sendThrough = Array($smtp_server, $port, $user, $pass, $ssl);
}
Function sendThroughMail(){
$this->sendThrough = false;
}
Function sendThroughGMail ($user, $pass){
$this->sendThroughSMTP('smtp.gmail.com', 465, $user, $pass, 1);
}
Function sendThroughHotMail($user, $pass){
$this->sendThroughSMTP('smtp.live.com', 25, $user, $pass, 2);
}
Function sendThroughYahoo ($user, $pass){
$this->sendThroughSMTP('smtp.mail.yahoo.com', 465, $user, $pass, 1);
}
Function sendThroughNowhere($randomError=0){
// Used ONLY for test purpose.
// $randomError between 0 and 1
$this->sendThrough = Array('NULL', $randomError);
}
Function sendThroughSetDefault(){
self::$StaticSendThrough = $this->sendThrough;
}
Function getError(){
return $this->error;
}
/** Private **/
Function callMail($subject, $headersJoined){
if(!$this->sendThrough){
$this->_log("Enviando através da função MAIL()");
return mail($this->to, $subject, $this->output, $headersJoined);
}
elseif($this->sendThrough[0] == 'NULL'){
$errProb = $this->sendThrough[1];
$this->_log("Modo de testes, não enviando para ninguém. Possibilidade de erro: {$errProb}.");
if($errProb && rand(0, 100) < (($errProb>1)?$errProb:$errProb*100)){
$this->error = "Simulando erro de testes.";
return false;
}
return true;
}
else{
$this->_log("Enviando através de SMTP");
$user = $this->sendThrough[2];
$pass = $this->sendThrough[3];
if($user){
$user = explode("@", $this->sendThrough[2], 2);
$realm = isset($user[1])?$user[1]:false;
$user = $user[0];
}
$smtp = new smtp_class;
$smtp->host_name = $this->sendThrough[0];
$smtp->host_port = $this->sendThrough[1];
$smtp->ssl = ($this->sendThrough[4]===1||($this->sendThrough[4]===true));
$smtp->start_tls = ($this->sendThrough[4]===2);
$smtp->localhost = ($this->localhost?$this->localhost:(isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:"localhost"));
$smtp->timeout = $this->timeout;
$smtp->data_timeout = 0;
$smtp->debug = $this->debug;
$smtp->html_debug = !true;
$smtp->pop3_auth_host = "";
$smtp->user = $user?$user :false;
$smtp->realm = $user?$realm:false;
$smtp->password = $user?$pass :false;
$arheader = $this->_convertStrHeaderToArray($headersJoined);
if(!isset($arheader['From'])) $arheader['From'] = $this->headers['From'];
if(!isset($arheader['To'])) $arheader['To'] = $this->to;
if(!isset($arheader['Subject']))$arheader['Subject'] = $subject;
if(!isset($arheader['Date'])) $arheader['Date'] = date('r');
$bccTo = false;
if(isset($arheader['Bcc'])){
$bccTo = $arheader['Bcc'];
unset($arheader['Bcc']);;
}
$newheader = Array();
foreach($arheader as $key=>$headerline){
$newheader[] = "{$key}: {$headerline}";
}
$ok = $smtp->SendMessage($this->_normalizeEmail($this->headers['From'], true), explode(",", $this->to.($bccTo?",{$bccTo}":"")), $newheader, $this->output);
if(!$ok){
$this->error = $smtp->error;
return false;
}
return true;
}
die("Don't know how to send.");
}
Function _log($event){
if($this->logFolder){
if(!is_writable($this->logFolder))
die("Impossível enviar e-mails - Pasta de log sem permissões. ($this->logFolder)");
if(!$this->logFile)
$this->logFile = fopen("{$this->logFolder}/log-".date('d.m.Y-H.i.s').'-'.substr(uniqid(), -4).".txt", "a+");
$toLog = date('d/m/Y H:i:s')." ".trim($event)."\r\n";
fwrite($this->logFile, $toLog);
}
}
Function _getAutoMimeType($filename){
$ext = strtolower(substr($filename, -3));
switch($ext){
case ".xls":
$content_type="application/excel";
break;
case ".hqx":
$content_type="application/macbinhex40";
break;
case ".doc":
case ".dot":
case ".wrd":
$content_type="application/msword";
break;
case ".pdf":
$content_type="application/pdf";
break;
case ".pgp":
$content_type="application/pgp";
break;
case ".ps":
case ".eps":
case ".ai":
$content_type="application/postscript";
break;
case ".ppt":
$content_type="application/powerpoint";
break;
case ".rtf":
$content_type="application/rtf";
break;
case ".tgz":
case ".gtar":
$content_type="application/x-gtar";
break;
case ".gz":
$content_type="application/x-gzip";
break;
case ".php":
case ".php3":
$content_type="application/x-httpd-php";
break;
case ".js":
$content_type="application/x-javascript";
break;
case ".ppd":
case ".psd":
$content_type="application/x-photoshop";
break;
case ".swf":
case ".swc":
case ".rf":
$content_type="application/x-shockwave-flash";
break;
case ".tar":
$content_type="application/x-tar";
break;
case ".zip":
$content_type="application/zip";
break;
case ".mid":
case ".midi":
case ".kar":
$content_type="audio/midi";
break;
case ".mp2":
case ".mp3":
case ".mpga":
$content_type="audio/mpeg";
break;
case ".ra":
$content_type="audio/x-realaudio";
break;
case ".wav":
$content_type="audio/wav";
break;
case ".bmp":
$content_type="image/bitmap";
break;
case ".gif":
$content_type="image/gif";
break;
case ".iff":
$content_type="image/iff";
break;
case ".jb2":
$content_type="image/jb2";
break;
case ".jpg":
case ".jpe":
case ".jpeg":
$content_type="image/jpeg";
break;
case ".jpx":
$content_type="image/jpx";
break;
case ".png":
$content_type="image/png";
break;
case ".tif":
case ".tiff":
$content_type="image/tiff";
break;
case ".wbmp":
$content_type="image/vnd.wap.wbmp";
break;
case ".xbm":
$content_type="image/xbm";
break;
case ".css":
$content_type="text/css";
break;
case ".txt":
$content_type="text/plain";
break;
case ".htm":
case ".html":
$content_type="text/html";
break;
case ".xml":
$content_type="text/xml";
break;
case ".mpg":
case ".mpe":
case ".mpeg":
$content_type="video/mpeg";
break;
case ".qt":
case ".mov":
$content_type="video/quicktime";
break;
case ".avi":
$content_type="video/x-ms-video";
break;
case ".eml":
$content_type="message/rfc822";
break;
default:
$content_type="application/octet-stream";
break;
}
return $content_type;
}
Function &_convertStrHeaderToArray($header){
$headers = Array();
$strHeader = explode("\n", $header);
foreach($strHeader as $lineHeader){
$parts = explode(": ", $lineHeader, 2);
if(sizeof($parts) == 2){
// If correct format (Title: value)
$lastHeaderTitle = implode("-", array_map('ucfirst', explode("-", $parts[0])));
if(preg_match("/^(from|to|cc|bcc|subject)$/i", $lastHeaderTitle)) // Check if the essential headers are correctly written
$lastHeaderTitle = ucfirst(strtolower($lastHeaderTitle)); // The whole string is lower-case, but the first letter
$headers[$lastHeaderTitle] = rtrim($parts[1]);
}
else // It's a continuation of the previous Title
if(!isset($lastHeaderTitle)) // But there's no previous title! Weird...
$headers[rtrim($parts[0])] = "";
else
$headers[$lastHeaderTitle] .= "\n".rtrim($parts[0]);
}
return $headers;
}
Function _normalizeEmail($email, $only_address=false){
if(!strpos($email, "<")){
// Padrão: a@b.c
return trim(str_replace(Array(" ", "<", ">"), "", strtolower($email)));
}
// Padrão: "Nome" <a@b.c>
$nome = trim(str_replace("\"", "", substr($email, 0, strpos($email, "<"))));
$email = substr($email, strpos($email, "<"));
$email = trim(str_replace(Array(" ", "<", ">"), "", $email));
$email = strtolower($email);
return $only_address?
$email:
"\"{$nome}\" <$email>";
}
Function _normalizeEmailAddress($email){
return $this->_normalizeEmail($email, true);
}
}
// MimeMessage Support
class htmlMimeMail {
var $html;
var $text;
var $output;
var $html_text;
var $html_images;
var $image_types;
var $build_params;
var $attachments;
var $headers;
var $is_built;
var $return_path;
var $smtp_params;
function htmlMimeMail(){
$this->html_images = array();
$this->headers = array();
$this->is_built = false;
$this->image_types = array(
'gif' => 'image/gif',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'jpe' => 'image/jpeg',
'bmp' => 'image/bmp',
'png' => 'image/png',
'tif' => 'image/tiff',
'tiff' => 'image/tiff',
'swf' => 'application/x-shockwave-flash'
);
/**
* Set these up
*/
$this->build_params['html_encoding'] = '7bit';
$this->build_params['text_encoding'] = '7bit';
$this->build_params['html_charset'] = 'ISO-8859-1';
$this->build_params['text_charset'] = 'ISO-8859-1';
$this->build_params['head_charset'] = 'ISO-8859-1';
$this->build_params['text_wrap'] = 998;
/**
* Defaults for smtp sending
*/
if (!empty($GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'])) {
$helo = $GLOBALS['HTTP_SERVER_VARS']['HTTP_HOST'];
} elseif (!empty($GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME'])) {
$helo = $GLOBALS['HTTP_SERVER_VARS']['SERVER_NAME'];
} else {
$helo = 'localhost';
}
$this->smtp_params['host'] = 'localhost';
$this->smtp_params['port'] = 25;
$this->smtp_params['helo'] = $helo;
$this->smtp_params['auth'] = false;
$this->smtp_params['user'] = '';
$this->smtp_params['pass'] = '';
/**
* Make sure the MIME version header is first.
*/
$this->headers['MIME-Version'] = '1.0';
}
/**
* This function will read a file in
* from a supplied filename and return
* it. This can then be given as the first
* argument of the the functions
* add_html_image() or add_attachment().
*/
function getFile($filename){
$return = '';
if ($fp = fopen($filename, 'rb')) {
while (!feof($fp)) {
$return .= fread($fp, 1024);
}
fclose($fp);
return $return;
} else {
return false;
}
}
/**
* Accessor to set the CRLF style
*/
function setCrlf($crlf = "\n"){
if (!defined('CRLF')) {
define('CRLF', $crlf, true);
}
if (!defined('MAIL_MIMEPART_CRLF')) {
define('MAIL_MIMEPART_CRLF', $crlf, true);
}
}
/**
* Accessor to set the SMTP parameters
*/
function setSMTPParams($host = null, $port = null, $helo = null, $auth = null, $user = null, $pass = null){
if (!is_null($host)) $this->smtp_params['host'] = $host;
if (!is_null($port)) $this->smtp_params['port'] = $port;
if (!is_null($helo)) $this->smtp_params['helo'] = $helo;
if (!is_null($auth)) $this->smtp_params['auth'] = $auth;
if (!is_null($user)) $this->smtp_params['user'] = $user;
if (!is_null($pass)) $this->smtp_params['pass'] = $pass;
}
/**
* Accessor function to set the text encoding
*/
function setTextEncoding($encoding = '7bit'){
$this->build_params['text_encoding'] = $encoding;
}
/**
* Accessor function to set the HTML encoding
*/
function setHtmlEncoding($encoding = 'quoted-printable'){
$this->build_params['html_encoding'] = $encoding;
}
/**
* Accessor function to set the text charset
*/
function setTextCharset($charset = 'ISO-8859-1')
{
$this->build_params['text_charset'] = $charset;
}
/**
* Accessor function to set the HTML charset
*/
function setHtmlCharset($charset = 'ISO-8859-1')
{
$this->build_params['html_charset'] = $charset;
}
/**
* Accessor function to set the header encoding charset
*/
function setHeadCharset($charset = 'ISO-8859-1')
{
$this->build_params['head_charset'] = $charset;
}
/**
* Accessor function to set the text wrap count
*/
function setTextWrap($count = 998)
{
$this->build_params['text_wrap'] = $count;
}
/**
* Accessor to set a header
*/
function setHeader($name, $value)
{
$this->headers[$name] = $value;
}
/**
* Accessor to add a Subject: header
*/
function setSubject($subject)
{
$this->headers['Subject'] = $subject;
}
/**
* Accessor to add a From: header
*/
function setFrom($from)
{
$this->headers['From'] = $from;
}
/**
* Accessor to set the return path
*/
function setReturnPath($return_path)
{
$this->return_path = $return_path;
}
/**
* Accessor to add a Cc: header
*/
function setCc($cc)
{
$this->headers['Cc'] = $cc;
}
/**
* Accessor to add a Bcc: header
*/
function setBcc($bcc)
{
$this->headers['Bcc'] = $bcc;
}
/**
* Adds plain text. Use this function
* when NOT sending html email
*/
function setText($text = '')
{
$this->text = $text;
}
/**
* Adds a html part to the mail.
* Also replaces image names with
* content-id's.
*/
function setHtml($html, $text = null, $images_dir = null)
{
$this->html = $html;
$this->html_text = $text;
if (isset($images_dir)) {
$this->_findHtmlImages($images_dir);
}
}
/**
* Function for extracting images from
* html source. This function will look
* through the html code supplied by add_html()
* and find any file that ends in one of the
* extensions defined in $obj->image_types.
* If the file exists it will read it in and
* embed it, (not an attachment).
*
* @author Dan Allen
*/
function _findHtmlImages($images_dir)
{
// Build the list of image extensions
while (list($key,) = each($this->image_types)) {
$extensions[] = $key;
}
preg_match_all('/(?:"|\')([^"\']+\.('.implode('|', $extensions).'))(?:"|\')/Ui', $this->html, $images);
for ($i=0; $i<count($images[1]); $i++) {
if (file_exists($images_dir . $images[1][$i])) {
$html_images[] = $images[1][$i];
$this->html = str_replace($images[1][$i], basename($images[1][$i]), $this->html);
}
}
if (!empty($html_images)) {
// If duplicate images are embedded, they may show up as attachments, so remove them.
$html_images = array_unique($html_images);
sort($html_images);
for ($i=0; $i<count($html_images); $i++) {
if ($image = $this->getFile($images_dir.$html_images[$i])) {
$ext = substr($html_images[$i], strrpos($html_images[$i], '.') + 1);
$content_type = $this->image_types[strtolower($ext)];
$this->addHtmlImage($image, basename($html_images[$i]), $content_type);
}
}
}
}
/**
* Adds an image to the list of embedded
* images.
*/
function addHtmlImage($file, $name = '', $c_type='application/octet-stream')
{
$cid = md5(uniqid());
$this->html_images[] = array(
'body' => $file,
'name' => $name,
'c_type' => $c_type,
'cid' => $cid
);
return $cid;
}
/**
* Adds a file to the list of attachments.
*/
function addAttachment($file, $name = '', $c_type='application/octet-stream', $encoding = 'base64')
{
$this->attachments[] = array(
'body' => $file,
'name' => $name,
'c_type' => $c_type,
'encoding' => $encoding
);
}
/**
* Adds a text subpart to a mime_part object
*/
function &_addTextPart(&$obj, $text)
{
$params['content_type'] = 'text/plain';
$params['encoding'] = $this->build_params['text_encoding'];
$params['charset'] = $this->build_params['text_charset'];
if (is_object($obj)) {
$return = $obj->addSubpart($text, $params);
} else {
$return = new Mail_mimePart($text, $params);
}
return $return;
}
/**
* Adds a html subpart to a mime_part object
*/
function &_addHtmlPart(&$obj)
{
$params['content_type'] = 'text/html';
$params['encoding'] = $this->build_params['html_encoding'];
$params['charset'] = $this->build_params['html_charset'];
if (is_object($obj)) {
$return = $obj->addSubpart($this->html, $params);
} else {
$return = new Mail_mimePart($this->html, $params);
}
return $return;
}
/**
* Starts a message with a mixed part
*/
function &_addMixedPart()
{
$params['content_type'] = 'multipart/mixed';
$return = new Mail_mimePart('', $params);
return $return;
}
/**
* Adds an alternative part to a mime_part object
*/
function &_addAlternativePart(&$obj)
{
$params['content_type'] = 'multipart/alternative';
if (is_object($obj)) {
$return = $obj->addSubpart('', $params);
} else {
$return = new Mail_mimePart('', $params);
}
return $return;
}
/**
* Adds a html subpart to a mime_part object
*/
function &_addRelatedPart(&$obj)
{
$params['content_type'] = 'multipart/related';
if (is_object($obj)) {
$return = $obj->addSubpart('', $params);
} else {
$return = new Mail_mimePart('', $params);
}
return $return;
}
/**
* Adds an html image subpart to a mime_part object
*/
function _addHtmlImagePart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = 'base64';
$params['disposition'] = 'inline';
$params['dfilename'] = $value['name'];
$params['cid'] = $value['cid'];
$obj->addSubpart($value['body'], $params);
}
/**
* Adds an attachment subpart to a mime_part object
*/
function _addAttachmentPart(&$obj, $value)
{
$params['content_type'] = $value['c_type'];
$params['encoding'] = $value['encoding'];
$params['disposition'] = 'attachment';
$params['dfilename'] = $value['name'];
$obj->addSubpart($value['body'], $params);
}
/**
* Builds the multipart message from the
* list ($this->_parts). $params is an
* array of parameters that shape the building
* of the message. Currently supported are:
*
* $params['html_encoding'] - The type of encoding to use on html. Valid options are
* "7bit", "quoted-printable" or "base64" (all without quotes).
* 7bit is EXPRESSLY NOT RECOMMENDED. Default is quoted-printable
* $params['text_encoding'] - The type of encoding to use on plain text Valid options are
* "7bit", "quoted-printable" or "base64" (all without quotes).
* Default is 7bit
* $params['text_wrap'] - The character count at which to wrap 7bit encoded data.
* Default this is 998.
* $params['html_charset'] - The character set to use for a html section.
* Default is ISO-8859-1
* $params['text_charset'] - The character set to use for a text section.
* - Default is ISO-8859-1
* $params['head_charset'] - The character set to use for header encoding should it be needed.
* - Default is ISO-8859-1
*/
function buildMessage($params = array())
{
if (!empty($params)) {
while (list($key, $value) = each($params)) {
$this->build_params[$key] = $value;
}
}
if (!empty($this->html_images)) {
foreach ($this->html_images as $value) {
$this->html = str_replace($value['name'], 'cid:'.$value['cid'], $this->html);
}
}
$null = null;
$attachments = !empty($this->attachments) ? true : false;
$html_images = !empty($this->html_images) ? true : false;
$html = !empty($this->html) ? true : false;
$text = isset($this->text) ? true : false;
switch (true) {
case $text AND !$attachments:
$message = &$this->_addTextPart($null, $this->text);
break;
case !$text AND $attachments AND !$html:
$message = &$this->_addMixedPart();
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
case $text AND $attachments:
$message = &$this->_addMixedPart();
$this->_addTextPart($message, $this->text);
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
case $html AND !$attachments AND !$html_images:
if (!is_null($this->html_text)) {
$message = &$this->_addAlternativePart($null);
$this->_addTextPart($message, $this->html_text);
$this->_addHtmlPart($message);
} else {
$message = &$this->_addHtmlPart($null);
}
break;
case $html AND !$attachments AND $html_images:
if (!is_null($this->html_text)) {
$message = &$this->_addAlternativePart($null);
$this->_addTextPart($message, $this->html_text);
$related = &$this->_addRelatedPart($message);
} else {
$message = &$this->_addRelatedPart($null);
$related = &$message;
}
$this->_addHtmlPart($related);
for ($i=0; $i<count($this->html_images); $i++) {
$this->_addHtmlImagePart($related, $this->html_images[$i]);
}
break;
case $html AND $attachments AND !$html_images:
$message = &$this->_addMixedPart();
if (!is_null($this->html_text)) {
$alt = &$this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->html_text);
$this->_addHtmlPart($alt);
} else {
$this->_addHtmlPart($message);
}
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
case $html AND $attachments AND $html_images:
$message = &$this->_addMixedPart();
if (!is_null($this->html_text)) {
$alt = &$this->_addAlternativePart($message);
$this->_addTextPart($alt, $this->html_text);
$rel = &$this->_addRelatedPart($alt);
} else {
$rel = &$this->_addRelatedPart($message);
}
$this->_addHtmlPart($rel);
for ($i=0; $i<count($this->html_images); $i++) {
$this->_addHtmlImagePart($rel, $this->html_images[$i]);
}
for ($i=0; $i<count($this->attachments); $i++) {
$this->_addAttachmentPart($message, $this->attachments[$i]);
}
break;
}
if (isset($message)) {
$output = $message->encode();
$this->output = $output['body'];
$this->headers = array_merge($this->headers, $output['headers']);
// Add message ID header
srand((double)microtime()*10000000);
$message_id = sprintf('<%s.%s@%s>', base_convert(time(), 10, 36), base_convert(rand(), 10, 36), isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'LOCALHOST');
$this->headers['Message-ID'] = $message_id;
$this->is_built = true;
return true;
} else {
return false;
}
}
/**
* Function to encode a header if necessary
* according to RFC2047
*/
function _encodeHeader($input, $charset = 'ISO-8859-1')
{
preg_match_all('/(\s?\w*[\x80-\xFF]+\w*\s?)/', $input, $matches);
foreach ($matches[1] as $value) {
$replacement = preg_replace('/([\x20\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $value);
$input = str_replace($value, '=?' . $charset . '?Q?' . $replacement . '?=', $input);
}
return $input;
}
/**
* Sends the mail.
*
* @param array $recipients
* @param string $type OPTIONAL
* @return mixed
*/
function send($recipients, $type = 'mail')
{
if (!defined('CRLF')) {
$this->setCrlf($type == 'mail' ? "\n" : "\r\n");
}
if (!$this->is_built) {
$this->buildMessage();
}
switch ($type) {
case 'mail':
$subject = '';
if (!empty($this->headers['Subject'])) {
$subject = $this->_encodeHeader($this->headers['Subject'], $this->build_params['head_charset']);
unset($this->headers['Subject']);
}
// Get flat representation of headers
foreach ($this->headers as $name => $value) {
$headers[] = $name . ': ' . $this->_encodeHeader($value, $this->build_params['head_charset']);
}
$to = $this->_encodeHeader(implode(', ', $recipients), $this->build_params['head_charset']);
if (!empty($this->return_path)) {
$result = mail($to, $subject, $this->output, implode(CRLF, $headers), '-f' . $this->return_path);
} else {
$result = mail($to, $subject, $this->output, implode(CRLF, $headers));
}
// Reset the subject in case mail is resent
if ($subject !== '') {
$this->headers['Subject'] = $subject;
}
// Return
return $result;
break;
case 'smtp':
die("Classe SMTP não está implementada.");
break;
}
}
/**
* Use this method to return the email
* in message/rfc822 format. Useful for
* adding an email to another email as
* an attachment. there's a commented
* out example in example.php.
*/
function getRFC822($recipients, $type='mail')
{
// Make up the date header as according to RFC822
$this->setHeader('Date', date('D, d M y H:i:s O'));
if (!defined('CRLF')) {
$this->setCrlf("\n");
}
if (!$this->is_built) {
$this->buildMessage();
}
// Return path ?
if (isset($this->return_path)) {
$headers[] = 'Return-Path: ' . $this->return_path;
}
// Get flat representation of headers
foreach ($this->headers as $name => $value) {
$headers[] = $name . ': ' . $value;
}
$headers[] = 'To: ' . implode(', ', $recipients);
return implode(CRLF, $headers) . CRLF . CRLF . $this->output;
}
} // End of class.
class Mail_mimePart {
var $_encoding; // The encoding type of this part
var $_subparts; // An array of subparts
var $_encoded; // The output of this part after being built
var $_headers; // Headers for this part
var $_body; // The body of this part (not encoded)
/**
* Constructor.
*
* Sets up the object.
*
* @param $body - The body of the mime part if any.
* @param $params - An associative array of parameters:
* content_type - The content type for this part eg multipart/mixed
* encoding - The encoding to use, 7bit, 8bit, base64, or quoted-printable
* cid - Content ID to apply
* disposition - Content disposition, inline or attachment
* dfilename - Optional filename parameter for content disposition
* description - Content description
* charset - Character set to use
* @access public
*/
function Mail_mimePart($body = '', $params = array()){
if (!defined('MAIL_MIMEPART_CRLF')) {
define('MAIL_MIMEPART_CRLF', defined('MAIL_MIME_CRLF') ? MAIL_MIME_CRLF : "\r\n", TRUE);
}
foreach ($params as $key => $value) {
switch ($key) {
case 'content_type':
$headers['Content-Type'] = $value . (isset($charset) ? '; charset="' . $charset . '"' : '');
break;
case 'encoding':
$this->_encoding = $value;
$headers['Content-Transfer-Encoding'] = $value;
break;
case 'cid':
$headers['Content-ID'] = '<' . $value . '>';
break;
case 'disposition':
$headers['Content-Disposition'] = $value . (isset($dfilename) ? '; filename="' . $dfilename . '"' : '');
break;
case 'dfilename':
if (isset($headers['Content-Disposition'])) {
$headers['Content-Disposition'] .= '; filename="' . $value . '"';
} else {
$dfilename = $value;
}
break;
case 'description':
$headers['Content-Description'] = $value;
break;
case 'charset':
if (isset($headers['Content-Type'])) {
$headers['Content-Type'] .= '; charset="' . $value . '"';
} else {
$charset = $value;
}
break;
}
}
// Default content-type
if (!isset($headers['Content-Type'])) {
$headers['Content-Type'] = 'text/plain';
}
//Default encoding
if (!isset($this->_encoding)) {
$this->_encoding = '7bit';
}
// Assign stuff to member variables
$this->_encoded = array();
$this->_headers = $headers;
$this->_body = $body;
}
/**
* encode()
*
* Encodes and returns the email. Also stores
* it in the encoded member variable
*
* @return An associative array containing two elements,
* body and headers. The headers element is itself
* an indexed array.
* @access public
*/
function encode(){
$encoded =& $this->_encoded;
if (!empty($this->_subparts)) {
srand((double)microtime()*1000000);
$boundary = '=_' . md5(uniqid(rand()) . microtime());
$this->_headers['Content-Type'] .= ';' . MAIL_MIMEPART_CRLF . "\t" . 'boundary="' . $boundary . '"';
// Add body parts to $subparts
for ($i = 0; $i < count($this->_subparts); $i++) {
$headers = array();
$tmp = $this->_subparts[$i]->encode();
foreach ($tmp['headers'] as $key => $value) {
$headers[] = $key . ': ' . $value;
}
$subparts[] = implode(MAIL_MIMEPART_CRLF, $headers) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF . $tmp['body'];
}
$encoded['body'] = '--' . $boundary . MAIL_MIMEPART_CRLF .
implode('--' . $boundary . MAIL_MIMEPART_CRLF, $subparts) .
'--' . $boundary.'--' . MAIL_MIMEPART_CRLF;
} else {
$encoded['body'] = $this->_getEncodedData($this->_body, $this->_encoding) . MAIL_MIMEPART_CRLF . MAIL_MIMEPART_CRLF;
}
// Add headers to $encoded
$encoded['headers'] =& $this->_headers;
return $encoded;
}
/**
* &addSubPart()
*
* Adds a subpart to current mime part and returns
* a reference to it
*
* @param $body The body of the subpart, if any.
* @param $params The parameters for the subpart, same
* as the $params argument for constructor.
* @return A reference to the part you just added. It is
* crucial if using multipart/* in your subparts that
* you use =& in your script when calling this function,
* otherwise you will not be able to add further subparts.
* @access public
*/
function &addSubPart($body, $params)
{
$this->_subparts[] = new Mail_mimePart($body, $params);
return $this->_subparts[count($this->_subparts) - 1];
}
/**
* _getEncodedData()
*
* Returns encoded data based upon encoding passed to it
*
* @param $data The data to encode.
* @param $encoding The encoding type to use, 7bit, base64,
* or quoted-printable.
* @access private
*/
function _getEncodedData($data, $encoding)
{
switch ($encoding) {
case '8bit':
case '7bit':
return $data;
break;
case 'quoted-printable':
return $this->_quotedPrintableEncode($data);
break;
case 'base64':
return rtrim(chunk_split(base64_encode($data), 76, MAIL_MIMEPART_CRLF));
break;
default:
return $data;
}
}
/**
* quoteadPrintableEncode()
*
* Encodes data to quoted-printable standard.
*
* @param $input The data to encode
* @param $line_max Optional max line length. Should
* not be more than 76 chars
*
* @access private
*/
function _quotedPrintableEncode($input , $line_max = 76)
{
$lines = preg_split("/\r?\n/", $input);
$eol = MAIL_MIMEPART_CRLF;
$escape = '=';
$output = '';
while(list(, $line) = each($lines)){
$linlen = strlen($line);
$newline = '';
for ($i = 0; $i < $linlen; $i++) {
$char = substr($line, $i, 1);
$dec = ord($char);
if (($dec == 32) AND ($i == ($linlen - 1))){ // convert space at eol only
$char = '=20';
} elseif($dec == 9) {
; // Do nothing if a tab.
} elseif(($dec == 61) OR ($dec < 32 ) OR ($dec > 126)) {
$char = $escape . strtoupper(sprintf('%02s', dechex($dec)));
}
if ((strlen($newline) + strlen($char)) >= $line_max) { // MAIL_MIMEPART_CRLF is not counted
$output .= $newline . $escape . $eol; // soft line break; " =\r\n" is okay
$newline = '';
}
$newline .= $char;
} // end of for
$output .= $newline . $eol;
}
$output = substr($output, 0, -1 * strlen($eol)); // Don't want last crlf
return $output;
}
} // End of class
class smtp_class{
// SMTP Support
/*
<version>@(#) $Id: smtp.php,v 1.41 2009/04/12 06:15:06 mlemos Exp $</version>
<copyright>Copyright © (C) Manuel Lemos 1999-2009</copyright>
<title>Sending e-mail messages via SMTP protocol</title>
<author>Manuel Lemos</author>
<authoraddress>mlemos-at-acm.org</authoraddress>
*/
var $user="";
var $realm="";
var $password="";
var $workstation="";
var $authentication_mechanism="";
var $host_name="";
var $host_port=25;
var $ssl=0;
var $start_tls = 0;
var $localhost="";
var $timeout=0;
var $data_timeout=0;
var $direct_delivery=0;
var $error="";
var $debug=0;
var $html_debug=0;
var $esmtp=1;
var $esmtp_extensions=array();
var $exclude_address="";
var $getmxrr="GetMXRR";
var $pop3_auth_host="";
var $pop3_auth_port=110;
/* private variables - DO NOT ACCESS */
var $state="Disconnected";
var $connection=0;
var $pending_recipients=0;
var $next_token="";
var $direct_sender="";
var $connected_domain="";
var $result_code;
var $disconnected_error=0;
var $esmtp_host="";
var $maximum_piped_recipients=100;
/* Private methods - DO NOT CALL */
Function Tokenize($string,$separator="")
{
if(!strcmp($separator,""))
{
$separator=$string;
$string=$this->next_token;
}
for($character=0;$character<strlen($separator);$character++)
{
if(GetType($position=strpos($string,$separator[$character]))=="integer")
$found=(IsSet($found) ? min($found,$position) : $position);
}
if(IsSet($found))
{
$this->next_token=substr($string,$found+1);
return(substr($string,0,$found));
}
else
{
$this->next_token="";
return($string);
}
}
Function setError($error){
$this->error = $error;
$this->OutputDebug("Erro ocurred: {$error}");
}
Function OutputDebug($message){
if($this->debug){
$message.="\n";
if($this->html_debug)
$message=str_replace("\n","<br />\n",HtmlEntities($message));
echo $message;
flush();
}
}
Function SetDataAccessError($error)
{
$this->setError($error);
if(function_exists("socket_get_status"))
{
$status=socket_get_status($this->connection);
if($status["timed_out"])
$this->error.=": data access time out";
elseif($status["eof"])
{
$this->error.=": the server disconnected";
$this->disconnected_error=1;
}
}
}
Function GetLine()
{
for($line="";;)
{
if(feof($this->connection))
{
$this->setError("reached the end of data while reading from the SMTP server conection");
return("");
}
if(GetType($data=@fgets($this->connection,100))!="string" || strlen($data)==0){
$this->SetDataAccessError("it was not possible to read line from the SMTP server");
return("");
}
$line .= $data;
$length = strlen($line);
if($length>=1 && substr($line,-1)=="\n"){
$this->OutputDebug("S ".str_replace(Array("\r\n", "\r", "\n"), Array("<CRNL>", "<CR>", "<NL>"), $line));
$line = rtrim($line, "\r\n");
return($line);
}
}
}
Function PutLine($line)
{
$this->OutputDebug("C {$line}<CRNL>");
if(!@fputs($this->connection,"$line\r\n"))
{
$this->SetDataAccessError("it was not possible to send a line to the SMTP server");
return(0);
}
return(1);
}
Function PutData(&$data)
{
if(strlen($data))
{
$this->OutputDebug("C $data");
if(!@fputs($this->connection,$data))
{
$this->SetDataAccessError("it was not possible to send data to the SMTP server");
return(0);
}
}
return(1);
}
Function VerifyResultLines($code,&$responses)
{
$responses=array();
Unset($this->result_code);
while(strlen($line=$this->GetLine($this->connection))){
if(IsSet($this->result_code)){
if(strcmp($this->Tokenize($line," -"),$this->result_code)){
$this->setError($line);
return(0);
}
}
else{
$this->result_code=$this->Tokenize($line," -");
if(GetType($code)=="array"){
for($codes=0;$codes<count($code) && strcmp($this->result_code,$code[$codes]);$codes++);
if($codes>=count($code)){
$this->setError($line);
return(0);
}
}
else{
if(strcmp($this->result_code,$code)){
$this->setError($line);
return(0);
}
}
}
$responses[]=$this->Tokenize("");
if(!strcmp($this->result_code,$this->Tokenize($line," ")))
return(1);
}
return(-1);
}
Function FlushRecipients()
{
if($this->pending_sender)
{
if($this->VerifyResultLines("250",$responses)<=0)
return(0);
$this->pending_sender=0;
}
for(;$this->pending_recipients;$this->pending_recipients--)
{
if($this->VerifyResultLines(array("250","251"),$responses)<=0)
return(0);
}
return(1);
}
Function ConnectToHost($domain, $port, $resolve_message)
{
if($this->ssl)
{
$version=explode(".",function_exists("phpversion") ? phpversion() : "3.0.7");
$php_version=intval($version[0])*1000000+intval($version[1])*1000+intval($version[2]);
if($php_version<4003000)
return("establishing SSL connections requires at least PHP version 4.3.0");
if(!function_exists("extension_loaded")
|| !extension_loaded("openssl"))
return("establishing SSL connections requires the OpenSSL extension enabled");
}
if(function_exists('preg_match') ? preg_match('/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $domain) : ereg('^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$',$domain))
$ip=$domain;
else
{
$this->OutputDebug($resolve_message);
if(!strcmp($ip=@gethostbyname($domain),$domain))
return("could not resolve host \"".$domain."\"");
}
if(strlen($this->exclude_address)
&& !strcmp(@gethostbyname($this->exclude_address),$ip))
return("domain \"".$domain."\" resolved to an address excluded to be valid");
$this->OutputDebug("Connecting to host address \"".$ip."\" port ".$port."...");
if(($this->connection=($this->timeout ? @fsockopen(($this->ssl ? "ssl://" : "").$ip,$port,$errno,$error,$this->timeout) : @fsockopen(($this->ssl ? "ssl://" : "").$ip,$port))))
return("");
$error=($this->timeout ? strval($error) : "??");
switch($error)
{
case "-3":
return("-3 socket could not be created");
case "-4":
return("-4 dns lookup on hostname \"".$domain."\" failed");
case "-5":
return("-5 connection refused or timed out");
case "-6":
return("-6 fdopen() call failed");
case "-7":
return("-7 setvbuf() call failed");
}
return("could not connect to the host \"".$domain."\": ".$error);
}
Function SASLAuthenticate($mechanisms, $credentials, &$authenticated, &$mechanism)
{
$authenticated=0;
if(!function_exists("class_exists")
|| !class_exists("sasl_client_class"))
{
$this->setError("it is not possible to authenticate using the specified mechanism because the SASL library class is not loaded");
return(0);
}
$sasl=new sasl_client_class;
$sasl->SetCredential("user",$credentials["user"]);
$sasl->SetCredential("password",$credentials["password"]);
if(IsSet($credentials["realm"]))
$sasl->SetCredential("realm",$credentials["realm"]);
if(IsSet($credentials["workstation"]))
$sasl->SetCredential("workstation",$credentials["workstation"]);
if(IsSet($credentials["mode"]))
$sasl->SetCredential("mode",$credentials["mode"]);
do
{
$status=$sasl->Start($mechanisms,$message,$interactions);
}
while($status==SASL_INTERACT);
switch($status)
{
case SASL_CONTINUE:
break;
case SASL_NOMECH:
if(strlen($this->authentication_mechanism)){
$this->setError("authenticated mechanism ".$this->authentication_mechanism." may not be used: ".$sasl->error);
return(0);
}
break;
default:
$this->setError("Could not start the SASL authentication client: ".$sasl->error);
return(0);
}
if(strlen($mechanism=$sasl->mechanism)){
if($this->PutLine("AUTH ".$sasl->mechanism.(IsSet($message) ? " ".base64_encode($message) : ""))==0){
$this->setError("Could not send the AUTH command");
return(0);
}
if(!$this->VerifyResultLines(array("235","334"),$responses))
return(0);
switch($this->result_code)
{
case "235":
$response="";
$authenticated=1;
break;
case "334":
$response=base64_decode($responses[0]);
break;
default:
$this->setError("Authentication error: ".$responses[0]);
return(0);
}
for(;!$authenticated;)
{
do
{
$status=$sasl->Step($response,$message,$interactions);
}
while($status==SASL_INTERACT);
switch($status)
{
case SASL_CONTINUE:
if($this->PutLine(base64_encode($message))==0)
{
$this->setError("Could not send the authentication step message");
return(0);
}
if(!$this->VerifyResultLines(array("235","334"),$responses))
return(0);
switch($this->result_code)
{
case "235":
$response="";
$authenticated=1;
break;
case "334":
$response=base64_decode($responses[0]);
break;
default:
$this->setError("Authentication error: ".$responses[0]);
return(0);
}
break;
default:
$this->setError("Could not process the SASL authentication step: ".$sasl->error);
return(0);
}
}
}
return(1);
}
Function StartSMTP($localhost)
{
$success = 1;
$this->esmtp_extensions = array();
$fallback=1;
if($this->esmtp
|| strlen($this->user))
{
if($this->PutLine('EHLO '.$localhost))
{
if(($success_code=$this->VerifyResultLines('250',$responses))>0)
{
$this->esmtp_host=$this->Tokenize($responses[0]," ");
for($response=1;$response<count($responses);$response++)
{
$extension=strtoupper($this->Tokenize($responses[$response]," "));
$this->esmtp_extensions[$extension]=$this->Tokenize("");
}
$success=1;
$fallback=0;
}
else
{
if($success_code==0)
{
$code=$this->Tokenize($this->error," -");
switch($code)
{
case "421":
$fallback=0;
break;
}
}
}
}
else
$fallback=0;
}
if($fallback)
{
if($this->PutLine("HELO $localhost")
&& $this->VerifyResultLines("250",$responses)>0)
$success=1;
}
return($success);
}
/* Public methods */
Function Connect($domain="")
{
if(strcmp($this->state,"Disconnected"))
{
$this->setError("connection is already established");
return(0);
}
$this->disconnected_error=0;
$this->error=$error="";
$this->esmtp_host="";
$this->esmtp_extensions=array();
$hosts=array();
if($this->direct_delivery)
{
if(strlen($domain)==0)
return(1);
$hosts=$weights=$mxhosts=array();
$getmxrr=$this->getmxrr;
if(function_exists($getmxrr)
&& $getmxrr($domain,$hosts,$weights))
{
for($host=0;$host<count($hosts);$host++)
$mxhosts[$weights[$host]]=$hosts[$host];
KSort($mxhosts);
for(Reset($mxhosts),$host=0;$host<count($mxhosts);Next($mxhosts),$host++)
$hosts[$host]=$mxhosts[Key($mxhosts)];
}
else
{
if(strcmp(@gethostbyname($domain),$domain)!=0)
$hosts[]=$domain;
}
}
else
{
if(strlen($this->host_name))
$hosts[]=$this->host_name;
if(strlen($this->pop3_auth_host))
{
$user=$this->user;
if(strlen($user)==0){
$this->setError("it was not specified the POP3 authentication user");
return(0);
}
$password=$this->password;
if(strlen($password)==0){
$this->setError("it was not specified the POP3 authentication password");
return(0);
}
$domain=$this->pop3_auth_host;
$this->setError($this->ConnectToHost($domain, $this->pop3_auth_port, "Resolving POP3 authentication host \"".$domain."\"..."));
if(strlen($this->error))
return(0);
if(strlen($response=$this->GetLine())==0)
return(0);
if(strcmp($this->Tokenize($response," "),"+OK"))
{
$this->setError("POP3 authentication server greeting was not found");
return(0);
}
if(!$this->PutLine("USER ".$this->user)
|| strlen($response=$this->GetLine())==0)
return(0);
if(strcmp($this->Tokenize($response," "),"+OK"))
{
$this->setError("POP3 authentication user was not accepted: ".$this->Tokenize("\r\n"));
return(0);
}
if(!$this->PutLine("PASS ".$password)
|| strlen($response=$this->GetLine())==0)
return(0);
if(strcmp($this->Tokenize($response," "),"+OK"))
{
$this->setError("POP3 authentication password was not accepted: ".$this->Tokenize("\r\n"));
return(0);
}
fclose($this->connection);
$this->connection=0;
}
}
if(count($hosts)==0)
{
$this->setError("could not determine the SMTP to connect");
return(0);
}
for($host=0, $error="not connected";strlen($error) && $host<count($hosts);$host++)
{
$domain=$hosts[$host];
$error=$this->ConnectToHost($domain, $this->host_port, "Resolving SMTP server domain \"$domain\"...");
}
if(strlen($error))
{
$this->setError($error);
return(0);
}
$timeout=($this->data_timeout ? $this->data_timeout : $this->timeout);
if($timeout && function_exists("socket_set_timeout"))
socket_set_timeout($this->connection,$timeout,0);
$this->OutputDebug("Connected to SMTP server \"".$domain."\".");
if(!strcmp($localhost=$this->localhost,"") && !strcmp($localhost=getenv("SERVER_NAME"),"") && !strcmp($localhost=getenv("HOST"),""))
$localhost="localhost";
$success=0;
if($this->VerifyResultLines("220",$responses)>0){
$success = $this->StartSMTP($localhost);
if($this->start_tls){
if(!IsSet($this->esmtp_extensions["STARTTLS"])){
$this->setError("server does not support starting TLS");
$success=0;
}
elseif(!function_exists('stream_socket_enable_crypto')){
$this->setError("this PHP installation or version does not support starting TLS");
$success=0;
}
elseif($success = ($this->PutLine('STARTTLS') && $this->VerifyResultLines('220',$responses)>0)){
$this->OutputDebug('Starting TLS cryptograpic protocol');
if(!($success = @stream_socket_enable_crypto($this->connection, 1, STREAM_CRYPTO_METHOD_TLS_CLIENT)))
$this->error = 'could not start TLS connection encryption protocol';
else{
$this->OutputDebug('TLS started');
$success = $this->StartSMTP($localhost);
}
}
}
if($success
&& strlen($this->user)
&& strlen($this->pop3_auth_host)==0)
{
if(!IsSet($this->esmtp_extensions["AUTH"]))
{
$this->setError("server does not require authentication");
if(IsSet($this->esmtp_extensions["STARTTLS"]))
$this->error .= ', it probably requires starting TLS';
$success=0;
}
else
{
if(strlen($this->authentication_mechanism))
$mechanisms=array($this->authentication_mechanism);
else
{
$mechanisms=array();
for($authentication=$this->Tokenize($this->esmtp_extensions["AUTH"]," ");strlen($authentication);$authentication=$this->Tokenize(" "))
$mechanisms[]=$authentication;
}
$credentials=array(
"user"=>$this->user,
"password"=>$this->password
);
if(strlen($this->realm))
$credentials["realm"]=$this->realm;
if(strlen($this->workstation))
$credentials["workstation"]=$this->workstation;
$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
if(!$success
&& !strcmp($mechanism,"PLAIN"))
{
/*
* Author: Russell Robinson, 25 May 2003, http://www.tectite.com/
* Purpose: Try various AUTH PLAIN authentication methods.
*/
$mechanisms=array("PLAIN");
$credentials=array(
"user"=>$this->user,
"password"=>$this->password
);
if(strlen($this->realm))
{
/*
* According to: http://www.sendmail.org/~ca/email/authrealms.html#authpwcheck_method
* some sendmails won't accept the realm, so try again without it
*/
$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
}
if(!$success)
{
/*
* It was seen an EXIM configuration like this:
* user^password^unused
*/
$credentials["mode"]=SASL_PLAIN_EXIM_DOCUMENTATION_MODE;
$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
}
if(!$success)
{
/*
* ... though: http://exim.work.de/exim-html-3.20/doc/html/spec_36.html
* specifies: ^user^password
*/
$credentials["mode"]=SASL_PLAIN_EXIM_MODE;
$success=$this->SASLAuthenticate($mechanisms,$credentials,$authenticated,$mechanism);
}
}
if($success
&& strlen($mechanism)==0)
{
$this->setError("it is not supported any of the authentication mechanisms required by the server");
$success=0;
}
}
}
}
if($success)
{
$this->state="Connected";
$this->connected_domain=$domain;
}
else
{
fclose($this->connection);
$this->connection=0;
}
return($success);
}
Function MailFrom($sender)
{
if($this->direct_delivery)
{
switch($this->state)
{
case "Disconnected":
$this->direct_sender=$sender;
return(1);
case "Connected":
$sender=$this->direct_sender;
break;
default:
$this->setError("direct delivery connection is already established and sender is already set");
return(0);
}
}
else
{
if(strcmp($this->state,"Connected"))
{
$this->setError("connection is not in the initial state");
return(0);
}
}
if(!$this->PutLine("MAIL FROM:<$sender>"))
return(0);
if(!IsSet($this->esmtp_extensions["PIPELINING"])
&& $this->VerifyResultLines("250",$responses)<=0)
return(0);
$this->state="SenderSet";
if(IsSet($this->esmtp_extensions["PIPELINING"]))
$this->pending_sender=1;
$this->pending_recipients=0;
return(1);
}
Function SetRecipient($recipient)
{
if($this->direct_delivery)
{
if(GetType($at=strrpos($recipient,"@"))!="integer")
return("it was not specified a valid direct recipient");
$domain=substr($recipient,$at+1);
switch($this->state)
{
case "Disconnected":
if(!$this->Connect($domain))
return(0);
if(!$this->MailFrom(""))
{
$error=$this->error;
$this->Disconnect();
$this->setError($error);
return(0);
}
break;
case "SenderSet":
case "RecipientSet":
if(strcmp($this->connected_domain,$domain))
{
$this->setError("it is not possible to deliver directly to recipients of different domains");
return(0);
}
break;
default:
$this->setError("connection is already established and the recipient is already set");
return(0);
}
}
else
{
switch($this->state)
{
case "SenderSet":
case "RecipientSet":
break;
default:
$this->setError("connection is not in the recipient setting state");
return(0);
}
}
if(!$this->PutLine("RCPT TO:<$recipient>"))
return(0);
if(IsSet($this->esmtp_extensions["PIPELINING"]))
{
$this->pending_recipients++;
if($this->pending_recipients>=$this->maximum_piped_recipients)
{
if(!$this->FlushRecipients())
return(0);
}
}
else
{
if($this->VerifyResultLines(array("250","251"),$responses)<=0)
return(0);
}
$this->state="RecipientSet";
return(1);
}
Function StartData()
{
if(strcmp($this->state,"RecipientSet"))
{
$this->setError("connection is not in the start sending data state");
return(0);
}
if(!$this->PutLine("DATA"))
return(0);
if($this->pending_recipients){
if(!$this->FlushRecipients())
return(0);
}
if($this->VerifyResultLines("354",$responses)<=0)
return(0);
$this->state="SendingData";
return(1);
}
Function PrepareData($data){
if(function_exists("preg_replace"))
return(preg_replace(array("/\n\n|\r\r/","/(^|[^\r])\n/","/\r([^\n]|\$)/D","/(^|\n)\\./"),array("\r\n\r\n","\\1\r\n","\r\n\\1","\\1.."),$data));
else
return(
ereg_replace("(^|\n)\\.","\\1..",
ereg_replace("\r([^\n]|\$)","\r\n\\1",
ereg_replace("(^|[^\r])\n","\\1\r\n",
ereg_replace("\n\n|\r\r","\r\n\r\n",$data)))));
}
Function SendData($data){
if(strcmp($this->state,"SendingData"))
{
$this->setError("connection is not in the sending data state");
return(0);
}
return($this->PutData($data));
}
Function EndSendingData(){
if(strcmp($this->state,"SendingData"))
{
$this->setError("connection is not in the sending data state");
return(0);
}
if(!$this->PutLine("\r\n.")
|| $this->VerifyResultLines("250",$responses)<=0)
return(0);
$this->state="Connected";
return(1);
}
Function ResetConnection(){
switch($this->state)
{
case "Connected":
return(1);
case "SendingData":
$this->setError("can not reset the connection while sending data");
return(0);
case "Disconnected":
$this->setError("can not reset the connection before it is established");
return(0);
}
if(!$this->PutLine("RSET") || $this->VerifyResultLines("250",$responses)<=0)
return(0);
$this->state="Connected";
return(1);
}
Function Disconnect($quit=1){
if(!strcmp($this->state,"Disconnected")){
$this->setError("it was not previously established a SMTP connection");
return(0);
}
$this->error="";
if(!strcmp($this->state,"Connected")
&& $quit
&& (!$this->PutLine("QUIT")
|| ($this->VerifyResultLines("221",$responses)<=0
&& !$this->disconnected_error)))
return(0);
if($this->disconnected_error)
$this->disconnected_error=0;
else
fclose($this->connection);
$this->connection=0;
$this->state="Disconnected";
$this->OutputDebug("Disconnected.");
return(1);
}
Function SendMessage($sender,$recipients,$headers,$body){
if(($success=$this->Connect()))
{
if(($success=$this->MailFrom($sender)))
{
for($recipient=0;$recipient<count($recipients);$recipient++)
{
if(!($success=$this->SetRecipient($recipients[$recipient])))
break;
}
if($success
&& ($success=$this->StartData()))
{
for($header_data="",$header=0;$header<count($headers);$header++)
$header_data.=$headers[$header]."\r\n";
$success=($this->SendData($header_data."\r\n")
&& $this->SendData($this->PrepareData($body))
&& $this->EndSendingData());
}
}
$error=$this->error;
$disconnect_success=$this->Disconnect($success);
if($success)
$success=$disconnect_success;
else
$this->setError($error);
}
return($success);
}
};
define("SASL_INTERACT", 2);
define("SASL_CONTINUE", 1);
define("SASL_OK", 0);
define("SASL_FAIL", -1);
define("SASL_NOMECH", -4);
class sasl_interact_class{
var $id;
var $challenge;
var $prompt;
var $default_result;
var $result;
};
class sasl_client_class{
var $error='';
var $mechanism='';
var $encode_response=1;
/* Private variables */
var $driver;
var $drivers=array(
"Digest" => array("digest_sasl_client_class", "digest_sasl_client.php" ),
"CRAM-MD5" => array("cram_md5_sasl_client_class", "cram_md5_sasl_client.php" ),
"LOGIN" => array("login_sasl_client_class", "login_sasl_client.php" ),
"NTLM" => array("ntlm_sasl_client_class", "ntlm_sasl_client.php" ),
"PLAIN" => array("plain_sasl_client_class", "plain_sasl_client.php" ),
"Basic" => array("basic_sasl_client_class", "basic_sasl_client.php" )
);
var $credentials=array();
/* Public functions */
Function SetCredential($key,$value){
$this->credentials[$key]=$value;
}
Function GetCredentials(&$credentials,$defaults,&$interactions){
Reset($credentials);
$end=(GetType($key=Key($credentials))!="string");
for(;!$end;)
{
if(!IsSet($this->credentials[$key]))
{
if(IsSet($defaults[$key]))
$credentials[$key]=$defaults[$key];
else
{
$this->error="the requested credential ".$key." is not defined";
return(SASL_NOMECH);
}
}
else
$credentials[$key]=$this->credentials[$key];
Next($credentials);
$end=(GetType($key=Key($credentials))!="string");
}
return(SASL_CONTINUE);
}
Function Start($mechanisms, &$message, &$interactions){
if(strlen($this->error))
return(SASL_FAIL);
if(IsSet($this->driver))
return($this->driver->Start($this,$message,$interactions));
$no_mechanism_error="";
for($m=0;$m<count($mechanisms);$m++)
{
$mechanism=$mechanisms[$m];
if(IsSet($this->drivers[$mechanism]))
{
if(!class_exists($this->drivers[$mechanism][0]))
require(dirname(__FILE__)."/".$this->drivers[$mechanism][1]);
$this->driver=new $this->drivers[$mechanism][0];
if($this->driver->Initialize($this))
{
$this->encode_response=1;
$status=$this->driver->Start($this,$message,$interactions);
switch($status)
{
case SASL_NOMECH:
Unset($this->driver);
if(strlen($no_mechanism_error)==0)
$no_mechanism_error=$this->error;
$this->error="";
break;
case SASL_CONTINUE:
$this->mechanism=$mechanism;
return($status);
default:
Unset($this->driver);
$this->error="";
return($status);
}
}
else
{
Unset($this->driver);
if(strlen($no_mechanism_error)==0)
$no_mechanism_error=$this->error;
$this->error="";
}
}
}
$this->error=(strlen($no_mechanism_error) ? $no_mechanism_error : "it was not requested any of the authentication mechanisms that are supported");
return(SASL_NOMECH);
}
Function Step($response, &$message, &$interactions){
if(strlen($this->error))
return(SASL_FAIL);
return($this->driver->Step($this,$response,$message,$interactions));
}
};
define("SASL_LOGIN_STATE_START", 0);
define("SASL_LOGIN_STATE_IDENTIFY_USER", 1);
define("SASL_LOGIN_STATE_IDENTIFY_PASSWORD", 2);
define("SASL_LOGIN_STATE_DONE", 3);
class login_sasl_client_class{
var $credentials=array();
var $state=SASL_LOGIN_STATE_START;
Function Initialize(&$client)
{
return(1);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_LOGIN_STATE_START)
{
$client->error="LOGIN authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>"",
"realm"=>""
);
$defaults=array(
"realm"=>""
);
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
$this->state=SASL_LOGIN_STATE_IDENTIFY_USER;
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
case SASL_LOGIN_STATE_IDENTIFY_USER:
$message=$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "");
$this->state=SASL_LOGIN_STATE_IDENTIFY_PASSWORD;
break;
case SASL_LOGIN_STATE_IDENTIFY_PASSWORD:
$message=$this->credentials["password"];
$this->state=SASL_LOGIN_STATE_DONE;
break;
case SASL_LOGIN_STATE_DONE:
$client->error="LOGIN authentication was finished without success";
break;
default:
$client->error="invalid LOGIN authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
define("SASL_PLAIN_STATE_START", 0);
define("SASL_PLAIN_STATE_IDENTIFY", 1);
define("SASL_PLAIN_STATE_DONE", 2);
define("SASL_PLAIN_DEFAULT_MODE", 0);
define("SASL_PLAIN_EXIM_MODE", 1);
define("SASL_PLAIN_EXIM_DOCUMENTATION_MODE", 2);
class plain_sasl_client_class{
var $credentials=array();
var $state=SASL_PLAIN_STATE_START;
Function Initialize(&$client)
{
return(1);
}
Function Start(&$client, &$message, &$interactions)
{
if($this->state!=SASL_PLAIN_STATE_START)
{
$client->error="PLAIN authentication state is not at the start";
return(SASL_FAIL);
}
$this->credentials=array(
"user"=>"",
"password"=>"",
"realm"=>"",
"mode"=>""
);
$defaults=array(
"realm"=>"",
"mode"=>""
);
$status=$client->GetCredentials($this->credentials,$defaults,$interactions);
if($status==SASL_CONTINUE)
{
switch($this->credentials["mode"])
{
case SASL_PLAIN_EXIM_MODE:
$message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
break;
case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
$message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
break;
default:
$message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
break;
}
$this->state=SASL_PLAIN_STATE_DONE;
}
else
Unset($message);
return($status);
}
Function Step(&$client, $response, &$message, &$interactions)
{
switch($this->state)
{
/*
case SASL_PLAIN_STATE_IDENTIFY:
switch($this->credentials["mode"])
{
case SASL_PLAIN_EXIM_MODE:
$message=$this->credentials["user"]."\0".$this->credentials["password"]."\0";
break;
case SASL_PLAIN_EXIM_DOCUMENTATION_MODE:
$message="\0".$this->credentials["user"]."\0".$this->credentials["password"];
break;
default:
$message=$this->credentials["user"]."\0".$this->credentials["user"].(strlen($this->credentials["realm"]) ? "@".$this->credentials["realm"] : "")."\0".$this->credentials["password"];
break;
}
var_dump($message);
$this->state=SASL_PLAIN_STATE_DONE;
break;
*/
case SASL_PLAIN_STATE_DONE:
$client->error="PLAIN authentication was finished without success";
return(SASL_FAIL);
default:
$client->error="invalid PLAIN authentication step state";
return(SASL_FAIL);
}
return(SASL_CONTINUE);
}
};
|