*
* SMTP delivery backend for the Deliver class.
*
- * @copyright © 1999-2006 The SquirrelMail Project Team
+ * @copyright 1999-2020 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
}
}
- function initStream($message, $domain, $length=0, $host='', $port='', $user='', $pass='', $authpop=false) {
+ function initStream($message, $domain, $length=0, $host='', $port='', $user='', $pass='', $authpop=false, $pop_host='', $stream_options=array()) {
global $use_smtp_tls,$smtp_auth_mech;
if ($authpop) {
- $this->authPop($host, '', $user, $pass);
+ $this->authPop($pop_host, '', $user, $pass);
}
$rfc822_header = $message->rfc822_header;
$from->mailbox = '';
}
+ // NB: Using "ssl://" ensures the highest possible TLS version
+ // will be negotiated with the server (whereas "tls://" only
+ // uses TLS version 1.0)
+ //
if ($use_smtp_tls == 1) {
if ((check_php_version(4,3)) && (extension_loaded('openssl'))) {
- $stream = @fsockopen('tls://' . $host, $port, $errorNumber, $errorString);
+ if (function_exists('stream_socket_client')) {
+ $server_address = 'ssl://' . $host . ':' . $port;
+ $ssl_context = @stream_context_create($stream_options);
+ $connect_timeout = ini_get('default_socket_timeout');
+ // null timeout is broken
+ if ($connect_timeout == 0)
+ $connect_timeout = 30;
+ $stream = @stream_socket_client($server_address, $errorNumber, $errorString, $connect_timeout, STREAM_CLIENT_CONNECT, $ssl_context);
+ } else {
+ $stream = @fsockopen('ssl://' . $host, $port, $errorNumber, $errorString);
+ }
$this->tls_enabled = true;
} else {
/**
$helohost = $domain;
}
+ // if the host is an IPv4 address, enclose it in brackets
+ //
+ if (preg_match('/^\d+\.\d+\.\d+\.\d+$/', $helohost))
+ $helohost = '[' . $helohost . ']';
+
+ $hook_result = do_hook('smtp_helo_override', $helohost);
+ if (!empty($hook_result)) $helohost = $hook_result;
+
/* Lets introduce ourselves */
fputs($stream, "EHLO $helohost\r\n");
// Read ehlo response
}
// FIXME: check ehlo response before using authentication
- if (( $smtp_auth_mech == 'cram-md5') or ( $smtp_auth_mech == 'digest-md5' )) {
+
+ // Try authentication by a plugin
+ //
+ // NOTE: there is another hook in functions/auth.php called "smtp_auth"
+ // that allows a plugin to specify a different set of login credentials
+ // (so is slightly mis-named, but is too old to change), so be careful
+ // that you do not confuse your hook names.
+ //
+ $smtp_auth_args = array(
+ 'auth_mech' => $smtp_auth_mech,
+ 'user' => $user,
+ 'pass' => $pass,
+ 'host' => $host,
+ 'port' => $port,
+ 'stream' => $stream,
+ );
+ if (boolean_hook_function('smtp_authenticate', $smtp_auth_args, 1)) {
+ // authentication succeeded
+ } else if (( $smtp_auth_mech == 'cram-md5') or ( $smtp_auth_mech == 'digest-md5' )) {
// Doing some form of non-plain auth
if ($smtp_auth_mech == 'cram-md5') {
fputs($stream, "AUTH CRAM-MD5\r\n");
}
/* Ok, who is sending the message? */
- $fromaddress = ($from->mailbox && $from->host) ?
+ $fromaddress = (strlen($from->mailbox) && $from->host) ?
$from->mailbox.'@'.$from->host : '';
fputs($stream, 'MAIL FROM:<'.$fromaddress.">\r\n");
$tmp = fgets($stream, 1024);
/* send who the recipients are */
for ($i = 0, $cnt = count($to); $i < $cnt; $i++) {
if (!$to[$i]->host) $to[$i]->host = $domain;
- if ($to[$i]->mailbox) {
+ if (strlen($to[$i]->mailbox)) {
fputs($stream, 'RCPT TO:<'.$to[$i]->mailbox.'@'.$to[$i]->host.">\r\n");
$tmp = fgets($stream, 1024);
if ($this->errorCheck($tmp, $stream)) {
for ($i = 0, $cnt = count($cc); $i < $cnt; $i++) {
if (!$cc[$i]->host) $cc[$i]->host = $domain;
- if ($cc[$i]->mailbox) {
+ if (strlen($cc[$i]->mailbox)) {
fputs($stream, 'RCPT TO:<'.$cc[$i]->mailbox.'@'.$cc[$i]->host.">\r\n");
$tmp = fgets($stream, 1024);
if ($this->errorCheck($tmp, $stream)) {
for ($i = 0, $cnt = count($bcc); $i < $cnt; $i++) {
if (!$bcc[$i]->host) $bcc[$i]->host = $domain;
- if ($bcc[$i]->mailbox) {
+ if (strlen($bcc[$i]->mailbox)) {
fputs($stream, 'RCPT TO:<'.$bcc[$i]->mailbox.'@'.$bcc[$i]->host.">\r\n");
$tmp = fgets($stream, 1024);
if ($this->errorCheck($tmp, $stream)) {
if (!$pop_server) {
$pop_server = 'localhost';
}
- $popConnection = fsockopen($pop_server, $pop_port, $err_no, $err_str);
+ $popConnection = @fsockopen($pop_server, $pop_port, $err_no, $err_str);
if (!$popConnection) {
error_log("Error connecting to POP Server ($pop_server:$pop_port)"
. " $err_no : $err_str");
+ return false;
} else {
$tmp = fgets($popConnection, 1024); /* banner */
if (substr($tmp, 0, 3) != '+OK') {
- return(0);
+ return false;
}
fputs($popConnection, "USER $user\r\n");
$tmp = fgets($popConnection, 1024);
if (substr($tmp, 0, 3) != '+OK') {
- return(0);
+ return false;
}
fputs($popConnection, 'PASS ' . $pass . "\r\n");
$tmp = fgets($popConnection, 1024);
if (substr($tmp, 0, 3) != '+OK') {
- return(0);
+ return false;
}
fputs($popConnection, "QUIT\r\n"); /* log off */
fclose($popConnection);
}
+ return true;
}
/**