* - Send mail
* - Save As Draft
*
- * @copyright 1999-2014 The SquirrelMail Project Team
+ * @copyright 1999-2021 The SquirrelMail Project Team
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @version $Id$
* @package squirrelmail
require_once(SM_PATH . 'functions/addressbook.php');
require_once(SM_PATH . 'functions/forms.php');
require_once(SM_PATH . 'functions/identity.php');
+global $imap_stream_options; // in case not defined in config
/* --------------------- Get globals ------------------------------------- */
// compose_messages only useful in SESSION when a forward-as-attachment
// has been preconstructed for us and passed in via that mechanism; once
// we have it, we can clear it from the SESSION
-sqsession_unregister('compose_messages');
+// -- No, this is useful in other scenarios, too -- removing:
+// sqsession_unregister('compose_messages');
// Turn on delayed error handling in case we wind up redirecting below
$oErrorHandler->setDelayedErrors(true);
}
sqgetGlobalVar('session',$session, $SQ_GLOBAL);
sqgetGlobalVar('mailbox',$mailbox, $SQ_GLOBAL);
+sqgetGlobalVar('identity',$orig_identity, $SQ_GLOBAL);
if(!sqgetGlobalVar('identity',$identity, $SQ_GLOBAL)) {
$identity=0;
}
/**
* 1) Remove the addresses we'll be sending the message 'to'
*/
- if (isset($header->reply_to)) {
+ if (isset($header->reply_to) && is_array($header->reply_to) && count($header->reply_to)) {
$excl_ar = $header->getAddr_a('reply_to');
+ } else if (is_object($header->reply_to)) { /* unneccesarry, just for failsafe purpose */
+ $excl_ar = $header->getAddr_a('reply_to');
+ } else {
+ $excl_ar = $header->getAddr_a('from');
}
/**
* 2) Remove our identities from the CC list (they still can be in the
$full_reply_citation = sprintf(_("%s wrote:"),$sOrig_from);
break;
case 'quote_who':
+ // TODO: the words "quote" and "who" are translated in 1.4.x so why not here? This isn't a real HTML tag...
$start = '<quote who="';
$end = '">';
$full_reply_citation = $start . $sOrig_from . $end;
// should never directly manipulate an object like this
if (!empty($attachments)) {
$attachments = unserialize(urldecode($attachments));
- if (!empty($attachments) && is_array($attachments))
- $composeMessage->entities = $attachments;
+ if (!empty($attachments) && is_array($attachments)) {
+ // sanitize the "att_local_name" since it is user-supplied and used to access the file system
+ // it must be alpha-numeric and 32 characters long (see the use of GenerateRandomString() below)
+ foreach ($attachments as $i => $attachment) {
+ if (empty($attachment->att_local_name) || strlen($attachment->att_local_name) !== 32) {
+ unset($attachments[$i]);
+ continue;
+ }
+ // probably marginal difference between (ctype_alnum + function_exists) and preg_match
+ if (function_exists('ctype_alnum')) {
+ if (!ctype_alnum($attachment->att_local_name))
+ unset($attachments[$i]);
+ }
+ else if (preg_match('/[^0-9a-zA-Z]/', $attachment->att_local_name))
+ unset($attachments[$i]);
+ }
+ if (!empty($attachments))
+ $composeMessage->entities = $attachments;
+ }
}
if (empty($mailbox)) {
$draft_message = _("Draft Email Saved");
/* If this is a resumed draft, then delete the original */
if(isset($delete_draft)) {
- $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false);
+ $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false, $imap_stream_options);
sqimap_mailbox_select($imap_stream, $draft_folder);
// force bypass_trash=true because message should be saved when deliverMessage() returns true.
// in current implementation of sqimap_msgs_list_flag() single message id can
/* if it is resumed draft, delete draft message */
if ( isset($delete_draft)) {
- $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false);
+ $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, false, $imap_stream_options);
sqimap_mailbox_select($imap_stream, $draft_folder);
// bypass_trash=true because message should be saved when deliverMessage() returns true.
// in current implementation of sqimap_msgs_list_flag() single message id can
exit();
} else {
if ( !isset($pageheader_sent) || !$pageheader_sent ) {
- header("Location: $location/right_main.php?mailbox=$urlMailbox".
- "&startMessage=$startMessage&mail_sent=$mail_sent");
+ global $return_to_message_after_reply;
+ if (($action === 'reply' || $action === 'reply_all' || $action === 'forward' || $action === 'forward_as_attachment')
+ && $return_to_message_after_reply && $passed_id)
+ header("Location: $location/read_body.php?passed_id=$passed_id&mailbox=$urlMailbox".
+ "&startMessage=$startMessage&mail_sent=$mail_sent");
+ else
+ header("Location: $location/right_main.php?mailbox=$urlMailbox".
+ "&startMessage=$startMessage&mail_sent=$mail_sent");
} else {
//FIXME: DON'T ECHO HTML FROM CORE!
echo ' <br><br><div style="text-align: center;"><a href="' . $location
if (isset($subject)) {
$values['subject'] = $subject;
}
+ if (isset($mailprio)) {
+ $values['mailprio'] = $mailprio;
+ }
+ if (isset($orig_identity)) {
+ $values['identity'] = $orig_identity;
+ }
showInputForm($session, $values);
}
function newMail ($mailbox='', $passed_id='', $passed_ent_id='', $action='', $session='') {
global $editor_size, $default_use_priority, $body, $idents,
$use_signature, $data_dir, $username,
- $key, $imapServerAddress, $imapPort,
+ $key, $imapServerAddress, $imapPort, $imap_stream_options,
$composeMessage, $body_quote, $request_mdn, $request_dr,
$mdn_user_support, $languages, $squirrelmail_language,
- $default_charset, $do_not_reply_to_self;
+ $default_charset, $do_not_reply_to_self, $compose_messages;
/*
* Set $default_charset to correspond with the user's selection
if ($passed_id) {
$imapConnection = sqimap_login($username, false, $imapServerAddress,
- $imapPort, 0);
+ $imapPort, 0, $imap_stream_options);
sqimap_mailbox_select($imapConnection, $mailbox);
$message = sqimap_get_message($imapConnection, $passed_id, $mailbox);
// rewrap the body to clean up quotations and line lengths
sqBodyWrap($body, $editor_size);
$composeMessage = getAttachments($message, $composeMessage, $passed_id, $entities, $imapConnection);
+ if (!empty($orig_header->x_sm_flag_reply))
+ $composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply'] = $orig_header->x_sm_flag_reply;
+//TODO: completely unclear if should be using $compose_session instead of $session below
+ $compose_messages[$session] = $composeMessage;
+ sqsession_register($compose_messages,'compose_messages');
break;
case ('edit_as_new'):
$send_to = decodeHeader($orig_header->getAddr_s('to'),false,false,true);
}
$attach = array();
- global $username, $attachment_dir;
+ global $username, $attachment_dir, $upload_filesize_divisor;
+ if (empty($upload_filesize_divisor))
+ $upload_filesize_divisor = 1000; // *not* 1024 -- does this break for some users?
$hashed_attachment_dir = getHashedDir($username, $attachment_dir);
if (!empty($attach_array)) {
foreach ($attach_array as $key => $attachment) {
$max = min($sizes);
$oTemplate->assign('max_file_size', empty($max) ? -1 : $max);
$oTemplate->assign('attachments', $attach);
+ $oTemplate->assign('upload_filesize_divisor', $upload_filesize_divisor);
// access keys...
//
*/
function deliverMessage(&$composeMessage, $draft=false) {
global $send_to, $send_to_cc, $send_to_bcc, $mailprio, $subject, $body,
- $username, $identity, $idents, $data_dir,
+ $username, $identity, $idents, $data_dir, $compose_messages, $session,
$request_mdn, $request_dr, $default_charset, $useSendmail,
$domain, $action, $default_move_to_sent, $move_to_sent,
- $imapServerAddress, $imapPort, $sent_folder, $key;
+ $imapServerAddress, $imapPort, $imap_stream_options, $sent_folder, $key;
$rfc822_header = $composeMessage->rfc822_header;
it over to deliver; plugin authors note that $composeMessage
is sent and modified by reference since 1.5.2 */
do_hook('compose_send', $composeMessage);
+//TODO: need to migrate to the following, but it neessitates changes in existing plugins, since the args are now an array
+ //$temp = array(&$composeMessage, &$draft);
+ //do_hook('compose_send', $temp);
+
+ // remove special header if present and prepare to mark
+ // a message that a draft was composed in reply to
+ if (!empty($composeMessage->rfc822_header->x_sm_flag_reply) && !$draft) {
+ global $passed_id, $mailbox;
+ // tricks the code below that marks the reply
+ list($action, $passed_id, $mailbox) = explode('::', $rfc822_header->x_sm_flag_reply, 3);
+ unset($composeMessage->rfc822_header->x_sm_flag_reply);
+ unset($composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply']);
+ }
if (!$useSendmail && !$draft) {
require_once(SM_PATH . 'class/deliver/Deliver_SMTP.class.php');
$deliver = new Deliver_SMTP();
- global $smtpServerAddress, $smtpPort, $pop_before_smtp, $pop_before_smtp_host;
+ global $smtpServerAddress, $smtpPort, $smtp_stream_options, $pop_before_smtp, $pop_before_smtp_host;
$authPop = (isset($pop_before_smtp) && $pop_before_smtp) ? true : false;
if (empty($pop_before_smtp_host)) $pop_before_smtp_host = $smtpServerAddress;
get_smtp_user($user, $pass);
$stream = $deliver->initStream($composeMessage,$domain,0,
- $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host);
+ $smtpServerAddress, $smtpPort, $user, $pass, $authPop, $pop_before_smtp_host, $smtp_stream_options);
} elseif (!$draft) {
require_once(SM_PATH . 'class/deliver/Deliver_SendMail.class.php');
global $sendmail_path, $sendmail_args;
} elseif ($draft) {
global $draft_folder;
$imap_stream = sqimap_login($username, false, $imapServerAddress,
- $imapPort, 0);
+ $imapPort, 0, $imap_stream_options);
if (sqimap_mailbox_exists ($imap_stream, $draft_folder)) {
+//TODO: this can leak private information about folders and message IDs if messages are accessed/sent from another client --- should this feature be optional?
+ // make note of the message to mark as having been replied to
+ global $passed_id, $mailbox;
+ if ($action == 'reply' || $action == 'reply_all' || $action == 'forward' || $action == 'forward_as_attachment') {
+ $composeMessage->rfc822_header->more_headers['X-SM-Flag-Reply'] = $action . '::' . $passed_id . '::' . $mailbox;
+ }
+
require_once(SM_PATH . 'class/deliver/Deliver_IMAP.class.php');
$imap_deliver = new Deliver_IMAP();
$success = $imap_deliver->mail($composeMessage, $imap_stream, $reply_id, $reply_ent_id, $imap_stream, $draft_folder);
sqimap_logout($imap_stream);
unset ($imap_deliver);
$composeMessage->purgeAttachments();
+//TODO: completely unclear if should be using $compose_session instead of $session below
+ unset($compose_messages[$session]);
+ sqsession_register($compose_messages,'compose_messages');
return $success;
} else {
$msg = '<br />'.sprintf(_("Error: Draft folder %s does not exist."), sm_encode_html_special_chars($draft_folder));
plain_error_message($msg);
} else {
unset ($deliver);
- $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, 0);
+ $imap_stream = sqimap_login($username, false, $imapServerAddress, $imapPort, 0, $imap_stream_options);
// mark as replied or forwarded if applicable
if ($action=='reply' || $action=='reply_all' || $action=='forward' || $action=='forward_as_attachment') {
require(SM_PATH . 'functions/mailbox_display.php');
- $aMailbox = sqm_api_mailbox_select($imap_stream, $iAccount, $mailbox,array('setindex' => $what, 'offset' => $startMessage),array());
- switch($action) {
- case 'reply':
- case 'reply_all':
- // check if we are allowed to set the \\Answered flag
- if (in_array('\\answered',$aMailbox['PERMANENTFLAGS'], true)) {
- $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, array($passed_id), '\\Answered', true, false);
- if (isset($aUpdatedMsgs[$passed_id]['FLAGS'])) {
- /**
- * Only update the cached headers if the header is
- * cached.
- */
- if (isset($aMailbox['MSG_HEADERS'][$passed_id])) {
- $aMailbox['MSG_HEADERS'][$passed_id]['FLAGS'] = $aMsg['FLAGS'];
+ // select errors here could be due to a draft reply being sent
+ // after the original message's mailbox is moved or deleted
+ $aMailbox = sqm_api_mailbox_select($imap_stream, $iAccount, $mailbox,array('setindex' => $what, 'offset' => $startMessage),array(), false);
+ // a non-empty return from above means we can proceed
+ if (!empty($aMailbox)) {
+ switch($action) {
+ case 'reply':
+ case 'reply_all':
+ // check if we are allowed to set the \\Answered flag
+ if (in_array('\\answered',$aMailbox['PERMANENTFLAGS'], true)) {
+ $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, array($passed_id), '\\Answered', true, false);
+ if (isset($aUpdatedMsgs[$passed_id]['FLAGS'])) {
+ /**
+ * Only update the cached headers if the header is
+ * cached.
+ */
+ if (isset($aMailbox['MSG_HEADERS'][$passed_id])) {
+ $aMailbox['MSG_HEADERS'][$passed_id]['FLAGS'] = $aMsg['FLAGS'];
+ }
}
}
- }
- break;
- case 'forward':
- case 'forward_as_attachment':
- // check if we are allowed to set the $Forwarded flag (RFC 4550 paragraph 2.8)
- if (in_array('$forwarded',$aMailbox['PERMANENTFLAGS'], true) ||
- in_array('\\*',$aMailbox['PERMANENTFLAGS'])) {
-
- // when forwarding as an attachment from the message
- // list, passed_id is not used, need to get UID(s)
- // from the query string
- //
- if (empty($passed_id) && !empty($fwduid))
- $ids = explode('_', $fwduid);
- else
- $ids = array($passed_id);
+ break;
+ case 'forward':
+ case 'forward_as_attachment':
+ // check if we are allowed to set the $Forwarded flag (RFC 4550 paragraph 2.8)
+ if (in_array('$forwarded',$aMailbox['PERMANENTFLAGS'], true) ||
+ in_array('\\*',$aMailbox['PERMANENTFLAGS'])) {
+
+ // when forwarding as an attachment from the message
+ // list, passed_id is not used, need to get UID(s)
+ // from the query string
+ //
+ if (empty($passed_id) && !empty($fwduid))
+ $ids = explode('_', $fwduid);
+ else
+ $ids = array($passed_id);
- $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, $ids, '$Forwarded', true, false);
+ $aUpdatedMsgs = sqimap_toggle_flag($imap_stream, $ids, '$Forwarded', true, false);
- foreach ($ids as $id) {
- if (isset($aUpdatedMsgs[$id]['FLAGS'])) {
- if (isset($aMailbox['MSG_HEADERS'][$id])) {
- $aMailbox['MSG_HEADERS'][$id]['FLAGS'] = $aMsg['FLAGS'];
+ foreach ($ids as $id) {
+ if (isset($aUpdatedMsgs[$id]['FLAGS'])) {
+ if (isset($aMailbox['MSG_HEADERS'][$id])) {
+ $aMailbox['MSG_HEADERS'][$id]['FLAGS'] = $aMsg['FLAGS'];
+ }
}
}
}
+ break;
}
- break;
- }
- /**
- * Write mailbox with updated seen flag information back to cache.
- */
- if(isset($aUpdatedMsgs[$passed_id])) {
- $mailbox_cache[$iAccount.'_'.$aMailbox['NAME']] = $aMailbox;
- sqsession_register($mailbox_cache,'mailbox_cache');
+ /**
+ * Write mailbox with updated seen flag information back to cache.
+ */
+ if(isset($aUpdatedMsgs[$passed_id])) {
+ $mailbox_cache[$iAccount.'_'.$aMailbox['NAME']] = $aMailbox;
+ sqsession_register($mailbox_cache,'mailbox_cache');
+ }
}
-
}
// final cleanup
//
$composeMessage->purgeAttachments();
+//TODO: completely unclear if should be using $compose_session instead of $session below
+ unset($compose_messages[$session]);
+ sqsession_register($compose_messages,'compose_messages');
sqimap_logout($imap_stream);
}