From 0b17277eaeebdee278230d7cd2550a1a9e2fcf9f Mon Sep 17 00:00:00 2001 From: till <till@php.net> Date: Mon, 24 Mar 2008 20:52:33 -0400 Subject: [PATCH] * committing patch from #1484783 --- program/steps/mail/func.inc | 661 +++++++++++++++++++++++++++++------------------------- 1 files changed, 351 insertions(+), 310 deletions(-) diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index fc17417..79e0248 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -21,6 +21,7 @@ require_once('lib/html2text.inc'); require_once('lib/enriched.inc'); +require_once('include/rcube_smtp.inc'); $EMAIL_ADDRESS_PATTERN = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i'; @@ -30,16 +31,10 @@ // set imap properties and session vars if ($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC)) - { - $IMAP->set_mailbox($mbox); - $_SESSION['mbox'] = $mbox; - } + $IMAP->set_mailbox(($_SESSION['mbox'] = $mbox)); if (!empty($_GET['_page'])) - { - $IMAP->set_page((int)$_GET['_page']); - $_SESSION['page'] = (int)$_GET['_page']; - } + $IMAP->set_page(($_SESSION['page'] = intval($_GET['_page']))); // set mailbox to INBOX if not set if (empty($_SESSION['mbox'])) @@ -53,7 +48,11 @@ // set message set for search result if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']])) + { $IMAP->set_search_set($_SESSION['search'][$_REQUEST['_search']]); + $OUTPUT->set_env('search_request', $_REQUEST['_search']); + $OUTPUT->set_env('search_text', $_SESSION['last_text_search']); + } // define url for getting message parts @@ -73,223 +72,12 @@ $OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']); if (!$OUTPUT->ajax_call) - rcube_add_label('checkingmail'); + rcube_add_label('checkingmail', 'deletemessage', 'movemessagetotrash'); +// set page title +if (empty($_action) || $_action == 'list') + $OUTPUT->set_pagetitle(rcmail_localize_foldername($IMAP->get_mailbox_name())); -// return the mailboxlist in HTML -function rcmail_mailbox_list($attrib) - { - global $IMAP, $CONFIG, $OUTPUT, $COMM_PATH; - static $s_added_script = FALSE; - static $a_mailboxes; - - // add some labels to client - rcube_add_label('purgefolderconfirm'); - rcube_add_label('deletemessagesconfirm'); - -// $mboxlist_start = rcube_timer(); - - $type = $attrib['type'] ? $attrib['type'] : 'ul'; - $add_attrib = $type=='select' ? array('style', 'class', 'id', 'name', 'onchange') : - array('style', 'class', 'id'); - - if ($type=='ul' && !$attrib['id']) - $attrib['id'] = 'rcmboxlist'; - - // allow the following attributes to be added to the <ul> tag - $attrib_str = create_attrib_string($attrib, $add_attrib); - - $out = '<' . $type . $attrib_str . ">\n"; - - // add no-selection option - if ($type=='select' && $attrib['noselection']) - $out .= sprintf('<option value="0">%s</option>'."\n", - rcube_label($attrib['noselection'])); - - // get mailbox list - $mbox_name = $IMAP->get_mailbox_name(); - - // for these mailboxes we have localized labels - $special_mailboxes = array('inbox', 'sent', 'drafts', 'trash', 'junk'); - - - // build the folders tree - if (empty($a_mailboxes)) - { - // get mailbox list - $a_folders = $IMAP->list_mailboxes(); - $delimiter = $IMAP->get_hierarchy_delimiter(); - $a_mailboxes = array(); - -// rcube_print_time($mboxlist_start, 'list_mailboxes()'); - - foreach ($a_folders as $folder) - rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter); - } - -// var_dump($a_mailboxes); - - if ($type=='select') - $out .= rcmail_render_folder_tree_select($a_mailboxes, $special_mailboxes, $mbox_name, $attrib['maxlength']); - else - $out .= rcmail_render_folder_tree_html($a_mailboxes, $special_mailboxes, $mbox_name, $attrib['maxlength']); - -// rcube_print_time($mboxlist_start, 'render_folder_tree()'); - - - if ($type=='ul') - $OUTPUT->add_gui_object('mailboxlist', $attrib['id']); - - return $out . "</$type>"; - } - - - - -// create a hierarchical array of the mailbox list -function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='') - { - $pos = strpos($folder, $delm); - if ($pos !== false) - { - $subFolders = substr($folder, $pos+1); - $currentFolder = substr($folder, 0, $pos); - } - else - { - $subFolders = false; - $currentFolder = $folder; - } - - $path .= $currentFolder; - - if (!isset($arrFolders[$currentFolder])) - { - $arrFolders[$currentFolder] = array('id' => $path, - 'name' => rcube_charset_convert($currentFolder, 'UTF-7'), - 'folders' => array()); - } - - if (!empty($subFolders)) - rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm); - } - - -// return html for a structured list <ul> for the mailbox tree -function rcmail_render_folder_tree_html(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0) - { - global $COMM_PATH, $IMAP, $CONFIG, $OUTPUT; - - $idx = 0; - $out = ''; - foreach ($arrFolders as $key => $folder) - { - $zebra_class = ($nestLevel*$idx)%2 ? 'even' : 'odd'; - $title = ''; - - $folder_lc = strtolower($folder['id']); - if (in_array($folder_lc, $special)) - $foldername = rcube_label($folder_lc); - else - { - $foldername = $folder['name']; - - // shorten the folder name to a given length - if ($maxlength && $maxlength>1) - { - $fname = abbrevate_string($foldername, $maxlength); - if ($fname != $foldername) - $title = ' title="'.Q($foldername).'"'; - $foldername = $fname; - } - } - - // add unread message count display - if ($unread_count = $IMAP->messagecount($folder['id'], 'RECENT', ($folder['id']==$mbox_name))) - $foldername .= sprintf(' (%d)', $unread_count); - - // make folder name safe for ids and class names - $folder_id = preg_replace('/[^A-Za-z0-9\-_]/', '', $folder['id']); - $class_name = preg_replace('/[^a-z0-9\-_]/', '', $folder_lc); - - // set special class for Sent, Drafts, Trash and Junk - if ($folder['id']==$CONFIG['sent_mbox']) - $class_name = 'sent'; - else if ($folder['id']==$CONFIG['drafts_mbox']) - $class_name = 'drafts'; - else if ($folder['id']==$CONFIG['trash_mbox']) - $class_name = 'trash'; - else if ($folder['id']==$CONFIG['junk_mbox']) - $class_name = 'junk'; - - $js_name = htmlspecialchars(JQ($folder['id'])); - $out .= sprintf('<li id="rcmli%s" class="mailbox %s %s%s%s"><a href="%s"'. - ' onclick="return %s.command(\'list\',\'%s\',this)"'. - ' onmouseover="return %s.focus_folder(\'%s\')"' . - ' onmouseout="return %s.unfocus_folder(\'%s\')"' . - ' onmouseup="return %s.folder_mouse_up(\'%s\')"%s>%s</a>', - $folder_id, - $class_name, - $zebra_class, - $unread_count ? ' unread' : '', - $folder['id']==$mbox_name ? ' selected' : '', - Q(rcmail_url('', array('_mbox' => $folder['id']))), - JS_OBJECT_NAME, - $js_name, - JS_OBJECT_NAME, - $js_name, - JS_OBJECT_NAME, - $js_name, - JS_OBJECT_NAME, - $js_name, - $title, - Q($foldername)); - - if (!empty($folder['folders'])) - $out .= "\n<ul>\n" . rcmail_render_folder_tree_html($folder['folders'], $special, $mbox_name, $maxlength, $nestLevel+1) . "</ul>\n"; - - $out .= "</li>\n"; - $idx++; - } - - return $out; - } - - -// return html for a flat list <select> for the mailbox tree -function rcmail_render_folder_tree_select(&$arrFolders, &$special, &$mbox_name, $maxlength, $nestLevel=0) - { - global $IMAP, $OUTPUT; - - $idx = 0; - $out = ''; - foreach ($arrFolders as $key=>$folder) - { - $folder_lc = strtolower($folder['id']); - if (in_array($folder_lc, $special)) - $foldername = rcube_label($folder_lc); - else - { - $foldername = $folder['name']; - - // shorten the folder name to a given length - if ($maxlength && $maxlength>1) - $foldername = abbrevate_string($foldername, $maxlength); - } - - $out .= sprintf('<option value="%s">%s%s</option>'."\n", - htmlspecialchars($folder['id']), - str_repeat(' ', $nestLevel*4), - Q($foldername)); - - if (!empty($folder['folders'])) - $out .= rcmail_render_folder_tree_select($folder['folders'], $special, $mbox_name, $maxlength, $nestLevel+1); - - $idx++; - } - - return $out; - } // return the message list as HTML table @@ -404,11 +192,7 @@ // no messages in this mailbox if (!sizeof($a_headers)) - { - $out .= sprintf('<tr><td colspan="%d">%s</td></tr>', - sizeof($a_show_cols)+2, - Q(rcube_label('nomessagesfound'))); - } + $OUTPUT->show_message('nomessagesfound', 'notice'); $a_js_message_arr = array(); @@ -460,7 +244,7 @@ $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid'; $cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset)); if (empty($cont)) $cont = Q(rcube_label('nosubject')); - $cont = sprintf('<a href="%s" onclick="return false">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont); + $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont); } else if ($col=='size') $cont = show_bytes($header->$col); @@ -506,6 +290,7 @@ $OUTPUT->set_env('attachmenticon', $skin_path . $attrib['attachmenticon']); $OUTPUT->set_env('messages', $a_js_message_arr); + $OUTPUT->set_env('coltypes', $a_show_cols); $OUTPUT->include_script('list.js'); @@ -529,11 +314,13 @@ $OUTPUT->command('set_message_coltypes', $a_show_cols); // loop through message headers - for ($n=0; $a_headers[$n]; $n++) + foreach ($a_headers as $n => $header) { - $header = $a_headers[$n]; $a_msg_cols = array(); $a_msg_flags = array(); + + if (empty($header)) + continue; // format each col; similar as in rcmail_message_list() foreach ($a_show_cols as $col) @@ -546,7 +333,7 @@ $uid_param = $mbox==$CONFIG['drafts_mbox'] ? '_draf_uid' : '_uid'; $cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset)); if (!$cont) $cont = Q(rcube_label('nosubject')); - $cont = sprintf('<a href="%s" onclick="return false">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont); + $cont = sprintf('<a href="%s" onclick="return rcube_event.cancel(event)">%s</a>', Q(rcmail_url($action, array($uid_param=>$header->uid, '_mbox'=>$mbox))), $cont); } else if ($col=='size') $cont = show_bytes($header->$col); @@ -695,6 +482,127 @@ } +/* Stolen from Squirrelmail */ +function sq_deent(&$attvalue, $regex, $hex=false) + { + $ret_match = false; + preg_match_all($regex, $attvalue, $matches); + if (is_array($matches) && sizeof($matches[0]) > 0) + { + $repl = Array(); + for ($i = 0; $i < sizeof($matches[0]); $i++) + { + $numval = $matches[1][$i]; + if ($hex) + $numval = hexdec($numval); + $repl{$matches[0][$i]} = chr($numval); + } + $attvalue = strtr($attvalue, $repl); + return true; + } + else + return false; + } + + +/* Stolen verbatim from Squirrelmail */ +function sq_defang(&$attvalue) + { + /* Skip this if there aren't ampersands or backslashes. */ + if ((strpos($attvalue, '&') === false) && + (strpos($attvalue, '\\') === false)) + return; + $m = false; + do + { + $m = false; + $m = $m || sq_deent($attvalue, '/\�*(\d+);*/s'); + $m = $m || sq_deent($attvalue, '/\�*((\d|[a-f])+);*/si', true); + $m = $m || sq_deent($attvalue, '/\\\\(\d+)/s', true); + } while ($m == true); + $attvalue = stripslashes($attvalue); + } + + +function rcmail_html_filter($html) + { + preg_match_all('/<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|\'.*?\'|[^\'">\s]+))?)+\s*|\s*)\/?>/', $html, $tags); + + /* From Squirrelmail: Translate all dangerous Unicode or Shift_JIS characters which are accepted by + * IE as regular characters. */ + $replace = array(array('ʟ', 'ʟ', /* L UNICODE IPA Extension */ + 'ʀ', 'ʀ', /* R UNICODE IPA Extension */ + 'ɴ', 'ɴ', /* N UNICODE IPA Extension */ + 'E', 'E', /* Unicode FULLWIDTH LATIN CAPITAL LETTER E */ + 'e', 'e', /* Unicode FULLWIDTH LATIN SMALL LETTER E */ + 'X', 'X', /* Unicode FULLWIDTH LATIN CAPITAL LETTER X */ + 'x', 'x', /* Unicode FULLWIDTH LATIN SMALL LETTER X */ + 'P', 'P', /* Unicode FULLWIDTH LATIN CAPITAL LETTER P */ + 'p', 'p', /* Unicode FULLWIDTH LATIN SMALL LETTER P */ + 'R', 'R', /* Unicode FULLWIDTH LATIN CAPITAL LETTER R */ + 'r', 'r', /* Unicode FULLWIDTH LATIN SMALL LETTER R */ + 'S', 'S', /* Unicode FULLWIDTH LATIN CAPITAL LETTER S */ + 's', 's', /* Unicode FULLWIDTH LATIN SMALL LETTER S */ + 'I', 'I', /* Unicode FULLWIDTH LATIN CAPITAL LETTER I */ + 'i', 'i', /* Unicode FULLWIDTH LATIN SMALL LETTER I */ + 'O', 'O', /* Unicode FULLWIDTH LATIN CAPITAL LETTER O */ + 'o', 'o', /* Unicode FULLWIDTH LATIN SMALL LETTER O */ + 'N', 'N', /* Unicode FULLWIDTH LATIN CAPITAL LETTER N */ + 'n', 'n', /* Unicode FULLWIDTH LATIN SMALL LETTER N */ + 'L', 'L', /* Unicode FULLWIDTH LATIN CAPITAL LETTER L */ + 'l', 'l', /* Unicode FULLWIDTH LATIN SMALL LETTER L */ + 'U', 'U', /* Unicode FULLWIDTH LATIN CAPITAL LETTER U */ + 'u', 'u', /* Unicode FULLWIDTH LATIN SMALL LETTER U */ + 'ⁿ', 'ⁿ' , /* Unicode SUPERSCRIPT LATIN SMALL LETTER N */ + "\xEF\xBC\xA5", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER E */ + /* in unicode this is some Chinese char range */ + "\xEF\xBD\x85", /* Shift JIS FULLWIDTH LATIN SMALL LETTER E */ + "\xEF\xBC\xB8", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER X */ + "\xEF\xBD\x98", /* Shift JIS FULLWIDTH LATIN SMALL LETTER X */ + "\xEF\xBC\xB0", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER P */ + "\xEF\xBD\x90", /* Shift JIS FULLWIDTH LATIN SMALL LETTER P */ + "\xEF\xBC\xB2", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER R */ + "\xEF\xBD\x92", /* Shift JIS FULLWIDTH LATIN SMALL LETTER R */ + "\xEF\xBC\xB3", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER S */ + "\xEF\xBD\x93", /* Shift JIS FULLWIDTH LATIN SMALL LETTER S */ + "\xEF\xBC\xA9", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER I */ + "\xEF\xBD\x89", /* Shift JIS FULLWIDTH LATIN SMALL LETTER I */ + "\xEF\xBC\xAF", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER O */ + "\xEF\xBD\x8F", /* Shift JIS FULLWIDTH LATIN SMALL LETTER O */ + "\xEF\xBC\xAE", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER N */ + "\xEF\xBD\x8E", /* Shift JIS FULLWIDTH LATIN SMALL LETTER N */ + "\xEF\xBC\xAC", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER L */ + "\xEF\xBD\x8C", /* Shift JIS FULLWIDTH LATIN SMALL LETTER L */ + "\xEF\xBC\xB5", /* Shift JIS FULLWIDTH LATIN CAPITAL LETTER U */ + "\xEF\xBD\x95", /* Shift JIS FULLWIDTH LATIN SMALL LETTER U */ + "\xE2\x81\xBF", /* Shift JIS FULLWIDTH SUPERSCRIPT N */ + "\xCA\x9F", /* L UNICODE IPA Extension */ + "\xCA\x80", /* R UNICODE IPA Extension */ + "\xC9\xB4"), /* N UNICODE IPA Extension */ + array('l', 'l', 'r', 'r', 'n', 'n', 'E', 'E', 'e', 'e', 'X', 'X', 'x', 'x', + 'P', 'P', 'p', 'p', 'R', 'R', 'r', 'r', 'S', 'S', 's', 's', 'I', 'I', + 'i', 'i', 'O', 'O', 'o', 'o', 'N', 'N', 'n', 'n', 'L', 'L', 'l', 'l', + 'U', 'U', 'u', 'u', 'n', 'n', 'E', 'e', 'X', 'x', 'P', 'p', 'R', 'r', + 'S', 's', 'I', 'i', 'O', 'o', 'N', 'n', 'L', 'l', 'U', 'u', 'n', 'l', 'r', 'n')); + if ((count($tags)>3) && (count($tags[3])>0)) + foreach ($tags[3] as $nr=>$value) + { + /* Remove comments */ + $newvalue = preg_replace('/(\/\*.*\*\/)/','$2',$value); + /* Translate dangerous characters */ + $newvalue = str_replace($replace[0], $replace[1], $newvalue); + sq_defang($newvalue); + /* Rename dangerous CSS */ + $newvalue = preg_replace('/expression/i', 'idiocy', $newvalue); + $newvalue = preg_replace('/url/i', 'idiocy', $newvalue); + $newattrs = preg_replace('/'.preg_quote($value, '/').'$/', $newvalue, $tags[1][$nr]); + $newtag = preg_replace('/'.preg_quote($tags[1][$nr], '/').'/', $newattrs, $tags[0][$nr]); + $html = preg_replace('/'.preg_quote($tags[0][$nr], '/').'/', $newtag, $html); + } + return $html; + } + + function rcmail_print_body($part, $safe=FALSE, $plain=FALSE) { global $IMAP, $REMOTE_OBJECTS; @@ -746,7 +654,7 @@ $body = preg_replace($remote_patterns, $remote_replaces, $body); } - return Q($body, 'show', FALSE); + return Q(rcmail_html_filter($body), 'show', FALSE); } // text/enriched @@ -787,10 +695,10 @@ $quotation = ''; $q = 0; - if (preg_match('/^(>+\s*)/', $line, $regs)) + if (preg_match('/^(>+\s*)+/', $line, $regs)) { - $q = strlen(preg_replace('/\s/', '', $regs[1])); - $line = substr($line, strlen($regs[1])); + $q = strlen(preg_replace('/\s/', '', $regs[0])); + $line = substr($line, strlen($regs[0])); if ($q > $quote_level) $quotation = str_repeat('<blockquote>', $q - $quote_level); @@ -852,7 +760,7 @@ $structure->type = 'content'; $a_return_parts[] = &$structure; } - + // message contains alternative parts else if ($message_ctype_primary=='multipart' && $message_ctype_secondary=='alternative' && is_array($structure->parts)) { @@ -861,6 +769,7 @@ foreach ($structure->parts as $p => $sub_part) { + $rel_parts = $attachmnts = null; $sub_ctype_primary = strtolower($sub_part->ctype_primary); $sub_ctype_secondary = strtolower($sub_part->ctype_secondary); @@ -871,19 +780,22 @@ $html_part = $p; else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='enriched') $enriched_part = $p; - else if ($sub_ctype_primary=='multipart' && $sub_ctype_secondary=='related') + else if ($sub_ctype_primary=='multipart' && ($sub_ctype_secondary=='related' || $sub_ctype_secondary=='mixed')) $related_part = $p; } - + // parse related part (alternative part could be in here) - if ($related_part!==NULL && $prefer_html) - { - list($parts, $attachmnts) = rcmail_parse_message($structure->parts[$related_part], $arg, TRUE); - $a_return_parts = array_merge($a_return_parts, $parts); + if ($related_part!==NULL) + { + list($rel_parts, $attachmnts) = rcmail_parse_message($structure->parts[$related_part], $arg, TRUE); $a_attachments = array_merge($a_attachments, $attachmnts); - } + } + + // merge related parts if any + if ($rel_parts && $prefer_html && !$html_part) + $a_return_parts = array_merge($a_return_parts, $rel_parts); - // print html/plain part + // choose html/plain part to print else if ($html_part!==NULL && $prefer_html) $print_part = &$structure->parts[$html_part]; else if ($enriched_part!==NULL) @@ -898,7 +810,7 @@ $a_return_parts[] = $print_part; } // show plaintext warning - else if ($html_part!==NULL) + else if ($html_part!==NULL && empty($a_return_parts)) { $c = new stdClass; $c->type = 'content'; @@ -940,7 +852,7 @@ // part text/[plain|html] OR message/delivery-status else if (($primary_type=='text' && ($secondary_type=='plain' || $secondary_type=='html') && $mail_part->disposition!='attachment') || - ($primary_type=='message' && $secondary_type=='delivery-status')) + ($primary_type=='message' && ($secondary_type=='delivery-status' || $secondary_type=='disposition-notification'))) { $mail_part->type = 'content'; $a_return_parts[] = $mail_part; @@ -954,6 +866,10 @@ $a_return_parts = array_merge($a_return_parts, $parts); $a_attachments = array_merge($a_attachments, $attachmnts); } + + // ignore "virtual" protocol parts + else if ($primary_type=='protocol') + continue; // part is file/attachment else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] || @@ -973,7 +889,7 @@ else { if (!$mail_part->filename) - $mail_part->filename = 'file_'.$mail_part->mime_id; + $mail_part->filename = 'Part '.$mail_part->mime_id; $a_attachments[] = $mail_part; } } @@ -1071,7 +987,7 @@ if (!$attrib['id']) $attrib['id'] = 'rcmailMsgBody'; - $safe_mode = (bool)$_GET['_safe']; + $safe_mode = $MESSAGE['is_safe'] || intval($_GET['_safe']); $attrib_str = create_attrib_string($attrib, array('style', 'class', 'id')); $out = '<div '. $attrib_str . ">\n"; @@ -1128,8 +1044,8 @@ $ctype_secondary = strtolower($MESSAGE['structure']->ctype_secondary); // list images after mail body - if (get_boolean($attrib['showimages']) && $ctype_primary=='multipart' && $ctype_secondary=='mixed' && - sizeof($MESSAGE['attachments']) && !strstr($message_body, '<html') && strlen($GET_URL)) + if (get_boolean($attrib['showimages']) && $ctype_primary=='multipart' && + !empty($MESSAGE['attachments']) && !strstr($message_body, '<html') && strlen($GET_URL)) { foreach ($MESSAGE['attachments'] as $attach_prop) { @@ -1157,8 +1073,13 @@ // remove any null-byte characters before parsing $body = preg_replace('/\x00/', '', $body); + $base_url = ""; $last_style_pos = 0; $body_lc = strtolower($body); + + // check for <base href> + if (preg_match(($base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i'), $body, $base_regs)) + $base_url = $base_regs[2]; // find STYLE tags while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos))) @@ -1166,7 +1087,7 @@ $pos = strpos($body_lc, '>', $pos)+1; // replace all css definitions with #container [def] - $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id); + $styles = rcmail_mod_css_styles(substr($body, $pos, $pos2-$pos), $container_id, $base_url); $body = substr($body, 0, $pos) . $styles . substr($body, $pos2); $body_lc = strtolower($body); @@ -1177,10 +1098,10 @@ // remove SCRIPT tags foreach (array('script', 'applet', 'object', 'embed', 'iframe') as $tag) { - while (($pos = strpos($body_lc, '<'.$tag)) && ($pos2 = strpos($body_lc, '</'.$tag.'>', $pos))) + while (($pos = strpos($body_lc, '<'.$tag)) && (($pos2 = strpos($body_lc, '</'.$tag.'>', $pos)) || ($pos3 = strpos($body_lc, '>', $pos)))) { - $pos2 += strlen('</'.$tag.'>'); - $body = substr($body, 0, $pos) . substr($body, $pos2, strlen($body)-$pos2); + $end = $pos2 ? $pos2 + strlen('</'.$tag.'>') : $pos3 + 1; + $body = substr($body, 0, $pos) . substr($body, $end, strlen($body)-$end); $body_lc = strtolower($body); } } @@ -1189,36 +1110,41 @@ while ($body != $prev_body) { $prev_body = $body; - $body = preg_replace('/(<[^!][^>]*\s)(on[^=>]+)=([^>]+>)/im', '$1__removed=$3', $body); + $body = preg_replace('/(<[^!][^>]*\s)on(?:load|unload|click|dblclick|mousedown|mouseup|mouseover|mousemove|mouseout|focus|blur|keypress|keydown|keyup|submit|reset|select|change)=([^>]+>)/im', '$1__removed=$2', $body); $body = preg_replace('/(<[^!][^>]*\shref=["\']?)(javascript:)([^>]*?>)/im', '$1null:$3', $body); } // resolve <base href> - $base_reg = '/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i'; - if (preg_match($base_reg, $body, $regs)) + if ($base_url) { - $base_url = $regs[2]; $body = preg_replace('/(src|background|href)=(["\']?)([\.\/]+[^"\'\s]+)(\2|\s|>)/Uie', "'\\1=\"'.make_absolute_url('\\3', '$base_url').'\"'", $body); $body = preg_replace('/(url\s*\()(["\']?)([\.\/]+[^"\'\)\s]+)(\2)\)/Uie', "'\\1\''.make_absolute_url('\\3', '$base_url').'\')'", $body); $body = preg_replace($base_reg, '', $body); } // modify HTML links to open a new window if clicked - $body = preg_replace('/<a\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1');", $body); + $body = preg_replace('/<(a|link)\s+([^>]+)>/Uie', "rcmail_alter_html_link('\\1','\\2', '$container_id');", $body); // add comments arround html and other tags - $out = preg_replace(array('/(<\/?html[^>]*>)/i', - '/(<\/?head[^>]*>)/i', - '/(<title[^>]*>.*<\/title>)/Ui', - '/(<\/?meta[^>]*>)/i'), - '<!--\\1-->', - $body); + $out = preg_replace(array( + '/(<!DOCTYPE.+)/i', + '/(<\/?html[^>]*>)/i', + '/(<\/?head[^>]*>)/i', + '/(<title[^>]*>.*<\/title>)/Ui', + '/(<\/?meta[^>]*>)/i'), + '<!--\\1-->', + $body); - $out = preg_replace(array('/(<body[^>]*>)/i', - '/(<\/body>)/i'), - array('<div class="rcmBody">', - '</div>'), - $out); + $out = preg_replace( + array( + '/<body([^>]*)>/i', + '/<\/body>/i', + ), + array( + '<div class="rcmBody"\\1>', + '</div>', + ), + $out); // quote <? of php and xml files that are specified as text/html $out = preg_replace(array('/<\?/', '/\?>/'), array('<?', '?>'), $out); @@ -1228,44 +1154,24 @@ // parse link attributes and set correct target -function rcmail_alter_html_link($in) +function rcmail_alter_html_link($tag, $attrs, $container_id) { $in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in); - $attrib = parse_attrib_string($in); + $attrib = parse_attrib_string($attrs); + + if ($tag == 'link' && preg_match('/^https?:\/\//i', $attrib['href'])) + $attrib['href'] = "./bin/modcss.php?u=" . urlencode($attrib['href']) . "&c=" . urlencode($container_id); - if (stristr((string)$attrib['href'], 'mailto:')) - $attrib['onclick'] = sprintf("return %s.command('compose','%s',this)", - JS_OBJECT_NAME, - JQ(substr($attrib['href'], 7))); + else if (stristr((string)$attrib['href'], 'mailto:')) + $attrib['onclick'] = sprintf( + "return %s.command('compose','%s',this)", + JS_OBJECT_NAME, + JQ(substr($attrib['href'], 7))); + else if (!empty($attrib['href']) && $attrib['href']{0}!='#') $attrib['target'] = '_blank'; - - return '<a' . create_attrib_string($attrib, array('href', 'name', 'target', 'onclick', 'id', 'class', 'style', 'title')) . '>'; - } - -// replace all css definitions with #container [def] -function rcmail_mod_css_styles($source, $container_id) - { - $a_css_values = array(); - $last_pos = 0; - - // cut out all contents between { and } - while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) - { - $key = sizeof($a_css_values); - $a_css_values[$key] = substr($source, $pos+1, $pos2-($pos+1)); - $source = substr($source, 0, $pos+1) . "<<str_replacement[$key]>>" . substr($source, $pos2, strlen($source)-$pos2); - $last_pos = $pos+2; - } - - // remove html commends and add #container to each tag selector. - // also replace body definition because we also stripped off the <body> tag - $styles = preg_replace(array('/(^\s*<!--)|(-->\s*$)/', '/(^\s*|,\s*|\}\s*)([a-z0-9\._][a-z0-9\.\-_]*)/im', '/<<str_replacement\[([0-9]+)\]>>/e', "/$container_id\s+body/i"), - array('', "\\1#$container_id \\2", "\$a_css_values[\\1]", "$container_id div.rcmBody"), - $source); - - return $styles; + return "<$tag" . create_attrib_string($attrib, array('href','name','target','onclick','id','class','style','title','rel','type','media')) . ' />'; } @@ -1416,15 +1322,15 @@ { global $CONFIG, $IMAP, $MESSAGE; - if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$_GET['_part']]) + $part = asciiwords(get_input_value('_part', RCUBE_INPUT_GPC)); + if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$part]) return ''; - $part = &$MESSAGE['parts'][$_GET['_part']]; - + $part = $MESSAGE['parts'][$part]; $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary')); $out = '<table '. $attrib_str . ">\n"; - if ($filename) + if ($part->filename) { $out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n", Q(rcube_label('filename')), @@ -1449,10 +1355,10 @@ { global $MESSAGE; - $part = $MESSAGE['parts'][$_GET['_part']]; + $part = $MESSAGE['parts'][asciiwords(get_input_value('_part', RCUBE_INPUT_GPC))]; $ctype_primary = strtolower($part->ctype_primary); - $attrib['src'] = './?'.str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING']); + $attrib['src'] = Q('./?'.str_replace('_frame=', ($ctype_primary=='text' ? '_show=' : '_preload='), $_SERVER['QUERY_STRING'])); $attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height')); $out = '<iframe '. $attrib_str . "></iframe>"; @@ -1474,6 +1380,141 @@ unset($_SESSION['compose']); } + + +/** + * Send the given message compose object using the configured method + */ +function rcmail_deliver_message(&$message, $from, $mailto) +{ + global $CONFIG; + + $headers = $message->headers(); + $msg_body = $message->get(); + + // send thru SMTP server using custom SMTP library + if ($CONFIG['smtp_server']) + { + // generate list of recipients + $a_recipients = array($mailto); + + if (strlen($headers['Cc'])) + $a_recipients[] = $headers['Cc']; + if (strlen($headers['Bcc'])) + $a_recipients[] = $headers['Bcc']; + + // clean Bcc from header for recipients + $send_headers = $headers; + unset($send_headers['Bcc']); + + // send message + $smtp_response = array(); + $sent = smtp_mail($from, $a_recipients, ($foo = $message->txtHeaders($send_headers)), $msg_body, $smtp_response); + + // log error + if (!$sent) + raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__, + 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE); + } + + // send mail using PHP's mail() function + else + { + // unset some headers because they will be added by the mail() function + $headers_enc = $message->headers($headers); + $headers_php = $message->_headers; + unset($headers_php['To'], $headers_php['Subject']); + + // reset stored headers and overwrite + $message->_headers = array(); + $header_str = $message->txtHeaders($headers_php); + + if (ini_get('safe_mode')) + $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str); + else + $sent = mail($headers_enc['To'], $headers_enc['Subject'], $msg_body, $header_str, "-f$from"); + } + + if ($sent) // remove MDN headers after sending + unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']); + + $message->_headers = array(); + $message->headers($headers); + + return $sent; +} + + +function rcmail_send_mdn($uid) +{ + global $CONFIG, $USER, $IMAP; + + $message = array('UID' => $uid); + $message['headers'] = $IMAP->get_headers($message['UID']); + $message['subject'] = rcube_imap::decode_mime_string($message['headers']->subject, $message['headers']->charset); + + if ($message['headers']->mdn_to && !$message['headers']->mdn_sent) + { + $identity = $USER->get_identity(); + $sender = format_email_recipient($identity['email'], $identity['name']); + $recipient = array_shift($IMAP->decode_address_list($message['headers']->mdn_to)); + $mailto = $recipient['mailto']; + + $compose = new rc_mail_mime(rcmail_header_delm()); + $compose->setParam(array( + 'text_encoding' => 'quoted-printable', + 'html_encoding' => 'quoted-printable', + 'head_encoding' => 'quoted-printable', + 'head_charset' => RCMAIL_CHARSET, + 'html_charset' => RCMAIL_CHARSET, + 'text_charset' => RCMAIL_CHARSET, + )); + + // compose headers array + $headers = array( + 'Date' => date('r'), + 'From' => $sender, + 'To' => $message['headers']->mdn_to, + 'Subject' => rcube_label('receiptread') . ': ' . $message['subject'], + 'Message-ID' => sprintf('<%s@%s>', md5(uniqid('rcmail'.rand(),true)), rcmail_mail_domain($_SESSION['imap_host'])), + 'X-Sender' => $identity['email'], + 'Content-Type' => 'multipart/report; report-type=disposition-notification', + ); + + if (!empty($CONFIG['useragent'])) + $headers['User-Agent'] = $CONFIG['useragent']; + + $body = rcube_label("yourmessage") . "\r\n\r\n" . + "\t" . rcube_label("to") . ': ' . rcube_imap::decode_mime_string($message['headers']->to, $message['headers']->charset) . "\r\n" . + "\t" . rcube_label("subject") . ': ' . $message['subject'] . "\r\n" . + "\t" . rcube_label("sent") . ': ' . format_date(strtotime($message['headers']->date), $CONFIG['date_long']) . "\r\n" . + "\r\n" . rcube_label("receiptnote") . "\r\n"; + + $ua = !empty($CONFIG['useragent']) ? $CONFIG['useragent'] : "RoundCube Webmail (Version ".RCMAIL_VERSION.")"; + $report = "Reporting-UA: $ua\r\n"; + + if ($message['headers']->to) + $report .= "Original-Recipient: {$message['headers']->to}\r\n"; + + $report .= "Final-Recipient: rfc822; {$identity['email']}\r\n" . + "Original-Message-ID: {$message['headers']->messageID}\r\n" . + "Disposition: manual-action/MDN-sent-manually; displayed\r\n"; + + $compose->headers($headers, true); + $compose->setTXTBody($body); + $compose->addAttachment($report, 'message/disposition-notification', 'MDNPart2.txt', false, '7bit', 'inline'); + + $sent = rcmail_deliver_message($compose, $identity['email'], $mailto); + + if ($sent) + { + $IMAP->set_flag($message['UID'], 'MDNSENT'); + return true; + } + } + + return false; +} // register UI objects @@ -1490,4 +1531,4 @@ 'searchform' => 'rcmail_search_form' )); -?> \ No newline at end of file +?> -- Gitblit v1.9.1