diff options
author | thomascube <thomas@roundcube.net> | 2006-08-18 12:48:33 +0000 |
---|---|---|
committer | thomascube <thomas@roundcube.net> | 2006-08-18 12:48:33 +0000 |
commit | 8d4bcda874962d81d9b1a86480538b40834d8040 (patch) | |
tree | 91d6a6cee9b1e06f38df2e814d64502d19a6470c /program | |
parent | 89406f36c20e4d785bfb35c68e87475329cfbaf5 (diff) |
Re-built message parsing (Bug #1327068)
Diffstat (limited to 'program')
-rw-r--r-- | program/include/main.inc | 2 | ||||
-rw-r--r-- | program/include/rcube_imap.inc | 326 | ||||
-rw-r--r-- | program/include/rcube_shared.inc | 4 | ||||
-rw-r--r-- | program/steps/mail/compose.inc | 304 | ||||
-rw-r--r-- | program/steps/mail/func.inc | 263 | ||||
-rw-r--r-- | program/steps/mail/get.inc | 80 | ||||
-rw-r--r-- | program/steps/mail/rss.inc | 6 | ||||
-rw-r--r-- | program/steps/mail/show.inc | 76 | ||||
-rw-r--r-- | program/steps/mail/viewsource.inc | 7 |
9 files changed, 633 insertions, 435 deletions
diff --git a/program/include/main.inc b/program/include/main.inc index c52b671e1..887668b47 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -1788,7 +1788,7 @@ function rcmail_charset_selector($attrib) */ function console($msg) { - if (is_string($msg)) + if (!is_string($msg)) $msg = var_export($msg, true); if (!($GLOBALS['CONFIG']['debug_level'] & 4)) diff --git a/program/include/rcube_imap.inc b/program/include/rcube_imap.inc index 9c93f628a..185565ca2 100644 --- a/program/include/rcube_imap.inc +++ b/program/include/rcube_imap.inc @@ -709,7 +709,14 @@ class rcube_imap } - // return sorted array of message UIDs + /** + * Return sorted array of message UIDs + * + * @param string Mailbox to get index from + * @param string Sort column + * @param string Sort order [ASC, DESC] + * @return array Indexed array with message ids + */ function message_index($mbox_name='', $sort_field=NULL, $sort_order=NULL) { if ($sort_field!=NULL) @@ -780,7 +787,6 @@ class rcube_imap // message in cache at correct position if ($cache_index[$id] == $uid) { -// console("$id / $uid: OK"); unset($cache_index[$id]); continue; } @@ -788,21 +794,17 @@ class rcube_imap // message in cache but in wrong position if (in_array((string)$uid, $cache_index, TRUE)) { -// console("$id / $uid: Moved"); unset($cache_index[$id]); } // other message at this position if (isset($cache_index[$id])) { -// console("$id / $uid: Delete"); $this->remove_message_cache($cache_key, $id); unset($cache_index[$id]); } -// console("$id / $uid: Add"); - // fetch complete headers and add to cache $headers = iil_C_FetchHeader($this->conn, $mailbox, $id); $this->add_message_cache($cache_key, $headers->id, $headers); @@ -867,12 +869,21 @@ class rcube_imap } + /** + * Return message headers object of a specific message + * + * @param int Message ID + * @param string Mailbox to read from + * @param boolean True if $id is the message UID + * @return object Message headers representation + */ function get_headers($id, $mbox_name=NULL, $is_uid=TRUE) { $mailbox = $mbox_name ? $this->_mod_mailbox($mbox_name) : $this->mailbox; + $uid = $is_uid ? $id : $this->_id2uid($id); // get cached headers - if ($is_uid && ($headers = $this->get_cached_message($mailbox.'.msg', $id))) + if ($uid && ($headers = $this->get_cached_message($mailbox.'.msg', $uid))) return $headers; $msg_id = $is_uid ? $this->_uid2id($id) : $id; @@ -886,25 +897,246 @@ class rcube_imap } - function get_body($uid, $part=1) + /** + * Fetch body structure from the IMAP server and build + * an object structure similar to the one generated by PEAR::Mail_mimeDecode + * + * @param Int Message UID to fetch + * @return object Standard object tree or False on failure + */ + function &get_structure($uid) { if (!($msg_id = $this->_uid2id($uid))) return FALSE; $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); $structure = iml_GetRawStructureArray($structure_str); - $body = iil_C_FetchPartBody($this->conn, $this->mailbox, $msg_id, $part); + $struct = false; + + // parse structure and add headers + if (!empty($structure)) + { + $this->_msg_id = $msg_id; + $headers = $this->get_headers($msg_id, NULL, FALSE); + + $struct = &$this->_structure_part($structure); + $struct->headers = get_object_vars($headers); + + // don't trust given content-type + if (empty($struct->parts)) + { + $struct->mime_id = '1'; + $struct->mimetype = strtolower($struct->headers['ctype']); + list($struct->ctype_primary, $struct->ctype_secondary) = explode('/', $struct->mimetype); + } + } + + return $struct; + } + + + /** + * Build message part object + * + * @access private + */ + function &_structure_part($part, $count=0, $parent='') + { + $struct = new rcube_message_part; + $struct->mime_id = empty($parent) ? (string)$count : "$parent.$count"; + + // multipart + if (is_array($part[0])) + { + $struct->ctype_primary = 'multipart'; + + // find first non-array entry + for ($i=1; count($part); $i++) + if (!is_array($part[$i])) + { + $struct->ctype_secondary = strtolower($part[$i]); + break; + } + + $struct->mimetype = 'multipart/'.$struct->ctype_secondary; + + $struct->parts = array(); + for ($i=0, $count=0; $i<count($part); $i++) + if (is_array($part[$i]) && count($part[$i]) > 5) + $struct->parts[] = $this->_structure_part($part[$i], ++$count, $struct->mime_id); + + return $struct; + } + + + // regular part + $struct->ctype_primary = strtolower($part[0]); + $struct->ctype_secondary = strtolower($part[1]); + $struct->mimetype = $struct->ctype_primary.'/'.$struct->ctype_secondary; + + // read content type parameters + if (is_array($part[2])) + { + $struct->ctype_parameters = array(); + for ($i=0; $i<count($part[2]); $i+=2) + $struct->ctype_parameters[strtolower($part[2][$i])] = $part[2][$i+1]; + + if (isset($struct->ctype_parameters['charset'])) + $struct->charset = $struct->ctype_parameters['charset']; + } + + // read content encoding + if (!empty($part[5]) && $part[5]!='NIL') + { + $struct->encoding = strtolower($part[5]); + $struct->headers['content-transfer-encoding'] = $struct->encoding; + } + + // get part size + if (!empty($part[6]) && $part[6]!='NIL') + $struct->size = intval($part[6]); + + // read part disposition + $di = count($part) - 3; + if (is_array($part[$di])) + { + $struct->disposition = strtolower($part[$di][0]); + + if (is_array($part[$di][1])) + for ($n=0; $n<count($part[$di][1]); $n+=2) + $struct->d_parameters[strtolower($part[$di][1][$n])] = $part[$di][1][$n+1]; + } + + // get child parts + if (is_array($part[8]) && $di != 8) + { + $struct->parts = array(); + for ($i=0, $count=0; $i<count($part[8]); $i++) + if (is_array($part[8][$i]) && count($part[8][$i]) > 5) + $struct->parts[] = $this->_structure_part($part[8][$i], ++$count, $struct->mime_id); + } + + // get part ID + if (!empty($part[3]) && $part[3]!='NIL') + { + $struct->content_id = $part[3]; + $struct->headers['content-id'] = $part[3]; + + if (empty($struct->disposition)) + $struct->disposition = 'inline'; + } + + // fetch message headers if message/rfc822 + if ($struct->ctype_primary=='message') + { + $headers = iil_C_FetchPartBody($this->conn, $this->mailbox, $this->_msg_id, $struct->mime_id.'.HEADER'); + $struct->headers = $this->_parse_headers($headers); + } + + return $struct; + } + + + /** + * Return a flat array with references to all parts, indexed by part numbmers + * + * @param object Message body structure + * @return Array with part number -> object pairs + */ + function get_mime_numbers(&$structure) + { + $a_parts = array(); + $this->_get_part_numbers($structure, $a_parts); + return $a_parts; + } + + + /** + * Helper method for recursive calls + * + * @access + */ + function _get_part_numbers(&$part, &$a_parts) + { + if ($part->mime_id) + $a_parts[$part->mime_id] = &$part; + + if (is_array($part->parts)) + for ($i=0; $i<count($part->parts); $i++) + $this->_get_part_numbers($part->parts[$i], &$a_parts); + } + - $encoding = iml_GetPartEncodingCode($structure, $part); + /** + * Fetch message body of a specific message from the server + * + * @param int Message UID + * @param string Part number + * @param object Part object created by get_structure() + * @param mixed True to print part, ressource to write part contents in + * @return Message/part body if not printed + */ + function &get_message_part($uid, $part=1, $o_part=NULL, $print=NULL) + { + if (!($msg_id = $this->_uid2id($uid))) + return FALSE; - if ($encoding==3) $body = $this->mime_decode($body, 'base64'); - else if ($encoding==4) $body = $this->mime_decode($body, 'quoted-printable'); + // get part encoding if not provided + if (!is_object($o_part)) + { + $structure_str = iil_C_FetchStructureString($this->conn, $this->mailbox, $msg_id); + $structure = iml_GetRawStructureArray($structure_str); + $part_type = iml_GetPartTypeCode($structure, $part); + $o_part = new rcube_message_part; + $o_part->ctype_primary = $part_type==0 ? 'text' : ($part_type==2 ? 'message' : 'other'); + $o_part->encoding = strtolower(iml_GetPartEncodingString($structure, $part)); + $o_part->charset = iml_GetPartCharset($structure, $part); + } + + // TODO: Add caching for message parts + + if ($print) + { + iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, ($o_part->encoding=='base64'?3:2)); + $body = TRUE; + } + else + { + $body = iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, $part, 1); + + // decode part body + if ($o_part->encoding=='base64' || $o_part->encoding=='quoted-printable') + $body = $this->mime_decode($body, $o_part->encoding); + + // convert charset (if text or message part) + if (!empty($o_part->charset) && ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message') && !stristr($body, 'charset=')) + $body = rcube_charset_convert($body, $o_part->charset); + } return $body; } - function get_raw_body($uid) + /** + * Fetch message body of a specific message from the server + * + * @param int Message UID + * @return Message/part body + * @see ::get_message_part() + */ + function &get_body($uid, $part=1) + { + return $this->get_message_part($uid, $part); + } + + + /** + * Returns the whole message source as string + * + * @param int Message UID + * @return Message source string + */ + function &get_raw_body($uid) { if (!($msg_id = $this->_uid2id($uid))) return FALSE; @@ -914,10 +1146,31 @@ class rcube_imap return $body; } + + /** + * Sends the whole message source to stdout + * + * @param int Message UID + */ + function print_raw_body($uid) + { + if (!($msg_id = $this->_uid2id($uid))) + return FALSE; - // set message flag to one or several messages - // possible flags are: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT + print iil_C_FetchPartHeader($this->conn, $this->mailbox, $msg_id, NULL); + flush(); + iil_C_HandlePartBody($this->conn, $this->mailbox, $msg_id, NULL, 2); + } + + + /** + * Set message flag to one or several messages + * + * @param mixed Message UIDs as array or as comma-separated string + * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT + * @return True on success, False on failure + */ function set_flag($uids, $flag) { $flag = strtoupper($flag); @@ -1589,7 +1842,7 @@ class rcube_imap } - function get_cached_message($key, $uid, $body=FALSE) + function &get_cached_message($key, $uid, $body=FALSE) { if (!$this->caching_enabled) return FALSE; @@ -2048,6 +2301,27 @@ class rcube_imap } + // split RFC822 header string into an associative array + function _parse_headers($headers) + { + $a_headers = array(); + $lines = explode("\n", $headers); + $c = count($lines); + for ($i=0; $i<$c; $i++) + { + if ($p = strpos($lines[$i], ': ')) + { + $field = strtolower(substr($lines[$i], 0, $p)); + $value = trim(substr($lines[$i], $p+1)); + if (!empty($value)) + $a_headers[$field] = $value; + } + } + + return $a_headers; + } + + function _parse_address_list($str) { $a = $this->_explode_quoted_string(',', $str); @@ -2093,6 +2367,25 @@ class rcube_imap } +/** + * Class representing a message part + */ +class rcube_message_part +{ + var $mime_id = ''; + var $ctype_primary = 'text'; + var $ctype_secondary = 'plain'; + var $mimetype = 'text/plain'; + var $disposition = ''; + var $encoding = '8bit'; + var $charset = ''; + var $size = 0; + var $headers = array(); + var $d_parameters = array(); + var $ctype_parameters = array(); + +} + /** * rcube_header_sorter @@ -2233,4 +2526,5 @@ function quoted_printable_encode($input, $line_max=76, $space_conv=false) return trim($output); } + ?> diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index eab175b65..768ae3f40 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -33,7 +33,7 @@ class rcube_html_page var $script_tag_file = "<script type=\"text/javascript\" src=\"%s%s\"></script>\n"; var $script_tag = "<script type=\"text/javascript\">\n<!--\n%s\n\n//-->\n</script>\n"; - var $default_template = "<html>\n<body></body>\n</html>"; + var $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>"; var $title = ''; var $header = ''; @@ -116,7 +116,7 @@ class rcube_html_page function write($templ='', $base_path='') { $output = empty($templ) ? $this->default_template : trim($templ); - + // set default page title if (!strlen($this->title)) $this->title = 'RoundCube Mail'; diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 639ea684e..f9ea876b7 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -19,9 +19,14 @@ */ - require_once('Mail/mimeDecode.php'); +// define constants for message compose mode +define('RCUBE_COMPOSE_REPLY', 0x0106); +define('RCUBE_COMPOSE_FORWARD', 0x0107); +define('RCUBE_COMPOSE_DRAFT', 0x0108); + + // remove an attachment if ($_action=='remove-attachment' && preg_match('/^rcmfile([0-9]+)$/', $_GET['_file'], $regs)) { @@ -38,9 +43,7 @@ if ($_action=='remove-attachment' && preg_match('/^rcmfile([0-9]+)$/', $_GET['_f $MESSAGE_FORM = NULL; -$REPLY_MESSAGE = NULL; -$FORWARD_MESSAGE = NULL; -$DRAFT_MESSAGE = NULL; +$MESSAGE = NULL; // nothing below is called during message composition, only at "new/forward/reply/draft" initialization // since there are many ways to leave the compose page improperly, it seems necessary to clean-up an old @@ -53,46 +56,42 @@ $_SESSION['compose'] = array('id' => uniqid(rand())); rcube_add_label('nosubject', 'norecipientwarning', 'nosubjectwarning', 'nobodywarning', 'notsentwarning', 'savingmessage', 'sendingmessage', 'messagesaved'); -if ($_GET['_reply_uid'] || $_GET['_forward_uid'] || $_GET['_draft_uid']) - { - $msg_uid = ($_GET['_reply_uid'] ? $_GET['_reply_uid'] : ($_GET['_forward_uid'] ? $_GET['_forward_uid'] : $_GET['_draft_uid'])); +// get reference message and set compose mode +if ($msg_uid = get_input_value('_reply_uid', RCUBE_INPUT_GET)) + $compose_mode = RCUBE_COMPOSE_REPLY; +else if ($msg_uid = get_input_value('_forward_uid', RCUBE_INPUT_GET)) + $compose_mode = RCUBE_COMPOSE_FORWARD; +else if ($msg_uid = get_input_value('_draft_uid', RCUBE_INPUT_GET)) + $compose_mode = RCUBE_COMPOSE_DRAFT; - // similar as in program/steps/mail/show.inc - $MESSAGE = array(); - $MESSAGE['headers'] = $IMAP->get_headers($msg_uid); - - $MESSAGE['source'] = rcmail_message_source($msg_uid); - - $mmd = new Mail_mimeDecode($MESSAGE['source']); - $MESSAGE['structure'] = $mmd->decode(array('include_bodies' => TRUE, - 'decode_headers' => TRUE, - 'decode_bodies' => FALSE)); +if (!empty($msg_uid)) + { + // similar as in program/steps/mail/show.inc + $MESSAGE = array('UID' => $msg_uid); + $MESSAGE['headers'] = &$IMAP->get_headers($msg_uid); + $MESSAGE['structure'] = &$IMAP->get_structure($msg_uid); $MESSAGE['subject'] = $IMAP->decode_header($MESSAGE['headers']->subject); - $MESSAGE['parts'] = $mmd->getMimeNumbers($MESSAGE['structure']); + $MESSAGE['parts'] = $IMAP->get_mime_numbers($MESSAGE['structure']); - if ($_GET['_reply_uid']) + if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $REPLY_MESSAGE = &$MESSAGE; - $_SESSION['compose']['reply_uid'] = $_GET['_reply_uid']; - $_SESSION['compose']['reply_msgid'] = $REPLY_MESSAGE['headers']->messageID; - $_SESSION['compose']['references'] = $REPLY_MESSAGE['headers']->reference; - $_SESSION['compose']['references'] .= !empty($REPLY_MESSAGE['headers']->reference) ? ' ' : ''; - $_SESSION['compose']['references'] .= $REPLY_MESSAGE['headers']->messageID; - - if ($_GET['_all']) - $REPLY_MESSAGE['reply_all'] = 1; - + $_SESSION['compose']['reply_uid'] = $msg_uid; + $_SESSION['compose']['reply_msgid'] = $MESSAGE['headers']->messageID; + $_SESSION['compose']['references'] = $MESSAGE['headers']->reference; + $_SESSION['compose']['references'] .= !empty($MESSAGE['headers']->reference) ? ' ' : ''; + $_SESSION['compose']['references'] .= $MESSAGE['headers']->messageID; + + if (!empty($_GET['_all'])) + $MESSAGE['reply_all'] = 1; } - else if ($_GET['_forward_uid']) + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - $FORWARD_MESSAGE = $MESSAGE; - $_SESSION['compose']['forward_uid'] = $_GET['_forward_uid']; + $_SESSION['compose']['forward_uid'] = $msg_uid; } - else + else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { - $DRAFT_MESSAGE = $MESSAGE; - $_SESSION['compose']['draft_uid'] = $_GET['_draft_uid']; + $_SESSION['compose']['draft_uid'] = $msg_uid; } } @@ -102,7 +101,7 @@ if ($_GET['_reply_uid'] || $_GET['_forward_uid'] || $_GET['_draft_uid']) function rcmail_compose_headers($attrib) { - global $IMAP, $REPLY_MESSAGE, $DRAFT_MESSAGE, $DB; + global $IMAP, $MESSAGE, $DB, $compose_mode; static $sa_recipients = array(); list($form_start, $form_end) = get_form_tags($attrib); @@ -137,7 +136,7 @@ function rcmail_compose_headers($attrib) $fvalue = join(', ', $a_recipients); } else if (!empty($_GET['_to'])) - $fvalue = $_GET['_to']; + $fvalue = get_input_value('_to', RCUBE_INPUT_GET); case 'cc': if (!$fname) @@ -164,28 +163,24 @@ function rcmail_compose_headers($attrib) if ($fname && !empty($_POST[$fname])) $fvalue = get_input_value($fname, RCUBE_INPUT_POST, TRUE); - else if ($header && is_object($REPLY_MESSAGE['headers'])) + + else if ($header && $compose_mode == RCUBE_COMPOSE_REPLY) { // get recipent address(es) out of the message headers - if ($header=='to' && $REPLY_MESSAGE['headers']->replyto) - $fvalue = $IMAP->decode_header($REPLY_MESSAGE['headers']->replyto); + if ($header=='to' && !empty($MESSAGE['headers']->replyto)) + $fvalue = $IMAP->decode_header($MESSAGE['headers']->replyto); - else if ($header=='to' && $REPLY_MESSAGE['headers']->from) - $fvalue = $IMAP->decode_header($REPLY_MESSAGE['headers']->from); + else if ($header=='to' && !empty($MESSAGE['headers']->from)) + $fvalue = $IMAP->decode_header($MESSAGE['headers']->from); // add recipent of original message if reply to all - else if ($header=='cc' && $REPLY_MESSAGE['reply_all']) + else if ($header=='cc' && !empty($MESSAGE['reply_all'])) { - if ($IMAP->decode_header($REPLY_MESSAGE['headers']->to)) - $fvalue .= $IMAP->decode_header($REPLY_MESSAGE['headers']->to); - - if ($IMAP->decode_header($REPLY_MESSAGE['headers']->cc)) - { - if($fvalue) - $fvalue .= ', '; + if ($v = $IMAP->decode_header($MESSAGE['headers']->to)) + $fvalue .= $v; - $fvalue .= $IMAP->decode_header($REPLY_MESSAGE['headers']->cc); - } + if ($v = $IMAP->decode_header($MESSAGE['headers']->cc)) + $fvalue .= (!empty($fvalue) ? ', ' : '') . $v; } // split recipients and put them back together in a unique way @@ -195,7 +190,7 @@ function rcmail_compose_headers($attrib) $fvalue = ''; foreach ($to_addresses as $addr_part) { - if (!in_array($addr_part['mailto'], $sa_recipients) && (!$REPLY_MESSAGE['FROM'] || !in_array($addr_part['mailto'], $REPLY_MESSAGE['FROM']))) + if (!in_array($addr_part['mailto'], $sa_recipients) && (!$MESSAGE['FROM'] || !in_array($addr_part['mailto'], $MESSAGE['FROM']))) { $fvalue .= (strlen($fvalue) ? ', ':'').$addr_part['string']; $sa_recipients[] = $addr_part['mailto']; @@ -203,17 +198,17 @@ function rcmail_compose_headers($attrib) } } } - else if ($header && is_object($DRAFT_MESSAGE['headers'])) + else if ($header && $compose_mode == RCUBE_COMPOSE_DRAFT) { // get drafted headers - if ($header=='to' && $DRAFT_MESSAGE['headers']->to) - $fvalue = $IMAP->decode_header($DRAFT_MESSAGE['headers']->to); + if ($header=='to' && !empty($MESSAGE['headers']->to)) + $fvalue = $IMAP->decode_header($MESSAGE['headers']->to); - if ($header=='cc' && $DRAFT_MESSAGE['headers']->cc) - $fvalue = $IMAP->decode_header($DRAFT_MESSAGE['headers']->cc); + if ($header=='cc' && !empty($MESSAGE['headers']->cc)) + $fvalue = $IMAP->decode_header($MESSAGE['headers']->cc); - if ($header=='bcc' && $DRAFT_MESSAGE['headers']->bcc) - $fvalue = $IMAP->decode_header($DRAFT_MESSAGE['headers']->bcc); + if ($header=='bcc' && !empty($MESSAGE['headers']->bcc)) + $fvalue = $IMAP->decode_header($MESSAGE['headers']->bcc); } @@ -241,7 +236,7 @@ function rcmail_compose_headers($attrib) function rcmail_compose_header_from($attrib) { - global $IMAP, $REPLY_MESSAGE, $DRAFT_MESSAGE, $DB, $OUTPUT, $JS_OBJECT_NAME; + global $IMAP, $MESSAGE, $DB, $OUTPUT, $JS_OBJECT_NAME, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -251,20 +246,20 @@ function rcmail_compose_header_from($attrib) // extract all recipients of the reply-message $a_recipients = array(); - if ($REPLY_MESSAGE && is_object($REPLY_MESSAGE['headers'])) + if ($compose_mode == RCUBE_COMPOSE_REPLY && is_object($MESSAGE['headers'])) { - $REPLY_MESSAGE['FROM'] = array(); + $MESSAGE['FROM'] = array(); - $a_to = $IMAP->decode_address_list($REPLY_MESSAGE['headers']->to); + $a_to = $IMAP->decode_address_list($MESSAGE['headers']->to); foreach ($a_to as $addr) { if (!empty($addr['mailto'])) $a_recipients[] = $addr['mailto']; } - if (!empty($REPLY_MESSAGE['headers']->cc)) + if (!empty($MESSAGE['headers']->cc)) { - $a_cc = $IMAP->decode_address_list($REPLY_MESSAGE['headers']->cc); + $a_cc = $IMAP->decode_address_list($MESSAGE['headers']->cc); foreach ($a_cc as $addr) { if (!empty($addr['mailto'])) @@ -301,17 +296,17 @@ function rcmail_compose_header_from($attrib) if (in_array($sql_arr['email'], $a_recipients)) $from_id = $sql_arr['identity_id']; - if ($REPLY_MESSAGE && is_array($REPLY_MESSAGE['FROM'])) - $REPLY_MESSAGE['FROM'][] = $sql_arr['email']; + if ($compose_mode == RCUBE_COMPOSE_REPLY && is_array($MESSAGE['FROM'])) + $MESSAGE['FROM'][] = $sql_arr['email']; - if (strstr($DRAFT_MESSAGE['headers']->from,$sql_arr['email'])) + if ($compose_mode == RCUBE_COMPOSE_DRAFT && strstr($MESSAGE['headers']->from, $sql_arr['email'])) $from_id = $sql_arr['identity_id']; } // overwrite identity selection with post parameter if (isset($_POST['_from'])) - $from_id = $_POST['_from']; + $from_id = get_input_value('_from', RCUBE_INPUT_POST); $out = $select_from->show($from_id); @@ -335,7 +330,7 @@ function rcmail_compose_header_from($attrib) function rcmail_compose_body($attrib) { - global $CONFIG, $OUTPUT, $REPLY_MESSAGE, $FORWARD_MESSAGE, $DRAFT_MESSAGE, $JS_OBJECT_NAME; + global $CONFIG, $OUTPUT, $MESSAGE, $JS_OBJECT_NAME, $compose_mode; list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -353,32 +348,32 @@ function rcmail_compose_body($attrib) $body = get_input_value('_message', RCUBE_INPUT_POST, TRUE); // compose reply-body - else if (is_array($REPLY_MESSAGE['parts'])) + else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - $body = rcmail_first_text_part($REPLY_MESSAGE['parts']); + $body = rcmail_first_text_part($MESSAGE); if (strlen($body)) $body = rcmail_create_reply_body($body); } // forward message body inline - else if (is_array($FORWARD_MESSAGE['parts'])) + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - $body = rcmail_first_text_part($FORWARD_MESSAGE['parts']); + $body = rcmail_first_text_part($MESSAGE); if (strlen($body)) $body = rcmail_create_forward_body($body); } // forward message body inline - else if (is_array($DRAFT_MESSAGE['parts'])) + else if ($compose_mode == RCUBE_COMPOSE_DRAFT) { - $body = rcmail_first_text_part($DRAFT_MESSAGE['parts']); + $body = rcmail_first_text_part($MESSAGE); if (strlen($body)) $body = rcmail_create_draft_body($body); } $out = $form_start ? "$form_start\n" : ''; - $saveid = new hiddenfield(array('name' => '_draft_saveid', 'value' => str_replace(array('<','>'),"",$DRAFT_MESSAGE['headers']->messageID) )); + $saveid = new hiddenfield(array('name' => '_draft_saveid', 'value' => str_replace(array('<','>'),"",$MESSAGE['headers']->messageID) )); $out .= $saveid->show(); $drafttoggle = new hiddenfield(array('name' => '_draft', 'value' => 'yes')); @@ -419,7 +414,7 @@ function rcmail_compose_body($attrib) function rcmail_create_reply_body($body) { - global $IMAP, $REPLY_MESSAGE; + global $IMAP, $MESSAGE; // soft-wrap message first $body = wordwrap($body, 75); @@ -440,8 +435,8 @@ function rcmail_create_reply_body($body) // add title line $pefix = sprintf("\n\n\nOn %s, %s wrote:\n", - $REPLY_MESSAGE['headers']->date, - $IMAP->decode_header($REPLY_MESSAGE['headers']->from)); + $MESSAGE['headers']->date, + $IMAP->decode_header($MESSAGE['headers']->from)); // try to remove the signature @@ -457,111 +452,80 @@ function rcmail_create_reply_body($body) function rcmail_create_forward_body($body) { - global $IMAP, $FORWARD_MESSAGE; + global $IMAP, $MESSAGE; // soft-wrap message first $body = wordwrap($body, 80); $prefix = sprintf("\n\n\n-------- Original Message --------\nSubject: %s\nDate: %s\nFrom: %s\nTo: %s\n\n", - $FORWARD_MESSAGE['subject'], - $FORWARD_MESSAGE['headers']->date, - $IMAP->decode_header($FORWARD_MESSAGE['headers']->from), - $IMAP->decode_header($FORWARD_MESSAGE['headers']->to)); - + $MESSAGE['subject'], + $MESSAGE['headers']->date, + $IMAP->decode_header($MESSAGE['headers']->from), + $IMAP->decode_header($MESSAGE['headers']->to)); + // add attachments - if (!isset($_SESSION['compose']['forward_attachments']) && is_array($FORWARD_MESSAGE['parts']) && sizeof($FORWARD_MESSAGE['parts'])>1) - { - $temp_dir = rcmail_create_compose_tempdir(); - - if (!is_array($_SESSION['compose']['attachments'])) - $_SESSION['compose']['attachments'] = array(); - - foreach ($FORWARD_MESSAGE['parts'] as $part) - { - if ($part->disposition=='attachment' || $part->disposition=='inline' || $part->headers['content-id'] || - (empty($part->disposition) && ($part->d_parameters['filename'] || $part->ctype_parameters['name']))) - { - $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); - if ($fp = fopen($tmp_path, 'w')) - { - fwrite($fp, $IMAP->mime_decode($part->body, $part->headers['content-transfer-encoding'])); - fclose($fp); - - if ($part->d_parameters['filename']) - $_SESSION['compose']['attachments'][] = array('name' => $part->d_parameters['filename'], - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, - 'path' => $tmp_path); - - else if ($part->ctype_parameters['name']) - $_SESSION['compose']['attachments'][] = array('name' => $part->ctype_parameters['name'], - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, - 'path' => $tmp_path); - - else if ($part->headers['content-description']) - $_SESSION['compose']['attachments'][] = array('name' => $part->headers['content-description'], - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, - 'path' => $tmp_path); - } - } - } - - $_SESSION['compose']['forward_attachments'] = TRUE; - } + if (!isset($_SESSION['compose']['forward_attachments']) && + is_array($MESSAGE['parts']) && sizeof($MESSAGE['parts'])>1) + rcmail_write_compose_attachments($MESSAGE); return $prefix.$body; } + function rcmail_create_draft_body($body) { - global $IMAP, $DRAFT_MESSAGE; + global $IMAP, $MESSAGE; // add attachments - if (!isset($_SESSION['compose']['forward_attachments']) && is_array($DRAFT_MESSAGE['parts']) && sizeof($DRAFT_MESSAGE['parts'])>1) - { - $temp_dir = rcmail_create_compose_tempdir(); + if (!isset($_SESSION['compose']['forward_attachments']) && + is_array($MESSAGE['parts']) && sizeof($MESSAGE['parts'])>1) + rcmail_write_compose_attachments($MESSAGE); - if (!is_array($_SESSION['compose']['attachments'])) - $_SESSION['compose']['attachments'] = array(); + return $body; + } + - foreach ($DRAFT_MESSAGE['parts'] as $part) +function rcmail_write_compose_attachments(&$message) + { + global $IMAP; + + $temp_dir = rcmail_create_compose_tempdir(); + + if (!is_array($_SESSION['compose']['attachments'])) + $_SESSION['compose']['attachments'] = array(); + + foreach ($message['parts'] as $pid => $part) + { + if ($part->ctype_primary != 'message' && $part->ctype_primary != 'text' && + ($part->disposition=='attachment' || $part->disposition=='inline' || $part->headers['content-id'] || + (empty($part->disposition) && ($part->d_parameters['filename'] || $part->ctype_parameters['name'])))) { - if ($part->disposition=='attachment' || $part->disposition=='inline' || $part->headers['content-id'] || - (empty($part->disposition) && ($part->d_parameters['filename'] || $part->ctype_parameters['name']))) + $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); + if ($fp = fopen($tmp_path, 'w')) { - $tmp_path = tempnam($temp_dir, 'rcmAttmnt'); - if ($fp = fopen($tmp_path, 'w')) - { - fwrite($fp, $IMAP->mime_decode($part->body, $part->headers['content-transfer-encoding'])); - fclose($fp); - - if ($part->d_parameters['filename']) - $_SESSION['compose']['attachments'][] = array('name' => $part->d_parameters['filename'], - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, - 'path' => $tmp_path); - - else if ($part->ctype_parameters['name']) - $_SESSION['compose']['attachments'][] = array('name' => $part->ctype_parameters['name'], - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, - 'path' => $tmp_path); - - else if ($part->headers['content-description']) - $_SESSION['compose']['attachments'][] = array('name' => $part->headers['content-description'], - 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, - 'path' => $tmp_path); - } + fwrite($fp, $IMAP->get_message_part($message['UID'], $pid, $part->encoding)); + fclose($fp); + + $filename = !empty($part->d_parameters['filename']) ? $part->d_parameters['filename'] : + (!empty($part->ctype_parameters['name']) ? $part->ctype_parameters['name'] : + (!empty($part->headers['content-description']) ? $part->headers['content-description'] : 'file')); + + $_SESSION['compose']['attachments'][] = array( + 'name' => rcube_imap::decode_mime_string($filename), + 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary, + 'path' => $tmp_path + ); } } - - $_SESSION['compose']['forward_attachments'] = TRUE; } - - return $body; + + $_SESSION['compose']['forward_attachments'] = TRUE; } function rcmail_compose_subject($attrib) { - global $CONFIG, $REPLY_MESSAGE, $FORWARD_MESSAGE, $DRAFT_MESSAGE; + global $CONFIG, $MESSAGE, $compose_mode; list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -576,26 +540,26 @@ function rcmail_compose_subject($attrib) $subject = get_input_value('_subject', RCUBE_INPUT_POST, TRUE); // create a reply-subject - else if (isset($REPLY_MESSAGE['subject'])) + else if ($compose_mode == RCUBE_COMPOSE_REPLY) { - if (eregi('^re:', $REPLY_MESSAGE['subject'])) - $subject = $REPLY_MESSAGE['subject']; + if (eregi('^re:', $MESSAGE['subject'])) + $subject = $MESSAGE['subject']; else - $subject = 'Re: '.$REPLY_MESSAGE['subject']; + $subject = 'Re: '.$MESSAGE['subject']; } // create a forward-subject - else if (isset($FORWARD_MESSAGE['subject'])) + else if ($compose_mode == RCUBE_COMPOSE_FORWARD) { - if (eregi('^fwd:', $REPLY_MESSAGE['subject'])) - $subject = $FORWARD_MESSAGE['subject']; + if (eregi('^fwd:', $MESSAGE['subject'])) + $subject = $MESSAGE['subject']; else - $subject = 'Fwd: '.$FORWARD_MESSAGE['subject']; + $subject = 'Fwd: '.$MESSAGE['subject']; } // creeate a draft-subject - else if (isset($DRAFT_MESSAGE['subject'])) - $subject = $DRAFT_MESSAGE['subject']; + else if ($compose_mode == RCUBE_COMPOSE_DRAFT) + $subject = $MESSAGE['subject']; $out = $form_start ? "$form_start\n" : ''; $out .= $textfield->show($subject); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 9c27ad9db..cbe455934 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -427,7 +427,7 @@ function rcmail_message_list($attrib) $message_icon = $attrib['messageicon']; // set attachment icon - if ($attrib['attachmenticon'] && preg_match("/multipart\/m/i", $header->ctype)) + if ($attrib['attachmenticon'] && preg_match("/multipart\/[mr]/i", $header->ctype)) $attach_icon = $attrib['attachmenticon']; $out .= sprintf('<tr id="rcmrow%d" class="message%s%s %s">'."\n", @@ -528,7 +528,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE) foreach ($a_show_cols as $col) { if ($col=='from' || $col=='to') - $cont = rep_specialchars_output(rcmail_address_string($header->$col, 3)); + $cont = rep_specialchars_output(rcmail_address_string($header->$col, 3), 'html'); else if ($col=='subject') $cont = rep_specialchars_output($IMAP->decode_header($header->$col), 'html', 'all'); else if ($col=='size') @@ -662,19 +662,14 @@ function rcmail_get_messagecount_text($count=NULL, $page=NULL) } -function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) // $body, $ctype_primary='text', $ctype_secondary='plain', $encoding='7bit', $safe=FALSE, $plain=FALSE) +function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) { global $IMAP, $REMOTE_OBJECTS, $JS_OBJECT_NAME; - - // extract part properties: body, ctype_primary, ctype_secondary, encoding, parameters - extract($part); - $block = $plain ? '%s' : '%s'; //'<div style="display:block;">%s</div>'; - $body = $IMAP->mime_decode($body, $encoding); - $body = $IMAP->charset_decode($body, $parameters); - + $body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body; + // text/html - if ($ctype_secondary=='html') + if ($part->ctype_secondary=='html') { if (!$safe) // remove remote images and scripts { @@ -707,14 +702,13 @@ function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) // $body, $ctype_pr $body = preg_replace($remote_patterns, $remote_replaces, $body); } - return sprintf($block, rep_specialchars_output($body, 'html', '', FALSE)); + return rep_specialchars_output($body, 'html', '', FALSE); } // text/enriched - if ($ctype_secondary=='enriched') + if ($part->ctype_secondary=='enriched') { - $body = enriched_to_html($body); - return sprintf($block, rep_specialchars_output($body, 'html')); + return rep_specialchars_output(enriched_to_html($body), 'html'); } else { @@ -764,7 +758,7 @@ function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) // $body, $ctype_pr // insert the links for urls and mailtos $body = preg_replace("/##string_replacement\{([0-9]+)\}##/e", "\$replace_strings[\\1]", join("\n", $a_lines)); - return sprintf($block, "<pre>\n".$body."\n</pre>"); + return "<pre>\n".$body."\n</pre>"; } } @@ -779,7 +773,7 @@ function rcmail_str_replacement($str, &$rep) } -function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE) +function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE) { global $IMAP; static $sa_inline_objects = array(); @@ -796,18 +790,18 @@ function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE) // show message headers if ($recursive && is_array($structure->headers) && isset($structure->headers['subject'])) - $a_return_parts[] = array('type' => 'headers', - 'headers' => $structure->headers); + { + $c = new stdClass; + $c->type = 'headers'; + $c->headers = &$structure->headers; + $a_return_parts[] = $c; + } // print body if message doesn't have multiple parts if ($message_ctype_primary=='text') { - $a_return_parts[] = array('type' => 'content', - 'body' => $structure->body, - 'ctype_primary' => $message_ctype_primary, - 'ctype_secondary' => $message_ctype_secondary, - 'parameters' => $structure->ctype_parameters, - 'encoding' => $structure->headers['content-transfer-encoding']); + $structure->type = 'content'; + $a_return_parts[] = &$structure; } // message contains alternative parts @@ -842,49 +836,52 @@ function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE) // print html/plain part else if ($html_part!==NULL && $prefer_html) - $print_part = $structure->parts[$html_part]; + $print_part = &$structure->parts[$html_part]; else if ($enriched_part!==NULL) - $print_part = $structure->parts[$enriched_part]; + $print_part = &$structure->parts[$enriched_part]; else if ($plain_part!==NULL) - $print_part = $structure->parts[$plain_part]; + $print_part = &$structure->parts[$plain_part]; // show message body if (is_object($print_part)) - $a_return_parts[] = array('type' => 'content', - 'body' => $print_part->body, - 'ctype_primary' => strtolower($print_part->ctype_primary), - 'ctype_secondary' => strtolower($print_part->ctype_secondary), - 'parameters' => $print_part->ctype_parameters, - 'encoding' => $print_part->headers['content-transfer-encoding']); + { + $print_part->type = 'content'; + $a_return_parts[] = $print_part; + } // show plaintext warning else if ($html_part!==NULL) - $a_return_parts[] = array('type' => 'content', - 'body' => rcube_label('htmlmessage'), - 'ctype_primary' => 'text', - 'ctype_secondary' => 'plain'); + { + $c = new stdClass; + $c->type = 'content'; + $c->body = rcube_label('htmlmessage'); + $c->ctype_primary = 'text'; + $c->ctype_secondary = 'plain'; + + $a_return_parts[] = $c; + } // add html part as attachment if ($html_part!==NULL && $structure->parts[$html_part]!==$print_part) { - $html_part = $structure->parts[$html_part]; - $a_attachments[] = array('filename' => rcube_label('htmlmessage'), - 'encoding' => $html_part->headers['content-transfer-encoding'], - 'mimetype' => 'text/html', - 'part_id' => $html_part->mime_id, - 'size' => strlen($IMAP->mime_decode($html_part->body, $html_part->headers['content-transfer-encoding']))); + $html_part = &$structure->parts[$html_part]; + $html_part->filename = rcube_label('htmlmessage'); + $html_part->mimetype = 'text/html'; + + $a_attachments[] = $html_part; } } // message contains multiple parts - else if ($message_ctype_primary=='multipart' && is_array($structure->parts)) + else if (is_array($structure->parts) && !empty($structure->parts)) { - foreach ($structure->parts as $mail_part) + for ($i=0; $i<count($structure->parts); $i++) { + $mail_part = &$structure->parts[$i]; $primary_type = strtolower($mail_part->ctype_primary); $secondary_type = strtolower($mail_part->ctype_secondary); // multipart/alternative - if ($primary_type=='multipart') // && ($secondary_type=='alternative' || $secondary_type=='mixed' || $secondary_type=='related')) + if ($primary_type=='multipart') { list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE); @@ -896,25 +893,15 @@ function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE) else if (($primary_type=='text' && ($secondary_type=='plain' || $secondary_type=='html') && $mail_part->disposition!='attachment') || ($primary_type=='message' && $secondary_type=='delivery-status')) { - $a_return_parts[] = array('type' => 'content', - 'body' => $mail_part->body, - 'ctype_primary' => $primary_type, - 'ctype_secondary' => $secondary_type, - 'parameters' => $mail_part->ctype_parameters, - 'encoding' => $mail_part->headers['content-transfer-encoding']); + $mail_part->type = 'content'; + $a_return_parts[] = $mail_part; } // part message/* else if ($primary_type=='message') { - /* don't parse headers here; they're parsed within the recursive call to rcmail_parse_message() - if ($mail_part->parts[0]->headers) - $a_return_parts[] = array('type' => 'headers', - 'headers' => $mail_part->parts[0]->headers); - */ - - list($parts, $attachmnts) = rcmail_parse_message($mail_part->parts[0], $arg, TRUE); - + list($parts, $attachmnts) = rcmail_parse_message($mail_part, $arg, TRUE); + $a_return_parts = array_merge($a_return_parts, $parts); $a_attachments = array_merge($a_attachments, $attachmnts); } @@ -923,35 +910,25 @@ function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE) else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] || (empty($mail_part->disposition) && ($mail_part->d_parameters['filename'] || $mail_part->ctype_parameters['name']))) { + // skip apple ressource files + if ($message_ctype_secondary=='appledouble' && $secondary_type=='applefile') + continue; + + // part belongs to a related message if ($message_ctype_secondary=='related' && $mail_part->headers['content-id']) - $sa_inline_objects[] = array('filename' => rcube_imap::decode_mime_string($mail_part->d_parameters['filename']), - 'mimetype' => strtolower("$primary_type/$secondary_type"), - 'part_id' => $mail_part->mime_id, - 'content_id' => preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id'])); - - else if ($mail_part->d_parameters['filename']) - $a_attachments[] = array('filename' => rcube_imap::decode_mime_string($mail_part->d_parameters['filename']), - 'encoding' => strtolower($mail_part->headers['content-transfer-encoding']), - 'mimetype' => strtolower("$primary_type/$secondary_type"), - 'part_id' => $mail_part->mime_id, - 'size' => strlen($IMAP->mime_decode($mail_part->body, $mail_part->headers['content-transfer-encoding'])) /*, - 'content' => $mail_part->body */); - - else if ($mail_part->ctype_parameters['name']) - $a_attachments[] = array('filename' => rcube_imap::decode_mime_string($mail_part->ctype_parameters['name']), - 'encoding' => strtolower($mail_part->headers['content-transfer-encoding']), - 'mimetype' => strtolower("$primary_type/$secondary_type"), - 'part_id' => $mail_part->mime_id, - 'size' => strlen($IMAP->mime_decode($mail_part->body, $mail_part->headers['content-transfer-encoding'])) /*, - 'content' => $mail_part->body */); - - else if ($mail_part->headers['content-description']) - $a_attachments[] = array('filename' => rcube_imap::decode_mime_string($mail_part->headers['content-description']), - 'encoding' => strtolower($mail_part->headers['content-transfer-encoding']), - 'mimetype' => strtolower("$primary_type/$secondary_type"), - 'part_id' => $mail_part->mime_id, - 'size' => strlen($IMAP->mime_decode($mail_part->body, $mail_part->headers['content-transfer-encoding'])) /*, - 'content' => $mail_part->body */); + { + $mail_part->filename = rcube_imap::decode_mime_string($mail_part->d_parameters['filename']); + $mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']); + $sa_inline_objects[] = $mail_part; + } + // is regular attachment + else if (($fname = $mail_part->d_parameters['filename']) || + ($fname = $mail_part->ctype_parameters['name']) || + ($fname = $mail_part->headers['content-description'])) + { + $mail_part->filename = rcube_imap::decode_mime_string($fname); + $a_attachments[] = $mail_part; + } } } @@ -959,30 +936,20 @@ function rcmail_parse_message($structure, $arg=array(), $recursive=FALSE) // if this was a related part try to resolve references if ($message_ctype_secondary=='related' && sizeof($sa_inline_objects)) { - $a_replace_patters = array(); - $a_replace_strings = array(); + $a_replaces = array(); foreach ($sa_inline_objects as $inline_object) - { - $a_replace_patters[] = 'cid:'.$inline_object['content_id']; - $a_replace_strings[] = sprintf($get_url, $inline_object['part_id']); - } + $a_replaces['cid:'.$inline_object->content_id] = sprintf($get_url, $inline_object->mime_id); - foreach ($a_return_parts as $i => $return_part) + // add replace array to each content part + // (will be applied later when part body is available) + for ($i=0; $i<count($a_return_parts); $i++) { - if ($return_part['type']!='content') - continue; - - // decode body and replace cid:... - $a_return_parts[$i]['body'] = str_replace($a_replace_patters, $a_replace_strings, $IMAP->mime_decode($return_part['body'], $return_part['encoding'])); - $a_return_parts[$i]['encoding'] = '7bit'; + if ($a_return_parts[$i]->type=='content') + $a_return_parts[$i]->replaces = $a_replaces; } } } - - - // join all parts together - //$out .= join($part_delimiter, $a_return_parts); return array($a_return_parts, $a_attachments); } @@ -1046,7 +1013,7 @@ function rcmail_message_headers($attrib, $headers=NULL) function rcmail_message_body($attrib) { - global $CONFIG, $OUTPUT, $MESSAGE, $GET_URL, $REMOTE_OBJECTS, $JS_OBJECT_NAME; + global $CONFIG, $OUTPUT, $MESSAGE, $IMAP, $GET_URL, $REMOTE_OBJECTS, $JS_OBJECT_NAME; if (!is_array($MESSAGE['parts']) && !$MESSAGE['body']) return ''; @@ -1068,28 +1035,33 @@ function rcmail_message_body($attrib) // -> create a plaintext body with the according message if (!sizeof($MESSAGE['parts']) && $MESSAGE['headers']->ctype=='multipart/encrypted') { - $MESSAGE['parts'][0] = array('type' => 'content', - 'ctype_primary' => 'text', - 'ctype_secondary' => 'plain', - 'body' => rcube_label('encryptedmessage')); + $p = new stdClass; + $p->type = 'content'; + $p->ctype_primary = 'text'; + $p->ctype_secondary = 'plain'; + $p->body = rcube_label('encryptedmessage'); + $MESSAGE['parts'][0] = $p; } if ($MESSAGE['parts']) { foreach ($MESSAGE['parts'] as $i => $part) { - if ($part['type']=='headers') - $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part['headers']); - else if ($part['type']=='content') + if ($part->type=='headers') + $out .= rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : NULL, $part->headers); + else if ($part->type=='content') { - if (empty($part['parameters']) || empty($part['parameters']['charset'])) - $part['parameters']['charset'] = $MESSAGE['headers']->charset; + if (empty($part->ctype_parameters) || empty($part->ctype_parameters['charset'])) + $$part->ctype_parameters['charset'] = $MESSAGE['headers']->charset; + + // fetch part if not available + if (!isset($part->body)) + $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part); - // $body = rcmail_print_body($part['body'], $part['ctype_primary'], $part['ctype_secondary'], $part['encoding'], $safe_mode); $body = rcmail_print_body($part, $safe_mode); $out .= '<div class="message-part">'; - if ($part['ctype_secondary']!='plain') + if ($part->ctype_secondary != 'plain') $out .= rcmail_mod_html_body($body, $attrib['id']); else $out .= $body; @@ -1111,11 +1083,11 @@ function rcmail_message_body($attrib) { foreach ($MESSAGE['attachments'] as $attach_prop) { - if (strpos($attach_prop['mimetype'], 'image/')===0) + if (strpos($attach_prop->mimetype, 'image/')===0) $out .= sprintf("\n<hr />\n<p align=\"center\"><img src=\"%s&_part=%s\" alt=\"%s\" title=\"%s\" /></p>\n", - $GET_URL, $attach_prop['part_id'], - $attach_prop['filename'], - $attach_prop['filename']); + $GET_URL, $attach_prop->mime_id, + $attach_prop->filename, + $attach_prop->filename); } } @@ -1242,41 +1214,33 @@ function rcmail_mod_css_styles($source, $container_id) // return first text part of a message -function rcmail_first_text_part($message_parts) +function rcmail_first_text_part($message_struct) { - if (!is_array($message_parts)) + global $IMAP; + + if (!is_array($message_struct['parts'])) return FALSE; - $html_part = NULL; - // check all message parts - foreach ($message_parts as $pid => $part) + foreach ($message_struct['parts'] as $pid => $part) { $mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary); + if ($mimetype=='text/plain') - { - $body = rcube_imap::mime_decode($part->body, $part->headers['content-transfer-encoding']); - $body = rcube_imap::charset_decode($body, $part->ctype_parameters); - return $body; - } + return $IMAP->get_message_part($message_struct['UID'], $pid, $part); + else if ($mimetype=='text/html') { - $html_part = rcube_imap::mime_decode($part->body, $part->headers['content-transfer-encoding']); - $html_part = rcube_imap::charset_decode($html_part, $part->ctype_parameters); - } - } - - - // convert HTML to plain text - if ($html_part) - { - // remove special chars encoding - $trans = array_flip(get_html_translation_table(HTML_ENTITIES)); - $html_part = strtr($html_part, $trans); + $html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part); + + // remove special chars encoding + $trans = array_flip(get_html_translation_table(HTML_ENTITIES)); + $html_part = strtr($html_part, $trans); - // create instance of html2text class - $txt = new html2text($html_part); - return $txt->get_text(); + // create instance of html2text class + $txt = new html2text($html_part); + return $txt->get_text(); + } } return FALSE; @@ -1284,6 +1248,7 @@ function rcmail_first_text_part($message_parts) // get source code of a specific message and cache it +// deprecated function rcmail_message_source($uid) { global $IMAP, $DB, $CONFIG; @@ -1435,13 +1400,13 @@ function rcmail_message_part_controls() if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$_GET['_part']]) return ''; - $part = $MESSAGE['parts'][$_GET['_part']]; + $part = &$MESSAGE['parts'][$_GET['_part']]; $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary')); $out = '<table '. $attrib_str . ">\n"; $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name']; - $filesize = strlen($IMAP->mime_decode($part->body, $part->headers['content-transfer-encoding'])); + $filesize = $part->size; if ($filename) { diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc index 99cd211c6..ded6a0022 100644 --- a/program/steps/mail/get.inc +++ b/program/steps/mail/get.inc @@ -37,23 +37,15 @@ if ($_GET['_preload']) } - // similar code as in program/steps/mail/show.inc if ($_GET['_uid']) { - $MESSAGE = array(); - $MESSAGE['source'] = rcmail_message_source($_GET['_uid']); - - $mmd = new Mail_mimeDecode($MESSAGE['source']); - $MESSAGE['structure'] = $mmd->decode(array('include_bodies' => TRUE, - 'decode_headers' => FALSE, - 'decode_bodies' => FALSE)); - - $MESSAGE['parts'] = $mmd->getMimeNumbers($MESSAGE['structure']); + $MESSAGE = array('UID' => get_input_value('_uid', RCUBE_INPUT_GET)); + $MESSAGE['structure'] = $IMAP->get_structure($MESSAGE['UID']); + $MESSAGE['parts'] = $IMAP->get_mime_numbers($MESSAGE['structure']); } - // show part page if ($_GET['_frame']) { @@ -61,9 +53,9 @@ if ($_GET['_frame']) exit; } -else if ($_GET['_part']) +else if ($pid = get_input_value('_part', RCUBE_INPUT_GET)) { - if ($part = $MESSAGE['parts'][$_GET['_part']]); + if ($part = $MESSAGE['parts'][$pid]); { $ctype_primary = strtolower($part->ctype_primary); $ctype_secondary = strtolower($part->ctype_secondary); @@ -71,18 +63,6 @@ else if ($_GET['_part']) $mimetype = sprintf('%s/%s', $ctype_primary, $ctype_secondary); $filename = $part->d_parameters['filename'] ? $part->d_parameters['filename'] : $part->ctype_parameters['name']; - if ($ctype_primary=='text' && $ctype_secondary=='html') - { - list($MESSAGE['parts']) = rcmail_parse_message($part, - array('safe' => (bool)$_GET['_safe'], - 'prefer_html' => TRUE, - 'get_url' => $GET_URL.'&_part=%s')); - - $cont = rcmail_print_body($MESSAGE['parts'][0], (bool)$_GET['_safe']); - } - else - $cont = $IMAP->mime_decode($part->body, $part->headers['content-transfer-encoding']); - // send correct headers for content type and length if ($_GET['_download']) { @@ -97,8 +77,6 @@ else if ($_GET['_part']) header(sprintf('Content-Disposition: inline; filename="%s"', $filename)); } - header(sprintf('Content-Length: %d', strlen($cont))); - // We need to set the following headers to make downloads work using IE in HTTPS mode. if (isset($_SERVER['HTTPS'])) { @@ -107,7 +85,26 @@ else if ($_GET['_part']) } // deliver part content - echo $cont; + if ($ctype_primary=='text' && $ctype_secondary=='html') + { + // get part body if not available + if (!$part->body) + $part->body = $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part); + + list($MESSAGE['parts']) = rcmail_parse_message($part, + array('safe' => (bool)$_GET['_safe'], + 'prefer_html' => TRUE, + 'get_url' => $GET_URL.'&_part=%s')); + + print rcmail_print_body($MESSAGE['parts'][0], (bool)$_GET['_safe']); + } + else + { + // turn off output buffering and print part content + //@ob_end_clean(); + $IMAP->get_message_part($MESSAGE['UID'], $part->mime_id, $part->encoding, true); + } + exit; } } @@ -127,34 +124,13 @@ else array('safe' => (bool)$_GET['_safe'], 'get_url' => $GET_URL.'&_part=%s')); - if ($MESSAGE['parts'] && $ctype_primary=='multipart') - { - // reset output page - $OUTPUT = new rcube_html_page(); - parse_template('messagepart'); - exit; - } - else if ($MESSAGE['parts'][0]) - { - $part = $MESSAGE['parts'][0]; - $cont = rcmail_print_body($part, (bool)$_GET['_safe']); - } - else - $cont = $IMAP->get_body($_GET['_uid']); + $cont = "<html>\n<head><title></title>\n</head>\n<body>"; + $cont .= rcmail_message_body(array()); + $cont .= "\n</body>\n</html>"; $OUTPUT = new rcube_html_page(); $OUTPUT->write($cont); -/* - if ($mimetype=='text/html') - print $cont; - else - { - print "<html>\n<body>\n"; - print $cont; - print "\n</body>\n</html>"; - } -*/ exit; } diff --git a/program/steps/mail/rss.inc b/program/steps/mail/rss.inc index 062a292b9..80f2e5d47 100644 --- a/program/steps/mail/rss.inc +++ b/program/steps/mail/rss.inc @@ -42,7 +42,7 @@ $webmail_url .= '/'; if (dirname($_SERVER['SCRIPT_NAME']) != '/') $webmail_url .= dirname($_SERVER['SCRIPT_NAME']).'/'; -$auth_webmail_url = $webmail_url.'?_auth='.$GLOBALS['sess_auth']; +$webmail_url .= '?_task=mail'; $messagecount_unread = $IMAP->messagecount('INBOX', 'UNSEEN', TRUE); $messagecount = $IMAP->messagecount(); @@ -68,7 +68,7 @@ echo ' <ttl>5</ttl> <docs>http://blogs.law.harvard.edu/tech/rss</docs> <description>INBOX contains '.$messagecount.' messages, of which '.$messagecount_unread.' unread</description> - <link>'.rss_encode($auth_webmail_url, 'xml') .'</link> + <link>'.rss_encode($webmail_url, 'xml') .'</link> <title>webmail for '.rss_encode($_SESSION['username'].' @ '.$_SESSION['imap_host']).'</title> <generator>'.rss_encode($CONFIG['useragent'], 'xml').' (RSS extension by Sjon Hortensius)</generator> <image> @@ -92,7 +92,7 @@ if ($messagecount > 0) if (strstr($item->from, '<')) $item->from = preg_replace('~"?([^"]*)"? <([^>]*)>~', '\2 (\1)', $item->from); - $item->link = $auth_webmail_url.'&_task=mail&_action=show&_uid='.$item->uid.'&_mbox=INBOX'; + $item->link = $webmail_url.'&_task=mail&_action=show&_uid='.$item->uid.'&_mbox=INBOX'; $item->body = $IMAP->get_body($item->uid); diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 26a3d3312..f381818ed 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -27,33 +27,28 @@ $PRINT_MODE = $_action=='print' ? TRUE : FALSE; // similar code as in program/steps/mail/get.inc if ($_GET['_uid']) { - $MESSAGE = array(); - $MESSAGE['headers'] = $IMAP->get_headers($_GET['_uid']); - $MESSAGE['source'] = rcmail_message_source($_GET['_uid']); - + $MESSAGE = array('UID' => get_input_value('_uid', RCUBE_INPUT_GET)); + $MESSAGE['headers'] = $IMAP->get_headers($MESSAGE['UID']); + $MESSAGE['structure'] = $IMAP->get_structure($MESSAGE['UID']); + // go back to list if message not found (wrong UID) - if (!$MESSAGE['headers'] || !$MESSAGE['source']) + if (!$MESSAGE['headers'] || !$MESSAGE['structure']) { $_action = 'list'; return; } - $mmd = new Mail_mimeDecode($MESSAGE['source']); - $MESSAGE['structure'] = $mmd->decode(array('include_bodies' => TRUE, - 'decode_headers' => FALSE, - 'decode_bodies' => FALSE)); - - $mmd->getMimeNumbers($MESSAGE['structure']); - - $MESSAGE['subject'] = $IMAP->decode_header($MESSAGE['structure']->headers['subject']); - + $MESSAGE['subject'] = $IMAP->decode_header($MESSAGE['headers']->subject); + if ($MESSAGE['structure']) - list($MESSAGE['parts'], $MESSAGE['attachments']) = rcmail_parse_message($MESSAGE['structure'], - array('safe' => (bool)$_GET['_safe'], - 'prefer_html' => $CONFIG['prefer_html'], - 'get_url' => $GET_URL.'&_part=%s')); + list($MESSAGE['parts'], $MESSAGE['attachments']) = rcmail_parse_message( + $MESSAGE['structure'], + array('safe' => (bool)$_GET['_safe'], + 'prefer_html' => $CONFIG['prefer_html'], + 'get_url' => $GET_URL.'&_part=%s') + ); else - $MESSAGE['body'] = $IMAP->get_body($_GET['_uid']); + $MESSAGE['body'] = $IMAP->get_body($MESSAGE['UID']); // mark message as read @@ -61,26 +56,29 @@ if ($_GET['_uid']) $IMAP->set_flag($_GET['_uid'], 'SEEN'); // give message uid to the client - $javascript = sprintf("%s.set_env('uid', '%s');\n", $JS_OBJECT_NAME, $_GET['_uid']); + $javascript = sprintf("%s.set_env('uid', '%s');\n", $JS_OBJECT_NAME, $MESSAGE['UID']); $javascript .= sprintf("%s.set_env('safemode', '%b');", $JS_OBJECT_NAME, $_GET['_safe']); $next = $prev = -1; // get previous and next message UID if (!($_SESSION['sort_col'] == 'date' && $_SESSION['sort_order'] == 'DESC') && - $IMAP->get_capability('sort')) { - // Only if we use custom sorting - $a_msg_index = $IMAP->message_index(NULL, $_SESSION['sort_col'], $_SESSION['sort_order']); + $IMAP->get_capability('sort')) + { + // Only if we use custom sorting + $a_msg_index = $IMAP->message_index(NULL, $_SESSION['sort_col'], $_SESSION['sort_order']); - $MESSAGE['index'] = array_search((string)$_GET['_uid'], $a_msg_index, TRUE); - $prev = isset($a_msg_index[$MESSAGE['index']-1]) ? $a_msg_index[$MESSAGE['index']-1] : -1 ; - $next = isset($a_msg_index[$MESSAGE['index']+1]) ? $a_msg_index[$MESSAGE['index']+1] : -1 ; - } else { - // this assumes that we are sorted by date_DESC - $seq = $IMAP->get_id($_GET['_uid']); - $prev = $IMAP->get_uid($seq + 1); - $next = $IMAP->get_uid($seq - 1); - $MESSAGE['index'] = $IMAP->messagecount() - $seq; - } + $MESSAGE['index'] = array_search((string)$MESSAGE['UID'], $a_msg_index, TRUE); + $prev = isset($a_msg_index[$MESSAGE['index']-1]) ? $a_msg_index[$MESSAGE['index']-1] : -1 ; + $next = isset($a_msg_index[$MESSAGE['index']+1]) ? $a_msg_index[$MESSAGE['index']+1] : -1 ; + } + else + { + // this assumes that we are sorted by date_DESC + $seq = $IMAP->get_id($MESSAGE['UID']); + $prev = $IMAP->get_uid($seq + 1); + $next = $IMAP->get_uid($seq - 1); + $MESSAGE['index'] = $IMAP->messagecount() - $seq; + } if ($prev > 0) $javascript .= sprintf("\n%s.set_env('prev_uid', '%s');", $JS_OBJECT_NAME, $prev); @@ -106,16 +104,16 @@ function rcmail_message_attachments($attrib) { if ($PRINT_MODE) $out .= sprintf('<li>%s (%s)</li>'."\n", - $attach_prop['filename'], - show_bytes($attach_prop['size'])); + $attach_prop->filename, + show_bytes($attach_prop->size)); else $out .= sprintf('<li><a href="%s&_part=%s" onclick="return %s.command(\'load-attachment\',{part:\'%s\', mimetype:\'%s\'},this)">%s</a></li>'."\n", htmlentities($GET_URL), - $attach_prop['part_id'], + $attach_prop->mime_id, $JS_OBJECT_NAME, - $attach_prop['part_id'], - $attach_prop['mimetype'], - $attach_prop['filename']); + $attach_prop->mime_id, + $attach_prop->mimetype, + $attach_prop->filename); } $out .= "</ul>"; diff --git a/program/steps/mail/viewsource.inc b/program/steps/mail/viewsource.inc index 0fcb1f9c5..a158bf281 100644 --- a/program/steps/mail/viewsource.inc +++ b/program/steps/mail/viewsource.inc @@ -21,16 +21,17 @@ // similar code as in program/steps/mail/get.inc -if ($_GET['_uid']) +if ($uid = get_input_value('_uid', RCUBE_INPUT_GET)) { header('Content-Type: text/plain'); - print rcmail_message_source($_GET['_uid']); + //@ob_end_clean(); + $IMAP->print_raw_body($uid); } else { raise_error(array('code' => 500, 'type' => 'php', - 'message' => 'Message UID '.$_GET['_uid'].' not found'), + 'message' => 'Message UID '.$uid.' not found'), TRUE, TRUE); } |