<?php
/**
* Defines vbms_mail_message, a class that simultaneously represents a single
* e-mail message and includes functionality to send that message via PHP's
* standard mail() function, complete with a variety of MIME headers ranging
* from message priorities to attachments.<br>
* All messages contain both text and HTML versions of the message using
* multipart MIME components.<br>
* <br>
* This code and all versions and releases of the vBulletin Mail System are
* protected by United States and international copyright and intellectual
* property protection laws. Distributing or otherwise manipulating this code
* not explicitly allowed as approved by written consent of the original author
* is a felony under United States law and illegal under international law and
* can result in jailtime and criminal prosecution.<br>
* <br>
* Anyone found to be violating this agreement will face criminal charges,
* regardless of age or nationality.<br>
* <br>
* Copyright © 2003 - 2006 Arien Talabac.
*
* @package vBMS2
*/
/** */
require_once(DIR . "/includes/vbms_functions.php");
require_once(DIR . "/includes/functions.php");
require_once(DIR . "/includes/functions_wysiwyg.php");
require_once(DIR . "/includes/class_bbcode.php");
define("VBMS_CRLF", "\r\n");
define("VBMS_MAIL_CHARSET", "iso-8859-1");
define("VBMS_MAIL_MESSAGE_ENCODING", "7bit");
/**
* Represents a single e-mail message constructed by vBMS.
*
* To use this class, use all of the set methods, call apply_options(), then
* add_attachment(), then send() to send it.
*
* @author Arien Talabac
*/
class vbms_mail_message
{
/**
* Recipient.
* @var string
*/
var $to;
/**
* From username.
* @var string
*/
var $fromusername;
/**
* From alias.
* @var string
*/
var $fromalias;
/**
* BB code of the message.
* @var string
*/
var $bbcode;
/**
* HTML code of the message (set when construct_message_html() is called)
* @var string
* @see construct_message_html()
*/
var $html;
/**
* Message subject.
* @var string
*/
var $subject;
/**
* List of attachments.
* @var array
*/
var $attachments = array();
/**
* Priority of the message.
* @var integer
*/
var $xpriority = VBMS_XPRIORITY_NORMAL;
/**
* Stack of MIME message boundaries.
* @var array
*/
var $boundarystack = array();
/**
* Starts a new MIME boundary level in the format
* "vbms-multipart-delimiter-leveln-x" where n is the level (0 being the
* lowest) and x is a random 32-character hex string. Closing and reopening
* a level will generate a new random hex string.
*
* @return string the new boundary
*
* @access private
*/
function open_boundary()
{
$delim = "vbms-multipart-delimiter-level" . sizeof($this->boundarystack) . "-" . rand(10000, 99999);
array_push($this->boundarystack, $delim);
return $delim;
}
/**
* Closes the current bondary. If the boundary stack is empty, an error is
* generated.
*
* @return string the current boundary after closing the highest-level one
*
* @access private
*/
function close_boundary()
{
if (empty($this->boundarystack))
{
trigger_error("Tried to pop empty MIME multipart boundary stack", E_USER_ERROR);
}
else
{
array_pop($this->boundarystack);
return $this->get_current_boundary();
}
}
/**
* Gets the current MIME boundary delimiter or raises an error if the stack
* is empty.
*
* @return string current MIME boundary
*
* @access private
*/
function get_current_boundary()
{
if (empty($this->boundarystack))
{
trigger_error("Boundary stack is empty", E_USER_ERROR);
}
else
{
return $this->boundarystack[sizeof($this->boundarystack) - 1];
}
}
/**
* Sets the recipients of this message.
*
* @param array $to list of RFC-compliant recpients
* @return void
* @access public
*/
function set_recipients($to)
{
$this->to = $this->clean_newlines($to);
}
/**
* Sets the sender of this message.
*
* @param string $alias alias of the sending user
* @param string $username username of the sending user
*
* @return void
*
* @access public
*/
function set_from($alias, $username)
{
$this->fromalias = $this->clean_newlines($alias);
$this->fromusername = $this->clean_newlines($username);
}
/**
* Sets the subject of this message.
*
* @param string $subject subject of the message
*
* @return void
*
* @access public
*/
function set_subject($subject)
{
$this->subject = $this->clean_newlines($subject);
}
/**
* Sets the body of this message.
*
* @param string $message body of this message
*
* @return void
*
* @access public
*/
function set_message_bbcode($bbcode)
{
$this->bbcode = $bbcode;
}
/**
* Modifies the previously set message body with the given arguments.
*
* @param string $signature empty to not modify the message with a signature, otherwise
* add the signature to the end of the user's message
* @param boolean $rewritesignature true to strip
vB code from the above
* signature (<strong>deprecated; ignored as of vBMS 2.5.0
* pre-final</strong>
* @param boolean $addtrailer true to add the vBMS trailer option to the end of the
* entire message
*
* @return void
*
* @access public
*/
function apply_options($signature, $rewritesignature, $addtrailer, $addabuseleader)
{
global $vbulletin, $vbphrase;
if (!empty($signature))
{
$this->bbcode .= "{hr}$signature";
}
if ($addtrailer)
{
$this->bbcode .= "{hr}" . $vbulletin->options['vbms_messagetrailer'];
}
if ($addabuseleader)
{
$abuseemail = $vbulletin->options['vbms_abuse_address'];
if (!empty($abuseemail))
{
$contacttext = construct_phrase(
$vbphrase['abuse_leader_text_both'],
$vbulletin->options['bbtitle'],
$vbulletin->options['bburl'], $abuseemail);
}
else
{
$contacttext = construct_phrase(
$vbphrase['abuse_leader_text_link'],
$vbulletin->options['bbtitle'],
$vbulletin->options['bburl']);
}
$text = construct_phrase($vbphrase['abuse_leader_text'],
$vbulletin->options['bbtitle'],
$vbulletin->options['bburl'], $contacttext);
$this->bbcode = $text . "{hr}" . $this->bbcode;
}
}
/**
* Sets the X-Priority of this message (one of the VBMS_XPRIORITY constants).
*
* @param integer $xpriority X-Priority of the message
*
* @return void
*
* @access public
*/
function set_xpriority($xpriority)
{
$this->xpriority = intval($xpriority);
}
/**
* Adds an attachment to this message.
*
* @param string $filename name of the file being attached
* @param string $data data of that file
* @param string $mimetype MIME type of the message
*
* @return void
*
* @access public
*/
function add_attachment($filename, $data, $mimetype)
{
array_push($this->attachments, array("filename" => $filename,
"data" => $data, "mimetype" => $mimetype));
}
/**
* Strips newlines from $s.
*
* @param string $s string from which to strip newlines
*
* @return string $s with newlines stripped
*
* @access private
*/
function clean_newlines($s)
{
$s = str_replace("\n", "", $s);
$s = str_replace("\r", "", $s);
return $s;
}
/**
* Generates a pseudo-random MIME multipart delimiter for separating parts of
* a multipart MIME message.
*
* @return string a pseudo-random string delimiting parts of a multipart MIME message
*
* @access private
*/
function generate_multipart_delimiter()
{
return "vbms-multipart-delimiter" . mt_rand();
}
/**
* Creates MIME headers from a map of attributes; the keys are the attribute
* names, the values are the attribute values.
*
* @param array $headermap map of headers
* @return string MIME headers
*
* @access private
*/
function create_mime_headers(&$headermap)
{
$headers = "";
foreach ($headermap as $key => $value)
{
$headers .= "$key: $value" . VBMS_CRLF;
}
return $headers;
}
/**
* Converts BB code to plain text via strip_bbcode().
*
* @param string $bbcode BB code to convert
* @return string plain-text representation of $bbcode
*
* @access private
* @see strip_bbcode()
*/
function bbcode_to_plain_text($bbcode)
{
global $vbulletin;
return unhtmlspecialchars(strip_bbcode(str_replace("{hr}" , "\n___________________________\n", $bbcode)));
}
/**
* Creates the HTML for this message. The final code is based off the
* template VBMS_MESSAGE_SHELL.
*
* @param mixed $previewtype same as specified in vbms_api_send_message()
* @return string message's final HTML
*
* @access public
* @see vbms_api_send_message()
*/
function construct_message_html($previewtype = false)
{
global $vbulletin, $vbphrase, $stylevar;
$title = htmlspecialchars_uni($this->subject);
$ispreview = ($previewtype !== false);
if ($previewtype == "html" or !$ispreview)
{
$basehref = $vbulletin->options['bburl'] . "/";
$parser =& new vB_BbCodeParser($vbulletin, fetch_tag_list());
$html = $parser->parse($this->bbcode);
$html = str_replace("{hr}", "<hr />", $html);
$this->html = $html;
}
else if ($previewtype == "plaintext")
{
$html = nl2br(wordwrap($this->bbcode_to_plain_text($this->bbcode), 80));
}
else if ($ispreview)
{
trigger_error("Invalid preview type "" .
htmlspecialchars_uni($previewtype) . "" specified in
vbms_mail_message::construct_message_html()", E_USER_ERROR);
}
eval("\$result = \"" . fetch_template("VBMS_MESSAGE_SHELL") . "\";");
return $result;
}
/**
* Creates all the MIME headers and content for this message, including the
* text/plain, text/html, and attachment sections.
*
* @return string MIME headers and content for this message
*
* @access private
*/
function construct_mime_message()
{
global $vbphrase, $vbulletin;
$headers = "";
$delim = $this->open_boundary();
$hasattachments = (!empty($this->attachments));
// create the main message headers and the non-MIME-client warning for ancient crappy e-mail clients
$headermap = array
(
"MIME-Version" => "1.0",
"From" => "\"$this->fromalias\" <$this->fromusername" . "@" . $vbulletin->options['vbms_todomain'] . ">",
"To" => $this->to,
"Subject" => $this->subject,
"Date" => date("r", TIMENOW),
"Message-ID" => "<untracked-" . md5(rand()) . "@" . $vbulletin->options['vbms_todomain'] . ">",
"Content-Type" => "multipart/" . ($hasattachments ? "mixed" : "alternative") . "; boundary=\"$delim\"",
"Content-Transfer-Encoding" => VBMS_MAIL_MESSAGE_ENCODING,
"Organization" => $vbulletin->options['bbtitle'] . " (" . $vbulletin->options['bburl'] . ")",
"X-Mailer" => vbms_human_readable_version(false),
"X-Mailer-Info" => VBMS_URL,
"X-Priority" => $this->xpriority,
);
$abuse = $vbulletin->options['vbms_abuse_address'];
if (!empty($abuse))
{
$abuse = $this->clean_newlines($abuse);
$headermap['Abuse-Reports-To'] = $abuse;
$headermap['X-Report'] = $abuse;
$headermap['X-Report-Abuse-To'] = $abuse;
$headermap['X-Abuse-Info'] = $abuse;
$headermap['X-Complaints-To'] = $abuse;
}
$headers .= $this->create_mime_headers($headermap);
// add the crappy warning for non-MIME clients
$headers .= VBMS_CRLF . str_replace("\n", VBMS_CRLF,
wordwrap($vbphrase['multipart_mime_not_supported'])) .
VBMS_CRLF . VBMS_CRLF;
if ($hasattachments)
{
// create message section
$headers .= "--$delim" . VBMS_CRLF;
$delim = $this->open_boundary();
$contentmap = array
(
"Content-Type" => "multipart/alternative; boundary=\"$delim\"",
"Content-Transfer-Encoding" => VBMS_MAIL_MESSAGE_ENCODING
);
$headers .= $this->create_mime_headers($contentmap) . VBMS_CRLF . VBMS_CRLF;
}
// add the plain text portion
$headers .= "--$delim" . VBMS_CRLF;
$text = $this->bbcode_to_plain_text($this->bbcode);
$plaintextmap = array
(
"Content-Type" => "text/plain; charset=\"" . VBMS_MAIL_CHARSET . "\"",
"Content-Transfer-Encoding" => VBMS_MAIL_MESSAGE_ENCODING,
"Content-Disposition" => "inline"
);
$headers .= $this->create_mime_headers($plaintextmap);
$headers .= VBMS_CRLF . str_replace("\n", VBMS_CRLF, $text) . VBMS_CRLF;
// add the HTML portion
$headers .= VBMS_CRLF . "--$delim" . VBMS_CRLF;
$htmlmap = array
(
"Content-Type" => "text/html; charset=\"" . VBMS_MAIL_CHARSET . "\"",
"Content-Transfer-Encoding" => VBMS_MAIL_MESSAGE_ENCODING,
"Content-Disposition" => "inline"
);
$html = $this->construct_message_html();
$headers .= $this->create_mime_headers($htmlmap);
$headers .= VBMS_CRLF . $html . VBMS_CRLF;
// close message section
// Krofh added the conditional, this line was showing up on all attachmented emails and was fine without it
if (!$hasattachments) { $headers .= VBMS_CRLF . "--$delim--" . VBMS_CRLF; }
if ($hasattachments)
{
$delim = $this->close_boundary();
// add attachments
foreach ($this->attachments as $attachment)
{
$filename = $attachment['filename'];
$data = chunk_split(base64_encode($attachment['data']));
$type = $attachment['mimetype'];
$attachmentmap = array
(
"Content-Type" => "$type; name=\"$filename\"",
"Content-Transfer-Encoding" => "base64",
"Content-Disposition" => "attachment; filename=\"$filename\""
);
$headers .= "--$delim" . VBMS_CRLF;
$headers .= $this->create_mime_headers($attachmentmap);
$headers .= VBMS_CRLF . $data . VBMS_CRLF;
}
$headers .= "--$delim--";
}
return $headers;
}
/**
* Sends this message via PHP's mail() function immediately.
*
* @param boolean $testonly true to dump the resulting headers and content of the message
* that would have otherwise been sent, false to just send the message
*
* @return mixed boolean true on success, error specified by PHP's mail() function on
* error
*
* @access public
*/
function send($testonly = false)
{
$headers = $this->construct_mime_message() . VBMS_CRLF;
if ($testonly)
{
$headers = htmlspecialchars_uni($headers);
// uncomment below to visually represent CR/LF
$headers = str_replace("\r", "<span style=\"color: #CCCCCC\">CR</span>", $headers);
$headers = str_replace("\n", "<span style=\"color: #99CCFF\">LF</span>\n", $headers);
$headers = preg_replace("/(vbms\-multipart\-delimiter\-level)([0-9])+(\-[0-9]{5})/siU",
"<span style=\"background-color: #FFFFCC; color: green\">" .
"\\1<span style=\"color: red\">\\2</span>\\3</span>",
$headers);
$headers = preg_replace("/^([a-zA-Z-]+
/simU",
"<span style=\"background-color: #EEEEEE\"><b><i>\\1</i></b></span>", $headers);
die("<pre>$headers</pre>");
}
else
{
ob_start();
$result = mail($this->to, $this->subject, $this->html, $headers); <------------
TO JEST LINIA 556 Z BŁĘDEM
$contents = ob_get_contents();
ob_end_clean();
return ($result !== true ? $contents : true);
}
}
}
?>