From e237eec8468e99b65a9160a0a3f07529b92725e3 Mon Sep 17 00:00:00 2001 From: alecpl Date: Fri, 2 Dec 2011 09:58:03 +0000 Subject: - Applied fixes from trunk up to r5526 --- CHANGELOG | 1 + plugins/enigma/lib/enigma_ui.php | 3 - program/include/rcmail.php | 4 +- program/include/rcube_imap.php | 2 +- program/include/rcube_ldap.php | 24 ++--- program/include/rcube_session.php | 13 --- program/steps/mail/compose.inc | 186 ++++++++++++++++++++------------------ program/steps/mail/func.inc | 1 - program/steps/mail/search.inc | 2 +- program/steps/mail/sendmail.inc | 44 ++++----- tests/maildecode.php | 46 ++++++++++ 11 files changed, 180 insertions(+), 146 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index f6f8b0253..cfe92646c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Improved handling of some malformed values encoded with quoted-printable (#1488232) - Add possibility to do LDAP bind before searching for bind DN - Fix handling of empty tags in HTML messages (#1488225) - Add content filter for embedded attachments to protect from XSS on IE (#1487895) diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index b9ccff53d..5901b58d9 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -412,9 +412,6 @@ class enigma_ui private function compose_ui() { - if (!is_array($_SESSION['compose']) || $_SESSION['compose']['id'] != get_input_value('_id', RCUBE_INPUT_GET)) - return; - // Options menu button // @TODO: make this work with non-default skins $this->enigma->add_button(array( diff --git a/program/include/rcmail.php b/program/include/rcmail.php index e06594fcd..6f0ba2ce9 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -453,8 +453,7 @@ class rcmail } // add to the 'books' array for shutdown function - if (!isset($this->address_books[$id])) - $this->address_books[$id] = $contacts; + $this->address_books[$id] = $contacts; return $contacts; } @@ -1228,7 +1227,6 @@ class rcmail // before closing the database connection, write session data if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) { - $this->session->cleanup(); session_write_close(); } diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index a0a5f8189..1c5dd2e3f 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -4162,7 +4162,7 @@ class rcube_imap $input = preg_replace("/\?=\s+=\?/", '?==?', $input); // encoded-word regexp - $re = '/=\?([^?]+)\?([BbQq])\?([^?\n]*)\?=/'; + $re = '/=\?([^?]+)\?([BbQq])\?([^\n]*?)\?=/'; // Find all RFC2047's encoded words if (preg_match_all($re, $input, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index 03347512c..3ec0e5f3b 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -655,14 +655,11 @@ class rcube_ldap extends rcube_addressbook $attrib = $count ? array('dn') : array_values($this->fieldmap); if ($result = @$func($this->conn, $m[1], $filter, - $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit'])) - { + $attrib, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) + ) { $this->_debug("S: ".ldap_count_entries($this->conn, $result)." record(s) for ".$m[1]); - if ($err = ldap_errno($this->conn)) - $this->_debug("S: Error: " .ldap_err2str($err)); } - else - { + else { $this->_debug("S: ".ldap_error($this->conn)); return $group_members; } @@ -1227,15 +1224,14 @@ class rcube_ldap extends rcube_addressbook // only fetch dn for count (should keep the payload low) $attrs = $count ? array('dn') : array_values($this->fieldmap); if ($this->ldap_result = @$function($this->conn, $this->base_dn, $filter, - $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit'])) - { - $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); - if ($err = ldap_errno($this->conn)) - $this->_debug("S: Error: " .ldap_err2str($err)); - return $count ? ldap_count_entries($this->conn, $this->ldap_result) : true; + $attrs, 0, (int)$this->prop['sizelimit'], (int)$this->prop['timelimit']) + ) { + $entries_count = ldap_count_entries($this->conn, $this->ldap_result); + $this->_debug("S: $count_entries record(s)"); + + return $count ? $count_entries : true; } - else - { + else { $this->_debug("S: ".ldap_error($this->conn)); } } diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php index 582b27efa..bd0ce60e4 100644 --- a/program/include/rcube_session.php +++ b/program/include/rcube_session.php @@ -335,19 +335,6 @@ class rcube_session } - /** - * Cleanup session data before saving - */ - public function cleanup() - { - // current compose information is stored in $_SESSION['compose'], move it to $_SESSION['compose_data_'] - if ($compose_id = $_SESSION['compose']['id']) { - $_SESSION['compose_data_'.$compose_id] = $_SESSION['compose']; - $this->remove('compose'); - } - } - - /** * Register additional garbage collector functions * diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 9df25f031..d98452afc 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -25,23 +25,26 @@ define('RCUBE_COMPOSE_FORWARD', 0x0107); define('RCUBE_COMPOSE_DRAFT', 0x0108); define('RCUBE_COMPOSE_EDIT', 0x0109); -$MESSAGE_FORM = NULL; -$MESSAGE = NULL; +$MESSAGE_FORM = null; +$MESSAGE = null; +$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET); +$COMPOSE = null; -$COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GET); -$_SESSION['compose'] = $_SESSION['compose_data_'.$COMPOSE_ID]; +if ($COMPOSE_ID && $_SESSION['compose_data_'.$COMPOSE_ID]) + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; // give replicated session storage some time to synchronize $retries = 0; -while ($COMPOSE_ID && !is_array($_SESSION['compose']) && $RCMAIL->db->is_replicated() && $retries++ < 5) { +while ($COMPOSE_ID && !is_array($COMPOSE) && $RCMAIL->db->is_replicated() && $retries++ < 5) { usleep(500000); $RCMAIL->session->reload(); - $_SESSION['compose'] = $_SESSION['compose_data_'.$COMPOSE_ID]; + if ($_SESSION['compose_data_'.$COMPOSE_ID]) + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; } // Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or // if a compose-ID is given (i.e. when the compose step is opened in a new window/tab). -if (!is_array($_SESSION['compose'])) +if (!is_array($COMPOSE)) { // Infinite redirect prevention in case of broken session (#1487028) if ($COMPOSE_ID) @@ -49,31 +52,33 @@ if (!is_array($_SESSION['compose'])) 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid compose ID"), true, true); - $_SESSION['compose'] = array( - 'id' => uniqid(mt_rand()), - 'param' => request2param(RCUBE_INPUT_GET), + $COMPOSE_ID = uniqid(mt_rand()); + $_SESSION['compose_data_'.$COMPOSE_ID] = array( + 'id' => $COMPOSE_ID, + 'param' => request2param(RCUBE_INPUT_GET), 'mailbox' => $IMAP->get_mailbox_name(), ); + $COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; // process values like "mailto:foo@bar.com?subject=new+message&cc=another" - if ($_SESSION['compose']['param']['to']) { + if ($COMPOSE['param']['to']) { // #1486037: remove "mailto:" prefix - $_SESSION['compose']['param']['to'] = preg_replace('/^mailto:/i', '', $_SESSION['compose']['param']['to']); - $mailto = explode('?', $_SESSION['compose']['param']['to']); + $COMPOSE['param']['to'] = preg_replace('/^mailto:/i', '', $COMPOSE['param']['to']); + $mailto = explode('?', $COMPOSE['param']['to']); if (count($mailto) > 1) { - $_SESSION['compose']['param']['to'] = $mailto[0]; + $COMPOSE['param']['to'] = $mailto[0]; parse_str($mailto[1], $query); foreach ($query as $f => $val) - $_SESSION['compose']['param'][$f] = $val; + $COMPOSE['param'][$f] = $val; } } // select folder where to save the sent message - $_SESSION['compose']['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox'); + $COMPOSE['param']['sent_mbox'] = $RCMAIL->config->get('sent_mbox'); // pipe compose parameters thru plugins - $plugin = $RCMAIL->plugins->exec_hook('message_compose', $_SESSION['compose']); - $_SESSION['compose']['param'] = array_merge($_SESSION['compose']['param'], $plugin['param']); + $plugin = $RCMAIL->plugins->exec_hook('message_compose', $COMPOSE); + $COMPOSE['param'] = array_merge($COMPOSE['param'], $plugin['param']); // add attachments listed by message_compose hook if (is_array($plugin['attachments'])) { @@ -100,18 +105,18 @@ if (!is_array($_SESSION['compose'])) if ($attachment['status'] && !$attachment['abort']) { unset($attachment['data'], $attachment['status'], $attachment['abort']); - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; } } } // check if folder for saving sent messages exists and is subscribed (#1486802) - if ($sent_folder = $_SESSION['compose']['param']['sent_mbox']) { + if ($sent_folder = $COMPOSE['param']['sent_mbox']) { rcmail_check_sent_folder($sent_folder, true); } // redirect to a unique URL with all parameters stored in session - $OUTPUT->redirect(array('_action' => 'compose', '_id' => $_SESSION['compose']['id'])); + $OUTPUT->redirect(array('_action' => 'compose', '_id' => $COMPOSE['id'])); } @@ -121,7 +126,7 @@ $OUTPUT->add_label('nosubject', 'nosenderwarning', 'norecipientwarning', 'nosubj 'messagesaved', 'converting', 'editorwarning', 'searching', 'uploading', 'uploadingmany', 'fileuploaderror'); -$OUTPUT->set_env('compose_id', $COMPOSE_ID); +$OUTPUT->set_env('compose_id', $COMPOSE['id']); // add config parameters to client script if (!empty($CONFIG['drafts_mbox'])) { @@ -135,15 +140,15 @@ $OUTPUT->set_env('top_posting', $RCMAIL->config->get('top_posting', false)); $OUTPUT->set_env('recipients_separator', trim($RCMAIL->config->get('recipients_separator', ','))); // get reference message and set compose mode -if ($msg_uid = $_SESSION['compose']['param']['draft_uid']) { +if ($msg_uid = $COMPOSE['param']['draft_uid']) { $RCMAIL->imap->set_mailbox($CONFIG['drafts_mbox']); $compose_mode = RCUBE_COMPOSE_DRAFT; } -else if ($msg_uid = $_SESSION['compose']['param']['reply_uid']) +else if ($msg_uid = $COMPOSE['param']['reply_uid']) $compose_mode = RCUBE_COMPOSE_REPLY; -else if ($msg_uid = $_SESSION['compose']['param']['forward_uid']) +else if ($msg_uid = $COMPOSE['param']['forward_uid']) $compose_mode = RCUBE_COMPOSE_FORWARD; -else if ($msg_uid = $_SESSION['compose']['param']['uid']) +else if ($msg_uid = $COMPOSE['param']['uid']) $compose_mode = RCUBE_COMPOSE_EDIT; $config_show_sig = $RCMAIL->config->get('show_sig', 1); @@ -175,20 +180,20 @@ if (!empty($msg_uid)) if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $_SESSION['compose']['reply_uid'] = $msg_uid; - $_SESSION['compose']['reply_msgid'] = $MESSAGE->headers->messageID; - $_SESSION['compose']['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); + $COMPOSE['reply_uid'] = $msg_uid; + $COMPOSE['reply_msgid'] = $MESSAGE->headers->messageID; + $COMPOSE['references'] = trim($MESSAGE->headers->references . " " . $MESSAGE->headers->messageID); - if (!empty($_SESSION['compose']['param']['all'])) - $MESSAGE->reply_all = $_SESSION['compose']['param']['all']; + if (!empty($COMPOSE['param']['all'])) + $MESSAGE->reply_all = $COMPOSE['param']['all']; $OUTPUT->set_env('compose_mode', 'reply'); // Save the sent message in the same folder of the message being replied to - if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $_SESSION['compose']['mailbox']) + if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $COMPOSE['mailbox']) && rcmail_check_sent_folder($sent_folder, false) ) { - $_SESSION['compose']['param']['sent_mbox'] = $sent_folder; + $COMPOSE['param']['sent_mbox'] = $sent_folder; } } else if ($compose_mode == RCUBE_COMPOSE_DRAFT) @@ -199,31 +204,31 @@ if (!empty($msg_uid)) $info = rcmail_draftinfo_decode($MESSAGE->headers->others['x-draft-info']); if ($info['type'] == 'reply') - $_SESSION['compose']['reply_uid'] = $info['uid']; + $COMPOSE['reply_uid'] = $info['uid']; else if ($info['type'] == 'forward') - $_SESSION['compose']['forward_uid'] = $info['uid']; + $COMPOSE['forward_uid'] = $info['uid']; - $_SESSION['compose']['mailbox'] = $info['folder']; + $COMPOSE['mailbox'] = $info['folder']; // Save the sent message in the same folder of the message being replied to if ($RCMAIL->config->get('reply_same_folder') && ($sent_folder = $info['folder']) && rcmail_check_sent_folder($sent_folder, false) ) { - $_SESSION['compose']['param']['sent_mbox'] = $sent_folder; + $COMPOSE['param']['sent_mbox'] = $sent_folder; } } if ($MESSAGE->headers->in_reply_to) - $_SESSION['compose']['reply_msgid'] = '<'.$MESSAGE->headers->in_reply_to.'>'; + $COMPOSE['reply_msgid'] = '<'.$MESSAGE->headers->in_reply_to.'>'; - $_SESSION['compose']['references'] = $MESSAGE->headers->references; + $COMPOSE['references'] = $MESSAGE->headers->references; } else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - $_SESSION['compose']['forward_uid'] = $msg_uid; + $COMPOSE['forward_uid'] = $msg_uid; $OUTPUT->set_env('compose_mode', 'forward'); - if (!empty($_SESSION['compose']['param']['attachment'])) + if (!empty($COMPOSE['param']['attachment'])) $MESSAGE->forward_attachment = true; } } @@ -247,8 +252,8 @@ if (count($MESSAGE->identities)) if (!empty($_POST['_from'])) { $MESSAGE->compose['from'] = get_input_value('_from', RCUBE_INPUT_POST); } -else if (!empty($_SESSION['compose']['param']['from'])) { - $MESSAGE->compose['from'] = $_SESSION['compose']['param']['from']; +else if (!empty($COMPOSE['param']['from'])) { + $MESSAGE->compose['from'] = $COMPOSE['param']['from']; } else if (count($MESSAGE->identities)) { $a_recipients = array(); @@ -340,17 +345,17 @@ foreach ($parts as $header) { $decode_header = true; // we have a set of recipients stored is session - if ($header == 'to' && ($mailto_id = $_SESSION['compose']['param']['mailto']) - && $_SESSION['mailto'][$mailto_id] + if ($header == 'to' && ($mailto_id = $COMPOSE['param']['mailto']) + && $COMPOSE[$mailto_id] ) { - $fvalue = urldecode($_SESSION['mailto'][$mailto_id]); + $fvalue = urldecode($COMPOSE[$mailto_id]); $decode_header = false; } else if (!empty($_POST['_'.$header])) { $fvalue = get_input_value('_'.$header, RCUBE_INPUT_POST, TRUE); } - else if (!empty($_SESSION['compose']['param'][$header])) { - $fvalue = $_SESSION['compose']['param'][$header]; + else if (!empty($COMPOSE['param'][$header])) { + $fvalue = $COMPOSE['param'][$header]; } else if ($compose_mode == RCUBE_COMPOSE_REPLY) { // get recipent address(es) out of the message headers @@ -530,7 +535,7 @@ function rcmail_compose_header_from($attrib) $select_from->add(format_email_recipient($sql_arr['email'], $sql_arr['name']), $identity_id); // add signature to array - if (!empty($sql_arr['signature']) && empty($_SESSION['compose']['param']['nosig'])) + if (!empty($sql_arr['signature']) && empty($COMPOSE['param']['nosig'])) { $a_signatures[$identity_id]['text'] = $sql_arr['signature']; $a_signatures[$identity_id]['is_html'] = ($sql_arr['html_signature'] == 1) ? true : false; @@ -584,22 +589,22 @@ function rcmail_compose_editor_mode() function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE; + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE; // use posted message body if (!empty($_POST['_message'])) { $body = get_input_value('_message', RCUBE_INPUT_POST, true); $isHtml = (bool) get_input_value('_is_html', RCUBE_INPUT_POST); } - else if ($_SESSION['compose']['param']['body']) { - $body = $_SESSION['compose']['param']['body']; + else if ($COMPOSE['param']['body']) { + $body = $COMPOSE['param']['body']; $isHtml = false; } // forward as attachment else if ($compose_mode == RCUBE_COMPOSE_FORWARD && $MESSAGE->forward_attachment) { $isHtml = rcmail_compose_editor_mode(); $body = ''; - if (empty($_SESSION['compose']['attachments'])) + if (empty($COMPOSE['attachments'])) rcmail_write_forward_attachment($MESSAGE); } // reply/edit/draft/forward @@ -662,9 +667,9 @@ function rcmail_prepare_message_body() // add blocked.gif attachment (#1486516) if ($isHtml && preg_match('#comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id'], + $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id'], $body); } } @@ -848,10 +853,10 @@ function rcmail_create_reply_body($body, $bodyIsHtml) function rcmail_create_forward_body($body, $bodyIsHtml) { - global $RCMAIL, $MESSAGE; + global $RCMAIL, $MESSAGE, $COMPOSE; // add attachments - if (!isset($_SESSION['compose']['forward_attachments']) && is_array($MESSAGE->mime_parts)) + if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); @@ -910,13 +915,13 @@ function rcmail_create_forward_body($body, $bodyIsHtml) function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $OUTPUT; + global $MESSAGE, $OUTPUT, $COMPOSE; /** * add attachments * sizeof($MESSAGE->mime_parts can be 1 - e.g. attachment, but no text! */ - if (empty($_SESSION['compose']['forward_attachments']) + if (empty($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts) && count($MESSAGE->mime_parts) > 0) { @@ -954,7 +959,7 @@ function rcmail_remove_signature($body) function rcmail_write_compose_attachments(&$message, $bodyIsHtml) { - global $RCMAIL; + global $RCMAIL, $COMPOSE; $cid_map = $messages = array(); foreach ((array)$message->mime_parts as $pid => $part) @@ -976,9 +981,9 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) } if (!$skip && ($attachment = rcmail_save_attachment($message, $pid))) { - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; if ($bodyIsHtml && ($part->content_id || $part->content_location)) { - $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id']; + $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id']; if ($part->content_id) $cid_map['cid:'.$part->content_id] = $url; else @@ -988,7 +993,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) } } - $_SESSION['compose']['forward_attachments'] = true; + $COMPOSE['forward_attachments'] = true; return $cid_map; } @@ -996,14 +1001,14 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) function rcmail_write_inline_attachments(&$message) { - global $RCMAIL; + global $RCMAIL, $COMPOSE; $cid_map = array(); foreach ((array)$message->mime_parts as $pid => $part) { if (($part->content_id || $part->content_location) && $part->filename) { if ($attachment = rcmail_save_attachment($message, $pid)) { - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; - $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$_SESSION['compose']['id']; + $COMPOSE['attachments'][$attachment['id']] = $attachment; + $url = $RCMAIL->comm_path.'&_action=display-attachment&_file=rcmfile'.$attachment['id'].'&_id='.$COMPOSE['id']; if ($part->content_id) $cid_map['cid:'.$part->content_id] = $url; else @@ -1018,7 +1023,7 @@ function rcmail_write_inline_attachments(&$message) // Creates an attachment from the forwarded message function rcmail_write_forward_attachment(&$message) { - global $RCMAIL; + global $RCMAIL, $COMPOSE; if (strlen($message->subject)) { $name = mb_substr($message->subject, 0, 64) . '.eml'; @@ -1045,7 +1050,7 @@ function rcmail_write_forward_attachment(&$message) } $attachment = array( - 'group' => $_SESSION['compose']['id'], + 'group' => $COMPOSE['id'], 'name' => $name, 'mimetype' => 'message/rfc822', 'data' => $data, @@ -1057,7 +1062,7 @@ function rcmail_write_forward_attachment(&$message) if ($attachment['status']) { unset($attachment['data'], $attachment['status'], $attachment['content_id'], $attachment['abort']); - $_SESSION['compose']['attachments'][$attachment['id']] = $attachment; + $COMPOSE['attachments'][$attachment['id']] = $attachment; return true; } else if ($path) { @unlink($path); @@ -1069,6 +1074,8 @@ function rcmail_write_forward_attachment(&$message) function rcmail_save_attachment(&$message, $pid) { + global $COMPOSE; + $rcmail = rcmail::get_instance(); $part = $message->mime_parts[$pid]; $mem_limit = parse_bytes(ini_get('memory_limit')); @@ -1089,7 +1096,7 @@ function rcmail_save_attachment(&$message, $pid) } $attachment = array( - 'group' => $_SESSION['compose']['id'], + 'group' => $COMPOSE['id'], 'name' => $part->filename ? $part->filename : 'Part_'.$pid.'.'.$part->ctype_secondary, 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, 'content_id' => $part->content_id, @@ -1112,11 +1119,13 @@ function rcmail_save_attachment(&$message, $pid) function rcmail_save_image($path, $mimetype='') { + global $COMPOSE; + // handle attachments in memory $data = file_get_contents($path); $attachment = array( - 'group' => $_SESSION['compose']['id'], + 'group' => $COMPOSE['id'], 'name' => rcmail_basename($path), 'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name), 'data' => $data, @@ -1145,11 +1154,11 @@ function rcmail_basename($filename) function rcmail_compose_subject($attrib) { - global $MESSAGE, $compose_mode; - + global $MESSAGE, $COMPOSE, $compose_mode; + list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); - + $attrib['name'] = '_subject'; $attrib['spellcheck'] = 'true'; $textfield = new html_inputfield($attrib); @@ -1178,10 +1187,10 @@ function rcmail_compose_subject($attrib) else if ($compose_mode == RCUBE_COMPOSE_DRAFT || $compose_mode == RCUBE_COMPOSE_EDIT) { $subject = $MESSAGE->subject; } - else if (!empty($_SESSION['compose']['param']['subject'])) { - $subject = $_SESSION['compose']['param']['subject']; + else if (!empty($COMPOSE['param']['subject'])) { + $subject = $COMPOSE['param']['subject']; } - + $out = $form_start ? "$form_start\n" : ''; $out .= $textfield->show($subject); $out .= $form_end ? "\n$form_end" : ''; @@ -1192,17 +1201,16 @@ function rcmail_compose_subject($attrib) function rcmail_compose_attachment_list($attrib) { - global $OUTPUT, $CONFIG; - + global $OUTPUT, $CONFIG, $COMPOSE; + // add ID if not given if (!$attrib['id']) $attrib['id'] = 'rcmAttachmentList'; - + $out = "\n"; $jslist = array(); - if (is_array($_SESSION['compose']['attachments'])) - { + if (is_array($COMPOSE['attachments'])) { if ($attrib['deleteicon']) { $button = html::img(array( 'src' => $CONFIG['skin_path'] . $attrib['deleteicon'], @@ -1212,11 +1220,11 @@ function rcmail_compose_attachment_list($attrib) else $button = Q(rcube_label('delete')); - foreach ($_SESSION['compose']['attachments'] as $id => $a_prop) + foreach ($COMPOSE['attachments'] as $id => $a_prop) { if (empty($a_prop)) continue; - + $out .= html::tag('li', array('id' => 'rcmfile'.$id), html::a(array( 'href' => "#delete", @@ -1229,7 +1237,7 @@ function rcmail_compose_attachment_list($attrib) } if ($attrib['deleteicon']) - $_SESSION['compose']['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; + $COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; if ($attrib['cancelicon']) $OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']); if ($attrib['loadingicon']) @@ -1397,13 +1405,15 @@ function rcmail_editor_selector($attrib) function rcmail_store_target_selection($attrib) { + global $COMPOSE; + $attrib['name'] = '_store_target'; $select = rcmail_mailbox_select(array_merge($attrib, array( 'noselection' => '- '.rcube_label('dontsave').' -', 'folder_filter' => 'mail', 'folder_rights' => 'w', ))); - return $select->show($_SESSION['compose']['param']['sent_mbox'], $attrib); + return $select->show($COMPOSE['param']['sent_mbox'], $attrib); } @@ -1429,14 +1439,14 @@ function rcmail_check_sent_folder($folder, $create=false) function get_form_tags($attrib) { - global $RCMAIL, $MESSAGE_FORM; + global $RCMAIL, $MESSAGE_FORM, $COMPOSE; $form_start = ''; if (!$MESSAGE_FORM) { $hiddenfields = new html_hiddenfield(array('name' => '_task', 'value' => $RCMAIL->task)); $hiddenfields->add(array('name' => '_action', 'value' => 'send')); - $hiddenfields->add(array('name' => '_id', 'value' => $_SESSION['compose']['id'])); + $hiddenfields->add(array('name' => '_id', 'value' => $COMPOSE['id'])); $form_start = empty($attrib['form']) ? $RCMAIL->output->form_tag(array('name' => "form", 'method' => "post")) : ''; $form_start .= $hiddenfields->show(); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index c070dad3a..b0a1e95bd 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1424,7 +1424,6 @@ function rcmail_compose_cleanup($id) $rcmail = rcmail::get_instance(); $rcmail->plugins->exec_hook('attachments_cleanup', array('group' => $id)); $rcmail->session->remove('compose_data_'.$id); - $rcmail->session->remove('compose'); } diff --git a/program/steps/mail/search.inc b/program/steps/mail/search.inc index 593eac427..49f31e0c1 100644 --- a/program/steps/mail/search.inc +++ b/program/steps/mail/search.inc @@ -107,7 +107,7 @@ $search_str = trim($search_str); // execute IMAP search if ($search_str) - $result = $IMAP->search($mbox, $search_str, $imap_charset, $_SESSION['sort_col']); + $IMAP->search($mbox, $search_str, $imap_charset, $_SESSION['sort_col']); // Get the headers $result_h = $IMAP->list_headers($mbox, 1, $_SESSION['sort_col'], $_SESSION['sort_order']); diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index 0fdcd78cd..64deb73d8 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -27,11 +27,11 @@ $OUTPUT->framed = TRUE; $savedraft = !empty($_POST['_draft']) ? true : false; $COMPOSE_ID = get_input_value('_id', RCUBE_INPUT_GPC); -$_SESSION['compose'] = $_SESSION['compose_data_'.$COMPOSE_ID]; +$COMPOSE =& $_SESSION['compose_data_'.$COMPOSE_ID]; /****** checks ********/ -if (!isset($_SESSION['compose']['id'])) { +if (!isset($COMPOSE['id'])) { raise_error(array('code' => 500, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Invalid compose ID"), true, false); @@ -340,20 +340,20 @@ if (!empty($headers['Reply-To'])) { if (!empty($_POST['_followupto'])) { $headers['Mail-Followup-To'] = rcmail_email_input_format(get_input_value('_followupto', RCUBE_INPUT_POST, TRUE, $message_charset)); } -if (!empty($_SESSION['compose']['reply_msgid'])) { - $headers['In-Reply-To'] = $_SESSION['compose']['reply_msgid']; +if (!empty($COMPOSE['reply_msgid'])) { + $headers['In-Reply-To'] = $COMPOSE['reply_msgid']; } // remember reply/forward UIDs in special headers -if (!empty($_SESSION['compose']['reply_uid']) && $savedraft) { - $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $_SESSION['compose']['reply_uid']); +if (!empty($COMPOSE['reply_uid']) && $savedraft) { + $headers['X-Draft-Info'] = array('type' => 'reply', 'uid' => $COMPOSE['reply_uid']); } -else if (!empty($_SESSION['compose']['forward_uid']) && $savedraft) { - $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $_SESSION['compose']['forward_uid']); +else if (!empty($COMPOSE['forward_uid']) && $savedraft) { + $headers['X-Draft-Info'] = array('type' => 'forward', 'uid' => $COMPOSE['forward_uid']); } -if (!empty($_SESSION['compose']['references'])) { - $headers['References'] = $_SESSION['compose']['references']; +if (!empty($COMPOSE['references'])) { + $headers['References'] = $COMPOSE['references']; } if (!empty($_POST['_priority'])) { @@ -374,7 +374,7 @@ $headers['Message-ID'] = $message_id; $headers['X-Sender'] = $from; if (is_array($headers['X-Draft-Info'])) { - $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $_SESSION['compose']['mailbox'])); + $headers['X-Draft-Info'] = rcmail_draftinfo_encode($headers['X-Draft-Info'] + array('folder' => $COMPOSE['mailbox'])); } if (!empty($CONFIG['useragent'])) { $headers['User-Agent'] = $CONFIG['useragent']; @@ -414,12 +414,12 @@ if (!$savedraft) { // Check spelling before send if ($CONFIG['spellcheck_before_send'] && $CONFIG['enable_spellcheck'] - && empty($_SESSION['compose']['spell_checked']) && !empty($message_body) + && empty($COMPOSE['spell_checked']) && !empty($message_body) ) { $spellchecker = new rcube_spellchecker(get_input_value('_lang', RCUBE_INPUT_GPC)); $spell_result = $spellchecker->check($message_body, $isHtml); - $_SESSION['compose']['spell_checked'] = true; + $COMPOSE['spell_checked'] = true; if (!$spell_result) { $result = $isHtml ? $spellchecker->get_words() : $spellchecker->get_xml(); @@ -458,12 +458,12 @@ $MAIL_MIME = new Mail_mime("\r\n"); // Check if we have enough memory to handle the message in it // It's faster than using files, so we'll do this if we only can -if (is_array($_SESSION['compose']['attachments']) && $CONFIG['smtp_server'] +if (is_array($COMPOSE['attachments']) && $CONFIG['smtp_server'] && ($mem_limit = parse_bytes(ini_get('memory_limit')))) { $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB - foreach ($_SESSION['compose']['attachments'] as $id => $attachment) + foreach ($COMPOSE['attachments'] as $id => $attachment) $memory += $attachment['size']; // Yeah, Net_SMTP needs up to 12x more memory, 1.33 is for base64 @@ -527,9 +527,9 @@ else { } // add stored attachments, if any -if (is_array($_SESSION['compose']['attachments'])) +if (is_array($COMPOSE['attachments'])) { - foreach ($_SESSION['compose']['attachments'] as $id => $attachment) { + foreach ($COMPOSE['attachments'] as $id => $attachment) { // This hook retrieves the attachment contents from the file storage backend $attachment = $RCMAIL->plugins->exec_hook('attachment_get', $attachment); @@ -626,10 +626,10 @@ if (!$savedraft) $RCMAIL->user->save_prefs(array('last_message_time' => time())); // set replied/forwarded flag - if ($_SESSION['compose']['reply_uid']) - $IMAP->set_flag($_SESSION['compose']['reply_uid'], 'ANSWERED', $_SESSION['compose']['mailbox']); - else if ($_SESSION['compose']['forward_uid']) - $IMAP->set_flag($_SESSION['compose']['forward_uid'], 'FORWARDED', $_SESSION['compose']['mailbox']); + if ($COMPOSE['reply_uid']) + $IMAP->set_flag($COMPOSE['reply_uid'], 'ANSWERED', $COMPOSE['mailbox']); + else if ($COMPOSE['forward_uid']) + $IMAP->set_flag($COMPOSE['forward_uid'], 'FORWARDED', $COMPOSE['mailbox']); } // End of SMTP Delivery Block @@ -729,7 +729,7 @@ if ($savedraft) { $draftuids = $IMAP->search_once($CONFIG['drafts_mbox'], 'HEADER Message-ID '.$msgid, true); $saved = $draftuids[0]; } - $_SESSION['compose']['param']['draft_uid'] = $saved; + $COMPOSE['param']['draft_uid'] = $saved; // display success $OUTPUT->show_message('messagesaved', 'confirmation'); diff --git a/tests/maildecode.php b/tests/maildecode.php index 7d67352c3..664161cce 100644 --- a/tests/maildecode.php +++ b/tests/maildecode.php @@ -84,4 +84,50 @@ class rcube_test_maildecode extends UnitTestCase } } + /** + * Test decoding of header values + * Uses rcube_imap::decode_mime_string() + */ + function test_header_decode_qp() + { + $test = array( + // #1488232: invalid character "?" + 'quoted-printable (1)' => array( + 'in' => '=?utf-8?Q?Certifica=C3=A7=C3=A3??=', + 'out' => 'Certifica=C3=A7=C3=A3?', + ), + 'quoted-printable (2)' => array( + 'in' => '=?utf-8?Q?Certifica=?= =?utf-8?Q?C3=A7=C3=A3?=', + 'out' => 'Certifica=C3=A7=C3=A3', + ), + 'quoted-printable (3)' => array( + 'in' => '=?utf-8?Q??= =?utf-8?Q??=', + 'out' => '', + ), + 'quoted-printable (4)' => array( + 'in' => '=?utf-8?Q??= a =?utf-8?Q??=', + 'out' => ' a ', + ), + 'quoted-printable (5)' => array( + 'in' => '=?utf-8?Q?a?= =?utf-8?Q?b?=', + 'out' => 'ab', + ), + 'quoted-printable (6)' => array( + 'in' => '=?utf-8?Q? ?= =?utf-8?Q?a?=', + 'out' => ' a', + ), + 'quoted-printable (7)' => array( + 'in' => '=?utf-8?Q?___?= =?utf-8?Q?a?=', + 'out' => ' a', + ), + ); + + foreach ($test as $idx => $item) { + $res = $this->app->imap->decode_mime_string($item['in'], 'UTF-8'); + $res = quoted_printable_encode($res); + + $this->assertEqual($item['out'], $res, "Header decoding for: " . $idx); + } + + } } -- cgit v1.2.3