<?php
// MIME functions written by other people (see comments)
/*
by Bill Adams <hide@address.com>
Notes from Dan Potter:
Sure. I changed a few other things in here too though. One is that I let
you specify what the destination filename is (i.e., what is shows up as in
the attachment). This is useful since in a web submission you often can't
tell what the filename was supposed to be from the submission itself. I
also added my own version of chunk_split because our production version of
PHP doesn't have it. You can change that back or whatever though =).
Finally, I added an extra "\n" before the message text gets added into the
MIME output because otherwise the message text wasn't showing up.
note: someone mentioned a command-line utility called 'mutt' that
can mail attachments.
If chunk_split does not work on your system, change the call to chunk_split
to my_chunk_split
Note: if you don't have base64_encode on your sytem it will not work
CHANGES by Jordan <hide@address.com>:
Sent Messages can be saved in an IMAP folder.
CHANGES by Bernard Piller:
I changed the handling of extra headers to make the function work better with
PHPwebmail.
Mirko Holler <hide@address.com> added the following:
I would like to tell you about a change I made in the code. I have a private Linux Server which uses another host to relay mail to. I am only allowed to do so, if the right sender address is specified in the header of the mail.
When I used the code as it comes with the package, and send a mail, my local mail queue looks like:
Mail Queue (1 request)
--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------
XAA14709 276 Fri Jan 3 23:54 wwwrun
hide@address.com
As you can see, the sender name is wwwrun, the user of my webserver. In the mail client, the from address still would look like hide@address.com, as specified in phpwebmail.
When adding wwwrun as a trusted user to sendmail, wwwrun will be allowed to send mail using a different user name. To make phpwebmail do so, I changed in mime.php line 88 from
if(mail($this->addr_to,$this->subject,$message,$headers))
to
if(mail($this->addr_to,$this->subject,$message,$headers, "-f".$from))
Which will have the following result, when sending a mail: Here is the mail queue:
Mail Queue (1 request)
--Q-ID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------
XAA14709 276 Fri Jan 3 23:54 mirko <hide@address.com>
hide@address.com
Now the sender name is correct and my relay server will accept my message.
Maybe this is an interesting point for other users, too?!
*/
// simple class that encapsulates mail() with addition of mime file attachment.
class CMailFile {
var $subject;
var $addr_to;
var $text_body;
var $text_encoded;
var $mime_headers;
var $mime_boundary = "--==================_846811060==_";
var $smtp_headers;
function CMailFile($subject,$to,$extra_headers,$msg,$the_file,$mimetype = "application/octet-stream", $mime_filename = false) {
$this->subject = $subject;
$this->addr_to = $to;
$this->smtp_headers = $extra_headers;
if ($the_file != "nope") {
$this->text_body = $this->write_body($msg);
$this->text_encoded = $this->attach_file($the_file,$mimetype,$mime_filename);
$this->mime_headers = $this->write_mimeheaders($the_file, $mime_filename);
} else $this->text_body = $msg;
}
function attach_file($the_file,$mimetype,$mime_filename) {
$encoded = $this->encode_file($the_file);
if ($mime_filename) $the_file = $mime_filename;
$out = "--" . $this->mime_boundary . "\n";
$out = $out . "Content-type: " . $mimetype . "; name=\"$the_file\";\n";
$out = $out . "Content-Transfer-Encoding: base64\n";
$out = $out . "Content-disposition: attachment; filename=\"$the_file\"\n\n";
$out = $out . $encoded . "\n";
$out = $out . "--" . $this->mime_boundary . "--" . "\n";
return $out;
// added -- to notify email client attachment is done
}
function encode_file($sourcefile) {
if (is_readable($sourcefile)) {
$fd = fopen($sourcefile, "r");
$contents = fread($fd, filesize($sourcefile));
$encoded = chunk_split(base64_encode($contents));
fclose($fd);
}
return $encoded;
}
function sendfile() {
global $imap_server;
global $name;
global $passwd;
global $from;
global $subject;
global $to;
global $sql_user, $sql_pw;
$headers = $this->smtp_headers . $this->mime_headers;
$message = $this->text_body . $this->text_encoded;
if(mail($this->addr_to,$this->subject,$message,$headers, "-f".$from))
{
if ($db_link = mysql_connect($sql_host,$sql_user,$sql_pw)) {
@mysql_select_db("phpwebmail");
$sql_query = "SELECT sent, folder FROM prefs WHERE user='$name'";
$result = mysql_query($sql_query);
// catch SQL errors
if (mysql_errno()) echo ("ERROR ".mysql_error());
$row = mysql_fetch_row($result);
$usersent = $row[0];
$folder_pre = $row[1];
if ($folder_pre && substr($folder_pre,-1)!="/") $folder_pre .= "/";
mysql_close($db_link);
} // if db_link ends
if ($usersent == "imap") {
$streammbox = imap_open("{".$imap_server.":143}".$folder_pre."Sent",$name,$passwd);
imap_append($streammbox,"{".$imap_server.":143}".$folder_pre."Sent",
"Date: " . date("D , d M Y H:i:s ") . (date("Z")/60) . "\r\n"
."Subject: " . $subject . "\r\n"
."To: " . $to . "\r\n"
.$headers."\r\n"
.$message . "\r\n"
);
// CHANGES BY MIRKO HOLLER (marks sent messages "seen")
$check = imap_check($streammbox);
$checknr = $check->Nmsgs;
imap_setflag_full ($streammbox, $checknr, "\\Seen");
imap_close($streammbox);
} // if usersent ends
} // if mail ends
}
function write_body($msgtext) {
$out = "--" . $this->mime_boundary . "\n";
$out = $out . "Content-Type: text/plain; charset=\"us-ascii\"\n\n";
$out = $out . $msgtext . "\n";
return $out;
}
function write_mimeheaders($the_file, $mime_filename) {
if ($mime_filename) $the_file = $mime_filename;
$out = "MIME-version: 1.0\n";
$out = $out . "Content-type: multipart/mixed; ";
$out = $out . "boundary=\"$this->mime_boundary\"\n";
$out = $out . "Content-transfer-encoding: 7BIT\n";
$out = $out . "X-attachments: $the_file;\n\n";
return $out;
}
}
// usage - mimetype example "image/gif"
// $mailfile = new CMailFile($subject,$to,$extra_headers,$body,$the_file,$mimetype);
// $mailfile->sendfile();
// Splits a string by RFC2045 semantics (76 chars per line, end with \r\n).
// This is not in all PHP versions so I define one here manuall.
function my_chunk_split($str)
{
$stmp = $str;
$len = strlen($stmp);
$out = "";
while ($len > 0) {
if ($len >= 76) {
$out = $out . substr($stmp, 0, 76) . "\r\n";
$stmp = substr($stmp, 76);
$len = $len - 76;
}
else {
$out = $out . $stmp . "\r\n";
$stmp = ""; $len = 0;
}
}
return $out;
}
/* mime and 8bit decoding and encoding functions for php */
/* by Chuck Hagenbuch <hide@address.com> */
function eightbit ($string) {
if (is_string($string)) {
for ($i = 0; $i < strlen($string); $i++) {
if (ord($string[$i])>>7)
return true;
}
return false;
}
return false;
} // eightbit()
function encode_mime_string ($text, $charset) {
if (eightbit($text)) {
if (((strlen($text) * 3) + strlen($charset) + 7) > 76) {
$text = encode_mime_string(substr($text, 0, (23 -
strlen($charset))), $charset) . "\r\n\t" .
encode_mime_string(substr($text, (23 - strlen($charset))), $charset);
} else {
$text = "=?$charset?Q?" . strtr(trim(imap_8bit($text)), ' ', '_') . '?=';
}
}
return $text;
} // encode_mime_string()
function encode_mime_address ($text, $charset, $defserver) {
$addr_arr = imap_rfc822_parse_adrlist($text, $defserver);
$text = '';
if (is_array($addr_arr) && count($addr_arr) > 0) {
while (list(,$addr) = each($addr_arr)) {
if (empty($addr->personal)) $personal = '';
else $personal = encode_mime_string($addr->personal, $charset);
if (strlen($text) != 0) $text .= ', ';
$text .= imap_rfc822_write_address($addr->mailbox, $addr->host, $personal);
}
}
return $text;
} // encode_mime_address()
/* Function to decode a MIME-encoded string, returns the original string, if not MIME */
function decode_mime_string ($string) {
$pos = strpos($string, '=?');
if (!is_int($pos)) {
return $string;
}
$preceding = substr($string, 0, $pos); // save any preceding text
$search = substr($string, $pos+2, 75); /* the mime header spec says this is the longest a single encoded word can be */
$d1 = strpos($search, '?');
if (!is_int($d1)) {
return $string;
}
$charset = substr($string, $pos+2, $d1);
$search = substr($search, $d1+1);
$d2 = strpos($search, '?');
if (!is_int($d2)) {
return $string;
}
$encoding = substr($search, 0, $d2);
$search = substr($search, $d2+1);
$end = strpos($search, '?=');
if (!is_int($end)) {
return $string;
}
$encoded_text = substr($search, 0, $end);
$rest = substr($string, (strlen($preceding . $charset . $encoding . $encoded_text)+6));
switch ($encoding) {
case 'Q':
case 'q':
$encoded_text = str_replace('_', '%20', $encoded_text);
$encoded_text = str_replace('=', '%', $encoded_text);
$decoded = urldecode($encoded_text);
if (strtolower($charset) == 'windows-1251') {
$decoded = convert_cyr_string($decoded, 'w', 'k');
}
break;
case 'B':
case 'b':
$decoded = urldecode(base64_decode($encoded_text));
if (strtolower($charset) == 'windows-1251') {
$decoded = convert_cyr_string($decoded, 'w', 'k');
}
break;
default:
$decoded = '=?' . $charset . '?' . $encoding . '?' . $encoded_text . '?=';
break;
}
return $preceding . $decoded . decode_mime_string($rest);
} // decode_mime_string()
?>