/********************************************************************************** * nWordPress is an automated migration of WordPress 2.5.1 performed by Numiton. * * copyright : (C) 2008 Numiton - www.numiton.com * email : numiton@users.sourceforge.net * * $Id: PHPMailer.java,v 1.2 2008/10/03 18:45:30 numiton Exp $ * **********************************************************************************/ /********************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * **********************************************************************************/ /*************************************************************************** * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * ***************************************************************************/ package org.numiton.nwp.wp_includes; import static com.numiton.VarHandling.*; import java.io.Serializable; import org.apache.log4j.Logger; import org.numiton.nwp.GlobalConsts; import org.numiton.nwp.GlobalVars; import com.numiton.*; import com.numiton.Math; import com.numiton.array.Array; import com.numiton.file.FileSystemOrSocket; import com.numiton.generic.*; import com.numiton.ntile.til.libraries.php.quercus.QMail; import com.numiton.ntile.til.libraries.php.quercus.QRegExPerl; import com.numiton.ntile.til.libraries.php.quercus.QStrings; import com.numiton.string.Strings; //////////////////////////////////////////////////// //PHPMailer - PHP email class // //Class for sending email using either //sendmail, PHP mail(), or SMTP. Methods are //based upon the standard AspEmail(tm) classes. // //Copyright (C) 2001 - 2003 Brent R. Matzelle // //License: LGPL, see LICENSE //////////////////////////////////////////////////// /** * PHPMailer - PHP email transport class * @package PHPMailer * @author Brent R. Matzelle * @copyright 2001 - 2003 Brent R. Matzelle */ public class PHPMailer implements ContextCarrierInterface, Serializable, Cloneable { protected static final Logger LOG = Logger.getLogger(PHPMailer.class.getName()); public GlobalConsts gConsts; public GlobalVars gVars; ///////////////////////////////////////////////// // PUBLIC VARIABLES ///////////////////////////////////////////////// /** * Email priority (1 = High, 3 = Normal, 5 = low). * @var int */ public int Priority = 3; /** * Sets the CharSet of the message. * @var string */ public String CharSet = "UTF-8"; /** * Sets the Content-type of the message. * @var string */ public String ContentType = "text/plain"; /** * Sets the Encoding of the message. Options for this are "8bit", "7bit", * "binary", "base64", and "quoted-printable". * @var string */ public String Encoding = "8bit"; /** * Holds the most recent mailer error message. * @var string */ public String ErrorInfo = ""; /** * Sets the From email address for the message. * @var string */ public String From = "localhost.localdomain"; /** * Sets the From name of the message. * @var string */ public String FromName = "Support"; /** * Sets the Sender email (Return-Path) of the message. If not empty, will * be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. * @var string */ public String Sender = ""; /** * Sets the Subject of the message. * @var string */ public String Subject = ""; /** * Sets the Body of the message. This can be either an HTML or text body. * If HTML then run IsHTML(true). * @var string */ public String Body = ""; /** * Sets the text-only body of the message. This automatically sets the * email to multipart/alternative. This body can be read by mail clients * that do not have HTML email capability such as mutt. Clients that can * read HTML will view the normal Body. * @var string */ public String AltBody = ""; /** * Sets word wrapping on the body of the message to a given number of * characters. * @var int */ public int WordWrap = 0; /** * Method to send mail: ("mail", "sendmail", or "smtp"). * @var string */ public String Mailer = "mail"; /** * Sets the path of the sendmail program. * @var string */ public String Sendmail = "/usr/sbin/sendmail"; /** * Path to PHPMailer plugins. This is now only useful if the SMTP class is * in a different directory than the PHP include path. * @var string */ public String PluginDir = ""; /** * Holds PHPMailer version. * @var string */ public String Version = "1.73"; /** * Sets the email address that a reading confirmation will be sent. * @var string */ public String ConfirmReadingTo = ""; /** * Sets the hostname to use in Message-Id and Received headers and as * default HELO string. If empty, the value returned by SERVER_NAME is used * or 'localhost.localdomain'. * @var string */ public String Hostname = ""; ///////////////////////////////////////////////// // SMTP VARIABLES ///////////////////////////////////////////////// /** * Sets the SMTP hosts. All hosts must be separated by a * semicolon. You can also specify a different port * for each host by using this format: [hostname:port] * (e.g. "smtp1.example.com:25;smtp2.example.com"). * Hosts will be tried in order. * @var string */ public String Host = "localhost"; /** * Sets the default SMTP server port. * @var int */ public int Port = 25; /** * Sets the SMTP HELO of the message (Default is $Hostname). * @var string */ public String Helo = ""; /** * Sets SMTP authentication. Utilizes the Username and Password variables. * @var bool */ public boolean SMTPAuth = false; /** * Sets SMTP username. * @var string */ public String Username = ""; /** * Sets SMTP password. * @var string */ public String Password = ""; /** * Sets the SMTP server timeout in seconds. This function will not work * with the win32 version. * @var int */ public int Timeout = 10; /** * Sets SMTP class debugging on or off. * @var bool */ public int SMTPDebug; /** * Prevents the SMTP connection from being closed after each mail sending. * If this is set to true then to close the connection requires an explicit * call to SmtpClose(). * @var bool */ public boolean SMTPKeepAlive = false; /** * #@+ * @access private */ public SMTP smtp; public Array<Object> to = new Array<Object>(); public Array<Object> cc = new Array<Object>(); public Array<Object> bcc = new Array<Object>(); public Array<Object> ReplyTo = new Array<Object>(); public Array<Object> attachment = new Array<Object>(); public Array<Object> CustomHeader = new Array<Object>(); public String message_type = ""; public Array<Object> boundary = new Array<Object>(); public Array<Object> language = new Array<Object>(); public int error_count = 0; public String LE = "\r\n"; // Added by Numiton: As requested by RFC, see http://cr.yp.to/docs/smtplf.html /**#@-*/ ///////////////////////////////////////////////// // VARIABLE METHODS ///////////////////////////////////////////////// public PHPMailer(GlobalVars javaGlobalVariables, GlobalConsts javaGlobalConstants) { setContext(javaGlobalVariables, javaGlobalConstants); } /** * Sets message type to HTML. * @param bool $bool * @return void */ public void IsHTML(boolean bool) { if (equal(bool, true)) { this.ContentType = "text/html"; } else this.ContentType = "text/plain"; } /** * Sets Mailer to send message using SMTP. * @return void */ public void IsSMTP() { this.Mailer = "smtp"; } /** * Sets Mailer to send message using PHP mail() function. * @return void */ public void IsMail() { this.Mailer = "mail"; } /** * Sets Mailer to send message using the $Sendmail program. * @return void */ public void IsSendmail() { this.Mailer = "sendmail"; } /** * Sets Mailer to send message using the qmail MTA. * @return void */ public void IsQmail() { this.Sendmail = "/var/qmail/bin/sendmail"; this.Mailer = "sendmail"; } public void AddAddress(String address) { AddAddress(address, ""); } ///////////////////////////////////////////////// // RECIPIENT METHODS ///////////////////////////////////////////////// /** * Adds a "To" address. * @param string $address * @param string $name * @return void */ public void AddAddress(String address, String name) { int cur = 0; cur = Array.count(this.to); this.to.getArrayValue(cur).putValue(0, Strings.trim(address)); this.to.getArrayValue(cur).putValue(1, name); } /** * Adds a "Cc" address. Note: this function works with the SMTP mailer on * win32, not with the "mail" mailer. * @param string $address * @param string $name * @return void */ public void AddCC(String address, String name) { int cur = 0; cur = Array.count(this.cc); this.cc.getArrayValue(cur).putValue(0, Strings.trim(address)); this.cc.getArrayValue(cur).putValue(1, name); } /** * Adds a "Bcc" address. Note: this function works with the SMTP mailer on * win32, not with the "mail" mailer. * @param string $address * @param string $name * @return void */ public void AddBCC(String address, String name) { int cur = 0; cur = Array.count(this.bcc); this.bcc.getArrayValue(cur).putValue(0, Strings.trim(address)); this.bcc.getArrayValue(cur).putValue(1, name); } /** * Adds a "Reply-to" address. * @param string $address * @param string $name * @return void */ public void AddReplyTo(String address, String name) { int cur = 0; cur = Array.count(this.ReplyTo); this.ReplyTo.getArrayValue(cur).putValue(0, Strings.trim(address)); this.ReplyTo.getArrayValue(cur).putValue(1, name); } ///////////////////////////////////////////////// // MAIL SENDING METHODS ///////////////////////////////////////////////// /** * Creates message and assigns Mailer. If the message is * not sent successfully then it returns false. Use the ErrorInfo * variable to view description of the error. * @return bool */ public boolean Send() { String header = null; String body = null; boolean result = false; header = ""; body = ""; result = true; if (Array.count(this.to) + Array.count(this.cc) + Array.count(this.bcc) < 1) { this.SetError(this.Lang("provide_address")); return false; } // Set whether the message is multipart/alternative if (!empty(this.AltBody)) { this.ContentType = "multipart/alternative"; } this.error_count = 0; // reset errors this.SetMessageType(); header = header + this.CreateHeader(); body = this.CreateBody(); if (equal(body, "")) { return false; } // Choose the mailer { int javaSwitchSelector48 = 0; if (equal(this.Mailer, "sendmail")) javaSwitchSelector48 = 1; if (equal(this.Mailer, "mail")) javaSwitchSelector48 = 2; if (equal(this.Mailer, "smtp")) javaSwitchSelector48 = 3; switch (javaSwitchSelector48) { case 1: { result = this.SendmailSend(header, body); break; } case 2: { result = this.MailSend(header, body); break; } case 3: { result = this.SmtpSend(header, body); break; } default: { this.SetError(this.Mailer + this.Lang("mailer_not_supported")); result = false; break; } } } return result; } /** * Sends mail using the $Sendmail program. * @access private * @return bool */ public boolean SendmailSend(String header, String body) { String sendmail = null; int mail = 0; int result = 0; if (!equal(this.Sender, "")) { sendmail = QStrings.sprintf("%s -oi -f %s -t", this.Sendmail, ProgramExecution.escapeshellarg(this.Sender)); } else sendmail = QStrings.sprintf("%s -oi -t", this.Sendmail); // Modified by Numiton Process process = null; int exitValue = 0; try { process = Runtime.getRuntime().exec(sendmail); process.getOutputStream().write(header.getBytes()); process.getOutputStream().write(body.getBytes()); process.getOutputStream().close(); exitValue = process.exitValue(); } catch (Exception ex) { LOG.warn(ex, ex); } if (!booleanval(process)) { this.SetError(this.Lang("execute") + this.Sendmail); return false; } result = exitValue >> 8 & 255; if (!equal(result, 0)) { this.SetError(this.Lang("execute") + this.Sendmail); return false; } return true; } /** * Sends mail using the PHP mail() function. * @access private * @return bool */ public boolean MailSend(String header, String body) { String to = null; int i = 0; String old_from = null; String params = null; boolean rt = false; to = ""; for (i = 0; i < Array.count(this.to); i++) { if (!equal(i, 0)) { to = to + ", "; } to = to + strval(this.to.getArrayValue(i).getValue(0)); } if (!equal(this.Sender, "") && Strings.strlen(Options.ini_get(gVars.webEnv, "safe_mode")) < 1) { old_from = Options.ini_get(gVars.webEnv, "sendmail_from"); Options.ini_set(gVars.webEnv, "sendmail_from", this.Sender); params = QStrings.sprintf("-oi -f %s", this.Sender); rt = QMail.mail(gVars.webEnv, to, this.EncodeHeader(this.Subject), body, header, params); } else rt = QMail.mail(gVars.webEnv, to, this.EncodeHeader(this.Subject), body, header); if (isset(old_from)) { Options.ini_set(gVars.webEnv, "sendmail_from", old_from); } if (!rt) { this.SetError(this.Lang("instantiate")); return false; } return true; } /** * Sends mail via SMTP using PhpSMTP (Author: Chris Ryan). Returns bool. * Returns false if there is a bad MAIL FROM, RCPT, or DATA input. * @access private * @return bool */ public boolean SmtpSend(String header, String body) { String error = null; Array<Object> bad_rcpt = new Array<Object>(); String smtp_from = null; int i = 0; error = ""; bad_rcpt = new Array<Object>(); if (!this.SmtpConnect()) { return false; } smtp_from = (equal(this.Sender, "") ? this.From : this.Sender); if (!this.smtp.Mail(smtp_from)) { error = this.Lang("from_failed") + smtp_from; this.SetError(error); this.smtp.Reset(); return false; } // Attempt to send attach all recipients for (i = 0; i < Array.count(this.to); i++) { if (!this.smtp.Recipient(this.to.getArrayValue(i).getValue(0))) { bad_rcpt.putValue(this.to.getArrayValue(i).getValue(0)); } } for (i = 0; i < Array.count(this.cc); i++) { if (!this.smtp.Recipient(this.cc.getArrayValue(i).getValue(0))) { bad_rcpt.putValue(this.cc.getArrayValue(i).getValue(0)); } } for (i = 0; i < Array.count(this.bcc); i++) { if (!this.smtp.Recipient(this.bcc.getArrayValue(i).getValue(0))) { bad_rcpt.putValue(this.bcc.getArrayValue(i).getValue(0)); } } if (Array.count(bad_rcpt) > 0) { // Create error message for (i = 0; i < Array.count(bad_rcpt); i++) { if (!equal(i, 0)) { error = error + ", "; } error = error + strval(bad_rcpt.getValue(i)); } error = this.Lang("recipients_failed") + error; this.SetError(error); this.smtp.Reset(); return false; } if (!this.smtp.Data(header + body)) { this.SetError(this.Lang("data_not_accepted")); this.smtp.Reset(); return false; } if (equal(this.SMTPKeepAlive, true)) { this.smtp.Reset(); } else this.SmtpClose(); return true; } /** * Generated in place of local variable 'host' from method 'SmtpConnect' * because it is used inside an inner class. */ String SmtpConnect_host = null; /** * Generated in place of local variable 'port' from method 'SmtpConnect' * because it is used inside an inner class. */ int SmtpConnect_port = 0; /** * Initiates a connection to an SMTP server. Returns false if the * operation failed. * @access private * @return bool */ public boolean SmtpConnect() { Array<String> hosts = new Array<String>(); int index = 0; boolean connection = false; if (equal(this.smtp, null)) { this.smtp = new SMTP(gVars, gConsts); } this.smtp.do_debug = this.SMTPDebug; hosts = Strings.explode(";", this.Host); index = 0; connection = this.smtp.Connected(); // Retry while there is no connection while (index < Array.count(hosts) && equal(connection, false)) { if (booleanval(Strings.strstr(hosts.getValue(index), ":"))) { new ListAssigner<String>() { public Array<String> doAssign(Array<String> srcArray) { if (strictEqual(srcArray, null)) { return null; } SmtpConnect_host = srcArray.getValue(0); SmtpConnect_port = intval(srcArray.getValue(1)); return srcArray; } }.doAssign(Strings.explode(":", hosts.getValue(index))); } else { SmtpConnect_host = hosts.getValue(index); SmtpConnect_port = this.Port; } if (this.smtp.Connect(SmtpConnect_host, SmtpConnect_port, this.Timeout)) { if (!equal(this.Helo, "")) { this.smtp.Hello(this.Helo); } else this.smtp.Hello(this.ServerHostname()); if (this.SMTPAuth) { if (!this.smtp.Authenticate(this.Username, this.Password)) { this.SetError(this.Lang("authenticate")); this.smtp.Reset(); connection = false; } } connection = true; } index++; } if (!connection) { this.SetError(this.Lang("connect_host")); } return connection; } /** * Closes the active SMTP session if one exists. * @return void */ public void SmtpClose() { if (!equal(this.smtp, null)) { if (this.smtp.Connected()) { this.smtp.Quit(); this.smtp.Close(); } } } public boolean SetLanguage(String lang_type) { return SetLanguage(lang_type, "language/"); } /** * Sets the language for all class error messages. Returns false if it * cannot load the language file. The default language type is English. * @param string $lang_type Type of language (e.g. Portuguese: "br") * @param string $lang_path Path to the language file directory * @access public * @return bool */ public boolean SetLanguage(String lang_type, String lang_path) { Object PHPMAILER_LANG = null; if (FileSystemOrSocket.file_exists(gVars.webEnv, lang_path + "phpmailer.lang-" + lang_type + ".php")) { } else // Commented by Numiton: This is never found if (FileSystemOrSocket.file_exists(gVars.webEnv, lang_path + "phpmailer.lang-en.php")) { } else // Commented by Numiton: This is never found { this.SetError("Could not load language file"); return false; } // Modified by Numiton: PHPMAILER_LANG is always empty this.language = new Array(PHPMAILER_LANG); return true; } ///////////////////////////////////////////////// // MESSAGE CREATION METHODS ///////////////////////////////////////////////// /** * Creates recipient headers. * @access private * @return string */ public String AddrAppend(String type, Array<Object> addr) { String addr_str = null; int i = 0; addr_str = type + ": "; addr_str = addr_str + this.AddrFormat(addr.getArrayValue(0)); if (Array.count(addr) > 1) { for (i = 1; i < Array.count(addr); i++) addr_str = addr_str + ", " + this.AddrFormat(addr.getArrayValue(i)); } addr_str = addr_str + this.LE; return addr_str; } /** * Formats an address correctly. * @access private * @return string */ public String AddrFormat(Array<Object> addr) { String formatted = null; if (empty(addr.getValue(1))) { formatted = strval(addr.getValue(0)); } else { formatted = this.EncodeHeader(strval(addr.getValue(1)), "phrase") + " <" + strval(addr.getValue(0)) + ">"; } return formatted; } public String WrapText(String message, int length) { return WrapText(message, length, false); } /** * Wraps message for use with mailers that do not automatically perform * wrapping and for quoted-printable. Original written by philippe. * @access private * @return string */ public String WrapText(String message, int length, boolean qp_mode) { String soft_break = null; Array<String> line = new Array<String>(); Array<String> line_part = new Array<String>(); int i = 0; String buf = null; String word = null; int e = 0; int space_left = 0; int len = 0; String part = null; String buf_o = null; soft_break = (qp_mode ? QStrings.sprintf(" =%s", this.LE) : this.LE); message = this.FixEOL(message); if (equal(Strings.substr(message, -1), this.LE)) { message = Strings.substr(message, 0, -1); } line = Strings.explode(this.LE, message); message = ""; for (i = 0; i < Array.count(line); i++) { line_part = Strings.explode(" ", line.getValue(i)); buf = ""; for (e = 0; e < Array.count(line_part); e++) { word = line_part.getValue(e); if (qp_mode && Strings.strlen(word) > length) { space_left = length - Strings.strlen(buf) - 1; if (!equal(e, 0)) { if (space_left > 20) { len = space_left; if (equal(Strings.substr(word, len - 1, 1), "=")) { len--; } else if (equal(Strings.substr(word, len - 2, 1), "=")) { len = len - 2; } part = Strings.substr(word, 0, len); word = Strings.substr(word, len); buf = buf + " " + part; message = message + buf + QStrings.sprintf("=%s", this.LE); } else { message = message + buf + soft_break; } buf = ""; } while (Strings.strlen(word) > 0) { len = length; if (equal(Strings.substr(word, len - 1, 1), "=")) { len--; } else if (equal(Strings.substr(word, len - 2, 1), "=")) { len = len - 2; } part = Strings.substr(word, 0, len); word = Strings.substr(word, len); if (Strings.strlen(word) > 0) { message = message + part + QStrings.sprintf("=%s", this.LE); } else buf = part; } } else { buf_o = buf; buf = buf + (equal(e, 0) ? word : (" " + word)); if (Strings.strlen(buf) > length && !equal(buf_o, "")) { message = message + buf_o + soft_break; buf = word; } } } message = message + buf + this.LE; } return message; } /** * Set the body wrapping. * @access private * @return void */ public void SetWordWrap() { if (this.WordWrap < 1) { return; } { int javaSwitchSelector49 = 0; if (equal(this.message_type, "alt")) javaSwitchSelector49 = 1; if (equal(this.message_type, "alt_attachments")) javaSwitchSelector49 = 2; switch (javaSwitchSelector49) { case 1: { // fall through } case 2: { this.AltBody = this.WrapText(this.AltBody, this.WordWrap); break; } default: { this.Body = this.WrapText(this.Body, this.WordWrap); break; } } } } /** * Assembles message header. * @access private * @return string */ public String CreateHeader() { String result = null; String uniq_id = null; Array<Object> from = new Array<Object>(); int index = 0; result = ""; // Set the boundaries uniq_id = Strings.md5(Misc.uniqid(strval(DateTime.time()))); this.boundary.putValue(1, "b1_" + uniq_id); this.boundary.putValue(2, "b2_" + uniq_id); result += this.HeaderLine("Date", this.RFCDate()); if (equal(this.Sender, "")) { result += this.HeaderLine("Return-Path", Strings.trim(this.From)); } else result += this.HeaderLine("Return-Path", Strings.trim(this.Sender)); // To be created automatically by mail() if (!equal(this.Mailer, "mail")) { if (Array.count(this.to) > 0) { result += this.AddrAppend("To", this.to); } else if (equal(Array.count(this.cc), 0)) { result += this.HeaderLine("To", "undisclosed-recipients:;"); } if (Array.count(this.cc) > 0) { result += this.AddrAppend("Cc", this.cc); } } from = new Array<Object>(); from.getArrayValue(0).putValue(0, Strings.trim(this.From)); from.getArrayValue(0).putValue(1, this.FromName); result += this.AddrAppend("From", from); // sendmail and mail() extract Bcc from the header before sending if ((equal(this.Mailer, "sendmail") || equal(this.Mailer, "mail")) && Array.count(this.bcc) > 0) { result += this.AddrAppend("Bcc", this.bcc); } if (Array.count(this.ReplyTo) > 0) { result += this.AddrAppend("Reply-to", this.ReplyTo); } // mail() sets the subject itself if (!equal(this.Mailer, "mail")) { result += this.HeaderLine("Subject", this.EncodeHeader(Strings.trim(this.Subject))); } result += QStrings.sprintf("Message-ID: <%s@%s>%s", uniq_id, this.ServerHostname(), this.LE); result += this.HeaderLine("X-Priority", this.Priority); if (!equal(this.ConfirmReadingTo, "")) { result += this.HeaderLine("Disposition-Notification-To", "<" + Strings.trim(this.ConfirmReadingTo) + ">"); } // Add custom headers for (index = 0; index < Array.count(this.CustomHeader); index++) { result += this.HeaderLine(Strings.trim(strval(this.CustomHeader.getArrayValue(index).getValue(0))), this.EncodeHeader(Strings.trim(strval(this.CustomHeader.getArrayValue(index) .getValue(1))))); } result += this.HeaderLine("MIME-Version", "1.0"); { int javaSwitchSelector50 = 0; if (equal(this.message_type, "plain")) javaSwitchSelector50 = 1; if (equal(this.message_type, "attachments")) javaSwitchSelector50 = 2; if (equal(this.message_type, "alt_attachments")) javaSwitchSelector50 = 3; if (equal(this.message_type, "alt")) javaSwitchSelector50 = 4; switch (javaSwitchSelector50) { case 1: { result += this.HeaderLine("Content-Transfer-Encoding", this.Encoding); result += QStrings.sprintf("Content-Type: %s; charset=\"%s\"", this.ContentType, this.CharSet); break; } case 2: // fall through case 3: { if (this.InlineImageExists()) { result = result + QStrings.sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", "multipart/related", this.LE, this.LE, this.boundary.getValue(1), this.LE); } else { result += this.HeaderLine("Content-Type", "multipart/mixed;"); result += this.TextLine("\tboundary=\"" + this.boundary.getValue(1) + "\""); } break; } case 4: { result += this.HeaderLine("Content-Type", "multipart/alternative;"); result += this.TextLine("\tboundary=\"" + this.boundary.getValue(1) + "\""); break; } } } if (!equal(this.Mailer, "mail")) { result += this.LE + this.LE; } return result; } /** * Assembles the message body. Returns an empty string on failure. * @access private * @return string */ public String CreateBody() { String result = null; result = ""; this.SetWordWrap(); { int javaSwitchSelector51 = 0; if (equal(this.message_type, "alt")) javaSwitchSelector51 = 1; if (equal(this.message_type, "plain")) javaSwitchSelector51 = 2; if (equal(this.message_type, "attachments")) javaSwitchSelector51 = 3; if (equal(this.message_type, "alt_attachments")) javaSwitchSelector51 = 4; switch (javaSwitchSelector51) { case 1: { result = result + this.GetBoundary(this.boundary.getValue(1), "", "text/plain", ""); result = result + this.EncodeString(this.AltBody, this.Encoding); result = result + this.LE + this.LE; result = result + this.GetBoundary(this.boundary.getValue(1), "", "text/html", ""); result = result + this.EncodeString(this.Body, this.Encoding); result = result + this.LE + this.LE; result = result + this.EndBoundary(this.boundary.getValue(1)); break; } case 2: { result = result + this.EncodeString(this.Body, this.Encoding); break; } case 3: { result = result + this.GetBoundary(this.boundary.getValue(1), "", "", ""); result = result + this.EncodeString(this.Body, this.Encoding); result = result + this.LE; result = result + this.AttachAll(); break; } case 4: { result = result + QStrings.sprintf("--%s%s", this.boundary.getValue(1), this.LE); result = result + QStrings.sprintf("Content-Type: %s;%s" + "\tboundary=\"%s\"%s", "multipart/alternative", this.LE, this.boundary.getValue(2), this.LE + this.LE); // Create text body result = result + this.GetBoundary(this.boundary.getValue(2), "", "text/plain", "") + this.LE; result = result + this.EncodeString(this.AltBody, this.Encoding); result = result + this.LE + this.LE; // Create the HTML body result = result + this.GetBoundary(this.boundary.getValue(2), "", "text/html", "") + this.LE; result = result + this.EncodeString(this.Body, this.Encoding); result = result + this.LE + this.LE; result = result + this.EndBoundary(this.boundary.getValue(2)); result = result + this.AttachAll(); break; } } } if (this.IsError()) { result = ""; } return result; } /** * Returns the start of a message boundary. * @access private */ public String GetBoundary(Object boundary, String charSet, String contentType, String encoding) { String result = null; result = ""; if (equal(charSet, "")) { charSet = this.CharSet; } if (equal(contentType, "")) { contentType = this.ContentType; } if (equal(encoding, "")) { encoding = this.Encoding; } result = result + this.TextLine("--" + boundary); result = result + QStrings.sprintf("Content-Type: %s; charset = \"%s\"", contentType, charSet); result = result + this.LE; result = result + this.HeaderLine("Content-Transfer-Encoding", encoding); result = result + this.LE; return result; } /** * Returns the end of a message boundary. * @access private */ public String EndBoundary(Object boundary) { return this.LE + "--" + strval(boundary) + "--" + this.LE; } /** * Sets the message type. * @access private * @return void */ public void SetMessageType() { if (Array.count(this.attachment) < 1 && Strings.strlen(this.AltBody) < 1) { this.message_type = "plain"; } else { if (Array.count(this.attachment) > 0) { this.message_type = "attachments"; } if (Strings.strlen(this.AltBody) > 0 && Array.count(this.attachment) < 1) { this.message_type = "alt"; } if (Strings.strlen(this.AltBody) > 0 && Array.count(this.attachment) > 0) { this.message_type = "alt_attachments"; } } } /** * Returns a formatted header line. * @access private * @return string */ public String HeaderLine(String name, Object value) { return name + ": " + value + this.LE; } /** * Returns a formatted mail line. * @access private * @return string */ public String TextLine(String value) { return value + this.LE; } ///////////////////////////////////////////////// // ATTACHMENT METHODS ///////////////////////////////////////////////// /** * Adds an attachment from a path on the filesystem. * Returns false if the file could not be found * or accessed. * @param string $path Path to the attachment. * @param string $name Overrides the attachment name. * @param string $encoding File encoding (see $Encoding). * @param string $type File extension (MIME) type. * @return bool */ public boolean AddAttachment(String path, String name, String encoding, String type) { String filename = null; int cur = 0; if (!FileSystemOrSocket.is_file(gVars.webEnv, path)) { this.SetError(this.Lang("file_access") + path); return false; } filename = FileSystemOrSocket.basename(path); if (equal(name, "")) { name = filename; } cur = Array.count(this.attachment); this.attachment.getArrayValue(cur).putValue(0, path); this.attachment.getArrayValue(cur).putValue(1, filename); this.attachment.getArrayValue(cur).putValue(2, name); this.attachment.getArrayValue(cur).putValue(3, encoding); this.attachment.getArrayValue(cur).putValue(4, type); this.attachment.getArrayValue(cur).putValue(5, false); // isStringAttachment this.attachment.getArrayValue(cur).putValue(6, "attachment"); this.attachment.getArrayValue(cur).putValue(7, 0); return true; } /** * Attaches all fs, string, and binary attachments to the message. Returns * an empty string on failure. * @access private * @return string */ public String AttachAll() { Array<String> mime; Object bString = null; int i = 0; String string = null; String path = null; Object filename = null; Object name = null; String encoding = null; Object type = null; Object disposition = null; Object cid = null; mime = new Array<String>(); // Return text of body for (i = 0; i < Array.count(this.attachment); i++) { // Check for string attachment bString = this.attachment.getArrayValue(i).getValue(5); if (booleanval(bString)) { string = strval(this.attachment.getArrayValue(i).getValue(0)); } else path = strval(this.attachment.getArrayValue(i).getValue(0)); filename = this.attachment.getArrayValue(i).getValue(1); name = this.attachment.getArrayValue(i).getValue(2); encoding = strval(this.attachment.getArrayValue(i).getValue(3)); type = this.attachment.getArrayValue(i).getValue(4); disposition = this.attachment.getArrayValue(i).getValue(6); cid = this.attachment.getArrayValue(i).getValue(7); mime.putValue(QStrings.sprintf("--%s%s", this.boundary.getValue(1), this.LE)); mime.putValue(QStrings.sprintf("Content-Type: %s; name=\"%s\"%s", type, name, this.LE)); mime.putValue(QStrings.sprintf("Content-Transfer-Encoding: %s%s", encoding, this.LE)); if (equal(disposition, "inline")) { mime.putValue(QStrings.sprintf("Content-ID: <%s>%s", cid, this.LE)); } mime.putValue(QStrings.sprintf("Content-Disposition: %s; filename=\"%s\"%s", disposition, name, this.LE + this.LE)); // Encode as string attachment if (booleanval(bString)) { mime.putValue(this.EncodeString(string, encoding)); if (this.IsError()) { return ""; } mime.putValue(this.LE + this.LE); } else { mime.putValue(this.EncodeFile(path, encoding)); if (this.IsError()) { return ""; } mime.putValue(this.LE + this.LE); } } mime.putValue(QStrings.sprintf("--%s--%s", this.boundary.getValue(1), this.LE)); return Strings.join("", mime); } /** * Encodes attachment in requested format. Returns an empty string on * failure. * @access private * @return string */ public String EncodeFile(String path, String encoding) { int fd = 0; int magic_quotes = 0; String file_buffer = null; if (!booleanval(fd = FileSystemOrSocket.fopen(gVars.webEnv, path, "rb"))) { this.SetError(this.Lang("file_open") + path); return ""; } magic_quotes = Options.get_magic_quotes_runtime(gVars.webEnv); Options.set_magic_quotes_runtime(gVars.webEnv, 0); file_buffer = FileSystemOrSocket.fread(gVars.webEnv, fd, FileSystemOrSocket.filesize(gVars.webEnv, path)); file_buffer = this.EncodeString(file_buffer, encoding); FileSystemOrSocket.fclose(gVars.webEnv, fd); Options.set_magic_quotes_runtime(gVars.webEnv, magic_quotes); return file_buffer; } /** * Encodes string to requested format. Returns an empty string on failure. * @access private * @return string */ public String EncodeString(String str, String encoding) { String encoded = null; encoded = ""; { int javaSwitchSelector52 = 0; if (equal(Strings.strtolower(encoding), "base64")) javaSwitchSelector52 = 1; if (equal(Strings.strtolower(encoding), "7bit")) javaSwitchSelector52 = 2; if (equal(Strings.strtolower(encoding), "8bit")) javaSwitchSelector52 = 3; if (equal(Strings.strtolower(encoding), "binary")) javaSwitchSelector52 = 4; if (equal(Strings.strtolower(encoding), "quoted-printable")) javaSwitchSelector52 = 5; switch (javaSwitchSelector52) { case 1: { // chunk_split is found in PHP >= 3.0.6 encoded = Strings.chunk_split(URL.base64_encode(str), 76, this.LE); break; } case 2: { } case 3: { encoded = this.FixEOL(str); if (!equal(Strings.substr(encoded, -Strings.strlen(this.LE)), this.LE)) { encoded = encoded + this.LE; } break; } case 4: { encoded = str; break; } case 5: { encoded = this.EncodeQP(str); break; } default: { this.SetError(this.Lang("encoding") + encoding); break; } } } return encoded; } public String EncodeHeader(String str) { return EncodeHeader(str, "text"); } /** * Encode a header string to best of Q, B, quoted or none. * @access private * @return string */ public String EncodeHeader(String str, String position) { int x = 0; String encoded = null; Array matches = new Array(); int maxlen = 0; String encoding = null; x = 0; { int javaSwitchSelector53 = 0; if (equal(Strings.strtolower(position), "phrase")) javaSwitchSelector53 = 1; if (equal(Strings.strtolower(position), "comment")) javaSwitchSelector53 = 2; if (equal(Strings.strtolower(position), "text")) javaSwitchSelector53 = 3; switch (javaSwitchSelector53) { case 1: { if (!QRegExPerl.preg_match("/[\\200-\\377]/", str)) { // Can't use addslashes as we don't know what value has magic_quotes_sybase. encoded = Strings.addcslashes(str, "\u0000..\u0025\u00B1\\\""); if (equal(str, encoded) && !QRegExPerl.preg_match("/[^A-Za-z0-9!#$%&\'*+\\/=?^_`{|}~ -]/", str)) { return encoded; } else return "\"" + encoded + "\""; } x = QRegExPerl.preg_match_all("/[^\\040\\041\\043-\\133\\135-\\176]/", str, matches); break; } case 2: { x = QRegExPerl.preg_match_all("/[()\"]/", str, matches); // Fall-through } case 3: { } default: { x = x + QRegExPerl.preg_match_all("/[\\000-\\010\\013\\014\\016-\\037\\177-\\377]/", str, matches); break; } } } if (equal(x, 0)) { return str; } maxlen = 75 - 7 - Strings.strlen(this.CharSet); // Try to select the encoding which should produce the shortest output if (floatval(Strings.strlen(str)) / floatval(3) < floatval(x)) { encoding = "B"; encoded = URL.base64_encode(str); maxlen = maxlen - maxlen % 4; encoded = Strings.trim(Strings.chunk_split(encoded, maxlen, "\n")); } else { encoding = "Q"; encoded = this.EncodeQ(str, position); encoded = this.WrapText(encoded, maxlen, true); encoded = Strings.str_replace("=" + this.LE, "\n", Strings.trim(encoded)); } encoded = QRegExPerl.preg_replace("/^(.*)$/m", " =?" + this.CharSet + "?" + encoding + "?\\1?=", encoded); encoded = Strings.trim(Strings.str_replace("\n", this.LE, encoded)); return encoded; } /** * Encode string to quoted-printable. * @access private * @return string */ public String EncodeQP(String str) { String encoded = null; encoded = this.FixEOL(str); if (!equal(Strings.substr(encoded, -Strings.strlen(this.LE)), this.LE)) { encoded = encoded + this.LE; } // Modified by Numiton // Replace every high ascii, control and = characters encoded = RegExPerl.preg_replace_callback("/([\\000-\\010\\013\\014\\016-\\037\\075\\177-\\377])/", new Callback("replaceSprintfOrd", this), encoded); // Modified by Numiton // Replace every spaces and tabs when it's the last character on a line encoded = RegExPerl.preg_replace_callback("/([\t ])" + this.LE + "/", new Callback("replaceSprintfOrdLE", this), encoded); // Maximum line length of 76 characters before CRLF (74 + space + '=') encoded = this.WrapText(encoded, 74, true); return encoded; } /** * Encode string to q encoding. * @access private * @return string */ public String EncodeQ(String str, String position) { // There should not be any EOL in the string String encoded = QRegExPerl.preg_replace("[\r\n]", "", str); { int javaSwitchSelector54 = 0; if (equal(Strings.strtolower(position), "phrase")) javaSwitchSelector54 = 1; if (equal(Strings.strtolower(position), "comment")) javaSwitchSelector54 = 2; if (equal(Strings.strtolower(position), "text")) javaSwitchSelector54 = 3; switch (javaSwitchSelector54) { case 1: { // Modified by Numiton encoded = RegExPerl.preg_replace_callback("/([^A-Za-z0-9!*+\\/ -])/", new Callback("replaceSprintfOrd", this), encoded); break; } case 2: { // Modified by Numiton encoded = RegExPerl.preg_replace_callback("/([\\(\\)\"])/", new Callback("replaceSprintfOrd", this), encoded); } case 3: { } default: { // Modified by Numiton // Replace every high ascii, control =, ? and _ characters encoded = RegExPerl.preg_replace_callback("/([\\000-\\011\\013\\014\\016-\\037\\075\\077\\137\\177-\\377])/", new Callback("replaceSprintfOrd", this), encoded); break; } } } // Replace every spaces to _ (more readable than =20) encoded = Strings.str_replace(" ", "_", encoded); return encoded; } /** * Adds a string or binary attachment (non-filesystem) to the list. This * method can be used to attach ascii or binary data, such as a BLOB record * from a database. * @param string $string String attachment data. * @param string $filename Name of the attachment. * @param string $encoding File encoding (see $Encoding). * @param string $type File extension (MIME) type. * @return void */ public void AddStringAttachment(Object string, Object filename, Object encoding, Object type) { int cur = 0; // Append to $attachment array cur = Array.count(this.attachment); this.attachment.getArrayValue(cur).putValue(0, string); this.attachment.getArrayValue(cur).putValue(1, filename); this.attachment.getArrayValue(cur).putValue(2, filename); this.attachment.getArrayValue(cur).putValue(3, encoding); this.attachment.getArrayValue(cur).putValue(4, type); this.attachment.getArrayValue(cur).putValue(5, true); // isString this.attachment.getArrayValue(cur).putValue(6, "attachment"); this.attachment.getArrayValue(cur).putValue(7, 0); } /** * Adds an embedded attachment. This can include images, sounds, and just * about any other document. Make sure to set the $type to an image type. * For JPEG images use "image/jpeg" and for GIF images use "image/gif". * @param string $path Path to the attachment. * @param string $cid Content ID of the attachment. Use this to identify the * Id for accessing the image in an HTML form. * @param string $name Overrides the attachment name. * @param string $encoding File encoding (see $Encoding). * @param string $type File extension (MIME) type. * @return bool */ public boolean AddEmbeddedImage(String path, String cid, String name, String encoding, String type) { String filename = null; int cur = 0; if (!FileSystemOrSocket.is_file(gVars.webEnv, path)) { this.SetError(this.Lang("file_access") + path); return false; } filename = FileSystemOrSocket.basename(path); if (equal(name, "")) { name = filename; } // Append to $attachment array cur = Array.count(this.attachment); this.attachment.getArrayValue(cur).putValue(0, path); this.attachment.getArrayValue(cur).putValue(1, filename); this.attachment.getArrayValue(cur).putValue(2, name); this.attachment.getArrayValue(cur).putValue(3, encoding); this.attachment.getArrayValue(cur).putValue(4, type); this.attachment.getArrayValue(cur).putValue(5, false); this.attachment.getArrayValue(cur).putValue(6, "inline"); this.attachment.getArrayValue(cur).putValue(7, cid); return true; } /** * Returns true if an inline attachment is present. * @access private * @return bool */ public boolean InlineImageExists() { boolean result = false; int i = 0; result = false; for (i = 0; i < Array.count(this.attachment); i++) { if (equal(this.attachment.getArrayValue(i).getValue(6), "inline")) { result = true; break; } } return result; } ///////////////////////////////////////////////// // MESSAGE RESET METHODS ///////////////////////////////////////////////// /** * Clears all recipients assigned in the TO array. Returns void. * @return void */ public void ClearAddresses() { this.to = new Array<Object>(); } /** * Clears all recipients assigned in the CC array. Returns void. * @return void */ public void ClearCCs() { this.cc = new Array<Object>(); } /** * Clears all recipients assigned in the BCC array. Returns void. * @return void */ public void ClearBCCs() { this.bcc = new Array<Object>(); } /** * Clears all recipients assigned in the ReplyTo array. Returns void. * @return void */ public void ClearReplyTos() { this.ReplyTo = new Array<Object>(); } /** * Clears all recipients assigned in the TO, CC and BCC array. Returns * void. * @return void */ public void ClearAllRecipients() { this.to = new Array<Object>(); this.cc = new Array<Object>(); this.bcc = new Array<Object>(); } /** * Clears all previously set filesystem, string, and binary attachments. * Returns void. * @return void */ public void ClearAttachments() { this.attachment = new Array<Object>(); } /** * Clears all custom headers. Returns void. * @return void */ public void ClearCustomHeaders() { this.CustomHeader = new Array<Object>(); } ///////////////////////////////////////////////// // MISCELLANEOUS METHODS ///////////////////////////////////////////////// /** * Adds the error message to the error container. * Returns void. * @access private * @return void */ public void SetError(String msg) { this.error_count++; this.ErrorInfo = msg; } /** * Returns the proper RFC 822 formatted date. * @access private * @return string */ public String RFCDate() { int tz; String tzs = null; String result = null; tz = intval(DateTime.date("Z")); tzs = ((tz < 0) ? "-" : "+"); tz = Math.abs(tz); tz = intval(tz / floatval(3600) * floatval(100) + floatval(tz % 3600) / floatval(60)); result = QStrings.sprintf("%s %s%04d", DateTime.date("D, j M Y H:i:s"), tzs, tz); return result; } /** * Returns the appropriate server variable. Should work with both PHP * 4.1.0+ as well as older versions. Returns an empty string if nothing is * found. * @access private * @return mixed */ public String ServerVar(String varName) { // Commented by Numiton. Meaningless in Java // if (!isset(gVars.webEnv._SERVER)) // { // gVars.webEnv._SERVER = HTTP_SERVER_VARS; // if (!isset(gVars.webEnv.getRemoteAddr())) { // gVars.webEnv._SERVER = HTTP_ENV_VARS; // must be Apache // } // } if (isset(gVars.webEnv._SERVER.getValue(varName))) { return strval(gVars.webEnv._SERVER.getValue(varName)); } else return ""; } /** * Returns the server hostname or 'localhost.localdomain' if unknown. * @access private * @return string */ public String ServerHostname() { String result = null; if (!equal(this.Hostname, "")) { result = this.Hostname; } else if (!equal(this.ServerVar("SERVER_NAME"), "")) { result = this.ServerVar("SERVER_NAME"); } else result = "localhost.localdomain"; return result; } /** * Returns a message in the appropriate language. * @access private * @return string */ public String Lang(String key) { if (Array.count(this.language) < 1) { this.SetLanguage("en"); // set the default language } if (isset(this.language.getValue(key))) { return strval(this.language.getValue(key)); } else return "Language string failed to load: " + key; } /** * Returns true if an error occurred. * @return bool */ public boolean IsError() { return this.error_count > 0; } /** * Changes every end of line from CR or LF to CRLF. * @access private * @return string */ public String FixEOL(String str) { str = Strings.str_replace("\r\n", "\n", str); str = Strings.str_replace("\r", "\n", str); str = Strings.str_replace("\n", this.LE, str); return str; } /** * Adds a custom header. * @return void */ public void AddCustomHeader(String custom_header) { this.CustomHeader.putValue(Strings.explode(":", custom_header, 2)); } public String replaceSprintfOrd(Array matches) { return "=" + QStrings.sprintf("%02X", Strings.ord(strval(matches.getValue(1)))); } public String replaceSprintfOrdLE(Array matches) { return "=" + QStrings.sprintf("%02X", Strings.ord(strval(matches.getValue(1)))) + this.LE; } public void setContext(GlobalVariablesContainer javaGlobalVariables, GlobalConstantsInterface javaGlobalConstants) { gConsts = (GlobalConsts) javaGlobalConstants; gVars = (GlobalVars) javaGlobalVariables; gVars.gConsts = gConsts; } public Object clone() throws CloneNotSupportedException { return super.clone(); } public GlobalVariablesContainer getGlobalVars() { return gVars; } }