* Copyright 1999-2004 Jon Parise * Copyright 2002-2004 Michael Slusarz * * See the enclosed file COPYING for license information (GPL). If you * did not receive this file, see http://www.fsf.org/copyleft/gpl.html. */ /** * Return an url for mailbox.php depending on what kind of start/page * information we have. */ function _mailboxReturnURL($url = null) { if (empty($url)) { $url = Horde::applicationUrl('mailbox.php'); } foreach (array('start', 'page') as $key) { if (($param = Util::getFormData($key))) { $url = Util::addParameter($url, $key, $param); } } return $url; } /** * Returns a To:, Cc: or Bcc: list build from a selection based on 'expand * names'. */ function _getAddressList($field) { $to_list = Util::getFormData($field . '_list'); $to = Util::getFormData($field . '_field'); if (isset($to_list) && is_array($to_list) && is_array($to)) { $tmp = array(); foreach ($to as $key => $address) { $address = _formatAddr($address); $tmp[$key] = $address; } foreach ($to_list as $key => $address) { $address = _formatAddr($address); if ($address != '') { $tmp[$key] = $address; } } $to_new = Util::getFormData($field . '_new'); if (!empty($to_new)) { $tmp[] = $to_new; } return implode(', ', $tmp); } } /** * Expand addresses. * * @param string $header The header to expand. * * @return string Expanded list of addresses in $header. */ function _expandAddresses($header) { global $notification; $result = IMP::expandAddresses(Util::getFormData($header, _getAddressList($header)), true); if (is_array($result)) { $notification->push(_("Please resolve ambiguous or invalid addresses."), 'horde.message'); } elseif (is_a($result, 'PEAR_Error')) { $error = $result; $result = array(); $list = $error->getUserInfo(); if (is_array($list)) { foreach ($list as $entry) { if (is_object($entry)) { $result[] = $entry->getUserInfo(); } else { $result[] = $entry; } } } $notification->push($error, 'horde.message'); } return $result; } /** * Checks for non-standard address formats, such as separating with * spaces or semicolons. * * @param string The address string. * * @return string The "cleaned" address string. */ function _formatAddr($addr) { /* If there are angle brackets (<>), or a colon (group name delimiter), assume the user knew what they were doing. */ if (!empty($addr) && (strpos($addr, '>') === false) && (strpos($addr, ':') === false)){ $addr = trim(strtr($addr, ';,', ' ')); $addr = preg_replace('|\s+|', ', ', $addr); } return $addr; } /** * Generate a recipient list. * * @param array An array of address strings. * * @return mixed A combined address string, or PEAR_Error on error. */ function _recipientList($addr) { global $imp; $addrlist = null; foreach ($addr as $val) { if (!empty($val)) { $addrlist .= (empty($addrlist)) ? $val : ', ' . $val; //Added by Fiona //$addrlist = trim(strtr($addrlist, ';' , ' ')); //$addrlist = preg_replace('|\s+|', ', ', $addrlist); } } if (empty($addrlist)) { return PEAR::raiseError(_("You must enter at least one recipient.")); } foreach (MIME::bareAddress($addrlist, $imp['maildomain'], true) as $val) { if (MIME::is8bit($val)) { return PEAR::raiseError(_("Invalid character in e-mail address.")); } } return $addrlist; } /** * Retrieves and wraps the submitted message text. */ function _getMessage() { global $prefs; $msg = Util::getFormData('message', ''); $reply_type = Util::getFormData('reply_type'); $msg = Text::wrap($msg, $prefs->getValue('wrap_width'), "\n", NLS::getCharset(), ($reply_type == 'reply')); return $msg; } /** * Returns the charset to use for outgoing messages based on * (by replying to or forwarding) the given mime message and * the user's default settings and any previously selected * charset. * * @param object &$mime_message The mime message that gets * forwarded or replied to. */ function _getEncoding($mime_message = null) { global $charset; if ($charset) { return $charset; } $encoding = NLS::getEmailCharset(); if (isset($mime_message)) { $mime_message = &Util::cloneObject($mime_message); $mime_part = &$mime_message->getBasePart(); if ($mime_part->getPrimaryType() == MIME::type(TYPEMULTIPART)) { foreach ($mime_part->getParts() as $part) { if ($part->getPrimaryType() == MIME::type(TYPETEXT)) { $mime_part = $part; break; } } } if ((NLS::getCharset() == 'UTF-8') && (String::upper($mime_part->getCharset()) != 'US-ASCII') && (String::upper($mime_part->getCharset()) != String::upper($encoding))) { $encoding = 'UTF-8'; } } return $encoding; } /** * Setup the base message MIME_Part object. */ function _baseMessage(&$imp_compose) { global $charset, $conf; $message = String::convertCharset(_getMessage(), NLS::getCharset(), $charset); if ($GLOBALS['rtemode']) { $message_html = $message; $html2text = &new Text_HTMLConverter($message); $message = $html2text->getText(); } /* Get trailer message (if any). */ $trailer = null; if ($conf['msg']['append_trailer'] && @is_readable(IMP_BASE . '/config/trailer.txt')) { $trailer = Text::expandEnvironment("\n" . implode(@file(IMP_BASE . '/config/trailer.txt'), '')); /* If there is a user defined function, call it with the current trailer as an argument. */ if (!empty($conf['hooks']['trailer'])) { require_once HORDE_BASE . '/config/hooks.php'; if (function_exists('_imp_hook_trailer')) { $trailer = call_user_func('_imp_hook_trailer', $trailer); } } } /* Set up the body part now. */ $textBody = &new MIME_Part('text/plain'); $textBody->setContents($textBody->replaceEOL($message)); $textBody->setCharset($charset); if (!is_null($trailer)) { $textBody->appendContents($trailer); } /* Should we send in flowed format? */ $reply_type = Util::getFormData('reply_type'); if ($reply_type == 'reply') { require_once HORDE_LIBS . 'Horde/Text/Flowed.php'; $flowed = &new Text_Flowed($textBody->getContents()); $textBody->setContents($flowed->toFlowed()); $textBody->setContentTypeParameter('format', 'flowed'); } /* Determine whether or not to send a multipart/alternative * message with an HTML part. */ if (!empty($message_html)) { $htmlBody = &new MIME_Part('text/html', Text::wrap($message_html), null, 'inline'); if (!is_null($trailer)) { $htmlBody->appendContents($trailer); } $basepart = &new MIME_Part('multipart/alternative'); $textBody->setDescription(_("Plaintext Version of Message")); $basepart->addPart($textBody); $htmlBody->setDescription(_("HTML Version of Message")); $htmlBody->setCharset($charset); /* Any image links will be downloaded and appended to the * message body. */ $htmlBody = $imp_compose->convertToMultipartRelated($htmlBody); $basepart->addPart($htmlBody); } else { $basepart = $textBody; } /* Add attachments now. */ if ($imp_compose->numberOfAttachments()) { $body = &new MIME_Part('multipart/mixed'); $body->addPart($basepart); $imp_compose->buildAttachments($body); } else { $body = $basepart; } return $body; } @define('IMP_BASE', dirname(__FILE__)); $session_control = 'netscape'; require_once IMP_BASE . '/lib/base.php'; require_once IMP_BASE . '/lib/Compose.php'; require_once IMP_BASE . '/lib/MIME/Contents.php'; require_once IMP_BASE . '/lib/MIME/Headers.php'; require_once IMP_BASE . '/lib/Folder.php'; require_once HORDE_LIBS . 'Horde/Identity.php'; require_once HORDE_LIBS . 'Horde/Menu.php'; require_once HORDE_LIBS . 'Horde/MIME.php'; require_once HORDE_LIBS . 'Horde/MIME/Part.php'; require_once HORDE_LIBS . 'Horde/Text.php'; /* The message text. */ $msg = ''; /* The headers of the message. */ $header = array(); $header['to'] = ''; $header['cc'] = ''; $header['bcc'] = ''; $header['subject'] = ''; $header['inreplyto'] = Util::getFormData('in_reply_to'); $header['references'] = Util::getFormData('references'); $get_sig = true; $pgp_passphrase_dialog = false; $smime_passphrase_dialog = false; $uploads = array( 'upload_1' => 'upload_disposition_1', 'upload_2' => 'upload_disposition_2', 'upload_3' => 'upload_disposition_3' ); $identity = &Identity::singleton(array('imp', 'imp')); $sent_mail_folder = $identity->getValue('sent_mail_folder', Util::getFormData('identity')); $actionID = Util::getFormData('actionID'); if (($index = Util::getFormData('index'))) { $imp_contents = &new IMP_Contents($index); $imp_headers = &new IMP_Headers($index); } $imp_folder = &IMP_Folder::singleton(); /* Set the current time zone. */ NLS::setTimeZone(); /* Set the default charset & encoding. * $charset holds the charset to use when sending messages, * $encoding the best guessed charset offered to the user * as the default value in the charset dropdown list. */ if ($prefs->isLocked('sending_charset')) { $charset = $prefs->getValue('sending_charset'); } else { $charset = Util::getFormData('charset'); } $encoding = _getEncoding(); /* Initialize the IMP_Compose:: object. */ $oldMessageCacheID = Util::getFormData('messageCache'); $imp_compose = &new IMP_Compose(array('cacheID' => $oldMessageCacheID)); /* Is this a popup window? */ $isPopup = (($prefs->getValue('compose_popup') || Util::getFormData('popup')) && $browser->hasFeature('javascript')); /* Determine the composition type - text or HTML. */ $rtemode = false; if ($browser->hasFeature('rte')) { if ($prefs->isLocked('compose_html')) { $rtemode = $prefs->getValue('compose_html'); } else { $rtemode = Util::getFormData('rtemode'); if (is_null($rtemode)) { $rtemode = $prefs->getValue('compose_html'); } else { $oldrtemode = Util::getFormData('oldrtemode'); $get_sig = false; } } } if ($rtemode) { require_once HORDE_LIBS . 'Horde/Editor.php'; $editor = &Horde_Editor::singleton('htmlarea', array('id' => 'message')); } /* Run through the action handlers. */ $title = _("Message Composition"); switch ($actionID) { case 'recompose': // Extract the stored form data. $formData = @unserialize($_SESSION['formData']); unset($_SESSION['formData']); if (!empty($formData['post'])) { $_POST = $formData['post']; } if (!empty($formData['get'])) { $_GET = $formData['get']; } $get_sig = false; break; case 'mailto': if (!empty($index)) { $header['to'] = ''; if (Util::getFormData('mailto')) { $header['to'] = $imp_headers->getOb('toaddress', true); } if (empty($header['to'])) { ($header['to'] = MIME::addrArray2String($imp_headers->getOb('from'))) || ($header['to'] = MIME::addrArray2String($imp_headers->getOb('reply_to'))); } $title = _("Message Composition"); } break; case 'draft': if (!empty($index)) { /* We need to make sure that all the parts have their contents stored within them. */ $mime_message = $imp_contents->rebuildMessage(); $res = $imp_compose->attachFilesFromMessage($mime_message); if (!empty($res)) { foreach ($res as $val) { $notification->push($val, 'horde.error'); } } $msg = "\n" . $imp_compose->findBody($mime_message, $index); if ($rtemode) { require_once HORDE_LIBS . 'Horde/Text.php'; $converter = &new Text($msg); $msg = $converter->toHtml($msg, TEXT_HTML_MICRO); } if (($fromaddr = $imp_headers->getOb('fromaddress'))) { $_GET['identity'] = $identity->getMatchingIdentity($fromaddr); $sent_mail_folder = IMP::addPreambleString($identity->getValue('sent_mail_folder', Util::getFormData('identity'))); } $header['to'] = MIME::addrArray2String($imp_headers->getOb('to')); $header['cc'] = MIME::addrArray2String($imp_headers->getOb('cc')); $header['bcc'] = MIME::addrArray2String($imp_headers->getOb('bcc')); $header['subject'] = $imp_headers->getOb('subject', true); $title = _("Message Composition"); } $get_sig = false; break; case 'compose_expand_addr': $header['to'] = _expandAddresses('to'); $header['cc'] = _expandAddresses('cc'); $header['bcc'] = _expandAddresses('bcc'); $get_sig = false; break; case 'redirect_expand_addr': $header['to'] = _expandAddresses('to'); $get_sig = false; break; case 'reply': case 'reply_all': case 'reply_list': if (!empty($index)) { /* Set the message_id and references headers. */ if (($msg_id = $imp_headers->getOb('message_id'))) { $header['inreplyto'] = chop($msg_id); if (($header['references'] = $imp_headers->getOb('references'))) { $header['references'] .= ' ' . $header['inreplyto']; } else { $header['references'] = $header['inreplyto']; } } if ($actionID == 'reply') { ($header['to'] = Util::getFormData('to')) || ($header['to'] = MIME::addrArray2String($imp_headers->getOb('reply_to'))) || ($header['to'] = MIME::addrArray2String($imp_headers->getOb('from'))); } elseif ($actionID == 'reply_all') { /* Filter out our own address from the addresses we reply to. */ $me = array_keys($identity->getAllFromAddresses(true)); /* Build the To: header. */ $from_arr = $imp_headers->getOb('from'); $to_arr = $imp_headers->getOb('reply_to'); $reply = ''; if (!empty($to_arr)) { $reply = MIME::addrArray2String($to_arr); } elseif (!empty($from_arr)) { $reply = MIME::addrArray2String($from_arr); } $header['to'] = MIME::addrArray2String(array_merge($to_arr, $from_arr)); /* Build the Cc: header. */ $cc_arr = $imp_headers->getOb('to'); if (!empty($cc_arr) && ($reply != MIME::addrArray2String($cc_arr))) { $cc_arr = array_merge($cc_arr, $imp_headers->getOb('cc')); } else { $cc_arr = $imp_headers->getOb('cc'); } $header['cc'] = MIME::addrArray2String($cc_arr, array_push($me, IMP::bareAddress($header['to']))); /* Build the Bcc: header. */ $header['bcc'] = MIME::addrArray2String($imp_headers->getOb('bcc') + $identity->getBccAddresses(), $me); } elseif ($actionID == 'reply_list') { $header['to'] = Util::getFormData('to'); } $qfrom = MIME::addrArray2String($imp_headers->getOb('from')); if (empty($qfrom)) { $qfrom = '<>'; } $mime_message = $imp_contents->getMIMEMessage(); $encoding = _getEncoding($mime_message); $msg = $imp_compose->replyMessage($mime_message, $index, $qfrom, $imp_headers); if ($rtemode) { require_once HORDE_LIBS . 'Horde/Text.php'; $converter = &new Text($msg); $msg = $converter->toHtml($msg, TEXT_HTML_MICRO); } $header['subject'] = $imp_headers->getOb('subject', true); if (!empty($header['subject'])) { if (String::lower(String::substr($header['subject'], 0, 3)) != 're:') { $header['subject'] = 'Re: ' . $header['subject']; } } else { $header['subject'] = 'Re: '; } if ($actionID == 'reply') { $title = _("Reply:") . ' ' . $header['subject']; } elseif ($actionID == 'reply_all') { $title = _("Reply to All:") . ' ' . $header['subject']; } elseif ($actionID == 'reply_list') { $title = _("Reply to List:") . ' ' . $header['subject']; } } break; case 'forward': if (!empty($index)) { /* We need to make sure that all the parts have their contents stored within them. */ $mime_message = $imp_contents->rebuildMessage(); $res = $imp_compose->attachFilesFromMessage($mime_message); if (!empty($res)) { foreach ($res as $val) { $notification->push($val, 'horde.error'); } } $encoding = _getEncoding($mime_message); $msg = $imp_compose->forwardMessage($mime_message, $index, $imp_headers); if ($rtemode) { require_once HORDE_LIBS . 'Horde/Text.php'; $converter = &new Text($msg); $msg = $converter->toHtml($msg, TEXT_HTML_MICRO); } /* We need the Message-Id so we can log this event. */ $header['inreplyto'] = chop($imp_headers->getOb('message_id')); $header['subject'] = $imp_headers->getOb('subject', true); if (!empty($header['subject'])) { $title = _("Forward:") . ' ' . $header['subject']; /* If the subject line already has signals indicating this message is a forward, do not add an additional signal. */ $fwd_signal = false; foreach (array('fwd:', 'fw:', '(fwd)', '[fwd]') as $signal) { if (stristr($header['subject'], $signal)) { $fwd_signal = true; break; } } if (!$fwd_signal) { $header['subject'] = _("Fwd:") . ' ' . $header['subject']; } } else { $title = _("Forward"); $header['subject'] = _("Fwd:"); } } break; case 'redirect_compose': $title = _("Redirect this message"); break; case 'redirect_send': $f_to = Util::getFormData('to', _getAddressList('to')); if (!empty($index) && $f_to) { $recipients = _recipientList(array($f_to)); if (is_a($recipients, 'PEAR_Error')) { $notification->push($recipients, 'horde.error'); $get_sig = false; break; } $imp_headers->buildHeaders(); $imp_headers->addResentHeaders($identity->getFromAddress(), $f_to); /* We need to set the Return-Path header to the current user - see RFC 2821 [4.4]. */ $imp_headers->removeHeader('return-path'); $imp_headers->addHeader('Return-Path', $identity->getFromAddress()); $bodytext = $imp_contents->getBody(); $status = $imp_compose->sendMessage($recipients, $imp_headers, $bodytext); if (!is_a($status, 'PEAR_Error')) { $entry = sprintf("%s Redirected message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $imp['user']); Horde::logMessage($entry, __FILE__, __LINE__, PEAR_LOG_INFO); /* Store history information. */ if (!empty($conf['maillog']['use_maillog'])) { require_once IMP_BASE . '/lib/Maillog.php'; IMP_Maillog::log('redirect', $imp_headers->getOb('message_id'), $recipients); } if ($isPopup) { if ($prefs->getValue('compose_confirm')) { $notification->push(_("Message redirected successfully."), 'horde.success'); require IMP_TEMPLATES . '/common-header.inc'; IMP::status(); require IMP_TEMPLATES . '/compose/success.inc'; require $registry->getParam('templates', 'horde') . '/common-footer.inc'; } else { Util::closeWindowJS(); } } else { if ($prefs->getValue('compose_confirm')) { $notification->push(_("Message redirected successfully."), 'horde.success'); } header('Location: ' . _mailboxReturnURL()); } exit; } else { Horde::logMessage($status->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR); } $actionID = 'redirect_compose'; $notification->push(_("Redirecting failed."), 'horde.error'); } break; case 'send_message': $f_cc = $f_bcc = null; $f_to = Util::getFormData('to', _getAddressList('to')); if ($conf['compose']['allow_cc']) { $f_cc = _formatAddr(Util::getFormData('cc', _getAddressList('cc'))); } if ($conf['compose']['allow_bcc']) { $f_bcc = _formatAddr(Util::getFormData('bcc', _getAddressList('bcc'))); } /* We need at least one recipient & RFC 2822 requires that no 8-bit characters can be in the address fields. */ $recipients = _recipientList(array($f_to, $f_cc, $f_bcc)); if (is_a($recipients, 'PEAR_Error')) { $notification->push($recipients, 'horde.error'); $get_sig = false; break; } require_once HORDE_LIBS . 'Horde/MIME/Message.php'; $mime_message = &new MIME_Message($imp['maildomain']); /* Set up the base message now. */ $body = _baseMessage($imp_compose); /* We need to get the from address now because it is used in some of the PGP code. */ $from = $identity->getFromLine(Util::getFormData('identity'), Util::getFormData('from')); $barefrom = IMP::bareAddress($from); /* Do encryption. */ $encrypt = Util::getFormData('encrypt_options'); $usePGP = ($prefs->getValue('use_pgp') && $conf['utils']['gnupg']); if ($usePGP && (($encrypt == IMP_PGP_ENCRYPT) || ($encrypt == IMP_PGP_SIGN) || ($encrypt == IMP_PGP_SIGNENC))) { require_once IMP_BASE .'/lib/Crypt/PGP.php'; $imp_pgp = &new IMP_PGP(); /* Get the user's passphrase, if we need it. */ $passphrase = ''; if (($encrypt == IMP_PGP_SIGN) || ($encrypt == IMP_PGP_SIGNENC)) { /* Check to see if we have the user's passphrase yet. */ $passphrase = $imp_pgp->getPassphrase(); if (empty($passphrase)) { $pgp_passphrase_dialog = true; $get_sig = false; $notification->push(_("PGP Error: Need passphrase for personal private key."), 'horde.error'); break; } } /* Do the encryption/signing requested. */ switch ($encrypt) { case IMP_PGP_SIGN: $body = $imp_pgp->signMIMEPart($body); break; case IMP_PGP_ENCRYPT: $body = $imp_pgp->encryptMIMEPart($body, $f_to); break; case IMP_PGP_SIGNENC: $body = $imp_pgp->signAndEncryptMIMEPart($body, $f_to); break; } /* Check for errors. */ if (is_a($body, 'PEAR_Error')) { $get_sig = false; $notification->push(_("PGP Error: ") . $body->getMessage(), 'horde.error'); break; } } elseif ($prefs->getValue('use_smime') && (($encrypt == IMP_SMIME_ENCRYPT) || ($encrypt == IMP_SMIME_SIGN) || ($encrypt == IMP_SMIME_SIGNENC))) { require_once IMP_BASE. '/lib/Crypt/SMIME.php'; $imp_smime = &new IMP_SMIME(); /* Check to see if we have the user's passphrase yet. */ if (!($passphrase = $imp_smime->getPassphrase()) && ($encrypt != IMP_SMIME_ENCRYPT)) { $smime_passphrase_dialog = true; $get_sig = false; $notification->push(_("S/MIME Error: Need passphrase for personal private key."), 'horde.error'); break; } /* S/MIME sign the message */ if (($encrypt == IMP_SMIME_SIGNENC) || ($encrypt == IMP_SMIME_SIGN)) { $body = $imp_smime->signMIMEPart($body, $imp_smime->signMessageParams()); } /* S/MIME encrypt the message */ if (($encrypt == IMP_SMIME_ENCRYPT) || ($encrypt == IMP_SMIME_SIGNENC)) { $body = $imp_smime->encryptMIMEPart($body, $imp_smime->encryptMessageParams($f_to)); } } /* Add data to MIME_Message object. */ $mime_message->addPart($body); /* Append PGP signature if set in the preferences. */ if ($usePGP && Util::getFormData('pgp_attach_pubkey')) { if (!isset($imp_pgp)) { require_once IMP_BASE . '/lib/Crypt/PGP.php'; $imp_pgp = &new IMP_PGP(); } $mime_message->addPart($imp_pgp->publicKeyMIMEPart()); } /* Initalize a header object for the outgoing message. */ $msg_headers = &new IMP_Headers(); /* Add a Received header for the hop from browser to server. */ $msg_headers->addReceivedHeader(); $msg_headers->addMessageIdHeader(); /* Add the X-Priority header, if requested. This appears here since this is the "general" location that other mail clients insert this header. */ if ($prefs->getValue('set_priority') && Util::getFormData('x_priority')) { $msg_headers->addHeader('X-Priority', Util::getFormData('x_priority')); } $msg_headers->addHeader('Date', date('r')); /* Add Return Receipt Headers. */ if ($conf['compose']['allow_receipts']) { if (Util::getFormData('request_read_receipt')) { $msg_headers->addReadReceiptHeaders($barefrom); } if (Util::getFormData('request_delivery_confirmation')) { $msg_headers->addDeliveryReceiptHeaders($barefrom); } } $msg_headers->addHeader('From', String::convertCharset($from, NLS::getCharset(), $charset)); $identity->setDefault(Util::getFormData('identity')); $replyto = $identity->getValue('replyto_addr'); if (!empty($replyto) && ($replyto != $barefrom)) { $msg_headers->addHeader('Reply-to', String::convertCharset($replyto, NLS::getCharset(), $charset)); } if (!empty($f_to)) { //Added by Fiona $f_to = ereg_replace(', ,', ', ', $f_to); $f_to = ereg_replace(', ,', ', ', $f_to); $f_to = ereg_replace(';,', ', ', $f_to); $f_to = ereg_replace(',;', ', ', $f_to); $msg_headers->addHeader('To', String::convertCharset($f_to, NLS::getCharset(), $charset)); } elseif (empty($f_to) && empty($f_cc)) { $msg_headers->addHeader('To', 'undisclosed-recipients:;'); } if (!empty($f_cc)) { $f_cc = ereg_replace(', ,', ', ', $f_cc); $f_cc = ereg_replace(', ,', ', ', $f_cc); $f_cc = ereg_replace(';,', ', ', $f_cc); $f_cc = ereg_replace(',;,', ', ', $f_cc); $msg_headers->addHeader('Cc', String::convertCharset($f_cc, NLS::getCharset(), $charset)); } $header['subject'] = Util::getFormData('subject'); if (!empty($header['subject'])) { $msg_headers->addHeader('Subject', String::convertCharset($header['subject'], NLS::getCharset(), $charset)); } /* Add necessary headers for replies. */ $reply_type = Util::getFormData('reply_type'); $irt = Util::getFormData('in_reply_to'); if ($reply_type == 'reply') { if ($ref = Util::getFormData('references')) { $msg_headers->addHeader('References', implode(' ', preg_split('|\s+|', trim($ref)))); } if ($irt) { $msg_headers->addHeader('In-Reply-To', $irt); } } $msg_headers->addMIMEHeaders($mime_message); $res = $imp_compose->sendMessage($recipients, $msg_headers, $mime_message, $charset); if (!is_a($res, 'PEAR_Error')) { $sent_saved = true; /* Log the reply. */ if ($reply_type && $irt) { if (!empty($conf['maillog']['use_maillog'])) { require_once IMP_BASE . '/lib/Maillog.php'; IMP_Maillog::log($reply_type, $irt, $recipients); } if ($index && ($reply_type == 'reply')) { /* Make sure to set the IMAP reply flag. */ imap_setflag_full($imp['stream'], $index, '\\ANSWERED', SE_UID); } } /* Delete the attachment data. */ $imp_compose->deleteAllAttachments(); $entry = sprintf("%s Message sent to %s from %s", $_SERVER['REMOTE_ADDR'], $recipients, $imp['user']); Horde::logMessage($entry, __FILE__, __LINE__, PEAR_LOG_INFO); /* Should we save this message in the sent mail folder? */ $sent_mail_folder = $identity->getSentmailFolder(null, Util::getFormData('sent_mail_folder')); if (!empty($sent_mail_folder) && ((!$prefs->isLocked('save_sent_mail') && Util::getFormData('save_sent_mail')) || ($prefs->isLocked('save_sent_mail') && $prefs->getValue('save_sent_mail')))) { /* Keep Bcc: headers on saved messages. */ if (!empty($f_bcc)) { $f_bcc = ereg_replace(', ,', ', ', $f_bcc); $f_bcc = ereg_replace(', ,', ', ', $f_bcc); $f_bcc = ereg_replace(';,', ', ', $f_bcc); $f_bcc = ereg_replace(',;', ', ', $f_bcc); $msg_headers->addHeader('Bcc', $f_bcc); } /* Loop through the envelope and add headers. */ $headerArray = $mime_message->encode($msg_headers->toArray(), $charset); foreach ($headerArray as $key => $value) { $msg_headers->addHeader($key, $value); } $fcc = $msg_headers->toString(); $fcc .= $mime_message->toString(); /* Make absolutely sure there are no bare newlines. */ $fcc = preg_replace("|([^\r])\n|", "\\1\r\n", $fcc); $fcc = str_replace("\n\n", "\n\r\n", $fcc); if (!$imp_folder->exists($imp['stream'], $sent_mail_folder)) { $imp_folder->create($imp['stream'], $sent_mail_folder, $prefs->getValue('subscribe')); } if (!@imap_append($imp['stream'], IMP::serverString($sent_mail_folder), $fcc, '\\Seen')) { $notification->push(sprintf(_("Message sent successfully, but not saved to %s"), IMP::displayFolder($sent_mail_folder))); $sent_saved = false; } } /* Save recipients to address book? */ if ($prefs->getValue('save_recipients') && $registry->hasMethod('contacts/add')) { $abook = $prefs->getValue('add_source'); if (!empty($abook)) { require_once 'Mail/RFC822.php'; $recipients_array = Mail_RFC822::parseAddressList($recipients); foreach ($recipients_array as $recipient) { /* Remove surrounding quotes. */ $name = trim($recipient->personal); if (preg_match('/^(["\']).*\1$/', $name)) { $name = substr($name, 1, -1); } /* Make sure we have a name. */ if (empty($name)) { $name = $recipient->mailbox; } $res = $registry->call('contacts/add', array($name, $recipient->mailbox . '@' . $recipient->host, $abook)); if (is_a($res, 'PEAR_Error')) { if ($res->getCode() == 'horde.error') { $notification->push($res, $res->getCode()); } } elseif (!$res) { $notification->push(_("An unknown error occured adding the new entry."), 'horde.error'); } else { $notification->push(sprintf(_("Entry \"%s\" was successfully added to the address book"), $name), 'horde.success'); } } } } if ($isPopup) { if ($prefs->getValue('compose_confirm') || !$sent_saved) { if ($sent_saved) { $notification->push(_("Message sent successfully."), 'horde.success'); } require IMP_TEMPLATES . '/common-header.inc'; IMP::status(); require IMP_TEMPLATES . '/compose/success.inc'; require $registry->getParam('templates', 'horde') . '/common-footer.inc'; } else { Util::closeWindowJS(); } } else { if ($prefs->getValue('compose_confirm') && $sent_saved) { $notification->push(_("Message sent successfully."), 'horde.success'); } header('Location: ' . _mailboxReturnURL()); } exit; } /* Unsuccessful send. */ Horde::logMessage($res->getMessage(), __FILE__, __LINE__, PEAR_LOG_ERR); $notification->push(sprintf(_("There was an error sending your message: %s"), $res->getMessage()), 'horde.error'); unset($msg); $get_sig = false; break; case 'save_draft': $drafts_folder = $prefs->getValue('drafts_folder'); if (!empty($drafts_folder)) { require_once HORDE_LIBS . 'Horde/MIME/Message.php'; $mime = &new MIME_Message($imp['maildomain']); /* We need to make sure we add "\r\n" after every line for * imap_append() - some servers require it (e.g. Cyrus). */ $mime->setEOL(MIME_PART_RFC_EOL); /* Set up the base message now. */ $body = _baseMessage($imp_compose); $mime->addPart($body); $body = $mime->toString(); $from = $identity->getFromLine(Util::getFormData('identity'), Util::getFormData('from')); /* Initalize a header object for the draft. */ $draft_headers = &new IMP_Headers(); $draft_headers->addHeader('Date', date('r')); if (!empty($from)) { $draft_headers->addHeader('From', $from); } if (($header['to'] = Util::getFormData('to'))) { $draft_headers->addHeader('To', MIME::encodeAddress(_formatAddr($header['to']), null, $imp['maildomain'])); } if (($header['cc'] = Util::getFormData('cc'))) { $draft_headers->addHeader('Cc', MIME::encodeAddress(_formatAddr($header['cc']), null, $imp['maildomain'])); } if (($header['bcc'] = Util::getFormData('bcc'))) { $draft_headers->addHeader('Bcc', MIME::encodeAddress(_formatAddr($header['bcc']), null, $imp['maildomain'])); } if (($sub = Util::getFormData('subject'))) { $draft_headers->addHeader('Subject', $sub); } if (isset($mime)) { $draft_headers->addMIMEHeaders($mime); } $body = $draft_headers->toString() . $body; // Make absolutely sure there are no bare newlines. $body = preg_replace("|([^\r])\n|", "\\1\r\n", $body); $body = str_replace("\n\n", "\n\r\n", $body); if ($prefs->getValue('unseen_drafts')) { $append_flags = '\\Draft'; } else { $append_flags = '\\Draft \\Seen'; } $drafts_folder = IMP::addPreambleString($drafts_folder); $draft_success = false; if ($imp_folder->exists($imp['stream'], $drafts_folder)) { $draft_success = true; } elseif ($imp_folder->create($imp['stream'], $drafts_folder, $prefs->getValue('subscribe'))) { $draft_success = true; } if ($draft_success) { if (!@imap_append($imp['stream'], IMP::serverString($drafts_folder), $body, $append_flags)) { $notification->push(sprintf(_("Saving the draft failed. This is what the server said: %s"), imap_last_error()), 'horde.error'); } elseif ($prefs->getValue('close_draft')) { if ($isPopup) { Util::closeWindowJS(); } else { header('Location: ' . _mailboxReturnURL()); } exit; } else { $notification->push(sprintf(_("The draft has been saved to the \"%s\" folder."), IMP::stripPreambleString($drafts_folder))); $get_sig = false; break; } } } $get_sig = false; $notification->push(_("There was an error saving this message as a draft."), 'horde.error'); break; case 'add_attachment': foreach ($uploads as $key => $val) { if (isset($HTTP_POST_FILES[$key]) && ($HTTP_POST_FILES[$key]['error'] != 4)) { $result = $imp_compose->addUploadAttachment($key, Util::getFormData($val)); if (is_a($result, 'PEAR_Error')) { $notification->push($result, 'horde.error'); } else { $notification->push(sprintf(_("Added \"%s\" as an attachment."), $result), 'horde.success'); } } } $get_sig = false; break; case 'update_attachment': $deleteList = Util::getPost('delattachments', array()); /* Update the attachment information. */ for ($i = 1; $i <= $imp_compose->numberOfAttachments(); $i++) { if (!in_array($i, $deleteList)) { $disposition = Util::getFormData('file_disposition_' . $i); $description = Util::getFormData('file_description_' . $i); $imp_compose->updateAttachment($i, array('disposition' => $disposition, 'description' => $description)); } } /* Delete attachments. */ if (!empty($deleteList)) { $filenames = $imp_compose->deleteAttachment($deleteList); foreach ($filenames as $val) { $notification->push(sprintf(_("Deleted the attachment \"%s\"."), $val), 'horde.success'); } } $get_sig = false; break; case 'fwd_digest': $indices = Util::getFormData('fwddigest'); if (!empty($indices)) { $msglist = unserialize(urldecode($indices)); foreach ($msglist as $index) { $part = &new MIME_Part('message/rfc822'); $digest_headers = &new IMP_Headers($index); $contents = &new IMP_Contents($index); if (!($name = $digest_headers->getOb('subject', true))) { $name = _("[No Subject]"); } $part->setName($name); $part->setContents($contents->fullMessageText($index)); $res = $imp_compose->addMIMEPartAttachment($part); if (is_a($res, 'PEAR_Error')) { $notification->push($res, 'horde.error'); } } if (count($msglist) == 1) { $header['subject'] = _("Fwd: ") . $name; } else { $header['subject'] = sprintf(_("Fwd: %u Forwarded Messages"), count($msglist)); } } break; case 'cancel_compose': $imp_compose->deleteAllAttachments(); if ($isPopup) { Util::closeWindowJS(); } else { header('Location: ' . _mailboxReturnURL()); } exit; break; case 'spell_check_cancel': $msg = "\n" . Util::getFormData('oldmsg'); $expanded = Util::getFormData('to_list'); if (!empty($expanded)) { $header['to'] = _expandAddresses('to'); $header['cc'] = _expandAddresses('cc'); $header['bcc'] = _expandAddresses('bcc'); } $get_sig = false; break; case 'spell_check_done': $msg = "\n"; $msg .= Util::getFormData('newmsg'); $msg .= Util::getFormData('message'); $expanded = Util::getFormData('to_list'); if (!empty($expanded)) { $header['to'] = _expandAddresses('to'); $header['cc'] = _expandAddresses('cc'); $header['bcc'] = _expandAddresses('bcc'); } $get_sig = false; break; case 'spell_check': case 'spell_check_forward': require IMP_BASE . '/spelling.php'; break; } /* Get the message cache ID. */ $messageCacheID = $imp_compose->getMessageCacheId(); /* Has this page been reloaded? */ $reloaded = Util::getFormData('reloaded'); /* Set the 'save_sent_mail' checkbox for the form. */ if ($reloaded) { $ssm_check = Util::getFormData('save_sent_mail') == 'on'; } else { $ssm_check = $identity->saveSentmail(Util::getFormData('identity')); } require IMP_TEMPLATES . '/common-header.inc'; if ($isPopup) { /* Include the JavaScript for the help system. */ Help::javascript(); /* If the attachments cache is not empty, we must reload this page and delete the attachments. */ if ($messageCacheID) { $url = Util::addParameter(Horde::selfUrl(), array('actionID' => 'cancel_compose', 'messageCache' => $messageCacheID, 'popup' => 1)); $cancel_js = 'self.location.href=\'' . $url . ';\''; } else { $cancel_js = 'self.close();'; } } else { /* If the attachments cache is not empty, we must reload this page and delete the attachments. */ if ($messageCacheID) { $url = Util::addParameter(_mailboxReturnUrl(Horde::selfUrl()), array('actionID' => 'cancel_compose', 'messageCache' => $messageCacheID)); $cancel_js = 'window.location = \'' . $url . '\';'; } else { $cancel_js = 'window.location = \'' . _mailboxReturnURL() . '\';'; } IMP::menu(); } $select_list = $identity->getSelectList(); if (Util::getFormData('from') || $prefs->isLocked('default_identity')) { $from = $identity->getFromLine(Util::getFormData('identity'), Util::getFormData('from')); } else { $from_selected = Util::getFormData('identity'); if (isset($from_selected)) { $identity->setDefault($from_selected); } } /* Grab any data that we were supplied with. */ if (empty($msg)) { $msg = _getMessage(); if ($browser->hasQuirk('double_linebreak_textarea')) { $msg = preg_replace('/(\r?\n){3}/', '$1', $msg); } $msg = "\n" . $msg; /* Convert from Text -> HTML or vice versa if RTE mode changed. */ if (isset($oldrtemode) && $oldrtemode != $rtemode) { if ($rtemode) { $converter = &new Text($msg); $msg = $converter->toHtml($msg, TEXT_HTML_MICRO); } else { $converter = &new Text_HTMLConverter($msg); $msg = $converter->getText(); } } } /* If this is the first page load for this compose item, add auto BCC addresses. */ if (empty($reloaded)) { $header['bcc'] = MIME::addrArray2String($identity->getBccAddresses()); } foreach (array('to', 'cc', 'bcc', 'subject') as $val) { if (empty($header[$val])) { $header[$val] = Util::getFormData($val, _getAddressList($val)); } } $all_sigs = $identity->getAllSignatures(); $folders = $imp_folder->flist_IMP(array('INBOX')); foreach ($all_sigs as $ident => $sig) { if ($conf['user']['select_sentmail_folder']) { $i = 0; $select = null; foreach ($folders as $folder) { if ($folder['val'] == IMP::addPreambleString($identity->getValue('sent_mail_folder', $ident))) { $select = $i; } $i++; } } else { $select = $identity->getValue('sent_mail_folder', $ident); } $identities[$ident] = array($sig, $identity->getValue('sig_first', $ident), $select, $identity->getValue('save_sent_mail', $ident), MIME::addrArray2String($identity->getBccAddresses($ident))); } $sig = $identity->getSignature(); if ($get_sig && isset($msg) && !empty($sig)) { //Changed by Fiona if ($rtemode) { $sig = Text::toHtml($sig, TEXT_HTML_MICRO); } if ($identity->getValue('sig_first')) { $msg = "\n" . $sig . $msg; } else { $msg .= "\n" . $sig; } } /* Define some variables used in the templates. */ $timeout = ini_get('session.gc_maxlifetime'); /* Reload nls.php to get the translated charset names. */ require HORDE_BASE . '/config/nls.php'; switch ($actionID) { case 'redirect_compose': case 'redirect_expand_addr': $mailbox = Util::getFormData('thismailbox', $imp['mailbox']); require_once IMP_TEMPLATES . '/compose/compose_expand.js'; require IMP_TEMPLATES . '/compose/redirect.inc'; break; case 'spell_check': case 'spell_check_forward': require_once IMP_TEMPLATES . '/compose/spelling.js'; require IMP_TEMPLATES . '/compose/spelling.inc'; break; default: /* We need to define $num_attachments and $upload_list as it is used in both compose.inc and attachments.js. */ if ($imp['file_upload']) { $num_attachments = $imp_compose->additionalAttachmentsAllowed(); if ($num_attachments === true) { $num_attachments = 3; } $upload_list = array_slice($uploads, 0, $num_attachments); } require_once IMP_TEMPLATES . '/compose/compose.js'; require_once IMP_TEMPLATES . '/compose/compose_expand.js'; require IMP_TEMPLATES . '/compose/compose.inc'; /* Insert javascript code. */ if ($imp['file_upload']) { require_once IMP_TEMPLATES . '/compose/attachments.js'; } break; } /* Open the passphrase window here. */ if ($pgp_passphrase_dialog) { require_once IMP_TEMPLATES . '/pgp/open_pgp_win.js'; echo ''; } elseif ($smime_passphrase_dialog) { require_once IMP_TEMPLATES . '/smime/open_smime_win.js'; echo ''; } require $registry->getParam('templates', 'horde') . '/common-footer.inc';