. */ class Mail { private $host; private $port; private $domain; private $from; private $rcpt; private $header; private $message; private $boundary; private $attachment; private $dlv_msg; private $dlv_ret_nr; const MAIL_FAIL = 0; const MAIL_OK = 1; const MAIL_QUEUE = 2; public function __construct($from, $rcpt, $domain="", $host="localhost", $port=25) { global $setup; if( $this->check_email($from) ) $this->from = $from; else { debug("Invalid from: ".$from); return false; } if( DEVELOPMENTVERSION ) { $this->rcpt = WEBMASTEREMAIL; }else { if( is_array($rcpt) ) { for( $i=0; $icheck_email($rcpt[$i]) ) { debug("Invalid rcpt: ".$rcpt[$i]); return false; } } $this->rcpt = $rcpt; }else { if( $this->check_email($rcpt) ) $this->rcpt = $rcpt; else { debug("Invalid rcpt: ".$rcpt); return false; } } } $this->host = $host; $this->port = $port; if( strlen($domain)>0 ) $this->domain = $domain; else $this->domain = $_SERVER['SERVER_NAME']; $this->header = array(); $this->message = ""; $this->boundary = date('YmdHis') . '_' . mt_rand(10000, 99999) . "/" . $this->domain; $this->attachment = array(); $this->dlv_msg = ""; $this->dlv_ret_nr = 0; return true; } public function __destruct() { } public function setMessage($msg) { $this->message = $msg; } #public function SetHeader($header) { #} public function addHeader($name, $value) { $this->header[ ucwords($name) ] = $value; } public function addAttachment($msg, $ContentType, $Encoding="") { $c = count($this->attachment); $this->attachment[$c]['contenttype'] = $ContentType; $this->attachment[$c]['encoding'] = $Encoding; $this->attachment[$c]['message'] = $msg; } public function send($sendLaterOnError=false) { $this->checkHeader(); if( is_array($this->rcpt) ) { $to = $this->rcpt[0]; for( $i=1; $ircpt); $i++ ) { $to .= " ,".$this->rcpt[$i]; } }elseif( strlen($this->rcpt)>0 ) { $to = $this->rcpt; }else { return self::MAIL_FAIL; } if( $stream=$this->initStream($this->from, $to) ) { // headers $this->sendHeaders($stream); // message $this->sendMessage($stream); // attachment if( count($this->attachment)>0 ) $this->sendAttachment($stream); // close mail if( $this->finalizeStream($stream) ) return self::MAIL_OK; else return self::MAIL_FAIL; }else { // failed debug("Failed initStream()"); debug("Error ".$this->dlv_ret_nr.": ".$this->dlv_msg); if( $sendLaterOnError ) { if( $this->queue() ) return self::MAIL_QUEUE; else return self::MAIL_FAIL; } return self::MAIL_FAIL; } } public function setSubject($subject) { $this->addHeader("Subject", $subject); } public function get_delivery_msg() { return $this->dlv_msg; } public function get_delivery_ret_nr() { return $this->dlv_ret_nr; } private function check_email($Email) { // Check if the supplied e-mail address is a valid e-mail address. If yes, return true, else return false $re="/(^(\w|\.|-)+@(\w|-)+(\.(\w|-)+)*\.[a-zA-Z]{2,4}$)/"; if( preg_match($re,$Email) ) { //Regex matches, now check MX if( getmxrr(substr($Email,strpos($Email,"@")+1), $mxhosts) ) { return true; }else { return false; } }else { return false; } } private function checkHeader() { global $setup; $k = array_keys($this->header); if( !in_array("From", $k) ) $this->header['From'] = $this->from; if( !in_array("To", $k) ) { if( is_array($this->rcpt) ) { $this->header['To'] = $this->rcpt[0]; for( $i=1; $ircpt); $i++ ) { $this->header['To'] .= $this->rcpt[$i]; } }else { $this->header['To'] = $this->rcpt; } } if( !in_array("Date", $k) ) $this->header['Date'] = date("r"); if( !in_array("Message-ID", $k) ) $this->header['Message-ID'] = "<" . date('YmdHis') . '.' . mt_rand(10000, 99999) . "@" . $this->domain . ">"; if( !in_array("Content-Type", $k) ) { if( count($this->attachment)>0 ) $this->header['Content-Type'] = "multipart/mixed; boundary=\"".$this->boundary."\""; else $this->header['Content-Type'] = "text/plain; charset=UTF-8"; } $this->header['X-Mailer'] = "AEGEE-Europe statutory event application"; if( isset($_SERVER['REMOTE_HOST']) ) $this->header['X-Posting-Host'] = $_SERVER['REMOTE_HOST']." [".$_SERVER['REMOTE_ADDR']."]"; } private function queue() { $query = "INSERT INTO `mailout` (`date`, `to`, `content`, `Mail`) VALUES ('".addslashes(date("Y-m-d H:i:s"))."', '"; if( is_array($this->rcpt) ) { $query .= addslashes($this->rcpt[0]); for( $i=1; $ircpt); $i++ ) { $query .= addslashes(", ".$this->rcpt[$i]); } }else { $query .= addslashes($this->rcpt); } $query .= "', '".$this->header['X-Content']."', '".addslashes(serialize($this))."')"; if( doquery($query) ) { return true; }else { return false; } } private function sendHeaders($stream) { $headerorder = array("Message-ID", "Date", "From", "To", "Cc", "Subject", "Content-Type"); $k = array_keys($this->header); for( $i=0; $iwriteToStream($stream, $this->headerLimit($headerorder[$i].": ".$this->header[ $headerorder[$i] ]."\n")); } } for( $i=0; $iwriteToStream($stream, $this->headerLimit($k[$i].": ".$this->header[ $k[$i] ]."\n")); } } $this->writeToStream($stream, "\n"); } private function sendMessage($stream) { global $setup; $this->writeToStream($stream, $this->messageLimit($this->message)); $this->writeToStream($stream, "\n"); if( substr($this->header['Content-Type'], 0, 10) == "text/plain" OR substr($this->header['Content-Type'], 0, 15) == "multipart/mixed" ) $this->writeToStream($stream, "\n".str_replace("\\n", "\n", MAILFOOTER)."\n"); } private function sendAttachment($stream) { ########## } private function headerLimit($header) { ########## return $header; } private function messageLimit($message) { ########## return $message; } private function preWriteToStream(&$s) { if( $s ) { if( $s{0} == '.' ) $s = '.' . $s; $s = str_replace("\n.","\n..",$s); } } private function initStream($from, $to) { $to.=","; $to_list=array(); $a=0; $b=strpos($to, ",", $a); while( !($b===false) ) { $to_list[]=substr($to, $a, $b-$a); $a=$b+1; $b=strpos($to, ",", $a); } $stream = @fsockopen($this->host, $this->port, $errorNumber, $errorString); if( !$stream ) { $this->dlv_msg = $errorString; $this->dlv_ret_nr = $errorNumber; return false; } $tmp = fgets($stream, 1024); if( $this->errorCheck($tmp, $stream) ) { return false; } if( $this->host=="localhost" ) $helodomain = "localhost"; else $helodomain = $this->domain; /* Lets introduce ourselves */ fputs($stream, "EHLO ".$helodomain."\r\n"); $tmp = fgets($stream,1024); if( $this->errorCheck($tmp,$stream) ) { // fall back to HELO if EHLO is not supported if( $this->dlv_ret_nr == '500' ) { fputs($stream, "HELO ".$helodomain."\r\n"); $tmp = fgets($stream,1024); if( $this->errorCheck($tmp,$stream) ) { return false; } }else { return false; } } /* Ok, who is sending the message? */ fputs($stream, "MAIL FROM: <".$from.">\r\n"); $tmp = fgets($stream, 1024); if( $this->errorCheck($tmp, $stream) ) { return false; } /* send who the recipients are */ for( $i = 0, $cnt = count($to_list); $i < $cnt; $i++ ) { fputs($stream, "RCPT TO: <".$to_list[$i].">\r\n"); $tmp = fgets($stream, 1024); if( $this->errorCheck($tmp, $stream) ) { return false; } } /* Lets start sending the actual message */ fputs($stream, "DATA\r\n"); $tmp = fgets($stream, 1024); if( $this->errorCheck($tmp, $stream) ) { return false; } return $stream; } private function writeToStream($stream, $data) { $this->preWriteToStream($data); fputs($stream, $data); } private function finalizeStream($stream) { fputs($stream, "\r\n.\r\n"); /* end the DATA part */ $tmp = fgets($stream, 1024); $this->errorCheck($tmp, $stream); if( $this->dlv_ret_nr != 250 ) { return false; } fputs($stream, "QUIT\r\n"); /* log off */ fclose($stream); return true; } /* check if an SMTP reply is an error and set an error message) */ private function errorCheck($line, $smtpConnection) { $err_num = substr($line, 0, 3); $this->dlv_ret_nr = $err_num; $server_msg = substr($line, 4); while( substr($line, 0, 4) == ($err_num.'-') ) { $line = fgets($smtpConnection, 1024); $server_msg .= substr($line, 4); } if( ((int) $err_num{0}) < 4 ) { return false; } switch( $err_num ) { case '421': $message = _("Service not available, closing channel"); break; case '432': $message = _("A password transition is needed"); break; case '450': $message = _("Requested mail action not taken: mailbox unavailable"); break; case '451': $message = _("Requested action aborted: error in processing"); break; case '452': $message = _("Requested action not taken: insufficient system storage"); break; case '454': $message = _("Temporary authentication failure"); break; case '500': $message = _("Syntax error; command not recognized"); break; case '501': $message = _("Syntax error in parameters or arguments"); break; case '502': $message = _("Command not implemented"); break; case '503': $message = _("Bad sequence of commands"); break; case '504': $message = _("Command parameter not implemented"); break; case '530': $message = _("Authentication required"); break; case '534': $message = _("Authentication mechanism is too weak"); break; case '535': $message = _("Authentication failed"); break; case '538': $message = _("Encryption required for requested authentication mechanism"); break; case '550': $message = _("Requested action not taken: mailbox unavailable"); break; case '551': $message = _("User not local; please try forwarding"); break; case '552': $message = _("Requested mail action aborted: exceeding storage allocation"); break; case '553': $message = _("Requested action not taken: mailbox name not allowed"); break; case '554': $message = _("Transaction failed"); break; default: $message = _("Unknown response"); break; } $this->dlv_msg = $message; $this->dlv_server_msg = nl2br(htmlspecialchars($server_msg)); return true; } } ?>