2001-01-11 10:52:33 +01:00
< ? php
/************************************************************************** \
2001-01-13 11:18:50 +01:00
* phpGroupWare API - smtp mailer *
* This file written by Itzchak Rehberg < izzysoft @ qumran . org > *
* and Joseph Engo < jengo @ phpgroupware . org > *
* This module should replace php ' s mail () function . It is fully syntax *
* compatible . In addition , when an error occures , a detailed error info *
* is stored in the array $send -> err ( see ../ inc / email / global . inc . php for *
* details on this variable ) . *
* Copyright ( C ) 2000 , 2001 Itzchak Rehberg *
* -------------------------------------------------------------------------*
2001-01-16 14:52:32 +01:00
* This library is part of the phpGroupWare API *
* http :// www . phpgroupware . org / api *
* ------------------------------------------------------------------------ *
2001-01-13 11:18:50 +01:00
* This library is free software ; you can redistribute it and / or modify it *
* under the terms of the GNU Lesser General Public License as published by *
* the Free Software Foundation ; either version 2.1 of the License , *
* or any later version . *
* This library is distributed in the hope that it will be useful , but *
* WITHOUT ANY WARRANTY ; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . *
* See the GNU Lesser General Public License for more details . *
* You should have received a copy of the GNU Lesser General Public License *
* along with this library ; if not , write to the Free Software Foundation , *
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA *
2001-01-11 10:52:33 +01:00
\ **************************************************************************/
/* $Id$ */
2001-09-28 23:38:29 +02:00
class send
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
var $err = array ( 'code' , 'msg' , 'desc' );
var $to_res = array ();
function send ()
2001-05-30 21:47:13 +02:00
{
2001-09-28 23:38:29 +02:00
$this -> err [ 'code' ] = ' ' ;
$this -> err [ 'msg' ] = ' ' ;
$this -> err [ 'desc' ] = ' ' ;
2003-11-03 11:35:32 +01:00
$this -> charset = $GLOBALS [ 'phpgw' ] -> translation -> charset ();
2001-05-30 21:47:13 +02:00
}
2001-01-11 10:52:33 +01:00
2003-05-17 22:41:14 +02:00
function msg ( $service , $to , $subject , $body , $msgtype = '' , $cc = '' , $bcc = '' , $from = '' , $sender = '' , $content_type = '' , $boundary = 'Message-Boundary' )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
if ( $from == '' )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
$from = $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'fullname' ] . ' <' . $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'address' ] . '>' ;
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
if ( $sender == '' )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
$sender = $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'fullname' ] . ' <' . $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'address' ] . '>' ;
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
if ( $service == " email " )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
$now = getdate ();
$header = 'Date: ' . gmdate ( 'D, d M Y H:i:s' ) . ' +0000' . " \n " ;
$header .= 'From: ' . $from . " \n " ;
if ( $from != $sender )
{
$header .= 'Sender: ' . $sender . " \n " ;
}
$header .= 'Reply-To: ' . $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'address' ] . " \n " ;
$header .= 'To: ' . $to . " \n " ;
if ( ! empty ( $cc ))
{
$header .= 'Cc: ' . $cc . " \n " ;
}
if ( ! empty ( $bcc ))
{
$header .= 'Bcc: ' . $bcc . " \n " ;
}
if ( ! empty ( $msgtype ))
{
$header .= 'X-phpGW-Type: ' . $msgtype . " \n " ;
}
2003-11-18 22:42:16 +01:00
$header .= 'X-Mailer: eGroupWare (http://www.egroupware.org)' . " \n " ;
2001-09-28 23:38:29 +02:00
/* // moved to email/send_message.php
if ( $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'email_sig' ] && $attach_sig )
{
//$body .= "\n-----\n".$GLOBALS['phpgw_info']['user']['preferences']['email']['email_sig'];
$get_sig = $this -> sig_html_to_text ( $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'email_sig' ]);
$body .= " \n ----- \n " . $get_sig ;
}
*/
2002-09-01 17:03:19 +02:00
if ( empty ( $content_type ))
{
$content_type = 'plain' ;
}
2003-05-17 22:41:14 +02:00
if ( ereg ( $boundary , $body ))
2001-09-28 23:38:29 +02:00
{
$header .= 'Subject: ' . stripslashes ( $subject ) . " \n "
. 'MIME-Version: 1.0' . " \n "
. 'Content-Type: multipart/mixed;' . " \n "
2003-05-17 22:41:14 +02:00
. " boundary= \" $boundary\ " \n\n "
. " -- $boundary\n "
2003-11-03 11:35:32 +01:00
. 'Content-type: text/' . $content_type . '; charset="' . $this -> charset . '"' . " \n " ;
2001-09-28 23:38:29 +02:00
// if (!empty($msgtype))
// {
2002-09-01 17:03:19 +02:00
// $header .= "Content-type: text/' .$content_type . '; phpgw-type=".$msgtype."\n";
2001-09-28 23:38:29 +02:00
// }
$header .= 'Content-Disposition: inline' . " \n "
. 'Content-transfer-encoding: 7BIT' . " \n \n "
. $body ;
$body = " " ;
}
else
{
$header .= 'Subject: ' . stripslashes ( $subject ) . " \n "
. 'MIME-version: 1.0' . " \n "
2003-11-03 11:35:32 +01:00
. 'Content-type: text/' . $content_type . '; charset="' . $this -> charset . '"' . " \n " ;
2001-09-28 23:38:29 +02:00
if ( ! empty ( $msgtype ))
{
2002-09-01 17:03:19 +02:00
$header .= 'Content-type: text/' . $content_type . '; phpgw-type=' . $msgtype . " \n " ;
2001-09-28 23:38:29 +02:00
}
$header .= 'Content-Disposition: inline' . " \n "
. 'Content-description: Mail message body' . " \n " ;
}
2003-05-17 22:41:14 +02:00
if ( $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'mail_server_type' ] == 'imap' && $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'apps' ][ 'email' ] &&
$GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'use_sent_folder' ])
2001-09-28 23:38:29 +02:00
{
2002-04-12 16:21:57 +02:00
if ( ! is_object ( $GLOBALS [ 'phpgw' ] -> msg ))
{
$GLOBALS [ 'phpgw' ] -> msg = CreateObject ( 'email.mail_msg' );
}
$args_array = Array ();
$args_array [ 'do_login' ] = True ;
$args_array [ 'folder' ] = $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'sent_folder_name' ];
$GLOBALS [ 'phpgw' ] -> msg -> begin_request ( $args_array );
$GLOBALS [ 'phpgw' ] -> msg -> phpgw_append ( 'Sent' , $header . " \n " . $body , " \\ Seen " );
$GLOBALS [ 'phpgw' ] -> msg -> end_request ();
2001-09-28 23:38:29 +02:00
}
if ( strlen ( $cc ) > 1 )
{
$to .= ',' . $cc ;
}
if ( strlen ( $bcc ) > 1 )
{
$to .= ',' . $bcc ;
}
$returnccode = $this -> smail ( $to , '' , $body , $header );
return $returnccode ;
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
elseif ( $type == 'nntp' )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
// nothing is here?
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
}
// ==================================================[ some sub-functions ]===
2001-01-11 10:52:33 +01:00
2003-05-17 22:41:14 +02:00
/*!
@ function encode_subject
@ abstract encode 8 - bit chars in subject - line
@ author ralfbecker
@ note the quoted subjects get a header stateing the charset ( eg . " =?iso-8859-1?Q? " ), the \
8 - bit chars as '=XX' ( XX is the hex - representation of the char ) and a trainling '?=' .
*/
function encode_subject ( $subject )
{
2003-11-23 11:41:19 +01:00
// remove unnecessary CR's as some mail-scanners complain about them
$subject = str_replace ( " \r " , '' , $subject );
2003-05-17 22:41:14 +02:00
$enc_start = $enc_end = 0 ;
$words = explode ( ' ' , $subject );
foreach ( $words as $w => $word )
{
$str = '' ;
for ( $i = 0 ; $i < strlen ( $word ); ++ $i )
{
if (( $n = ord ( $word [ $i ])) > 127 || $word [ $i ] == '=' ) {
$str .= sprintf ( '=%0X' , $n );
if ( ! $enc_start )
{
$enc_start = $w + 1 ;
}
$enc_end = $w + 1 ;
}
else
{
$str .= $word [ $i ];
}
}
$strs [] = $str ;
//echo "word='$word', start=$enc_start, end=$enc_end, encoded='$str'<br>\n";
}
if ( ! $enc_start )
{
return $subject ;
}
$str = '' ;
foreach ( $strs as $w => $s )
{
$str .= $str != '' ? ' ' : '' ;
if ( $enc_start == $w + 1 ) // first word to encode
{
2003-11-03 11:35:32 +01:00
$str .= '=?' . $this -> charset . '?Q?' ;
2003-05-17 22:41:14 +02:00
}
$str .= $w + 1 > $enc_end ? str_replace ( '=3D' , '=' , $s ) : $s ;
if ( $enc_end == $w + 1 ) // last word to encode
{
$str .= '?=' ;
}
}
//echo "<p>send::encode_subject('$subject')='$str'</p>\n";
return $str ;
}
2001-09-28 23:38:29 +02:00
function socket2msg ( $socket )
{
$followme = '-' ;
$this -> err [ 'msg' ] = '' ;
do
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
$rmsg = fgets ( $socket , 255 );
// echo "< $rmsg<BR>\n";
$this -> err [ 'code' ] = substr ( $rmsg , 0 , 3 );
$followme = substr ( $rmsg , 3 , 1 );
$this -> err [ 'msg' ] = substr ( $rmsg , 4 );
if ( substr ( $this -> err [ " code " ], 0 , 1 ) != 2 && substr ( $this -> err [ " code " ], 0 , 1 ) != 3 )
{
$rc = fclose ( $socket );
return False ;
}
if ( $followme = ' ' )
{
break ;
}
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
while ( $followme = '-' );
return True ;
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
function msg2socket ( $socket , $message )
{
// send single line\n
// echo "raw> $message<BR>\n";
// echo "hex> ".bin2hex($message)."<BR>\n";
$rc = fputs ( $socket , " $message " );
if ( ! $rc )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
$this -> err [ 'code' ] = '420' ;
$this -> err [ 'msg' ] = 'lost connection' ;
$this -> err [ 'desc' ] = 'Lost connection to smtp server.' ;
$rc = fclose ( $socket );
return False ;
}
return True ;
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
function put2socket ( $socket , $message )
{
// check for multiple lines 1st
$pos = strpos ( $message , " \n " );
if ( ! is_int ( $pos ))
{
// no new line found
$message .= " \r \n " ;
$this -> msg2socket ( $socket , $message );
2001-03-26 00:24:19 +02:00
}
else
{
2001-09-28 23:38:29 +02:00
// multiple lines, we have to split it
do
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
$msglen = $pos + 1 ;
$msg = substr ( $message , 0 , $msglen );
$message = substr ( $message , $msglen );
$pos = strpos ( $msg , " \r \n " );
if ( ! is_int ( $pos ))
{
// line not terminated
$msg = chop ( $msg ) . " \r \n " ;
}
$pos = strpos ( $msg , '.' ); // escape leading periods
if ( is_int ( $pos ) && ! $pos )
{
$msg = '.' . $msg ;
}
if ( ! $this -> msg2socket ( $socket , $msg ))
{
return False ;
}
$pos = strpos ( $message , " \n " );
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
while ( strlen ( $message ) > 0 );
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
return True ;
}
function check_header ( $subject , $header )
{
// check if header contains subject and is correctly terminated
$header = chop ( $header );
$header .= " \n " ;
if ( is_string ( $subject ) && ! $subject )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
// no subject specified
return $header ;
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
$theader = strtolower ( $header );
$pos = strpos ( $theader , " \n subject: " );
if ( is_int ( $pos ))
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
// found after a new line
return $header ;
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
$pos = strpos ( $theader , 'subject:' );
if ( is_int ( $pos ) && ! $pos )
2001-03-26 00:24:19 +02:00
{
2001-09-28 23:38:29 +02:00
// found at start
return $header ;
2001-03-26 00:24:19 +02:00
}
2001-09-28 23:38:29 +02:00
$pos = substr ( $subject , " \n " );
if ( ! is_int ( $pos ))
{
$subject .= " \n " ;
}
$subject = 'Subject: ' . $subject ;
$header .= $subject ;
return $header ;
2001-05-30 21:47:13 +02:00
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
function sig_html_to_text ( $sig )
2001-05-30 21:47:13 +02:00
{
2001-09-28 23:38:29 +02:00
// convert HTML chars for ' and " in the email sig to normal text
$sig_clean = $sig ;
$sig_clean = ereg_replace ( '"' , '"' , $sig_clean );
$sig_clean = ereg_replace ( ''' , '\'' , $sig_clean );
return $sig_clean ;
2001-05-30 21:47:13 +02:00
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
// ==============================================[ main function: smail() ]===
2001-05-30 21:47:13 +02:00
2001-09-28 23:38:29 +02:00
function smail ( $to , $subject , $message , $header )
2001-05-30 21:47:13 +02:00
{
2001-09-28 23:38:29 +02:00
$fromuser = $GLOBALS [ 'phpgw_info' ][ 'user' ][ 'preferences' ][ 'email' ][ 'address' ];
$mymachine = $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'hostname' ];
// error code and message of failed connection
$errcode = '' ;
$errmsg = '' ;
// timeout in secs
$timeout = 5 ;
// now we try to open the socket and check, if any smtp server responds
2003-05-30 18:11:36 +02:00
$smtp_port = $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'smtp_port' ] ? $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'smtp_port' ] : 25 ;
$socket = fsockopen ( $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'smtp_server' ], $smtp_port , $errcode , $errmsg , $timeout );
2001-09-28 23:38:29 +02:00
if ( ! $socket )
2001-05-30 21:47:13 +02:00
{
2001-09-28 23:38:29 +02:00
$this -> err [ 'code' ] = '420' ;
$this -> err [ 'msg' ] = $errcode . ':' . $errmsg ;
$this -> err [ 'desc' ] = 'Connection to ' . $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'smtp_server' ] . ':' . $GLOBALS [ 'phpgw_info' ][ 'server' ][ 'smtp_port' ] . ' failed - could not open socket.' ;
return False ;
2001-05-30 21:47:13 +02:00
}
2001-09-28 23:38:29 +02:00
else
2001-05-30 21:47:13 +02:00
{
2001-09-28 23:38:29 +02:00
$rrc = $this -> socket2msg ( $socket );
2001-05-30 21:47:13 +02:00
}
2001-09-28 23:38:29 +02:00
// now we can send our message. 1st we identify ourselves and the sender
$cmds = array (
" \$ src = \$ this->msg2socket( \$ socket, \" HELO \$ mymachine \r \n \" ); " ,
" \$ rrc = \$ this->socket2msg( \$ socket); " ,
" \$ src = \$ this->msg2socket( \$ socket, \" MAIL FROM:< \$ fromuser> \r \n \" ); " ,
" \$ rrc = \$ this->socket2msg( \$ socket); "
);
for ( $src = True , $rrc = True , $i = 0 ; $i < count ( $cmds ); $i ++ )
2001-05-30 21:47:13 +02:00
{
2001-09-28 23:38:29 +02:00
eval ( $cmds [ $i ]);
if ( ! $src || ! $rrc )
{
return False ;
}
2001-05-30 21:47:13 +02:00
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
// now we've got to evaluate the $to's
$toaddr = explode ( " , " , $to );
$numaddr = count ( $toaddr );
for ( $i = 0 ; $i < $numaddr ; $i ++ )
{
$src = $this -> msg2socket ( $socket , 'RCPT TO:<' . $toaddr [ $i ] . " > \r \n " );
$rrc = $this -> socket2msg ( $socket );
// for lateron validation
$this -> to_res [ $i ][ 'addr' ] = $toaddr [ $i ];
$this -> to_res [ $i ][ 'code' ] = $this -> err [ 'code' ];
$this -> to_res [ $i ][ 'msg' ] = $this -> err [ 'msg' ];
$this -> to_res [ $i ][ 'desc' ] = $this -> err [ 'desc' ];
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
//now we have to make sure that at least one $to-address was accepted
$stop = 1 ;
for ( $i = 0 ; $i < count ( $this -> to_res ); $i ++ )
{
$rc = substr ( $this -> to_res [ $i ][ 'code' ], 0 , 1 );
if ( $rc == 2 )
{
// at least to this address we can deliver
$stop = 0 ;
}
}
if ( $stop )
{
// no address found we can deliver to
return False ;
}
2001-01-11 10:52:33 +01:00
2001-09-28 23:38:29 +02:00
// now we can go to deliver the message!
if ( ! $this -> msg2socket ( $socket , " DATA \r \n " ))
{
return False ;
}
if ( ! $this -> socket2msg ( $socket ))
{
return False ;
}
if ( $header != " " )
{
$header = $this -> check_header ( $subject , $header );
if ( ! $this -> put2socket ( $socket , $header ))
{
return False ;
}
if ( ! $this -> put2socket ( $socket , " \r \n " ))
{
return False ;
}
}
$message = chop ( $message );
$message .= " \n " ;
if ( ! $this -> put2socket ( $socket , $message ))
{
return False ;
}
if ( ! $this -> msg2socket ( $socket , " . \r \n " ))
{
return False ;
}
if ( ! $this -> socket2msg ( $socket ))
{
return False ;
}
if ( ! $this -> msg2socket ( $socket , " QUIT \r \n " ))
{
return False ;
}
do
{
$closing = $this -> socket2msg ( $socket );
}
while ( $closing );
return True ;
2001-05-30 21:47:13 +02:00
}
2003-05-17 22:41:14 +02:00
} /* end of class */