<?php
/**
 * $Horde: imp/compose.php,v 2.677 2003/08/05 19:11:48 slusarz Exp $
 *
 * Copyright 1999-2003 Charles J. Hagenbuch <chuck@horde.org>
 * Copyright 1999-2003 Jon Parise <jon@horde.org>
 *
 * 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 = Horde::getFormData($key))) {
            $url = Horde::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 = Horde::getFormData($field . '_list');
    $to = Horde::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 = Horde::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(Horde::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 = _cleanExpandedAddressList($error->getUserInfo());
        $notification->push($error, 'horde.message');
    }

    return $result;
}

/**
 * TODO
 *
 * @param array  TODO
 */
function _cleanExpandedAddressList($list)
{
    $results = array();
    if (is_array($list)) {
        foreach ($list as $entry) {
            if (is_object($entry)) {
                $results[] = $entry->getUserInfo();
            } else {
                $results[] = $entry;
            }
        }
    }

    return $results;
}

/**
 * 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;
        }
    }

    if (empty($addrlist)) {
        return PEAR::raiseError(_("You must have 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 = Horde::getFormData('message', '');
    $msg = Text::wrap($msg, $prefs->getValue('wrap_width'), "\n", NLS::getCharset());
    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)
{
    $encoding = NLS::getEmailCharset();

    if (Horde::getFormData('charset')) {
        return Horde::getFormData('charset');
    }

    if (isset($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') &&
            (strtoupper($mime_part->getCharset()) != 'US-ASCII') &&
            (strtoupper($mime_part->getCharset()) != strtoupper($encoding))) {
            $encoding = 'UTF-8';
        }
    }

    return $encoding;
}

@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/Contents.php';
require_once IMP_BASE . '/lib/Headers.php';
require_once IMP_BASE . '/lib/Folder.php';
require_once HORDE_BASE . '/lib/Identity.php';
require_once HORDE_BASE . '/lib/Menu.php';
require_once HORDE_BASE . '/lib/MIME.php';
require_once HORDE_BASE . '/lib/MIME/Part.php';
require_once HORDE_BASE . '/lib/Text.php';

/* The message text. */
$msg = '';

/* The headers of the message. */
$header = array();
$header['to'] = '';
$header['cc'] = '';
$header['bcc'] = '';
$header['subject'] = '';
$header['inreplyto'] = Horde::getFormData('in_reply_to');
$header['references'] = Horde::getFormData('references');

$get_sig = true;
$pgp_passphrase_dialog = false;
$smime_passphrase_dialog = false;

$identity = &Identity::singleton(array('imp', 'imp'));
$sent_mail_folder = $identity->getValue('sent_mail_folder', Horde::getFormData('identity'));
$actionID = Horde::getFormData('actionID');
if (($index = Horde::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 encoding. */
$encoding = _getEncoding();

/* Initialize the IMP_Compose:: object. */
$imp_compose = &new IMP_Compose(array('cacheID' => Horde::getFormData('messageCache')));

/* Is this a popup window? */
$isPopup = (($prefs->getValue('compose_popup') || Horde::getFormData('popup')) && $browser->hasFeature('javascript'));

/* 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 (Horde::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 (($fromaddr = $imp_headers->getOb('fromaddress'))) {
            $_GET['identity'] = $identity->getMatchingIdentity($fromaddr);
            $sent_mail_folder = IMP::addPreambleString($identity->getValue('sent_mail_folder', Horde::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 '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'] = Horde::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_merge($me, IMP::bareAddress($header['to'])));

            /* Build the Bcc: header. */
            $header['bcc'] = MIME::addrArray2String($imp_headers->getOb('bcc'), $me);
        } elseif ($actionID == 'reply_list') {
            $header['to'] = Horde::getFormData('to');
        }

        $qfrom = MIME::addrArray2String($imp_headers->getOb('from'));
        if (empty($qfrom)) {
            $qfrom = '&lt;&gt;';
        }

        $mime_message = $imp_contents->getMIMEMessage();
        $encoding = _getEncoding($mime_message);
        $msg = $imp_compose->replyMessage($mime_message, $index, $qfrom, $imp_headers);

        $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);

        $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':
    if (!empty($index) && ($f_to = Horde::getFormData('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);

            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 IMP_TEMPLATES . '/common-footer.inc';
                } else {
                    Horde::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;
    $message = _getMessage();

    $f_to = Horde::getFormData('to', _getAddressList('to'));
    if ($conf['compose']['allow_cc']) {
        $f_cc = _formatAddr(Horde::getFormData('cc', _getAddressList('cc')));
    }
    if ($conf['compose']['allow_bcc']) {
        $f_bcc = _formatAddr(Horde::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_BASE . '/lib/MIME/Message.php';
    $mime_message = &new MIME_Message($imp['maildomain']);

    /* 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');
    $charset = Horde::getFormData('charset');
    $message = String::convertCharset($message, NLS::getCharset(), $charset);
    $textBody->setContents($textBody->replaceEOL($message));
    $textBody->setCharset($charset);
    if (!is_null($trailer)) {
        $textBody->appendContents($trailer);
    }

    /* Determine whether or not to send a multipart/alternative
       message with an HTML part. */
    if (($message_html = Horde::getFormData('messageHTML'))) {
        $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"));
        $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;
    }

    /* We need to get the from address now because it is used in some
       of the PGP code. */
    $from = $identity->getFromLine(Horde::getFormData('identity'), Horde::getFormData('from'));
    $barefrom = IMP::bareAddress($from);

    /* Do encryption. */
    $encrypt = Horde::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/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/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 && Horde::getFormData('pgp_attach_pubkey')) {
        if (!isset($imp_pgp)) {
            require_once IMP_BASE . '/lib/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') &&
        Horde::getFormData('x_priority')) {
        $msg_headers->addHeader('X-Priority', Horde::getFormData('x_priority'));
    }

    $msg_headers->addHeader('Date', date('r'));

    /* Add Return Receipt Headers. */
    if ($conf['compose']['allow_receipts']) {
        if (Horde::getFormData('request_read_receipt')) {
            $msg_headers->addReadReceiptHeaders($barefrom);
        }
        if (Horde::getFormData('request_delivery_confirmation')) {
            $msg_headers->addDeliveryReceiptHeaders($barefrom);
        }
    }

    $msg_headers->addHeader('From', $from);

    $identity->setDefault(Horde::getFormData('identity'));
    $replyto = $identity->getValue('replyto_addr');
    if (!empty($replyto) && ($replyto != $barefrom)) {
        $msg_headers->addHeader('Reply-to', $replyto);
    }
    if (!empty($f_to)) {
        $msg_headers->addHeader('To', $f_to);
    } elseif (empty($f_to) && empty($f_cc)) {
        $msg_headers->addHeader('To', 'undisclosed-recipients:;');
    }
    if (!empty($f_cc)) {
        $msg_headers->addHeader('Cc', $f_cc);
    }
    $header['subject'] = Horde::getFormData('subject');
    if (!empty($header['subject'])) {
        $msg_headers->addHeader('Subject', $header['subject']);
    }
    if ($ref = Horde::getFormData('references')) {
        $msg_headers->addHeader('References', implode(' ', preg_split('|\s+|', trim($ref))));
    }
    if ($irt = Horde::getFormData('in_reply_to')) {
        $msg_headers->addHeader('In-Reply-To', $irt);
    }
    $msg_headers->addMIMEHeaders($mime_message);

    $res = $imp_compose->sendMessage($recipients, $msg_headers, $mime_message);
    if (!is_a($res, 'PEAR_Error')) {
        $sent_saved = true;

        /* Set the reply flag. */
        if (Horde::getFormData('is_reply') && $index) {
            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, Horde::getFormData('sent_mail_folder'));
        if (!empty($sent_mail_folder) &&
            ((!$prefs->isLocked('save_sent_mail') &&
              Horde::getFormData('save_sent_mail')) ||
             ($prefs->isLocked('save_sent_mail') &&
              $prefs->getValue('save_sent_mail')))) {

            /* Keep Bcc: headers on saved messages. */
            if (!empty($f_bcc)) {
                $msg_headers->addHeader('Bcc', $f_bcc);
            }

            /* Loop through the envelope and add headers. */
            $headerArray = $mime_message->encode($msg_headers->toArray());
            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;
            }
        }

        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 IMP_TEMPLATES . '/common-footer.inc';
            } else {
                Horde::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)) {
        $drafts_folder = IMP::addPreambleString($drafts_folder);
        if ($message = _getMessage()) {
            require_once HORDE_BASE . '/lib/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);

            $body = &new MIME_Part('text/plain');
            $body->setContents($body->replaceEOL($message));
            $mime->addPart($body);
            $body = $mime->toString();
        } else {
            $body = '';
        }

        $from = $identity->getFromLine(Horde::getFormData('identity'), Horde::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'] = Horde::getFormData('to'))) {
            $draft_headers->addHeader('To', MIME::encodeAddress(_formatAddr($header['to']), null, $imp['maildomain']));
        }
        if (($header['cc'] = Horde::getFormData('cc'))) {
            $draft_headers->addHeader('Cc', MIME::encodeAddress(_formatAddr($header['cc']), null, $imp['maildomain']));
        }
        if (($header['bcc'] = Horde::getFormData('bcc'))) {
            $draft_headers->addHeader('Bcc', MIME::encodeAddress(_formatAddr($header['bcc']), null, $imp['maildomain']));
        }
        if (($sub = Horde::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';
        }
        if ($imp_folder->exists($imp['stream'], $drafts_folder) ||
            $imp_folder->create($imp['stream'], $drafts_folder, $prefs->getValue('subscribe'))) {
            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) {
                    Horde::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':
    require_once HORDE_BASE . '/lib/Server.php';
    $result = $imp_compose->addUploadAttachment(Horde::getFormData('file_disposition'));
    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 = Horde::getPost('delattachments', array());

    /* Update the attachment information. */
    for ($i = 1; $i <= $imp_compose->numberOfAttachments(); $i++) {
        if (!in_array($i, $deleteList)) {
            $disposition = Horde::getFormData('file_disposition_' . $i);
            $description = Horde::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 = Horde::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) {
        Horde::closeWindowJS();
    } else {
        header('Location: ' . _mailboxReturnURL());
    }
    exit;
    break;

case 'spell_check_cancel':
    $msg = "\n" . Horde::getFormData('oldmsg');
    $expanded = Horde::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 .= Horde::getFormData('newmsg');
    $msg .= Horde::getFormData('message');
    $expanded = Horde::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();

/* Set the 'save_sent_mail' checkbox for the form. */
if (Horde::getFormData('reloaded')) {
    $ssm_check = Horde::getFormData('save_sent_mail') == 'on';
} else {
    $ssm_check = $identity->saveSentmail(Horde::getFormData('identity'));
}

/* Determine the composition type - text or HTML. */
$availRichtext = $useRichtext = false;
if ($actionID != 'redirect_compose') {
    if ($browser->hasFeature('rte')) {
        $formData = Horde::getFormData('richtext');
        if (!is_null($formData)) {
            $get_sig = false;
        }
        if ($formData !== null) {
            $useRichtext = (boolean)$formData;
        } else {
            $useRichtext = $prefs->getValue('compose_html');
        }
        $availRichtext = true;
    }
}

$js_onLoad = null;
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 = Horde::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 = Horde::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 (Horde::getFormData('from') || $prefs->isLocked('default_identity')) {
    $from = $identity->getFromLine(Horde::getFormData('identity'), Horde::getFormData('from'));
} else {
    $from_selected = Horde::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;
}
foreach (array('to', 'cc', 'bcc', 'subject') as $val) {
    if (empty($header[$val])) {
        $header[$val] = Horde::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));
}
$sig = $identity->getSignature();

if ($get_sig && isset($msg) && !empty($sig)) {
    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':
    $mailbox = Horde::getFormData('thismailbox', $imp['mailbox']);
    require_once IMP_TEMPLATES . '/compose/compose.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:
    require_once IMP_TEMPLATES . '/compose/compose.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 '<script language="JavaScript" type="text/javascript">' . $imp_pgp->getJSOpenWinCode('open_passphrase_dialog', "opener.focus();opener.document.compose.actionID.value='send_message';opener.uniqSubmit();") . '</script>';
} elseif ($smime_passphrase_dialog) {
    require_once IMP_TEMPLATES . '/smime/open_smime_win.js';
    echo '<script language="JavaScript" type="text/javascript">' . $imp_smime->getJSOpenWinCode('open_passphrase_dialog', "opener.focus();opener.document.compose.actionID.value='send_message';opener.uniqSubmit();") . '</script>';
}

require IMP_TEMPLATES . '/common-footer.inc';

// Catch error messages from c-client.
imap_errors();
