*/ require_once ('net.const.php'); /** * @version 0.0.2.2 * @access public * @todo split messages, attachments */ class smtp { /** * lagnut-smtp version, send in the headers * * @var string * @access private */ var $_version = '0.0.2.2'; /** * Turn debugon / off * * @var bool * @access private */ var $_debug = false; /** * Serverconnection resource * * @var resource * @access private */ var $_connection = null; /** * E-mailheaders * * @var array headers * @access private */ var $_hdrs = array(); /** * E-mailbody * * @var string * @access private */ var $_body = ''; /** * Default Content type * * @var string * @access private */ var $_mime = 'text/html'; /** * Default Charset * * @var string * @access private */ var $_charset = 'UTF-8'; /** * Default Transfer-Content-Encoding * * @var string * @access private */ var $_CTEncoding = 'base64'; // These are actually not necessary, but for the shitty eYou email system /** * Charset for Special Case * * @var string * @access private */ var $_charset_eYou = 'GBK'; /** * Charset for Special Case * * @var string * @access private */ var $_specialcase = 'eYou'; /** * Class contruction, sets client headers * * @access public */ function smtp($charset = 'UTF-8', $specialcase = "") { $this->_specialcase = $specialcase; $this->_charset = $charset; $this->_add_hdr('X-Mailer', sprintf('LAGNUT-SMTP/%s', $this->_version)); $this->_add_hdr('User-Agent', sprintf('LAGNUT-SMTP/%s', $this->_version)); $this->_add_hdr('MIME-Version', '1.0'); } /** * Turn debugging on/off * * @access public * @param bool $debug command */ function debug($debug) { $this->_debug = (bool)$debug; } /** * Clean input to prevent injection * * @param string $input User data */ function _clean(&$input) { if (!is_string($input)) { return false; } $input = urldecode($input); $input = str_replace("\n", '', str_replace("\r", '', $input)); } /** * Send command to server * * @access private * @param string $cmdcommand * @param optional $data data */ function _cmd($cmd, $data = false) { $this->_clean($cmd); $this->_clean($data); if ($this->_is_closed()) { return false; } if (!$data) { $command = sprintf("%s\r\n", $cmd); }else { $command = sprintf("%s: %s\r\n", $cmd,$data); } fwrite($this->_connection, $command); $resp = $this->_read(); if ($this->_debug){ printf($command); printf($resp); } if ($this->_is_closed($resp)) { return false; } return $resp; } /** * Collects header * * @access private * @param string$key * @param string $data */ function _add_hdr($key, $data) { $this->_clean($key); $this->_clean($data); $this->_hdrs[$key] = sprintf("%s: %s\r\n", $key, $data); } /** * Read server output * * @access private * @return string */ function _read() { if ($this->_is_closed()) { return false; } $o = ''; do { $str = @fgets($this->_connection, 515); if (!$str) { break; } $o .= $str; if (substr($str, 3, 1) == ' ') { break; } } while (true); return $o; } /** * Checks if server denies more commands * * @access private * @param $int * @return bool true if connection is closed */ function _is_closed($response = false) { if (!$this->_connection) { return true; } if (isset($response{0}) && ($response{0} == 4|| $response{0}== 5)) { $this->close(); return true; } return false; } /** * Open connection to server * * @access public * @param string $server SMTP server * @param int $port Server port */ function open($server, $port = 25) { $this->_connection = fsockopen($server, $port, $e, $er, 8); if ($this->_is_closed()) { return false; } $init= $this->_read(); if ($this->_debug){ printf($init); } if ($this->_is_closed($init)) { return false; } $lhost = (isset($_SERVER['SERVER_ADDR']) ? $_SERVER['SERVER_ADDR'] : '127.0.0.1'); if (strpos($init,'ESMTP') === false){ $this->_cmd('HELO '. gethostbyaddr($lhost)); } else { $this->_cmd('EHLO '. gethostbyaddr($lhost)); } } /** * Start TLS communication * * @access public */ function start_tls() { if (!function_exists('stream_socket_enable_crypto')) { trigger_error('TLS is not supported', E_USER_ERROR); return false; } $this->_cmd('STARTTLS'); stream_socket_enable_crypto($this->_connection, true, STREAM_CRYPTO_METHOD_TLS_CLIENT); } /** * Performs SMTP authentication * * @access public * @param string $username username * @param string $password password * @param int authentication mecanism */ function auth($username, $password, $type = LOGIN) { include_once ('sasl.lib.php'); $sasl =& new sasl($sasl, $username, $password); switch ($type) { case PLAIN: $this->_cmd('AUTH PLAIN'); $this->_cmd($sasl->plain($username, $password)); break; case LOGIN: $this->_cmd('AUTH LOGIN'); $this->_cmd($sasl->login($username)); $this->_cmd($sasl->login($password)); break; case CRAM_MD5: $resp = explode(' ', $this->_cmd('AUTH CRAM-MD5')); $this->_cmd($sasl->cram_md5($username, $password, trim($resp[1]))); break; } } /** * Closes connection to the server * * @access public */ function close() { if ($this->_is_closed()) { return false; } $this->_cmd('RSET'); $this->_cmd('QUIT'); fclose($this->_connection); $this->_connection = null; } /** * E-mail sender * * @access public * @param string $from Sender */ function from($email, $name = '') { $from = !empty($name) ? sprintf('%s <%s>', $name, $email) : $email; $this->_cmd('MAIL FROM', sprintf('<%s>', $email)); $this->_add_hdr('FROM', $from); $this->_add_hdr('Return-path', $email); } /** * Set BCC header * * @access public * @param string $tolist recipients whose email address should be concealed */ function bcc($tolist) { $this->_add_hdr('Bcc', $tolist); } /** * Send reply-to header * * @param string $to */ function reply_to($email, $name = '') { $to = !empty($name) ? sprintf('%s <%s>', $name, $email) : $email; $this->_add_hdr('REPLY-TO', $to); } /** * E-mail reciever * * @access public * @param string $to Reciever */ function to($email, $name = '') { $to = !empty($name) ? sprintf('%s <%s>', $name, $email) : $email; $this->_cmd('RCPT TO', sprintf('<%s>', $email)); $this->_add_hdr('TO', $to); } /** * Multiple E-mail reciever * * @access public * @param string $email Reciever, with out other recepients info disclosed */ function multi_to($email) { $this->_cmd('RCPT TO', sprintf('<%s>', $email)); } /** * E-mail reciever * * @access public * @param string $email TO head on mass mailing */ function multi_to_head($to) { $this->_add_hdr('TO', $to); } /** * MIME type * * @access public * @param string $mime MIME type */ function mime_charset($mime = 'text/html',$charset = 'UTF-8') { $this->_charset = $charset; $this->_mime = $mime; $this->_add_hdr('Content-type', sprintf('%s; charset=%s', $this->_mime, $this->_charset)); } /** * MIME Content-Transfer-Encoding * * @access public * @param string $mime MIME type */ function mime_content_transfer_encoding($CTEncoding = 'base64') { $this->_CTEncoding = $CTEncoding; $this->_add_hdr('Content-Transfer-Encoding', sprintf('%s', $this->_CTEncoding)); } /** * E-mail subject * * @access public * @param string $subject subject */ function subject($subject) { $this->_clean($subject); if($this->_specialcase = "") $this->_add_hdr('SUBJECT', $this->encode_hdrs($subject)); elseif($this->_specialcase = "eYou") { $temp = $this->_charset; $this->_charset = $this->_charset_eYou; $this->_add_hdr('SUBJECT', $this->encode_hdrs($subject)); $this->_charset = $temp; } } /** * E-mail body * * @access public * @param string $body body */ function body($body) { $body = preg_replace("/([\n|\r])\.([\n|\r])/", "$1..$2", $body); if($this->_CTEncoding == 'base64') $this->_body = sprintf("\r\n%s", base64_encode($body)); } /** * Send the mail * * @access public */ function send() { $resp = $this->_cmd('DATA'); if ($this->_is_closed($resp)) { $this->close(); return false; } foreach ($this->_hdrs as $header) { fwrite($this->_connection, $header); if ($this->_debug) { printf($header); } } fwrite($this->_connection,$this->_body); fwrite($this->_connection, "\r\n.\r\n"); $resp = trim($this->_read()); if ($this->_debug){ printf("%s\r\n", $this->_body); printf("\r\n.\r\n"); printf('%s', $resp); } if ((int)$resp{0} != 2) { return false; } else { return true; } } /** * encode headers * * @access private * @param string $input * @return string */ function encode_hdrs($input) { $replacement = preg_replace('/([\x80-\xFF])/e', '"=" . strtoupper(dechex(ord("\1")))', $input); $input = str_replace($input, sprintf('=?%s?Q?%s?=', $this->_charset, $replacement), $input); return $input; } } ?>