nocc_webmail/webmail/classes/class_smtp.php
2023-09-05 12:44:50 +02:00

385 lines
12 KiB
PHP

<?php
/**
* Class for sending a mail with SMTP
*
* Class based on a work from Unk <rgroesb_garbage@triple-it_garbage.nl>
*
* Copyright 2001 Nicolas Chalanset <nicocha@free.fr>
* Copyright 2001 Olivier Cahagne <cahagn_o@epita.fr>
* Copyright 2008-2011 Tim Gerundt <tim@gerundt.de>
*
* This file is part of NOCC. NOCC is free software under the terms of the
* GNU General Public License. You should have received a copy of the license
* along with NOCC. If not, see <http://www.gnu.org/licenses/>.
*
* @package NOCC
* @license http://www.gnu.org/licenses/ GNU General Public License
* @version SVN: $Id: class_smtp.php 3097 2023-09-05 10:44:26Z oheil $
*/
require_once 'exception.php';
/**
* Sending a mail with SMTP
* @package NOCC
*/
class smtp {
var $smtp_server;
var $port;
var $from;
var $to;
var $cc;
var $bcc;
var $subject;
var $data;
var $pipelining;
var $pipelining_count;
/**
* Initialize the class
*/
public function __construct() {
$this->smtp_server = '';
$this->port = '';
$this->from = '';
$this->to = Array();
$this->cc = Array();
$this->bcc = Array();
$this->subject = '';
$this->data = '';
$this->pipelining = false;
$this->pipelining_count = 0;
}
public function check_response($cmd,$smtp,&$response) {
$error=false;
$response='';
if( $this->pipelining && ($cmd=="MAIL" || $cmd=="RCPT" || $cmd=="DATA") ) {
$this->pipelining_count++;
}
if( ! $this->pipelining || ($cmd!="MAIL" && $cmd!="RCPT") ) {
do {
$line=fgets($smtp, 1024);
if( $line != false ) {
if( $this->pipelining && $this->pipelining_count>0 ) {
$this->pipelining_count--;
}
if( substr($line,4,10)=="PIPELINING" ) {
$this->pipelining=true;
$this->pipelining_count=0;
}
$response=$response.$cmd.':'.trim($line)." | ";
if( $line[0]!='2' && $line[0]!='3' ) {
$error=true;
}
}
} while( $line != false && (
empty($line) || substr($line, 3, 1) == '-' || ($this->pipelining && $this->pipelining_count>0)
) );
}
return $error;
}
public function smtp_open() {
global $conf;
global $html_smtp_error_no_conn;
global $html_smtp_error_unexpected;
// $smtp = fsockopen($this->smtp_server, $this->port, $errno, $errstr);
$context = stream_context_create();
$domainnum=$_SESSION['nocc_domainnum'];
if( isset($conf->domains[$domainnum]->smtp_allow_self_signed) && $conf->domains[$domainnum]->smtp_allow_self_signed==true ) {
stream_context_set_option($context, "ssl", "allow_self_signed", $conf->domains[$domainnum]->smtp_allow_self_signed);
}
if( isset($conf->domains[$domainnum]->smtp_verify_peer) && $conf->domains[$domainnum]->smtp_verify_peer==false ) {
stream_context_set_option($context, "ssl", "verify_peer", $conf->domains[$domainnum]->smtp_verify_peer);
}
if( isset($conf->domains[$domainnum]->smtp_verify_peer_name) && $conf->domains[$domainnum]->smtp_verify_peer_name==false ) {
stream_context_set_option($context, "ssl", "verify_peer_name", $conf->domains[$domainnum]->smtp_verify_peer_name);
}
if( isset($conf->domains[$domainnum]->smtp_peer_name) && $conf->domains[$domainnum]->smtp_peer_name!="" ) {
stream_context_set_option($context, "ssl", "peer_name", $conf->domains[$domainnum]->smtp_peer_name);
}
if( isset($conf->domains[$domainnum]->smtp_security_level) && $conf->domains[$domainnum]->smtp_security_level>=0 ) {
stream_context_set_option($context, "ssl", "security_level", $conf->domains[$domainnum]->smtp_security_level);
}
$remote_socket=$this->smtp_server.":".$this->port;
$smtp=stream_socket_client($remote_socket,$errno,$errstr,ini_get("default_socket_timeout"),STREAM_CLIENT_CONNECT,$context);
if (!$smtp)
return new NoccException($html_smtp_error_no_conn . ' : ' . $errstr);
$response="";
if( $this->check_response("OPEN",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return $smtp;
}
public function smtp_helo($smtp) {
global $html_smtp_error_unexpected;
fputs($smtp, "helo " . $_SERVER['SERVER_NAME'] . "\r\n");
$response="";
if( $this->check_response("HELO",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return (true);
}
public function smtp_ehlo($smtp) {
global $html_smtp_error_unexpected;
fputs($smtp, "ehlo " . $_SERVER['SERVER_NAME'] . "\r\n");
$response="";
if( $this->check_response("EHLO",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return true;
}
public function smtp_auth($smtp) {
global $conf;
global $html_smtp_error_unexpected;
require_once './utils/crypt.php';
if( isset($_SESSION['nocc_domainnum'])
&& isset($conf->domains[$_SESSION['nocc_domainnum']]->smtp_user)
&& strlen($conf->domains[$_SESSION['nocc_domainnum']]->smtp_user)>0
) {
$user=$conf->domains[$_SESSION['nocc_domainnum']]->smtp_user;
$password=$conf->domains[$_SESSION['nocc_domainnum']]->smtp_password;
}
else {
$user=$_SESSION['nocc_login'];
$password=decpass($_SESSION['nocc_passwd'],$conf->master_key);
}
if( isset($conf->domains[$_SESSION['nocc_domainnum']]->smtp_user_without_domain)
&& $conf->domains[$_SESSION['nocc_domainnum']]->smtp_user_without_domain==true
) {
$domain_char='@';
if( isset($conf->domains[$_SESSION['nocc_domainnum']]->login_with_domain_character)
&& strlen($conf->domains[$_SESSION['nocc_domainnum']]->login_with_domain_character)>0
) {
$domain_char=$conf->domains[$_SESSION['nocc_domainnum']]->login_with_domain_character;
}
$user=preg_replace("/".$domain_char.".*?$/","",$user);
}
switch ($_SESSION['smtp_auth']) {
case 'LOGIN':
fputs($smtp, "auth login\r\n");
$response="";
if( $this->check_response("LOGIN",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, base64_encode($user) . "\r\n");
$response="";
if( $this->check_response("LOGIN USER",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, base64_encode($password) . "\r\n");
$response="";
if( $this->check_response("LOGIN PASS",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return (true);
break;
case 'NTLM':
fputs($smtp, "helo " . $_SERVER['SERVER_NAME'] . "\r\n");
$response="";
if( $this->check_response("STARTTLS HELO",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, "AUTH NTLM\r\n");
$response="";
if( $this->check_response("STARTTLS AUTH NTLM",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
$message=NTLM_type1message();
fputs($smtp, base64_encode($message)."\r\n");
$response="";
if( $this->check_response("NTLMSSP",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
$matches=array();
if( preg_match("/^NTLMSSP:334\s+(.*)\s+|$/",$response,$matches) ) {
$response=$matches[1];
}
$response=base64_decode($response);
$message=NTLM_type3message($response,"","",$user, $password);
fputs($smtp, base64_encode($message)."\r\n");
$response="";
if( $this->check_response("NTLMSSP",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return(true);
break;
case 'TLS':
fputs($smtp, "STARTTLS\r\n");
$response="";
if( $this->check_response("STARTTLS",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
//stream_socket_enable_crypto( $smtp,true,STREAM_CRYPTO_METHOD_SSLv23_CLIENT);
stream_socket_enable_crypto( $smtp,true,STREAM_CRYPTO_METHOD_TLS_CLIENT);
fputs($smtp, "helo " . $_SERVER['SERVER_NAME'] . "\r\n");
$response="";
if( $this->check_response("STARTTLS HELO",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, "auth login\r\n");
$response="";
if( $this->check_response("STARTTLS LOGIN",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, base64_encode($user) . "\r\n");
$response="";
if( $this->check_response("STARTTLS LOGIN USER",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, base64_encode($password) . "\r\n");
$response="";
if( $this->check_response("STARTTLS LOGIN PASS",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return (true);
break;
case 'PLAIN':
fputs($smtp, "auth plain " . base64_encode($user . chr(0) . $user . chr(0) . $password) . "\r\n");
$response="";
if( $this->check_response("PLAIN",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return (true);
break;
case '':
break;
}
return true;
}
public function smtp_mail_from($smtp) {
global $html_smtp_error_unexpected;
fputs($smtp, "MAIL FROM:$this->from\r\n");
$response="";
if( $this->check_response("MAIL",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return true;
}
public function smtp_rcpt_to($smtp) {
global $html_smtp_error_unexpected;
// Modified by nicocha to use to, cc and bcc field
while ($tmp = array_shift($this->to)) {
if($tmp == '' || $tmp == '<>')
continue;
fputs($smtp, "RCPT TO:$tmp\r\n");
$response="";
if( $this->check_response("RCPT",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
}
while ($tmp = array_shift($this->cc)) {
if($tmp == '' || $tmp == '<>')
continue;
fputs($smtp, "RCPT TO:$tmp\r\n");
$response="";
if( $this->check_response("RCPT",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
}
while ($tmp = array_shift($this->bcc)) {
if($tmp == '' || $tmp == '<>')
continue;
fputs($smtp, "RCPT TO:$tmp\r\n");
$response="";
if( $this->check_response("RCPT",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
}
return true;
}
public function smtp_data($smtp) {
global $html_smtp_error_unexpected;
fputs($smtp, "DATA\r\n");
$response="";
if( $this->check_response("DATA",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
fputs($smtp, "$this->data");
fputs($smtp, "\r\n.\r\n");
$response="";
if( $this->check_response("RCVD DATA",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return true;
}
public function smtp_quit($smtp) {
global $html_smtp_error_unexpected;
fputs($smtp, "QUIT\r\n");
$response="";
if( $this->check_response("QUIT",$smtp,$response) ) {
return new NoccException($html_smtp_error_unexpected . ' : ' . $response);
}
return true;
}
public function send() {
$smtp = $this->smtp_open();
if(NoccException::isException($smtp))
return $smtp;
unset ($ev);
$ev = $this->smtp_ehlo($smtp);
if(NoccException::isException($ev))
return $ev;
unset ($ev);
$ev = $this->smtp_auth($smtp);
if(NoccException::isException($ev))
return $ev;
unset ($ev);
$ev = $this->smtp_mail_from($smtp);
if(NoccException::isException($ev))
return $ev;
unset ($ev);
$ev = $this->smtp_rcpt_to($smtp);
if(NoccException::isException($ev))
return $ev;
unset ($ev);
$ev = $this->smtp_data($smtp);
if(NoccException::isException($ev))
return $ev;
unset ($ev);
$ev = $this->smtp_quit($smtp);
if(NoccException::isException($ev))
return $ev;
}
}