summaryrefslogtreecommitdiff
path: root/program/steps/mail/func.inc
diff options
context:
space:
mode:
Diffstat (limited to 'program/steps/mail/func.inc')
-rw-r--r--program/steps/mail/func.inc336
1 files changed, 199 insertions, 137 deletions
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 0211fabc4..50b1e8292 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -5,7 +5,7 @@
| program/steps/mail/func.inc |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2013, The Roundcube Dev Team |
+ | Copyright (C) 2005-2014, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -23,40 +23,8 @@
// always instantiate storage object (but not connect to server yet)
$RCMAIL->storage_init();
-// set imap properties and session vars
-if (strlen(trim($mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true)))) {
- $RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox));
-}
-else if ($RCMAIL->storage) {
- $_SESSION['mbox'] = $RCMAIL->storage->get_folder();
-}
-
-if (!empty($_GET['_page'])) {
- $RCMAIL->storage->set_page(($_SESSION['page'] = intval($_GET['_page'])));
-}
-
-$a_threading = $RCMAIL->config->get('message_threading', array());
-$message_sort_col = $RCMAIL->config->get('message_sort_col');
-$message_sort_order = $RCMAIL->config->get('message_sort_col');
-
-// set default sort col/order to session
-if (!isset($_SESSION['sort_col'])) {
- $_SESSION['sort_col'] = $message_sort_col ? $message_sort_col : '';
-}
-if (!isset($_SESSION['sort_order'])) {
- $_SESSION['sort_order'] = strtoupper($message_sort_order) == 'ASC' ? 'ASC' : 'DESC';
-}
-
-// set threads mode
-if (isset($_GET['_threads'])) {
- if ($_GET['_threads'])
- $a_threading[$_SESSION['mbox']] = true;
- else
- unset($a_threading[$_SESSION['mbox']]);
-
- $RCMAIL->user->save_prefs(array('message_threading' => $a_threading));
-}
-$RCMAIL->storage->set_threading($a_threading[$_SESSION['mbox']]);
+// init environment - set current folder, page, list mode
+rcmail_init_env();
// set message set for search result
if (!empty($_REQUEST['_search']) && isset($_SESSION['search'])
@@ -68,6 +36,26 @@ if (!empty($_REQUEST['_search']) && isset($_SESSION['search'])
$OUTPUT->set_env('search_text', $_SESSION['last_text_search']);
}
+// remove mbox part from _uid
+if (($_uid = rcube_utils::get_input_value('_uid', RCUBE_INPUT_GPC)) && !is_array($_uid) && preg_match('/^\d+-.+/', $_uid)) {
+ list($_uid, $mbox) = explode('-', $_uid, 2);
+ if (isset($_GET['_uid'])) $_GET['_uid'] = $_uid;
+ if (isset($_POST['_uid'])) $_POST['_uid'] = $_uid;
+ $_REQUEST['_uid'] = $_uid;
+ unset($_uid);
+
+ // override mbox
+ if (!empty($mbox)) {
+ $_GET['_mbox'] = $mbox;
+ $_POST['_mbox'] = $mbox;
+ $RCMAIL->storage->set_folder(($_SESSION['mbox'] = $mbox));
+ }
+}
+
+if (!empty($_SESSION['browser_caps']) && !$OUTPUT->ajax_call) {
+ $OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']);
+}
+
// set main env variables, labels and page title
if (empty($RCMAIL->action) || $RCMAIL->action == 'list') {
// connect to storage server and trigger error on failure
@@ -88,6 +76,9 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') {
}
$OUTPUT->set_env('search_mods', rcmail_search_mods());
+
+ if (!empty($_SESSION['search_scope']))
+ $OUTPUT->set_env('search_scope', $_SESSION['search_scope']);
}
$threading = (bool) $RCMAIL->storage->get_threading();
@@ -117,17 +108,13 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') {
$RCMAIL->set_env_config(array('delete_junk', 'flag_for_deletion', 'read_when_deleted',
'skip_deleted', 'display_next', 'message_extwin', 'compose_extwin', 'forward_attachment'));
- if (!empty($_SESSION['browser_caps'])) {
- $OUTPUT->set_env('browser_capabilities', $_SESSION['browser_caps']);
- }
-
if (!$OUTPUT->ajax_call) {
$OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash',
'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage',
- 'copy', 'move', 'quota', 'replyall', 'replylist', 'importwait');
+ 'copy', 'move', 'quota', 'replyall', 'replylist', 'stillsearching');
}
- $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true);
+ $pagetitle = $RCMAIL->localize_foldername($mbox_name, true);
$pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle);
$OUTPUT->set_pagetitle($pagetitle);
@@ -166,6 +153,60 @@ $RCMAIL->register_action_map(array(
));
+/**
+ * Sets storage properties and session
+ */
+function rcmail_init_env()
+{
+ global $RCMAIL;
+
+ $a_threading = $RCMAIL->config->get('message_threading', array());
+ $message_sort_col = $RCMAIL->config->get('message_sort_col');
+ $message_sort_order = $RCMAIL->config->get('message_sort_order');
+
+ // set imap properties and session vars
+ if (!strlen($mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_GPC, true))) {
+ $mbox = strlen($_SESSION['mbox']) ? $_SESSION['mbox'] : 'INBOX';
+ }
+ if (!($page = intval($_GET['_page']))) {
+ $page = $_SESSION['page'] ? $_SESSION['page'] : 1;
+ }
+
+ $RCMAIL->storage->set_folder($_SESSION['mbox'] = $mbox);
+ $RCMAIL->storage->set_page($_SESSION['page'] = $page);
+
+ // set default sort col/order to session
+ if (!isset($_SESSION['sort_col'])) {
+ $_SESSION['sort_col'] = $message_sort_col ? $message_sort_col : '';
+ }
+ if (!isset($_SESSION['sort_order'])) {
+ $_SESSION['sort_order'] = strtoupper($message_sort_order) == 'ASC' ? 'ASC' : 'DESC';
+ }
+
+ // set threads mode
+ if (isset($_GET['_threads'])) {
+ if ($_GET['_threads']) {
+ // re-set current page number when listing mode changes
+ if (!$a_threading[$_SESSION['mbox']]) {
+ $RCMAIL->storage->set_page($_SESSION['page'] = 1);
+ }
+
+ $a_threading[$_SESSION['mbox']] = true;
+ }
+ else {
+ // re-set current page number when listing mode changes
+ if ($a_threading[$_SESSION['mbox']]) {
+ $RCMAIL->storage->set_page($_SESSION['page'] = 1);
+ }
+
+ unset($a_threading[$_SESSION['mbox']]);
+ }
+
+ $RCMAIL->user->save_prefs(array('message_threading' => $a_threading));
+ }
+
+ $RCMAIL->storage->set_threading($a_threading[$_SESSION['mbox']]);
+}
/**
* Returns default search mods
@@ -298,7 +339,7 @@ function rcmail_message_list($attrib)
$OUTPUT->set_env('sort_col', $_SESSION['sort_col']);
$OUTPUT->set_env('sort_order', $_SESSION['sort_order']);
$OUTPUT->set_env('messages', array());
- $OUTPUT->set_env('coltypes', $a_show_cols);
+ $OUTPUT->set_env('listcols', $a_show_cols);
$OUTPUT->include_script('list.js');
@@ -315,7 +356,7 @@ function rcmail_message_list($attrib)
/**
* return javascript commands to add rows to the message list
*/
-function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null)
+function rcmail_js_message_list($a_headers, $insert_top=false, $a_show_cols=null)
{
global $RCMAIL, $OUTPUT;
@@ -334,6 +375,14 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
$head_replace = true;
}
+ // add 'folder' column to list on multi-folder searches
+ $search_set = $RCMAIL->storage->get_search_set();
+ $multifolder = $search_set && $search_set[1]->multi;
+ if ($multifolder && !in_array('folder', $a_show_cols)) {
+ $a_show_cols[] = 'folder';
+ $head_replace = true;
+ }
+
$mbox = $RCMAIL->storage->get_folder();
// make sure 'threads' and 'subject' columns are present
@@ -342,8 +391,6 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
if (!in_array('threads', $a_show_cols))
array_unshift($a_show_cols, 'threads');
- $_SESSION['list_attrib']['columns'] = $a_show_cols;
-
// Make sure there are no duplicated columns (#1486999)
$a_show_cols = array_unique($a_show_cols);
@@ -364,6 +411,12 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
$OUTPUT->command('set_message_coltypes', $a_show_cols, $thead, $smart_col);
+ if ($multifolder && $_SESSION['search_scope'] == 'all') {
+ $OUTPUT->command('select_folder', '');
+ }
+
+ $OUTPUT->set_env('multifolder_listing', $multifolder);
+
if (empty($a_headers)) {
return;
}
@@ -380,6 +433,14 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
if (empty($header))
continue;
+ // make message UIDs unique by appending the folder name
+ if ($multifolder) {
+ $header->uid .= '-'.$header->folder;
+ $header->flags['skip_mbox_check'] = true;
+ if ($header->parent_uid)
+ $header->parent_uid .= '-'.$header->folder;
+ }
+
$a_msg_cols = array();
$a_msg_flags = array();
@@ -398,6 +459,8 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
$cont = show_bytes($header->$col);
else if ($col == 'date')
$cont = $RCMAIL->format_date($header->date);
+ else if ($col == 'folder')
+ $cont = rcube::Q(rcube_charset::convert($header->folder, 'UTF7-IMAP'));
else
$cont = rcube::Q($header->$col);
@@ -421,7 +484,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
$a_msg_flags['prio'] = (int) $header->priority;
$a_msg_flags['ctype'] = rcube::Q($header->ctype);
- $a_msg_flags['mbox'] = $mbox;
+ $a_msg_flags['mbox'] = $header->folder;
// merge with plugin result (Deprecated, use $header->flags)
if (!empty($header->list_flags) && is_array($header->list_flags))
@@ -481,7 +544,7 @@ function rcmail_message_list_head($attrib, $a_show_cols)
$list_menu = '';
}
- $cells = array();
+ $cells = $coltypes = array();
// get name of smart From/To column in folder context
if (array_search('fromto', $a_show_cols) !== false) {
@@ -489,32 +552,39 @@ function rcmail_message_list_head($attrib, $a_show_cols)
}
foreach ($a_show_cols as $col) {
+ $label = '';
+ $sortable = false;
+
// get column name
switch ($col) {
case 'flag':
- $col_name = '<span class="flagged">&nbsp;</span>';
+ $col_name = html::span('flagged', '&nbsp;');
break;
case 'attachment':
case 'priority':
case 'status':
- $col_name = '<span class="' . $col .'">&nbsp;</span>';
+ $col_name = html::span($col, '&nbsp;');
break;
case 'threads':
$col_name = $list_menu;
break;
case 'fromto':
- $col_name = rcube::Q($RCMAIL->gettext($smart_col));
+ $label = $RCMAIL->gettext($smart_col);
+ $col_name = rcube::Q($label);
break;
default:
- $col_name = rcube::Q($RCMAIL->gettext($col));
+ $label = $RCMAIL->gettext($col);
+ $col_name = rcube::Q($label);
}
// make sort links
if (in_array($col, $a_sort_cols)) {
+ $sortable = true;
$col_name = html::a(array(
- 'href' => "./#sort",
- 'onclick' => 'return '.rcmail_output::JS_OBJECT_NAME.".command('sort','".$col."',this)",
- 'title' => $RCMAIL->gettext('sortby')
+ 'href' => "./#sort",
+ 'class' => 'sortcol',
+ 'rel' => $col,
+ 'title' => $RCMAIL->gettext('sortby')
), $col_name);
}
else if ($col_name[0] != '<') {
@@ -526,8 +596,10 @@ function rcmail_message_list_head($attrib, $a_show_cols)
// put it all together
$cells[] = array('className' => $class_name, 'id' => "rcm$col", 'html' => $col_name);
+ $coltypes[$col] = array('className' => $class_name, 'id' => "rcm$col", 'label' => $label, 'sortable' => $sortable);
}
+ $RCMAIL->output->set_env('coltypes', $coltypes);
return $cells;
}
@@ -583,7 +655,7 @@ function rcmail_get_messagecount_text($count = null, $page = null)
$max = $RCMAIL->storage->count(NULL, $RCMAIL->storage->get_threading() ? 'THREADS' : 'ALL');
if ($max == 0)
- $out = $RCMAIL->gettext('mailboxempty');
+ $out = $RCMAIL->storage->get_search_set() ? $RCMAIL->gettext('nomessages') : $RCMAIL->gettext('mailboxempty');
else
$out = $RCMAIL->gettext(array('name' => $RCMAIL->storage->get_threading() ? 'threadsfromto' : 'messagesfromto',
'vars' => array('from' => $start_msg,
@@ -806,95 +878,29 @@ function rcmail_print_body($part, $p = array())
// plaintext postprocessing
if ($part->ctype_secondary == 'plain') {
- if ($part->ctype_secondary == 'plain' && $part->ctype_parameters['format'] == 'flowed') {
- $body = rcube_mime::unfold_flowed($body);
- }
-
- $body = rcmail_plain_body($body);
+ $body = rcmail_plain_body($body, $part->ctype_parameters['format'] == 'flowed');
}
// allow post-processing of the message body
$data = $RCMAIL->plugins->exec_hook('message_part_after',
array('type' => $part->ctype_secondary, 'body' => $body, 'id' => $part->mime_id) + $data);
- return $data['type'] == 'html' ? $data['body'] : html::tag('pre', array(), $data['body']);
+ return $data['body'];
}
/**
* Handle links and citation marks in plain text message
*
* @param string Plain text string
+ * @param boolean Set to True if the source text is in format=flowed
*
* @return string Formatted HTML string
*/
-function rcmail_plain_body($body)
+function rcmail_plain_body($body, $flowed = false)
{
- global $RCMAIL;
-
- // make links and email-addresses clickable
- $attribs = array('link_attribs' => array('rel' => 'noreferrer', 'target' => '_blank'));
- $replacer = new rcmail_string_replacer($attribs);
-
- // search for patterns like links and e-mail addresses and replace with tokens
- $body = $replacer->replace($body);
-
- // split body into single lines
- $body = preg_split('/\r?\n/', $body);
- $quote_level = 0;
- $last = -1;
-
- // find/mark quoted lines...
- for ($n=0, $cnt=count($body); $n < $cnt; $n++) {
- if ($body[$n][0] == '>' && preg_match('/^(>+ {0,1})+/', $body[$n], $regs)) {
- $q = substr_count($regs[0], '>');
- $body[$n] = substr($body[$n], strlen($regs[0]));
-
- if ($q > $quote_level) {
- $body[$n] = $replacer->get_replacement($replacer->add(
- str_repeat('<blockquote>', $q - $quote_level))) . $body[$n];
- $last = $n;
- }
- else if ($q < $quote_level) {
- $body[$n] = $replacer->get_replacement($replacer->add(
- str_repeat('</blockquote>', $quote_level - $q))) . $body[$n];
- $last = $n;
- }
- }
- else {
- $q = 0;
- if ($quote_level > 0)
- $body[$n] = $replacer->get_replacement($replacer->add(
- str_repeat('</blockquote>', $quote_level))) . $body[$n];
- }
-
- $quote_level = $q;
- }
-
- $body = join("\n", $body);
-
- // quote plain text (don't use rcube::Q() here, to display entities "as is")
- $table = get_html_translation_table(HTML_SPECIALCHARS);
- unset($table['?']);
- $body = strtr($body, $table);
-
- // colorize signature (up to <sig_max_lines> lines)
- $len = strlen($body);
- $sig_max_lines = $RCMAIL->config->get('sig_max_lines', 15);
-
- while (($sp = strrpos($body, "-- \n", $sp ? -$len+$sp-1 : 0)) !== false) {
- if ($sp == 0 || $body[$sp-1] == "\n") {
- // do not touch blocks with more that X lines
- if (substr_count($body, "\n", $sp) < $sig_max_lines) {
- $body = substr($body, 0, max(0, $sp))
- . '<span class="sig">'.substr($body, $sp).'</span>';
- }
-
- break;
- }
- }
-
- // insert url/mailto links and citation tags
- $body = $replacer->resolve($body);
+ $options = array('flowed' => $flowed, 'wrap' => !$flowed);
+ $text2html = new rcube_text2html($body, false, $options);
+ $body = $text2html->get_html();
return $body;
}
@@ -1049,7 +1055,9 @@ function rcmail_message_headers($attrib, $headers=null)
$plugin = $RCMAIL->plugins->exec_hook('message_headers_output', array(
'output' => $output_headers,
'headers' => $headers_obj,
- 'exclude' => $exclude_headers
+ 'exclude' => $exclude_headers, // readonly
+ 'folder' => $MESSAGE->folder, // readonly
+ 'uid' => $MESSAGE->uid, // readonly
));
// single header value is requested
@@ -1224,8 +1232,8 @@ function rcmail_message_body($attrib)
$plugin = $RCMAIL->plugins->exec_hook('message_body_prefix',
array('part' => $MESSAGE, 'prefix' => ''));
- $out .= html::div('message-part', $plugin['prefix'] . html::tag('pre', array(),
- rcmail_plain_body(rcube::Q($MESSAGE->body, 'strict', false))));
+ $out .= html::div('message-part',
+ $plugin['prefix'] . rcmail_plain_body($MESSAGE->body));
}
}
@@ -1295,12 +1303,10 @@ function rcmail_message_body($attrib)
function rcmail_part_image_type($part)
{
- $rcmail = rcmail::get_instance();
-
// Skip TIFF images if browser doesn't support this format...
$tiff_support = !empty($_SESSION['browser_caps']) && !empty($_SESSION['browser_caps']['tif']);
// until we can convert them to JPEG
- $tiff_support = $tiff_support || $rcmail->config->get('im_convert_path');
+ $tiff_support = $tiff_support || rcube_image::is_convertable('image/tiff');
// Content-type regexp
$mime_regex = $tiff_support ? '/^image\//i' : '/^image\/(?!tif)/i';
@@ -1693,7 +1699,8 @@ function rcmail_draftinfo_encode($p)
{
$parts = array();
foreach ($p as $key => $val) {
- $parts[] = $key . '=' . ($key == 'folder' ? base64_encode($val) : $val);
+ $encode = $key == 'folder' || strpos($val, ';') !== false;
+ $parts[] = $key . '=' . ($encode ? 'B::' . base64_encode($val) : $val);
}
return join('; ', $parts);
@@ -1705,7 +1712,10 @@ function rcmail_draftinfo_decode($str)
foreach (preg_split('/;\s+/', $str) as $part) {
list($key, $val) = explode('=', $part, 2);
- if ($key == 'folder') {
+ if (strpos($val, 'B::') === 0) {
+ $val = base64_decode(substr($val, 3));
+ }
+ else if ($key == 'folder') {
$val = base64_decode($val);
}
@@ -1984,7 +1994,7 @@ function rcmail_search_filter($attrib)
$ctypes = array('application/', 'multipart/m', 'multipart/signed', 'multipart/report');
// Build search string of "with attachment" filter
- $attachment = str_repeat(' OR', count($ctypes)-1);
+ $attachment = trim(str_repeat(' OR', count($ctypes)-1));
foreach ($ctypes as $type) {
$attachment .= ' HEADER Content-Type ' . rcube_imap_generic::escape($type);
}
@@ -2070,6 +2080,58 @@ function rcmail_message_import_form($attrib = array())
$content);
$RCMAIL->output->add_gui_object('importform', $attrib['id'].'Frm');
+ $RCMAIL->output->add_label('selectimportfile','importwait');
return html::div($attrib, $out);
}
+
+/**
+ * Add groups from the given address source to the address book widget
+ */
+function rcmail_compose_contact_groups($abook, $source_id, $search = null, $search_mode = 0)
+{
+ global $RCMAIL, $OUTPUT;
+
+ $jsresult = array();
+ foreach ($abook->list_groups($search, $search_mode) as $group) {
+ $abook->reset();
+ $abook->set_group($group['ID']);
+ $group_prop = $abook->get_group($group['ID']);
+
+ // group (distribution list) with email address(es)
+ if ($group_prop['email']) {
+ foreach ((array)$group_prop['email'] as $email) {
+ $row_id = 'G'.$group['ID'];
+ $jsresult[$row_id] = format_email_recipient($email, $group['name']);
+ $OUTPUT->command('add_contact_row', $row_id, array(
+ 'contactgroup' => html::span(array('title' => $email), rcube::Q($group['name']))), 'group');
+ }
+ }
+ // make virtual groups clickable to list their members
+ else if ($group_prop['virtual']) {
+ $row_id = 'G'.$group['ID'];
+ $OUTPUT->command('add_contact_row', $row_id, array(
+ 'contactgroup' => html::a(array(
+ 'href' => '#list',
+ 'rel' => $group['ID'],
+ 'title' => $RCMAIL->gettext('listgroup'),
+ 'onclick' => sprintf("return %s.command('pushgroup',{'source':'%s','id':'%s'},this,event)",
+ rcmail_output::JS_OBJECT_NAME, $source_id, $group['ID']),
+ ), rcube::Q($group['name']) . '&nbsp;' . html::span('action', '&raquo;'))),
+ 'group',
+ array('ID' => $group['ID'], 'name' => $group['name'], 'virtual' => true));
+ }
+ // show group with count
+ else if (($result = $abook->count()) && $result->count) {
+ $row_id = 'E'.$group['ID'];
+ $jsresult[$row_id] = $group['name'];
+ $OUTPUT->command('add_contact_row', $row_id, array(
+ 'contactgroup' => rcube::Q($group['name'] . ' (' . intval($result->count) . ')')), 'group');
+ }
+ }
+
+ $abook->reset();
+ $abook->set_group(0);
+
+ return $jsresult;
+}