Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2571832
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
73 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/program/include/rcmail_template.inc b/program/include/rcmail_template.inc
index e2fa682e4..6e3fe52b8 100644
--- a/program/include/rcmail_template.inc
+++ b/program/include/rcmail_template.inc
@@ -1,631 +1,631 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/include/rcmail_template.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2007, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Class to handle HTML page output using a skin template. |
| Extends rcube_html_page class from rcube_shared.inc |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id: $
*/
require_once('include/rcube_shared.inc');
class rcmail_template extends rcube_html_page
{
var $config;
var $task = '';
var $framed = false;
var $ajax_call = false;
var $pagetitle = '';
var $env = array();
var $js_env = array();
var $js_commands = array();
var $object_handlers = array();
// PHP 5 constructor
function __construct(&$config, $task)
{
parent::__construct();
$this->task = $task;
$this->config = $config;
$this->ajax_call = !empty($_GET['_remote']) || !empty($_POST['_remote']);
// add common javascripts
if (!$this->ajax_call)
{
$javascript = "var ".JS_OBJECT_NAME." = new rcube_webmail();";
// don't wait for page onload. Call init at the bottom of the page (delayed)
$javascript_foot = "if (window.call_init)\n call_init('".JS_OBJECT_NAME."');";
$this->add_script($javascript, 'head_top');
$this->add_script($javascript_foot, 'foot');
$this->scripts_path = 'program/js/';
$this->include_script('common.js');
$this->include_script('app.js');
}
}
// PHP 4 compatibility
function rcmail_template(&$config, $task)
{
$this->__construct($config, $task);
}
/**
* Set environment variable
*/
function set_env($name, $value, $addtojs=true)
{
$this->env[$name] = $value;
if ($addtojs || isset($this->js_env[$name]))
$this->js_env[$name] = $value;
}
/**
* Set page title variable
*/
function set_pagetitle($title)
{
$this->pagetitle = $title;
}
/**
* Register a template object handler
*
* @param string Object name
* @param string Function name to call
*/
function add_handler($obj, $func)
{
$this->object_handlers[$obj] = $func;
}
/**
* Register a list of template object handlers
*
* @param array Hash array with object=>handler pairs
*/
function add_handlers($arr)
{
$this->object_handlers = array_merge($this->object_handlers, $arr);
}
/**
* Register a GUI object to the client script
*
* @param string Object name
* @param string Object ID
*/
function add_gui_object($obj, $id)
{
$this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
}
/**
* Call a client method
*
* @param string Method to call
* @param ... Additional arguments
*/
function command()
{
$this->js_commands[] = func_get_args();
}
/**
* Invoke display_message command
*/
function show_message($message, $type='notice', $vars=NULL)
{
$this->command(
'display_message',
rcube_label(array('name' => $message, 'vars' => $vars)),
$type);
}
/**
* Delete all stored env variables and commands
*/
function reset()
{
$this->env = array();
$this->js_env = array();
$this->js_commands = array();
$this->object_handlers = array();
parent::reset();
}
/**
* Send the request output to the client.
* This will either parse a skin tempalte or send an AJAX response
*
* @param string Template name
* @param boolean True if script should terminate (default)
*/
function send($templ=null, $exit=true)
{
if ($this->ajax_call)
$this->remote_response('', !$exit);
else if ($templ != 'iframe')
$this->parse($templ, false);
else
{
$this->framed = $templ == 'iframe' ? true : $this->framed;
$this->write();
}
if ($exit)
exit;
}
/**
* Send an AJAX response with executable JS code
*
* @param string Additional JS code
* @param boolean True if output buffer should be flushed
*/
function remote_response($add='', $flush=false)
{
static $s_header_sent = FALSE;
if (!$s_header_sent)
{
$s_header_sent = TRUE;
send_nocacheing_headers();
header('Content-Type: application/x-javascript; charset='.RCMAIL_CHARSET);
print '/** ajax response ['.date('d/M/Y h:i:s O')."] **/\n";
}
// unset default env vars
unset($this->js_env['task'], $this->js_env['action'], $this->js_env['comm_path']);
// send response code
print rcube_charset_convert($this->get_js_commands() . $add, RCMAIL_CHARSET, $this->get_charset());
if ($flush) // flush the output buffer
flush();
}
/**
* @override
*/
function write($template='')
{
// write all env variables to client
$js = $this->framed ? "if(window.parent) {\n" : '';
$js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
$this->add_script($js, 'head_top');
// call super method
parent::write($template, $this->config['skin_path']);
}
/**
* Parse a specific skin template and deliver to stdout
*
* @param string Template name
* @param boolean Exit script
*/
function parse($name='main', $exit=true)
{
$skin_path = $this->config['skin_path'];
// read template file
$templ = '';
$path = "$skin_path/templates/$name.html";
if($fp = @fopen($path, 'r'))
{
$templ = fread($fp, filesize($path));
fclose($fp);
}
else
{
raise_error(array(
'code' => 501,
'type' => 'php',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Error loading template for '$name'"), TRUE, TRUE);
return FALSE;
}
// parse for specialtags
$output = $this->parse_xml($this->parse_conditions($templ));
// add debug console
if ($this->config['debug_level'] & 8)
$this->add_footer('<div style="position:absolute;top:5px;left:5px;width:400px;padding:0.2em;background:white;opacity:0.8;z-index:9000">
<a href="#toggle" onclick="con=document.getElementById(\'dbgconsole\');con.style.display=(con.style.display==\'none\'?\'block\':\'none\');return false">console</a>
<form action="/" name="debugform"><textarea name="console" id="dbgconsole" rows="20" cols="40" wrap="off" style="display:none;width:400px;border:none;font-size:x-small"></textarea></form></div>');
$this->write(trim($this->parse_with_globals($output)), $skin_path);
if ($exit)
exit;
}
/**
* Return executable javascript code for all registered commands
* @private
*/
function get_js_commands()
{
$out = '';
if (!$this->framed)
$out .= ($this->ajax_call ? 'this' : JS_OBJECT_NAME) . '.set_env('.json_serialize($this->js_env).");\n";
foreach ($this->js_commands as $i => $args)
{
$method = array_shift($args);
foreach ($args as $i => $arg)
$args[$i] = json_serialize($arg);
$parent = $this->framed || preg_match('/^parent\./', $method);
$out .= sprintf(
"%s.%s(%s);\n",
$this->ajax_call ? 'this' : ($parent ? 'parent.' : '') . JS_OBJECT_NAME,
preg_replace('/^parent\./', '', $method),
join(',', $args));
}
return $out;
}
/**
* Make URLs starting with a slash point to skin directory
*/
function abs_url($str)
{
return preg_replace('/^\//', $this->config['skin_path'].'/', $str);
}
/***** Template parsing methods *****/
/**
* Replace all strings ($varname) with the content
* of the according global variable.
*/
function parse_with_globals($input)
{
$GLOBALS['__comm_path'] = $GLOBALS['COMM_PATH'];
return preg_replace('/\$(__[a-z0-9_\-]+)/e', '$GLOBALS["\\1"]', $input);
}
/**
* Parse for conditional tags
*/
function parse_conditions($input)
{
if (($matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE)) && count($matches)==4)
{
if (preg_match('/^(else|endif)$/i', $matches[1]))
return $matches[0] . $this->parse_conditions($matches[3]);
else
{
$attrib = parse_attrib_string($matches[2]);
if (isset($attrib['condition']))
{
$condmet = $this->check_condition($attrib['condition']);
$submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
if ($condmet)
- $result = $submatches[0] . preg_replace('/.*<roundcube:endif\s+[^>]+>/is', '', $submatches[3]);
+ $result = $submatches[0] . ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>/Uis', '', $submatches[3], 1) : $submatches[3]);
else
$result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
return $matches[0] . $this->parse_conditions($result);
}
else
{
raise_error(array('code' => 500, 'type' => 'php', 'line' => __LINE__, 'file' => __FILE__,
'message' => "Unable to parse conditional tag " . $matches[2]), TRUE, FALSE);
}
}
}
return $input;
}
/**
* Determines if a given condition is met
*
* @return True if condition is valid, False is not
*/
function check_condition($condition)
{
$condition = preg_replace(
array('/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)/i', '/env:([a-z0-9_]+)/i', '/request:([a-z0-9_]+)/ie'),
array("\$_SESSION['\\1']", "\$this->config['\\1']", "\$this->env['\\1']", "get_input_value('\\1', RCUBE_INPUT_GPC)"),
$condition);
return @eval("return (".$condition.");");
}
/**
* Search for special tags in input and replace them
* with the appropriate content
*
* @param string Input string to parse
* @return Altered input string
*/
function parse_xml($input)
{
return preg_replace('/<roundcube:([-_a-z]+)\s+([^>]+)>/Uie', "\$this->xml_command('\\1', '\\2')", $input);
}
/**
* Convert a xml command tag into real content
*
* @param string Tag command: object,button,label, etc.
* @param string Attribute string
* @return Tag/Object content string
*/
function xml_command($command, $str_attrib, $add_attrib=array())
{
$command = strtolower($command);
$attrib = parse_attrib_string($str_attrib) + $add_attrib;
// empty output if required condition is not met
if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition']))
return '';
// execute command
switch ($command)
{
// return a button
case 'button':
if ($attrib['command'])
return $this->button($attrib);
break;
// show a label
case 'label':
if ($attrib['name'] || $attrib['command'])
return Q(rcube_label($attrib + array('vars' => array('product' => $this->config['product_name']))));
break;
// include a file
case 'include':
$path = realpath($this->config['skin_path'].$attrib['file']);
if ($fp = @fopen($path, 'r'))
{
$incl = fread($fp, filesize($path));
fclose($fp);
return $this->parse_xml($incl);
}
break;
// return code for a specific application object
case 'object':
$object = strtolower($attrib['name']);
// execute object handler function
if ($this->object_handlers[$object] && function_exists($this->object_handlers[$object]))
return call_user_func($this->object_handlers[$object], $attrib);
else if ($object=='productname')
{
$name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'RoundCube Webmail';
return Q($name);
}
else if ($object=='version')
{
return (string)RCMAIL_VERSION;
}
else if ($object=='pagetitle')
{
$task = $this->task;
$title = !empty($this->config['product_name']) ? $this->config['product_name'].' :: ' : '';
if (!empty($this->pagetitle))
$title .= $this->pagetitle;
else if ($task == 'login')
$title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
else
$title .= ucfirst($task);
return Q($title);
}
break;
}
return '';
}
/**
* Create and register a button
*
* @param array Button attributes
* @return HTML button
*/
function button($attrib)
{
global $CONFIG, $OUTPUT, $BROWSER, $MAIN_TASKS;
static $sa_buttons = array();
static $s_button_count = 100;
// these commands can be called directly via url
$a_static_commands = array('compose', 'list');
$skin_path = $this->config['skin_path'];
if (!($attrib['command'] || $attrib['name']))
return '';
// try to find out the button type
if ($attrib['type'])
$attrib['type'] = strtolower($attrib['type']);
else
$attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
$command = $attrib['command'];
// take the button from the stack
if($attrib['name'] && $sa_buttons[$attrib['name']])
$attrib = $sa_buttons[$attrib['name']];
// add button to button stack
else if($attrib['image'] || $attrib['imageact'] || $attrib['imagepas'] || $attrib['class'])
{
if (!$attrib['name'])
$attrib['name'] = $command;
if (!$attrib['image'])
$attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
$sa_buttons[$attrib['name']] = $attrib;
}
// get saved button for this command/name
else if ($command && $sa_buttons[$command])
$attrib = $sa_buttons[$command];
//else
// return '';
// set border to 0 because of the link arround the button
if ($attrib['type']=='image' && !isset($attrib['border']))
$attrib['border'] = 0;
if (!$attrib['id'])
$attrib['id'] = sprintf('rcmbtn%d', $s_button_count++);
// get localized text for labels and titles
if ($attrib['title'])
$attrib['title'] = Q(rcube_label($attrib['title']));
if ($attrib['label'])
$attrib['label'] = Q(rcube_label($attrib['label']));
if ($attrib['alt'])
$attrib['alt'] = Q(rcube_label($attrib['alt']));
// set title to alt attribute for IE browsers
if ($BROWSER['ie'] && $attrib['title'] && !$attrib['alt'])
{
$attrib['alt'] = $attrib['title'];
unset($attrib['title']);
}
// add empty alt attribute for XHTML compatibility
if (!isset($attrib['alt']))
$attrib['alt'] = '';
// register button in the system
if ($attrib['command'])
{
$this->add_script(sprintf(
"%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
JS_OBJECT_NAME,
$command,
$attrib['id'],
$attrib['type'],
$attrib['imageact'] ? $skin_path.$attrib['imageact'] : $attrib['classact'],
$attrib['imagesel'] ? $skin_path.$attrib['imagesel'] : $attrib['classsel'],
$attrib['imageover'] ? $skin_path.$attrib['imageover'] : '')
);
// make valid href to specific buttons
if (in_array($attrib['command'], $MAIN_TASKS))
$attrib['href'] = Q(rcmail_self_url(null, null, $attrib['command']));
else if (in_array($attrib['command'], $a_static_commands))
$attrib['href'] = Q(rcmail_self_url($attrib['command']));
}
// overwrite attributes
if (!$attrib['href'])
$attrib['href'] = '#';
if ($command)
$attrib['onclick'] = sprintf("return %s.command('%s','%s',this)", JS_OBJECT_NAME, $command, $attrib['prop']);
if ($command && $attrib['imageover'])
{
$attrib['onmouseover'] = sprintf("return %s.button_over('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
$attrib['onmouseout'] = sprintf("return %s.button_out('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
}
if ($command && $attrib['imagesel'])
{
$attrib['onmousedown'] = sprintf("return %s.button_sel('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
$attrib['onmouseup'] = sprintf("return %s.button_out('%s','%s')", JS_OBJECT_NAME, $command, $attrib['id']);
}
$out = '';
// generate image tag
if ($attrib['type']=='image')
{
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'width', 'height', 'border', 'hspace', 'vspace', 'align', 'alt'));
$img_tag = sprintf('<img src="%%s"%s />', $attrib_str);
$btn_content = sprintf($img_tag, $skin_path.$attrib['image']);
if ($attrib['label'])
$btn_content .= ' '.$attrib['label'];
$link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'title');
}
else if ($attrib['type']=='link')
{
$btn_content = $attrib['label'] ? $attrib['label'] : $attrib['command'];
$link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style');
}
else if ($attrib['type']=='input')
{
$attrib['type'] = 'button';
if ($attrib['label'])
$attrib['value'] = $attrib['label'];
$attrib_str = create_attrib_string($attrib, array('type', 'value', 'onclick', 'id', 'class', 'style'));
$out = sprintf('<input%s disabled />', $attrib_str);
}
// generate html code for button
if ($btn_content)
{
$attrib_str = create_attrib_string($attrib, $link_attrib);
$out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
}
return $out;
}
}
?>
\ No newline at end of file
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 7416fb5d4..1848d301a 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1,1483 +1,1483 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/mail/func.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2007, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Provide webmail functionality and GUI objects |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
require_once('lib/html2text.inc');
require_once('lib/enriched.inc');
$EMAIL_ADDRESS_PATTERN = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i';
if (empty($_SESSION['mbox']))
$_SESSION['mbox'] = $IMAP->get_mailbox_name();
// set imap properties and session vars
if ($mbox = get_input_value('_mbox', RCUBE_INPUT_GPC))
{
$IMAP->set_mailbox($mbox);
$_SESSION['mbox'] = $mbox;
}
if (!empty($_GET['_page']))
{
$IMAP->set_page((int)$_GET['_page']);
$_SESSION['page'] = (int)$_GET['_page'];
}
// set mailbox to INBOX if not set
if (empty($_SESSION['mbox']))
$_SESSION['mbox'] = $IMAP->get_mailbox_name();
// set default sort col/order to session
if (!isset($_SESSION['sort_col']))
$_SESSION['sort_col'] = $CONFIG['message_sort_col'];
if (!isset($_SESSION['sort_order']))
$_SESSION['sort_order'] = $CONFIG['message_sort_order'];
// set message set for search result
if (!empty($_GET['_search']) && isset($_SESSION['search'][$_GET['_search']]))
$IMAP->set_search_set($_SESSION['search'][$_GET['_search']]);
// define url for getting message parts
if (strlen($_GET['_uid']))
$GET_URL = sprintf('%s&_action=get&_mbox=%s&_uid=%d', $COMM_PATH, $IMAP->get_mailbox_name(), get_input_value('_uid', RCUBE_INPUT_GET));
// set current mailbox in client environment
$OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name());
-//$OUTPUT->set_pagetitle(rcube_charset_convert($IMAP->get_mailbox_name(), 'UTF-7', 'UTF-8'));
+$OUTPUT->set_env('quota', $IMAP->get_capability('quota'));
if ($CONFIG['trash_mbox'])
$OUTPUT->set_env('trash_mailbox', $CONFIG['trash_mbox']);
if ($CONFIG['drafts_mbox'])
$OUTPUT->set_env('drafts_mailbox', $CONFIG['drafts_mbox']);
if ($CONFIG['junk_mbox'])
$OUTPUT->set_env('junk_mailbox', $CONFIG['junk_mbox']);
if (!$OUTPUT->ajax_call)
rcube_add_label('checkingmail');
// 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_self_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
function rcmail_message_list($attrib)
{
global $IMAP, $CONFIG, $COMM_PATH, $OUTPUT;
$skin_path = $CONFIG['skin_path'];
$image_tag = '<img src="%s%s" alt="%s" border="0" />';
// check to see if we have some settings for sorting
$sort_col = $_SESSION['sort_col'];
$sort_order = $_SESSION['sort_order'];
// add some labels to client
rcube_add_label('from', 'to');
// get message headers
$a_headers = $IMAP->list_headers('', '', $sort_col, $sort_order);
// add id to message list table if not specified
if (!strlen($attrib['id']))
$attrib['id'] = 'rcubemessagelist';
// allow the following attributes to be added to the <table> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
$out = '<table' . $attrib_str . ">\n";
// define list of cols to be displayed
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
$a_sort_cols = array('subject', 'date', 'from', 'to', 'size');
// show 'to' instead of from in sent messages
if (($IMAP->get_mailbox_name()==$CONFIG['sent_mbox'] || $IMAP->get_mailbox_name()==$CONFIG['drafts_mbox']) && ($f = array_search('from', $a_show_cols))
&& !array_search('to', $a_show_cols))
$a_show_cols[$f] = 'to';
// add col definition
$out .= '<colgroup>';
$out .= '<col class="icon" />';
foreach ($a_show_cols as $col)
$out .= sprintf('<col class="%s" />', $col);
$out .= '<col class="icon" />';
$out .= "</colgroup>\n";
// add table title
$out .= "<thead><tr>\n<td class=\"icon\"> </td>\n";
$javascript = '';
foreach ($a_show_cols as $col)
{
// get column name
$col_name = Q(rcube_label($col));
// make sort links
$sort = '';
if ($IMAP->get_capability('sort') && in_array($col, $a_sort_cols))
{
// have buttons configured
if (!empty($attrib['sortdescbutton']) || !empty($attrib['sortascbutton']))
{
$sort = ' ';
// asc link
if (!empty($attrib['sortascbutton']))
{
$sort .= $OUTPUT->button(array(
'command' => 'sort',
'prop' => $col.'_ASC',
'image' => $attrib['sortascbutton'],
'align' => 'absmiddle',
'title' => 'sortasc'));
}
// desc link
if (!empty($attrib['sortdescbutton']))
{
$sort .= $OUTPUT->button(array(
'command' => 'sort',
'prop' => $col.'_DESC',
'image' => $attrib['sortdescbutton'],
'align' => 'absmiddle',
'title' => 'sortdesc'));
}
}
// just add a link tag to the header
else
{
$col_name = sprintf('<a href="./#sort" onclick="return %s.command(\'sort\',\'%s\',this)" title="%s">%s</a>',
JS_OBJECT_NAME,
$col,
rcube_label('sortby'),
$col_name);
}
}
$sort_class = $col==$sort_col ? " sorted$sort_order" : '';
// put it all together
$out .= '<td class="'.$col.$sort_class.'" id="rcmHead'.$col.'">' . "$col_name$sort</td>\n";
}
$out .= '<td class="icon">'.($attrib['attachmenticon'] ? sprintf($image_tag, $skin_path, $attrib['attachmenticon'], '') : '')."</td>\n";
$out .= "</tr></thead>\n<tbody>\n";
// 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')));
}
$a_js_message_arr = array();
// create row for each message
foreach ($a_headers as $i => $header) //while (list($i, $header) = each($a_headers))
{
$message_icon = $attach_icon = '';
$js_row_arr = array();
$zebra_class = $i%2 ? 'even' : 'odd';
// set messag attributes to javascript array
if ($header->deleted)
$js_row_arr['deleted'] = true;
if (!$header->seen)
$js_row_arr['unread'] = true;
if ($header->answered)
$js_row_arr['replied'] = true;
// set message icon
if ($attrib['deletedicon'] && $header->deleted)
$message_icon = $attrib['deletedicon'];
else if ($attrib['unreadicon'] && !$header->seen)
$message_icon = $attrib['unreadicon'];
else if ($attrib['repliedicon'] && $header->answered)
$message_icon = $attrib['repliedicon'];
else if ($attrib['messageicon'])
$message_icon = $attrib['messageicon'];
// set attachment icon
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",
$header->uid,
$header->seen ? '' : ' unread',
$header->deleted ? ' deleted' : '',
$zebra_class);
$out .= sprintf("<td class=\"icon\">%s</td>\n", $message_icon ? sprintf($image_tag, $skin_path, $message_icon, '') : '');
// format each col
foreach ($a_show_cols as $col)
{
if ($col=='from' || $col=='to')
$cont = Q(rcmail_address_string($header->$col, 3, $attrib['addicon']), 'show');
else if ($col=='subject')
{
$cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
if (empty($cont)) $cont = Q(rcube_label('nosubject'));
}
else if ($col=='size')
$cont = show_bytes($header->$col);
else if ($col=='date')
$cont = format_date($header->date);
else
$cont = Q($header->$col);
$out .= '<td class="'.$col.'">' . $cont . "</td>\n";
}
$out .= sprintf("<td class=\"icon\">%s</td>\n", $attach_icon ? sprintf($image_tag, $skin_path, $attach_icon, '') : '');
$out .= "</tr>\n";
if (sizeof($js_row_arr))
$a_js_message_arr[$header->uid] = $js_row_arr;
}
// complete message table
$out .= "</tbody></table>\n";
$message_count = $IMAP->messagecount();
// set client env
$OUTPUT->add_gui_object('mailcontframe', 'mailcontframe');
$OUTPUT->add_gui_object('messagelist', $attrib['id']);
$OUTPUT->set_env('messagecount', $message_count);
$OUTPUT->set_env('current_page', $IMAP->list_page);
$OUTPUT->set_env('pagecount', ceil($message_count/$IMAP->page_size));
$OUTPUT->set_env('sort_col', $sort_col);
$OUTPUT->set_env('sort_order', $sort_order);
if ($attrib['messageicon'])
$OUTPUT->set_env('messageicon', $skin_path . $attrib['messageicon']);
if ($attrib['deletedicon'])
$OUTPUT->set_env('deletedicon', $skin_path . $attrib['deletedicon']);
if ($attrib['unreadicon'])
$OUTPUT->set_env('unreadicon', $skin_path . $attrib['unreadicon']);
if ($attrib['repliedicon'])
$OUTPUT->set_env('repliedicon', $skin_path . $attrib['repliedicon']);
if ($attrib['attachmenticon'])
$OUTPUT->set_env('attachmenticon', $skin_path . $attrib['attachmenticon']);
$OUTPUT->set_env('messages', array2js($a_js_message_arr));
$OUTPUT->include_script('list.js');
return $out;
}
// return javascript commands to add rows to the message list
function rcmail_js_message_list($a_headers, $insert_top=FALSE)
{
global $CONFIG, $IMAP, $OUTPUT;
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
// show 'to' instead of from in sent messages
if (($IMAP->get_mailbox_name() == $CONFIG['sent_mbox'] || $IMAP->get_mailbox_name() == $CONFIG['drafts_mbox'])
&& (($f = array_search('from', $a_show_cols)) !== false) && array_search('to', $a_show_cols) === false)
$a_show_cols[$f] = 'to';
$OUTPUT->command('set_message_coltypes', $a_show_cols);
// loop through message headers
for ($n=0; $a_headers[$n]; $n++)
{
$header = $a_headers[$n];
$a_msg_cols = array();
$a_msg_flags = array();
// format each col; similar as in rcmail_message_list()
foreach ($a_show_cols as $col)
{
if ($col=='from' || $col=='to')
$cont = Q(rcmail_address_string($header->$col, 3), 'show');
else if ($col=='subject')
{
$cont = Q(rcube_imap::decode_mime_string($header->$col, $header->charset));
if (!$cont) $cont = Q(rcube_label('nosubject'));
}
else if ($col=='size')
$cont = show_bytes($header->$col);
else if ($col=='date')
$cont = format_date($header->date);
else
$cont = Q($header->$col);
$a_msg_cols[$col] = $cont;
}
$a_msg_flags['deleted'] = $header->deleted ? 1 : 0;
$a_msg_flags['unread'] = $header->seen ? 0 : 1;
$a_msg_flags['replied'] = $header->answered ? 1 : 0;
$OUTPUT->command('add_message_row',
$header->uid,
$a_msg_cols,
$a_msg_flags,
preg_match("/multipart\/m/i", $header->ctype),
$insert_top);
}
}
// return an HTML iframe for loading mail content
function rcmail_messagecontent_frame($attrib)
{
global $OUTPUT;
if (empty($attrib['id']))
$attrib['id'] = 'rcmailcontentwindow';
// allow the following attributes to be added to the <iframe> tag
$attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'src', 'width', 'height', 'frameborder'));
$framename = $attrib['id'];
$out = sprintf('<iframe name="%s"%s></iframe>'."\n",
$framename,
$attrib_str);
$OUTPUT->set_env('contentframe', $framename);
$OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/blank.gif');
return $out;
}
function rcmail_messagecount_display($attrib)
{
global $IMAP, $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmcountdisplay';
$OUTPUT->add_gui_object('countdisplay', $attrib['id']);
// allow the following attributes to be added to the <span> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
$out = '<span' . $attrib_str . '>';
$out .= rcmail_get_messagecount_text();
$out .= '</span>';
return $out;
}
function rcmail_quota_display($attrib)
{
global $OUTPUT, $COMM_PATH;
if (!$attrib['id'])
$attrib['id'] = 'rcmquotadisplay';
$OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
// allow the following attributes to be added to the <span> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
$out = '<span' . $attrib_str . '>';
$out .= rcmail_quota_content($attrib['display']);
$out .= '</span>';
return $out;
}
function rcmail_quota_content($display)
{
global $IMAP, $COMM_PATH;
if (!$IMAP->get_capability('QUOTA'))
$quota_text = rcube_label('unknown');
else if ($quota = $IMAP->get_quota())
{
$quota_text = sprintf("%s / %s (%.0f%%)",
show_bytes($quota["used"] * 1024),
show_bytes($quota["total"] * 1024),
$quota["percent"]);
// show quota as image (by Brett Patterson)
if ($display == 'image' && function_exists('imagegif'))
{
$attrib = array('width' => 100, 'height' => 14);
$quota_text = sprintf('<img src="./bin/quotaimg.php?u=%s&q=%d&w=%d&h=%d" width="%d" height="%d" alt="%s" title="%s / %s" />',
$quota['used'], $quota['total'],
$attrib['width'], $attrib['height'],
$attrib['width'], $attrib['height'],
$quota_text,
show_bytes($quota["used"] * 1024),
show_bytes($quota["total"] * 1024));
}
}
else
$quota_text = rcube_label('unlimited');
return $quota_text;
}
function rcmail_get_messagecount_text($count=NULL, $page=NULL)
{
global $IMAP, $MESSAGE;
if (isset($MESSAGE['index']))
{
return rcube_label(array('name' => 'messagenrof',
'vars' => array('nr' => $MESSAGE['index']+1,
'count' => $count!==NULL ? $count : $IMAP->messagecount())));
}
if ($page===NULL)
$page = $IMAP->list_page;
$start_msg = ($page-1) * $IMAP->page_size + 1;
$max = $count!==NULL ? $count : $IMAP->messagecount();
if ($max==0)
$out = rcube_label('mailboxempty');
else
$out = rcube_label(array('name' => 'messagesfromto',
'vars' => array('from' => $start_msg,
'to' => min($max, $start_msg + $IMAP->page_size - 1),
'count' => $max)));
return Q($out);
}
function rcmail_print_body($part, $safe=FALSE, $plain=FALSE)
{
global $IMAP, $REMOTE_OBJECTS;
$body = is_array($part->replaces) ? strtr($part->body, $part->replaces) : $part->body;
// convert html to text/plain
if ($part->ctype_secondary=='html' && $plain)
{
$txt = new html2text($body, false, true);
$body = $txt->get_text();
$part->ctype_secondary = 'plain';
}
// text/html
if ($part->ctype_secondary=='html')
{
// remove charset specification in HTML message
$body = preg_replace('/charset=[a-z0-9\-]+/i', '', $body);
if (!$safe) // remove remote images and scripts
{
$remote_patterns = array('/<img\s+(.*)src=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
'/(src|background)=(["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)(\2|\s|>)/Ui',
'/(<base.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
'/(<link.*href=["\']?)([hftps]{3,5}:\/{2}[^"\'\s]+)([^<]*>)/i',
'/url\s*\(["\']?([hftps]{3,5}:\/{2}[^"\'\s]+)["\']?\)/i',
'/url\s*\(["\']?([\.\/]+[^"\'\s]+)["\']?\)/i',
'/<script.+<\/script>/Umis');
$remote_replaces = array('<img \\1src=\\2./program/blocked.gif\\4',
'',
'',
'',
'none',
'none',
'');
// set flag if message containes remote obejcts that where blocked
foreach ($remote_patterns as $pattern)
{
if (preg_match($pattern, $body))
{
$REMOTE_OBJECTS = TRUE;
break;
}
}
$body = preg_replace($remote_patterns, $remote_replaces, $body);
}
return Q($body, 'show', FALSE);
}
// text/enriched
if ($part->ctype_secondary=='enriched')
{
return Q(enriched_to_html($body), 'show');
}
else
{
// make links and email-addresses clickable
$convert_patterns = $convert_replaces = $replace_strings = array();
$url_chars = 'a-z0-9_\-\+\*\$\/&%=@#:;';
$url_chars_within = '\?\.~,!';
$convert_patterns[] = "/([\w]+):\/\/([a-z0-9\-\.]+[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
$convert_replaces[] = "rcmail_str_replacement('<a href=\"\\1://\\2\" target=\"_blank\">\\1://\\2</a>', \$replace_strings)";
$convert_patterns[] = "/([^\/:]|\s)(www\.)([a-z0-9\-]{2,}[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/ie";
$convert_replaces[] = "rcmail_str_replacement('\\1<a href=\"http://\\2\\3\" target=\"_blank\">\\2\\3</a>', \$replace_strings)";
$convert_patterns[] = '/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/ie';
$convert_replaces[] = "rcmail_str_replacement('<a href=\"mailto:\\1\" onclick=\"return ".JS_OBJECT_NAME.".command(\'compose\',\'\\1\',this)\">\\1</a>', \$replace_strings)";
if ($part->ctype_parameters['format'] != 'flowed')
$body = wordwrap(trim($body), 80);
$body = preg_replace($convert_patterns, $convert_replaces, $body);
// split body into single lines
$a_lines = preg_split('/\r?\n/', $body);
$quote_level = 0;
// colorize quoted parts
for($n=0; $n<sizeof($a_lines); $n++)
{
$line = $a_lines[$n];
$quotation = '';
$q = 0;
if (preg_match('/^(>+\s*)/', $line, $regs))
{
$q = strlen(preg_replace('/\s/', '', $regs[1]));
$line = substr($line, strlen($regs[1]));
if ($q > $quote_level)
$quotation = str_repeat('<blockquote>', $q - $quote_level);
else if ($q < $quote_level)
$quotation = str_repeat("</blockquote>", $quote_level - $q);
}
else if ($quote_level > 0)
$quotation = str_repeat("</blockquote>", $quote_level);
$quote_level = $q;
$a_lines[$n] = $quotation . Q($line, 'replace', FALSE);
}
// insert the links for urls and mailtos
$body = preg_replace("/##string_replacement\{([0-9]+)\}##/e", "\$replace_strings[\\1]", join("\n", $a_lines));
return "<div class=\"pre\">".$body."\n</div>";
}
}
// add a string to the replacement array and return a replacement string
function rcmail_str_replacement($str, &$rep)
{
static $count = 0;
$rep[$count] = stripslashes($str);
return "##string_replacement{".($count++)."}##";
}
function rcmail_parse_message(&$structure, $arg=array(), $recursive=FALSE)
{
global $IMAP;
static $sa_inline_objects = array();
// arguments are: (bool)$prefer_html, (string)$get_url
extract($arg);
$a_attachments = array();
$a_return_parts = array();
$out = '';
$message_ctype_primary = strtolower($structure->ctype_primary);
$message_ctype_secondary = strtolower($structure->ctype_secondary);
// show message headers
if ($recursive && is_array($structure->headers) && isset($structure->headers['subject']))
{
$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')
{
$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))
{
// get html/plaintext parts
$plain_part = $html_part = $print_part = $related_part = NULL;
foreach ($structure->parts as $p => $sub_part)
{
$sub_ctype_primary = strtolower($sub_part->ctype_primary);
$sub_ctype_secondary = strtolower($sub_part->ctype_secondary);
// check if sub part is
if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='plain')
$plain_part = $p;
else if ($sub_ctype_primary=='text' && $sub_ctype_secondary=='html')
$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')
$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);
$a_attachments = array_merge($a_attachments, $attachmnts);
}
// print html/plain part
else if ($html_part!==NULL && $prefer_html)
$print_part = &$structure->parts[$html_part];
else if ($enriched_part!==NULL)
$print_part = &$structure->parts[$enriched_part];
else if ($plain_part!==NULL)
$print_part = &$structure->parts[$plain_part];
// show message body
if (is_object($print_part))
{
$print_part->type = 'content';
$a_return_parts[] = $print_part;
}
// show plaintext warning
else if ($html_part!==NULL)
{
$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];
$html_part->filename = rcube_label('htmlmessage');
$html_part->mimetype = 'text/html';
$a_attachments[] = $html_part;
}
}
// message contains multiple parts
else if (is_array($structure->parts) && !empty($structure->parts))
{
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')
{
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);
}
// 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'))
{
$mail_part->type = 'content';
$a_return_parts[] = $mail_part;
}
// part message/*
else if ($primary_type=='message')
{
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);
}
// part is file/attachment
else if ($mail_part->disposition=='attachment' || $mail_part->disposition=='inline' || $mail_part->headers['content-id'] ||
(empty($mail_part->disposition) && $mail_part->filename))
{
// skip apple resource forks
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'])
{
$mail_part->content_id = preg_replace(array('/^</', '/>$/'), '', $mail_part->headers['content-id']);
$sa_inline_objects[] = $mail_part;
}
// is regular attachment
else
{
if (!$mail_part->filename)
$mail_part->filename = 'file_'.$mail_part->mime_id;
$a_attachments[] = $mail_part;
}
}
}
// if this was a related part try to resolve references
if ($message_ctype_secondary=='related' && sizeof($sa_inline_objects))
{
$a_replaces = array();
foreach ($sa_inline_objects as $inline_object)
$a_replaces['cid:'.$inline_object->content_id] = htmlspecialchars(sprintf($get_url, $inline_object->mime_id));
// 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 ($a_return_parts[$i]->type=='content')
$a_return_parts[$i]->replaces = $a_replaces;
}
}
}
// message is single part non-text
else if ($structure->filename)
$a_attachments[] = $structure;
return array($a_return_parts, $a_attachments);
}
// return table with message headers
function rcmail_message_headers($attrib, $headers=NULL)
{
global $IMAP, $OUTPUT, $MESSAGE;
static $sa_attrib;
// keep header table attrib
if (is_array($attrib) && !$sa_attrib)
$sa_attrib = $attrib;
else if (!is_array($attrib) && is_array($sa_attrib))
$attrib = $sa_attrib;
if (!isset($MESSAGE))
return FALSE;
// get associative array of headers object
if (!$headers)
$headers = is_object($MESSAGE['headers']) ? get_object_vars($MESSAGE['headers']) : $MESSAGE['headers'];
$header_count = 0;
// allow the following attributes to be added to the <table> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
$out = '<table' . $attrib_str . ">\n";
// show these headers
$standard_headers = array('subject', 'from', 'organization', 'to', 'cc', 'bcc', 'reply-to', 'date');
foreach ($standard_headers as $hkey)
{
if (!$headers[$hkey])
continue;
if ($hkey=='date' && !empty($headers[$hkey]))
$header_value = format_date(strtotime($headers[$hkey]));
else if (in_array($hkey, array('from', 'to', 'cc', 'bcc', 'reply-to')))
$header_value = Q(rcmail_address_string($headers[$hkey], NULL, $attrib['addicon']), 'show');
else
$header_value = Q(rcube_imap::decode_mime_string($headers[$hkey], $headers['charset']));
$out .= "\n<tr>\n";
$out .= '<td class="header-title">'.Q(rcube_label($hkey)).": </td>\n";
$out .= '<td class="'.$hkey.'" width="90%">'.$header_value."</td>\n</tr>";
$header_count++;
}
$out .= "\n</table>\n\n";
return $header_count ? $out : '';
}
function rcmail_message_body($attrib)
{
global $CONFIG, $OUTPUT, $MESSAGE, $IMAP, $GET_URL, $REMOTE_OBJECTS;
if (!is_array($MESSAGE['parts']) && !$MESSAGE['body'])
return '';
if (!$attrib['id'])
$attrib['id'] = 'rcmailMsgBody';
$safe_mode = (bool)$_GET['_safe'];
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
$out = '<div '. $attrib_str . ">\n";
$header_attrib = array();
foreach ($attrib as $attr => $value)
if (preg_match('/^headertable([a-z]+)$/i', $attr, $regs))
$header_attrib[$regs[1]] = $value;
// this is an ecrypted message
// -> create a plaintext body with the according message
if (!sizeof($MESSAGE['parts']) && $MESSAGE['headers']->ctype=='multipart/encrypted')
{
$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 (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, $safe_mode, !$CONFIG['prefer_html']);
$out .= '<div class="message-part">';
if ($part->ctype_secondary != 'plain')
$out .= rcmail_sanitize_html($body, $attrib['id']);
else
$out .= $body;
$out .= "</div>\n";
}
}
}
else
$out .= $MESSAGE['body'];
$ctype_primary = strtolower($MESSAGE['structure']->ctype_primary);
$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))
{
foreach ($MESSAGE['attachments'] as $attach_prop)
{
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",
htmlspecialchars($GET_URL), $attach_prop->mime_id,
$attach_prop->filename,
$attach_prop->filename);
}
}
// tell client that there are blocked remote objects
if ($REMOTE_OBJECTS && !$safe_mode)
$OUTPUT->set_env('blockedobjects', true);
$out .= "\n</div>";
return $out;
}
// modify a HTML message that it can be displayed inside a HTML page
function rcmail_sanitize_html($body, $container_id)
{
// remove any null-byte characters before parsing
$body = preg_replace('/\x00/', '', $body);
$last_style_pos = 0;
$body_lc = strtolower($body);
// find STYLE tags
while (($pos = strpos($body_lc, '<style', $last_style_pos)) && ($pos2 = strpos($body_lc, '</style>', $pos)))
{
$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);
$body = substr($body, 0, $pos) . $styles . substr($body, $pos2);
$body_lc = strtolower($body);
$last_style_pos = $pos2;
}
// remove SCRIPT tags
foreach (array('script', 'applet', 'object', 'embed', 'iframe') as $tag)
{
while (($pos = strpos($body_lc, '<'.$tag)) && ($pos2 = strpos($body_lc, '</'.$tag.'>', $pos)))
{
$pos2 += strlen('</'.$tag.'>');
$body = substr($body, 0, $pos) . substr($body, $pos2, strlen($body)-$pos2);
$body_lc = strtolower($body);
}
}
// replace event handlers on any object
while ($body != $prev_body)
{
$prev_body = $body;
$body = preg_replace('/(<[^!][^>]*\s)(on[^=>]+)=([^>]+>)/im', '$1__removed=$3', $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))
{
$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);
// 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('/(<body[^>]*>)/i',
'/(<\/body>)/i'),
array('<div class="rcmBody">',
'</div>'),
$out);
// quote <? of php and xml files that are specified as text/html
$out = preg_replace(array('/<\?/', '/\?>/'), array('<?', '?>'), $out);
return $out;
}
// parse link attributes and set correct target
function rcmail_alter_html_link($in)
{
$in = preg_replace('/=([^("|\'|\s)]+)(\s|$)/', '="\1"', $in);
$attrib = parse_attrib_string($in);
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;
}
function rcmail_has_html_part($message_parts)
{
if (!is_array($message_parts))
return FALSE;
// check all message parts
foreach ($message_parts as $pid => $part)
{
$mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
if ($mimetype=='text/html')
{
return TRUE;
}
}
return FALSE;
}
// return first HTML part of a message
function rcmail_first_html_part($message_struct)
{
global $IMAP;
if (!is_array($message_struct['parts']))
return FALSE;
$html_part = NULL;
// check all message parts
foreach ($message_struct['parts'] as $pid => $part)
{
$mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
if ($mimetype=='text/html')
{
$html_part = $IMAP->get_message_part($message_struct['UID'], $pid, $part);
}
}
if ($html_part)
{
// remove special chars encoding
//$trans = array_flip(get_html_translation_table(HTML_ENTITIES));
//$html_part = strtr($html_part, $trans);
return $html_part;
}
return FALSE;
}
// return first text part of a message
function rcmail_first_text_part($message_struct)
{
global $IMAP;
if (empty($message_struct['parts']))
return $message_struct['UID'] ? $IMAP->get_body($message_struct['UID']) : false;
// check all message parts
foreach ($message_struct['parts'] as $pid => $part)
{
$mimetype = strtolower($part->ctype_primary.'/'.$part->ctype_secondary);
if ($mimetype=='text/plain')
return $IMAP->get_message_part($message_struct['UID'], $pid, $part);
else if ($mimetype=='text/html')
{
$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();
}
}
return FALSE;
}
// decode address string and re-format it as HTML links
function rcmail_address_string($input, $max=NULL, $addicon=NULL)
{
global $IMAP, $PRINT_MODE, $CONFIG, $OUTPUT, $EMAIL_ADDRESS_PATTERN;
$a_parts = $IMAP->decode_address_list($input);
if (!sizeof($a_parts))
return $input;
$c = count($a_parts);
$j = 0;
$out = '';
foreach ($a_parts as $part)
{
$j++;
if ($PRINT_MODE)
$out .= sprintf('%s <%s>', Q($part['name']), $part['mailto']);
else if (preg_match($EMAIL_ADDRESS_PATTERN, $part['mailto']))
{
$out .= sprintf('<a href="mailto:%s" onclick="return %s.command(\'compose\',\'%s\',this)" class="rcmContactAddress" title="%s">%s</a>',
Q($part['mailto']),
JS_OBJECT_NAME,
JQ($part['mailto']),
Q($part['mailto']),
Q($part['name']));
if ($addicon)
$out .= sprintf(' <a href="#add" onclick="return %s.command(\'add-contact\',\'%s\',this)" title="%s"><img src="%s%s" alt="add" border="0" /></a>',
JS_OBJECT_NAME,
urlencode($part['string']),
rcube_label('addtoaddressbook'),
$CONFIG['skin_path'],
$addicon);
}
else
{
if ($part['name'])
$out .= Q($part['name']);
if ($part['mailto'])
$out .= (strlen($out) ? ' ' : '') . sprintf('<%s>', Q($part['mailto']));
}
if ($c>$j)
$out .= ','.($max ? ' ' : ' ');
if ($max && $j==$max && $c>$j)
{
$out .= '...';
break;
}
}
return $out;
}
function rcmail_message_part_controls()
{
global $CONFIG, $IMAP, $MESSAGE;
if (!is_array($MESSAGE) || !is_array($MESSAGE['parts']) || !($_GET['_uid'] && $_GET['_part']) || !$MESSAGE['parts'][$_GET['_part']])
return '';
$part = &$MESSAGE['parts'][$_GET['_part']];
$attrib_str = create_attrib_string($attrib, array('id', 'class', 'style', 'cellspacing', 'cellpadding', 'border', 'summary'));
$out = '<table '. $attrib_str . ">\n";
if ($filename)
{
$out .= sprintf('<tr><td class="title">%s</td><td>%s</td><td>[<a href="./?%s">%s</a>]</tr>'."\n",
Q(rcube_label('filename')),
Q($part->filename),
str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING']),
Q(rcube_label('download')));
}
if ($part->size)
$out .= sprintf('<tr><td class="title">%s</td><td>%s</td></tr>'."\n",
Q(rcube_label('filesize')),
show_bytes($part->size));
$out .= "\n</table>";
return $out;
}
function rcmail_message_part_frame($attrib)
{
global $MESSAGE;
$part = $MESSAGE['parts'][$_GET['_part']];
$ctype_primary = strtolower($part->ctype_primary);
$attrib['src'] = './?'.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>";
return $out;
}
// clear message composing settings
function rcmail_compose_cleanup()
{
if (!isset($_SESSION['compose']))
return;
// remove attachment files from temp dir
if (is_array($_SESSION['compose']['attachments']))
foreach ($_SESSION['compose']['attachments'] as $attachment)
@unlink($attachment['path']);
unset($_SESSION['compose']);
}
// register UI objects
$OUTPUT->add_handlers(array(
'mailboxlist' => 'rcmail_mailbox_list',
'messages' => 'rcmail_message_list',
'messagecountdisplay' => 'rcmail_messagecount_display',
'quotadisplay' => 'rcmail_quota_display',
'messageheaders' => 'rcmail_message_headers',
'messagebody' => 'rcmail_message_body',
'messagecontentframe' => 'rcmail_messagecontent_frame',
'messagepartframe' => 'rcmail_message_part_frame',
'messagepartcontrols' => 'rcmail_message_part_controls',
'searchform' => 'rcmail_search_form'
));
?>
\ No newline at end of file
diff --git a/skins/default/templates/mail.html b/skins/default/templates/mail.html
index d7f11bdfd..183a14ff7 100644
--- a/skins/default/templates/mail.html
+++ b/skins/default/templates/mail.html
@@ -1,84 +1,86 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title><roundcube:object name="pagetitle" /></title>
<roundcube:include file="/includes/links.html" />
<link rel="stylesheet" type="text/css" href="/mail.css" />
<script type="text/javascript" src="/splitter.js"></script>
</head>
<body>
<roundcube:include file="/includes/taskbar.html" />
<roundcube:include file="/includes/header.html" />
<div id="messagetoolbar">
<roundcube:button command="checkmail" imageSel="/images/buttons/inbox_sel.png" imageAct="/images/buttons/inbox_act.png" imagePas="/images/buttons/inbox_pas.png" width="32" height="32" title="checkmail" />
<roundcube:button command="compose" imageSel="/images/buttons/compose_sel.png" imageAct="/images/buttons/compose_act.png" imagePas="/images/buttons/compose_pas.png" width="32" height="32" title="writenewmessage" />
<roundcube:button command="reply" imageSel="/images/buttons/reply_sel.png" imageAct="/images/buttons/reply_act.png" imagePas="/images/buttons/reply_pas.png" width="32" height="32" title="replytomessage" />
<roundcube:button command="reply-all" imageSel="/images/buttons/replyall_sel.png" imageAct="/images/buttons/replyall_act.png" imagePas="/images/buttons/replyall_pas.png" width="32" height="32" title="replytoallmessage" />
<roundcube:button command="forward" imageSel="/images/buttons/forward_sel.png" imageAct="/images/buttons/forward_act.png" imagePas="/images/buttons/forward_pas.png" width="32" height="32" title="forwardmessage" />
<roundcube:button command="delete" imageSel="/images/buttons/delete_sel.png" imageAct="/images/buttons/delete_act.png" imagePas="/images/buttons/delete_pas.png" width="32" height="32" title="deletemessage" />
<roundcube:button command="print" imageSel="/images/buttons/print_sel.png" imageAct="/images/buttons/print_act.png" imagePas="/images/buttons/print_pas.png" width="32" height="32" title="printmessage" />
</div>
<div id="quicksearchbar">
<roundcube:object name="searchform" type="search" results="5" id="quicksearchbox" /><roundcube:button command="reset-search" id="searchreset" image="/images/icons/reset.gif" title="resetsearch" />
</div>
<div id="messagecountbar">
<roundcube:button command="firstpage" imageSel="/images/buttons/first_sel.png" imageAct="/images/buttons/first_act.png" imagePas="/images/buttons/first_pas.png" width="11" height="11" title="firstmessages" />
<roundcube:button command="previouspage" imageSel="/images/buttons/previous_sel.png" imageAct="/images/buttons/previous_act.png" imagePas="/images/buttons/previous_pas.png" width="11" height="11" title="previousmessages" />
<roundcube:object name="messageCountDisplay" />
<roundcube:button command="nextpage" imageSel="/images/buttons/next_sel.png" imageAct="/images/buttons/next_act.png" imagePas="/images/buttons/next_pas.png" width="11" height="11" title="nextmessages" />
<roundcube:button command="lastpage" imageSel="/images/buttons/last_sel.png" imageAct="/images/buttons/last_act.png" imagePas="/images/buttons/last_pas.png" width="11" height="11" title="lastmessages" />
</div>
<div id="mailboxlist-header"><roundcube:label name="mailboxlist" /></div>
<div id="mailboxlist-container"><roundcube:object name="mailboxlist" id="mailboxlist" maxlength="16" /></div>
<div id="mailboxcontrols">
<roundcube:label name="folder" />:
<roundcube:button command="expunge" label="compact" classAct="active" />
<roundcube:button command="purge" label="empty" classAct="active" />
</div>
<div id="mailcontframe">
<roundcube:object name="messages"
id="messagelist"
cellspacing="0"
summary="Message list"
messageIcon="/images/icons/dot.png"
unreadIcon="/images/icons/unread.png"
deletedIcon="/images/icons/deleted.png"
repliedIcon="/images/icons/replied.png"
attachmentIcon="/images/icons/attachment.png" />
</div>
<roundcube:if condition="config:preview_pane == true" />
<script type="text/javascript">
var mailviewsplit = new rcube_splitter({id:'mailviewsplitter', p1: 'mailcontframe', p2: 'mailpreviewframe', orientation: 'h'});
rcmail.add_onload('mailviewsplit.init()');
</script>
<div id="mailpreviewframe">
<roundcube:object name="messagecontentframe" id="messagecontframe" width="100%" height="100%" frameborder="0" src="/watermark.html" />
</div>
<style type="text/css">
#mailcontframe {
bottom: auto;
height: 208px;
}
</style>
<roundcube:endif />
<div id="listcontrols">
<roundcube:label name="select" />:
<roundcube:button command="select-all" label="all" classAct="active" />
<roundcube:button command="select-all" prop="unread" label="unread" classAct="active" />
<roundcube:button command="select-none" label="none" classAct="active" />
+<roundcube:if condition="env:quota" />
<roundcube:label name="quota" />: <roundcube:object name="quotaDisplay" display="image" width="120" id="quotadisplay" />
+<roundcube:endif />
</div>
</body>
</html>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Mar 19, 9:04 AM (22 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
458563
Default Alt Text
(73 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment