Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2571626
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
161 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/program/include/main.inc b/program/include/main.inc
index 71534f6b1..6aa8b91a1 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -1,1670 +1,1658 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/include/main.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2005-2007, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Provide basic functions for the webmail package |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
require_once('lib/des.inc');
require_once('lib/utf7.inc');
require_once('lib/utf8.class.php');
require_once('include/rcmail_template.inc');
// define constannts for input reading
define('RCUBE_INPUT_GET', 0x0101);
define('RCUBE_INPUT_POST', 0x0102);
define('RCUBE_INPUT_GPC', 0x0103);
// register session and connect to server
function rcmail_startup($task='mail')
{
global $sess_id, $sess_user_lang;
global $CONFIG, $INSTALL_PATH, $BROWSER, $OUTPUT, $_SESSION, $IMAP, $DB;
// check client
$BROWSER = rcube_browser();
// load configuration
$CONFIG = rcmail_load_config();
// set session garbage collecting time according to session_lifetime
if (!empty($CONFIG['session_lifetime']))
ini_set('session.gc_maxlifetime', ($CONFIG['session_lifetime']) * 120);
// prepare DB connection
require_once('include/rcube_'.(empty($CONFIG['db_backend']) ? 'db' : $CONFIG['db_backend']).'.inc');
$DB = new rcube_db($CONFIG['db_dsnw'], $CONFIG['db_dsnr'], $CONFIG['db_persistent']);
$DB->sqlite_initials = $INSTALL_PATH.'SQL/sqlite.initial.sql';
$DB->db_connect('w');
// use database for storing session data
include_once('include/session.inc');
// init session
session_start();
$sess_id = session_id();
// create session and set session vars
if (!isset($_SESSION['auth_time']))
{
$_SESSION['user_lang'] = rcube_language_prop($CONFIG['locale_string']);
$_SESSION['auth_time'] = time();
$_SESSION['temp'] = true;
}
// set session vars global
$sess_user_lang = rcube_language_prop($_SESSION['user_lang']);
// overwrite config with user preferences
if (is_array($_SESSION['user_prefs']))
$CONFIG = array_merge($CONFIG, $_SESSION['user_prefs']);
// reset some session parameters when changing task
if ($_SESSION['task'] != $task)
unset($_SESSION['page']);
// set current task to session
$_SESSION['task'] = $task;
// create IMAP object
if ($task=='mail')
rcmail_imap_init();
// set localization
if ($CONFIG['locale_string'])
setlocale(LC_ALL, $CONFIG['locale_string']);
else if ($sess_user_lang)
setlocale(LC_ALL, $sess_user_lang);
register_shutdown_function('rcmail_shutdown');
}
// load roundcube configuration into global var
function rcmail_load_config()
{
global $INSTALL_PATH;
// load config file
include_once('config/main.inc.php');
$conf = is_array($rcmail_config) ? $rcmail_config : array();
// load host-specific configuration
rcmail_load_host_config($conf);
$conf['skin_path'] = $conf['skin_path'] ? unslashify($conf['skin_path']) : 'skins/default';
// load db conf
include_once('config/db.inc.php');
$conf = array_merge($conf, $rcmail_config);
if (empty($conf['log_dir']))
$conf['log_dir'] = $INSTALL_PATH.'logs';
else
$conf['log_dir'] = unslashify($conf['log_dir']);
// set PHP error logging according to config
if ($conf['debug_level'] & 1)
{
ini_set('log_errors', 1);
ini_set('error_log', $conf['log_dir'].'/errors');
}
if ($conf['debug_level'] & 4)
ini_set('display_errors', 1);
else
ini_set('display_errors', 0);
return $conf;
}
// load a host-specific config file if configured
function rcmail_load_host_config(&$config)
{
$fname = NULL;
if (is_array($config['include_host_config']))
$fname = $config['include_host_config'][$_SERVER['HTTP_HOST']];
else if (!empty($config['include_host_config']))
$fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php';
if ($fname && is_file('config/'.$fname))
{
include('config/'.$fname);
$config = array_merge($config, $rcmail_config);
}
}
// create authorization hash
function rcmail_auth_hash($sess_id, $ts)
{
global $CONFIG;
$auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s',
$sess_id,
$ts,
$CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***',
$_SERVER['HTTP_USER_AGENT']);
if (function_exists('sha1'))
return sha1($auth_string);
else
return md5($auth_string);
}
// compare the auth hash sent by the client with the local session credentials
function rcmail_authenticate_session()
{
global $CONFIG, $SESS_CLIENT_IP, $SESS_CHANGED;
// advanced session authentication
if ($CONFIG['double_auth'])
{
$now = time();
$valid = ($_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['auth_time']) ||
$_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['last_auth']));
// renew auth cookie every 5 minutes (only for GET requests)
if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now-$_SESSION['auth_time'] > 300))
{
$_SESSION['last_auth'] = $_SESSION['auth_time'];
$_SESSION['auth_time'] = $now;
setcookie('sessauth', rcmail_auth_hash(session_id(), $now));
}
}
else
$valid = $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] == $SESS_CLIENT_IP : true;
// check session filetime
if (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < time())
$valid = false;
return $valid;
}
// create IMAP object and connect to server
function rcmail_imap_init($connect=FALSE)
{
global $CONFIG, $DB, $IMAP, $OUTPUT;
$IMAP = new rcube_imap($DB);
$IMAP->debug_level = $CONFIG['debug_level'];
$IMAP->skip_deleted = $CONFIG['skip_deleted'];
// connect with stored session data
if ($connect)
{
if (!($conn = $IMAP->connect($_SESSION['imap_host'], $_SESSION['username'], decrypt_passwd($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl'])))
$OUTPUT->show_message('imaperror', 'error');
rcmail_set_imap_prop();
}
// enable caching of imap data
if ($CONFIG['enable_caching']===TRUE)
$IMAP->set_caching(TRUE);
// set pagesize from config
if (isset($CONFIG['pagesize']))
$IMAP->set_pagesize($CONFIG['pagesize']);
}
// set root dir and last stored mailbox
// this must be done AFTER connecting to the server
function rcmail_set_imap_prop()
{
global $CONFIG, $IMAP;
// set root dir from config
if (!empty($CONFIG['imap_root']))
$IMAP->set_rootdir($CONFIG['imap_root']);
if (is_array($CONFIG['default_imap_folders']))
$IMAP->set_default_mailboxes($CONFIG['default_imap_folders']);
if (!empty($_SESSION['mbox']))
$IMAP->set_mailbox($_SESSION['mbox']);
if (isset($_SESSION['page']))
$IMAP->set_page($_SESSION['page']);
}
// do these things on script shutdown
function rcmail_shutdown()
{
global $IMAP;
if (is_object($IMAP))
{
$IMAP->close();
$IMAP->write_cache();
}
// before closing the database connection, write session data
session_write_close();
}
// destroy session data and remove cookie
function rcmail_kill_session()
{
// save user preferences
$a_user_prefs = $_SESSION['user_prefs'];
if (!is_array($a_user_prefs))
$a_user_prefs = array();
if ((isset($_SESSION['sort_col']) && $_SESSION['sort_col']!=$a_user_prefs['message_sort_col']) ||
(isset($_SESSION['sort_order']) && $_SESSION['sort_order']!=$a_user_prefs['message_sort_order']))
{
$a_user_prefs['message_sort_col'] = $_SESSION['sort_col'];
$a_user_prefs['message_sort_order'] = $_SESSION['sort_order'];
rcmail_save_user_prefs($a_user_prefs);
}
$_SESSION = array('user_lang' => $GLOBALS['sess_user_lang'], 'auth_time' => time(), 'temp' => true);
setcookie('sessauth', '-del-', time()-60);
}
// return correct name for a specific database table
function get_table_name($table)
{
global $CONFIG;
// return table name if configured
$config_key = 'db_table_'.$table;
if (strlen($CONFIG[$config_key]))
return $CONFIG[$config_key];
return $table;
}
// return correct name for a specific database sequence
// (used for Postres only)
function get_sequence_name($sequence)
{
global $CONFIG;
// return table name if configured
$config_key = 'db_sequence_'.$sequence;
if (strlen($CONFIG[$config_key]))
return $CONFIG[$config_key];
return $table;
}
// check the given string and returns language properties
function rcube_language_prop($lang, $prop='lang')
{
global $INSTALL_PATH;
static $rcube_languages, $rcube_language_aliases, $rcube_charsets;
if (empty($rcube_languages))
@include($INSTALL_PATH.'program/localization/index.inc');
// check if we have an alias for that language
if (!isset($rcube_languages[$lang]) && isset($rcube_language_aliases[$lang]))
$lang = $rcube_language_aliases[$lang];
// try the first two chars
if (!isset($rcube_languages[$lang]) && strlen($lang)>2)
{
$lang = substr($lang, 0, 2);
$lang = rcube_language_prop($lang);
}
if (!isset($rcube_languages[$lang]))
$lang = 'en_US';
// language has special charset configured
if (isset($rcube_charsets[$lang]))
$charset = $rcube_charsets[$lang];
else
$charset = 'UTF-8';
if ($prop=='charset')
return $charset;
else
return $lang;
}
// init output object for GUI and add common scripts
function rcmail_load_gui()
{
global $CONFIG, $OUTPUT, $sess_user_lang;
// init output page
$OUTPUT = new rcmail_template($CONFIG, $GLOBALS['_task']);
$OUTPUT->set_env('comm_path', $GLOBALS['COMM_PATH']);
if (is_array($CONFIG['javascript_config']))
{
foreach ($CONFIG['javascript_config'] as $js_config_var)
$OUTPUT->set_env($js_config_var, $CONFIG[$js_config_var]);
}
if (!empty($GLOBALS['_framed']))
$OUTPUT->set_env('framed', true);
// set locale setting
rcmail_set_locale($sess_user_lang);
// set user-selected charset
if (!empty($CONFIG['charset']))
$OUTPUT->set_charset($CONFIG['charset']);
// register common UI objects
$OUTPUT->add_handlers(array(
'loginform' => 'rcmail_login_form',
'username' => 'rcmail_current_username',
'message' => 'rcmail_message_container',
'charsetselector' => 'rcmail_charset_selector',
));
// add some basic label to client
if (!$OUTPUT->ajax_call)
rcube_add_label('loading');
}
// set localization charset based on the given language
function rcmail_set_locale($lang)
{
global $OUTPUT, $MBSTRING;
static $s_mbstring_loaded = NULL;
// settings for mbstring module (by Tadashi Jokagi)
if (is_null($s_mbstring_loaded))
$MBSTRING = $s_mbstring_loaded = extension_loaded("mbstring");
else
$MBSTRING = $s_mbstring_loaded = FALSE;
if ($MBSTRING)
mb_internal_encoding(RCMAIL_CHARSET);
$OUTPUT->set_charset(rcube_language_prop($lang, 'charset'));
}
// auto-select IMAP host based on the posted login information
function rcmail_autoselect_host()
{
global $CONFIG;
$host = isset($_POST['_host']) ? get_input_value('_host', RCUBE_INPUT_POST) : $CONFIG['default_host'];
if (is_array($host))
{
list($user, $domain) = explode('@', get_input_value('_user', RCUBE_INPUT_POST));
if (!empty($domain))
{
foreach ($host as $imap_host => $mail_domains)
if (is_array($mail_domains) && in_array($domain, $mail_domains))
{
$host = $imap_host;
break;
}
}
// take the first entry if $host is still an array
if (is_array($host))
$host = array_shift($host);
}
return $host;
}
// perfom login to the IMAP server and to the webmail service
function rcmail_login($user, $pass, $host=NULL)
{
global $CONFIG, $IMAP, $DB, $sess_user_lang;
$user_id = NULL;
if (!$host)
$host = $CONFIG['default_host'];
// Validate that selected host is in the list of configured hosts
if (is_array($CONFIG['default_host']))
{
$allowed = FALSE;
foreach ($CONFIG['default_host'] as $key => $host_allowed)
{
if (!is_numeric($key))
$host_allowed = $key;
if ($host == $host_allowed)
{
$allowed = TRUE;
break;
}
}
if (!$allowed)
return FALSE;
}
else if (!empty($CONFIG['default_host']) && $host != $CONFIG['default_host'])
return FALSE;
// parse $host URL
$a_host = parse_url($host);
if ($a_host['host'])
{
$host = $a_host['host'];
$imap_ssl = (isset($a_host['scheme']) && in_array($a_host['scheme'], array('ssl','imaps','tls'))) ? TRUE : FALSE;
$imap_port = isset($a_host['port']) ? $a_host['port'] : ($imap_ssl ? 993 : $CONFIG['default_port']);
}
else
$imap_port = $CONFIG['default_port'];
/* Modify username with domain if required
Inspired by Marco <P0L0_notspam_binware.org>
*/
// Check if we need to add domain
if (!empty($CONFIG['username_domain']) && !strstr($user, '@'))
{
if (is_array($CONFIG['username_domain']) && isset($CONFIG['username_domain'][$host]))
$user .= '@'.$CONFIG['username_domain'][$host];
else if (is_string($CONFIG['username_domain']))
$user .= '@'.$CONFIG['username_domain'];
}
// query if user already registered
$sql_result = $DB->query("SELECT user_id, username, language, preferences
FROM ".get_table_name('users')."
WHERE mail_host=? AND (username=? OR alias=?)",
$host,
$user,
$user);
// user already registered -> overwrite username
if ($sql_arr = $DB->fetch_assoc($sql_result))
{
$user_id = $sql_arr['user_id'];
$user = $sql_arr['username'];
}
// try to resolve email address from virtuser table
if (!empty($CONFIG['virtuser_file']) && strstr($user, '@'))
$user = rcmail_email2user($user);
// exit if IMAP login failed
if (!($imap_login = $IMAP->connect($host, $user, $pass, $imap_port, $imap_ssl)))
return FALSE;
// user already registered
if ($user_id && !empty($sql_arr))
{
// get user prefs
if (strlen($sql_arr['preferences']))
{
$user_prefs = unserialize($sql_arr['preferences']);
$_SESSION['user_prefs'] = $user_prefs;
array_merge($CONFIG, $user_prefs);
}
// set user specific language
if (strlen($sql_arr['language']))
$sess_user_lang = $_SESSION['user_lang'] = $sql_arr['language'];
// update user's record
$DB->query("UPDATE ".get_table_name('users')."
SET last_login=".$DB->now()."
WHERE user_id=?",
$user_id);
}
// create new system user
else if ($CONFIG['auto_create_user'])
{
$user_id = rcmail_create_user($user, $host);
}
if ($user_id)
{
$_SESSION['user_id'] = $user_id;
$_SESSION['imap_host'] = $host;
$_SESSION['imap_port'] = $imap_port;
$_SESSION['imap_ssl'] = $imap_ssl;
$_SESSION['username'] = $user;
$_SESSION['user_lang'] = $sess_user_lang;
$_SESSION['password'] = encrypt_passwd($pass);
$_SESSION['login_time'] = mktime();
// force reloading complete list of subscribed mailboxes
rcmail_set_imap_prop();
$IMAP->clear_cache('mailboxes');
$IMAP->create_default_folders();
return TRUE;
}
return FALSE;
}
// create new entry in users and identities table
function rcmail_create_user($user, $host)
{
global $DB, $CONFIG, $IMAP;
$user_email = '';
// try to resolve user in virtusertable
if (!empty($CONFIG['virtuser_file']) && strstr($user, '@')==FALSE)
$user_email = rcmail_user2email($user);
$DB->query("INSERT INTO ".get_table_name('users')."
(created, last_login, username, mail_host, alias, language)
VALUES (".$DB->now().", ".$DB->now().", ?, ?, ?, ?)",
strip_newlines($user),
strip_newlines($host),
strip_newlines($user_email),
$_SESSION['user_lang']);
if ($user_id = $DB->insert_id(get_sequence_name('users')))
{
$mail_domain = rcmail_mail_domain($host);
if ($user_email=='')
$user_email = strstr($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain);
$user_name = $user!=$user_email ? $user : '';
// try to resolve the e-mail address from the virtuser table
if (!empty($CONFIG['virtuser_query']) &&
($sql_result = $DB->query(preg_replace('/%u/', $user, $CONFIG['virtuser_query']))) &&
($DB->num_rows()>0))
while ($sql_arr = $DB->fetch_array($sql_result))
{
$DB->query("INSERT INTO ".get_table_name('identities')."
(user_id, del, standard, name, email)
VALUES (?, 0, 1, ?, ?)",
$user_id,
strip_newlines($user_name),
preg_replace('/^@/', $user . '@', $sql_arr[0]));
}
else
{
// also create new identity records
$DB->query("INSERT INTO ".get_table_name('identities')."
(user_id, del, standard, name, email)
VALUES (?, 0, 1, ?, ?)",
$user_id,
strip_newlines($user_name),
strip_newlines($user_email));
}
// get existing mailboxes
$a_mailboxes = $IMAP->list_mailboxes();
}
else
{
raise_error(array('code' => 500,
'type' => 'php',
'line' => __LINE__,
'file' => __FILE__,
'message' => "Failed to create new user"), TRUE, FALSE);
}
return $user_id;
}
// load virtuser table in array
function rcmail_getvirtualfile()
{
global $CONFIG;
if (empty($CONFIG['virtuser_file']) || !is_file($CONFIG['virtuser_file']))
return FALSE;
// read file
$a_lines = file($CONFIG['virtuser_file']);
return $a_lines;
}
// find matches of the given pattern in virtuser table
function rcmail_findinvirtual($pattern)
{
$result = array();
$virtual = rcmail_getvirtualfile();
if ($virtual==FALSE)
return $result;
// check each line for matches
foreach ($virtual as $line)
{
$line = trim($line);
if (empty($line) || $line{0}=='#')
continue;
if (eregi($pattern, $line))
$result[] = $line;
}
return $result;
}
// resolve username with virtuser table
function rcmail_email2user($email)
{
$user = $email;
$r = rcmail_findinvirtual("^$email");
for ($i=0; $i<count($r); $i++)
{
$data = $r[$i];
$arr = preg_split('/\s+/', $data);
if(count($arr)>0)
{
$user = trim($arr[count($arr)-1]);
break;
}
}
return $user;
}
// resolve e-mail address with virtuser table
function rcmail_user2email($user)
{
$email = "";
$r = rcmail_findinvirtual("$user$");
for ($i=0; $i<count($r); $i++)
{
$data=$r[$i];
$arr = preg_split('/\s+/', $data);
if (count($arr)>0)
{
$email = trim($arr[0]);
break;
}
}
return $email;
}
function rcmail_save_user_prefs($a_user_prefs)
{
global $DB, $CONFIG, $sess_user_lang;
$DB->query("UPDATE ".get_table_name('users')."
SET preferences=?,
language=?
WHERE user_id=?",
serialize($a_user_prefs),
$sess_user_lang,
$_SESSION['user_id']);
if ($DB->affected_rows())
{
$_SESSION['user_prefs'] = $a_user_prefs;
$CONFIG = array_merge($CONFIG, $a_user_prefs);
return TRUE;
}
return FALSE;
}
// overwrite action variable
function rcmail_overwrite_action($action)
{
global $OUTPUT;
$GLOBALS['_action'] = $action;
$OUTPUT->set_env('action', $action);
}
-// compose a URL to the given action
-function rcmail_self_url($action, $p=array(), $task=null)
+/**
+ * Compose an URL for a specific action
+ *
+ * @param string Request action
+ * @param array More URL parameters
+ * @param string Request task (omit if the same)
+ * @return The application URL
+ */
+function rcmail_url($action, $p=array(), $task=null)
{
global $MAIN_TASKS, $COMM_PATH;
$qstring = '';
$base = $COMM_PATH;
if ($task && in_array($task, $MAIN_TASKS))
$base = ereg_replace('_task=[a-z]+', '_task='.$task, $COMM_PATH);
if (is_array($p))
foreach ($p as $key => $val)
$qstring .= '&'.urlencode($key).'='.urlencode($val);
return $base . ($action ? '&_action='.$action : '') . $qstring;
}
// @deprecated
function show_message($message, $type='notice', $vars=NULL)
{
global $OUTPUT;
$OUTPUT->show_message($message, $type, $vars);
}
// encrypt IMAP password using DES encryption
function encrypt_passwd($pass)
{
$cypher = des(get_des_key(), $pass, 1, 0, NULL);
return base64_encode($cypher);
}
// decrypt IMAP password using DES encryption
function decrypt_passwd($cypher)
{
$pass = des(get_des_key(), base64_decode($cypher), 0, 0, NULL);
return preg_replace('/\x00/', '', $pass);
}
// return a 24 byte key for the DES encryption
function get_des_key()
{
$key = !empty($GLOBALS['CONFIG']['des_key']) ? $GLOBALS['CONFIG']['des_key'] : 'rcmail?24BitPwDkeyF**ECB';
$len = strlen($key);
// make sure the key is exactly 24 chars long
if ($len<24)
$key .= str_repeat('_', 24-$len);
else if ($len>24)
substr($key, 0, 24);
return $key;
}
// read directory program/localization/ and return a list of available languages
function rcube_list_languages()
{
global $CONFIG, $INSTALL_PATH;
static $sa_languages = array();
if (!sizeof($sa_languages))
{
@include($INSTALL_PATH.'program/localization/index.inc');
if ($dh = @opendir($INSTALL_PATH.'program/localization'))
{
while (($name = readdir($dh)) !== false)
{
if ($name{0}=='.' || !is_dir($INSTALL_PATH.'program/localization/'.$name))
continue;
if ($label = $rcube_languages[$name])
$sa_languages[$name] = $label ? $label : $name;
}
closedir($dh);
}
}
return $sa_languages;
}
// add a localized label to the client environment
function rcube_add_label()
{
global $OUTPUT;
$arg_list = func_get_args();
foreach ($arg_list as $i => $name)
$OUTPUT->command('add_label', $name, rcube_label($name));
}
// remove temp files older than two day
function rcmail_temp_gc()
{
$tmp = unslashify($CONFIG['temp_dir']);
$expire = mktime() - 172800; // expire in 48 hours
if ($dir = opendir($tmp))
{
while (($fname = readdir($dir)) !== false)
{
if ($fname{0} == '.')
continue;
if (filemtime($tmp.'/'.$fname) < $expire)
@unlink($tmp.'/'.$fname);
}
closedir($dir);
}
}
// remove all expired message cache records
function rcmail_message_cache_gc()
{
global $DB, $CONFIG;
// no cache lifetime configured
if (empty($CONFIG['message_cache_lifetime']))
return;
// get target timestamp
$ts = get_offset_time($CONFIG['message_cache_lifetime'], -1);
$DB->query("DELETE FROM ".get_table_name('messages')."
WHERE created < ".$DB->fromunixtime($ts));
}
/**
* Convert a string from one charset to another.
* Uses mbstring and iconv functions if possible
*
* @param string Input string
* @param string Suspected charset of the input string
* @param string Target charset to convert to; defaults to RCMAIL_CHARSET
* @return Converted string
*/
function rcube_charset_convert($str, $from, $to=NULL)
{
global $MBSTRING;
$from = strtoupper($from);
$to = $to==NULL ? strtoupper(RCMAIL_CHARSET) : strtoupper($to);
if ($from==$to || $str=='' || empty($from))
return $str;
// convert charset using mbstring module
if ($MBSTRING)
{
$to = $to=="UTF-7" ? "UTF7-IMAP" : $to;
$from = $from=="UTF-7" ? "UTF7-IMAP": $from;
// return if convert succeeded
if (($out = mb_convert_encoding($str, $to, $from)) != '')
return $out;
}
// convert charset using iconv module
if (function_exists('iconv') && $from!='UTF-7' && $to!='UTF-7')
return iconv($from, $to, $str);
$conv = new utf8();
// convert string to UTF-8
if ($from=='UTF-7')
$str = utf7_to_utf8($str);
else if (($from=='ISO-8859-1') && function_exists('utf8_encode'))
$str = utf8_encode($str);
else if ($from!='UTF-8')
{
$conv->loadCharset($from);
$str = $conv->strToUtf8($str);
}
// encode string for output
if ($to=='UTF-7')
return utf8_to_utf7($str);
else if ($to=='ISO-8859-1' && function_exists('utf8_decode'))
return utf8_decode($str);
else if ($to!='UTF-8')
{
$conv->loadCharset($to);
return $conv->utf8ToStr($str);
}
// return UTF-8 string
return $str;
}
/**
* Replacing specials characters to a specific encoding type
*
* @param string Input string
* @param string Encoding type: text|html|xml|js|url
* @param string Replace mode for tags: show|replace|remove
* @param boolean Convert newlines
* @return The quoted string
*/
function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
{
global $OUTPUT_TYPE, $OUTPUT;
static $html_encode_arr, $js_rep_table, $xml_rep_table;
if (!$enctype)
$enctype = $GLOBALS['OUTPUT_TYPE'];
// convert nbsps back to normal spaces if not html
if ($enctype!='html')
$str = str_replace(chr(160), ' ', $str);
// encode for plaintext
if ($enctype=='text')
return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
// encode for HTML output
if ($enctype=='html')
{
if (!$html_encode_arr)
{
$html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
unset($html_encode_arr['?']);
}
$ltpos = strpos($str, '<');
$encode_arr = $html_encode_arr;
// don't replace quotes and html tags
if (($mode=='show' || $mode=='') && $ltpos!==false && strpos($str, '>', $ltpos)!==false)
{
unset($encode_arr['"']);
unset($encode_arr['<']);
unset($encode_arr['>']);
unset($encode_arr['&']);
}
else if ($mode=='remove')
$str = strip_tags($str);
// avoid douple quotation of &
$out = preg_replace('/&([a-z]{2,5}|#[0-9]{2,4});/', '&\\1;', strtr($str, $encode_arr));
return $newlines ? nl2br($out) : $out;
}
if ($enctype=='url')
return rawurlencode($str);
// if the replace tables for XML and JS are not yet defined
if (!$js_rep_table)
{
$js_rep_table = $xml_rep_table = array();
$xml_rep_table['&'] = '&';
for ($c=160; $c<256; $c++) // can be increased to support more charsets
{
$hex = dechex($c);
$xml_rep_table[Chr($c)] = "&#$c;";
if ($OUTPUT->get_charset()=='ISO-8859-1')
$js_rep_table[Chr($c)] = sprintf("\u%s%s", str_repeat('0', 4-strlen($hex)), $hex);
}
$xml_rep_table['"'] = '"';
}
// encode for XML
if ($enctype=='xml')
return strtr($str, $xml_rep_table);
// encode for javascript use
if ($enctype=='js')
{
if ($OUTPUT->get_charset()!='UTF-8')
$str = rcube_charset_convert($str, RCMAIL_CHARSET, $OUTPUT->get_charset());
return preg_replace(array("/\r?\n/", "/\r/"), array('\n', '\n'), addslashes(strtr($str, $js_rep_table)));
}
// no encoding given -> return original string
return $str;
}
/**
* Quote a given string. Alias function for rep_specialchars_output
* @see rep_specialchars_output
*/
function Q($str, $mode='strict', $newlines=TRUE)
{
return rep_specialchars_output($str, 'html', $mode, $newlines);
}
/**
* Quote a given string. Alias function for rep_specialchars_output
* @see rep_specialchars_output
*/
function JQ($str)
{
return rep_specialchars_output($str, 'js');
}
/**
* Read input value and convert it for internal use
* Performs stripslashes() and charset conversion if necessary
*
* @param string Field name to read
* @param int Source to get value from (GPC)
* @param boolean Allow HTML tags in field value
* @param string Charset to convert into
* @return string Field value or NULL if not available
*/
function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
{
global $OUTPUT;
$value = NULL;
if ($source==RCUBE_INPUT_GET && isset($_GET[$fname]))
$value = $_GET[$fname];
else if ($source==RCUBE_INPUT_POST && isset($_POST[$fname]))
$value = $_POST[$fname];
else if ($source==RCUBE_INPUT_GPC)
{
if (isset($_POST[$fname]))
$value = $_POST[$fname];
else if (isset($_GET[$fname]))
$value = $_GET[$fname];
else if (isset($_COOKIE[$fname]))
$value = $_COOKIE[$fname];
}
// strip slashes if magic_quotes enabled
if ((bool)get_magic_quotes_gpc())
$value = stripslashes($value);
// remove HTML tags if not allowed
if (!$allow_html)
$value = strip_tags($value);
// convert to internal charset
if (is_object($OUTPUT))
return rcube_charset_convert($value, $OUTPUT->get_charset(), $charset);
else
return $value;
}
/**
* Remove single and double quotes from given string
*/
function strip_quotes($str)
{
return preg_replace('/[\'"]/', '', $str);
}
/**
* Remove new lines characters from given string
*/
function strip_newlines($str)
{
return preg_replace('/[\r\n]/', '', $str);
}
-/**
- * Compose an URL for a specific action
- *
- * @param string Request action
- * @param array More URL parameters
- * @return The application URL
- */
-function rcmail_url($action, $param=NULL)
-{
- $url = $GLOBALS['COMM_PATH'] . '&'.$action;
-
- if (is_array($param))
- foreach ($param as $p => $val)
- $url .= sprintf('&%s=%s', urlencode($p), urlencode($val));
-
- return $url;
-}
-
-
// return boolean if a specific template exists
function template_exists($name)
{
global $CONFIG;
$skin_path = $CONFIG['skin_path'];
// check template file
return is_file("$skin_path/templates/$name.html");
}
// Wrapper for rcmail_template::parse()
// @deprecated
function parse_template($name='main', $exit=true)
{
$GLOBALS['OUTPUT']->parse($name, $exit);
}
function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col)
{
global $DB;
// 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'));
$table = '<table' . $attrib_str . ">\n";
// add table title
$table .= "<thead><tr>\n";
foreach ($a_show_cols as $col)
$table .= '<td class="'.$col.'">' . Q(rcube_label($col)) . "</td>\n";
$table .= "</tr></thead>\n<tbody>\n";
$c = 0;
if (!is_array($table_data))
{
while ($table_data && ($sql_arr = $DB->fetch_assoc($table_data)))
{
$zebra_class = $c%2 ? 'even' : 'odd';
$table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $sql_arr[$id_col]);
// format each col
foreach ($a_show_cols as $col)
{
$cont = Q($sql_arr[$col]);
$table .= '<td class="'.$col.'">' . $cont . "</td>\n";
}
$table .= "</tr>\n";
$c++;
}
}
else
{
foreach ($table_data as $row_data)
{
$zebra_class = $c%2 ? 'even' : 'odd';
$table .= sprintf('<tr id="rcmrow%d" class="contact '.$zebra_class.'">'."\n", $row_data[$id_col]);
// format each col
foreach ($a_show_cols as $col)
{
$cont = Q($row_data[$col]);
$table .= '<td class="'.$col.'">' . $cont . "</td>\n";
}
$table .= "</tr>\n";
$c++;
}
}
// complete message table
$table .= "</tbody></table>\n";
return $table;
}
/**
* Create an edit field for inclusion on a form
*
* @param string col field name
* @param string value field value
* @param array attrib HTML element attributes for field
* @param string type HTML element type (default 'text')
* @return string HTML field definition
*/
function rcmail_get_edit_field($col, $value, $attrib, $type='text')
{
$fname = '_'.$col;
$attrib['name'] = $fname;
if ($type=='checkbox')
{
$attrib['value'] = '1';
$input = new checkbox($attrib);
}
else if ($type=='textarea')
{
$attrib['cols'] = $attrib['size'];
$input = new textarea($attrib);
}
else
$input = new textfield($attrib);
// use value from post
if (!empty($_POST[$fname]))
$value = $_POST[$fname];
$out = $input->show($value);
return $out;
}
// return the mail domain configured for the given host
function rcmail_mail_domain($host)
{
global $CONFIG;
$domain = $host;
if (is_array($CONFIG['mail_domain']))
{
if (isset($CONFIG['mail_domain'][$host]))
$domain = $CONFIG['mail_domain'][$host];
}
else if (!empty($CONFIG['mail_domain']))
$domain = $CONFIG['mail_domain'];
return $domain;
}
// compose a valid attribute string for HTML tags
function create_attrib_string($attrib, $allowed_attribs=array('id', 'class', 'style'))
{
// allow the following attributes to be added to the <iframe> tag
$attrib_str = '';
foreach ($allowed_attribs as $a)
if (isset($attrib[$a]))
$attrib_str .= sprintf(' %s="%s"', $a, str_replace('"', '"', $attrib[$a]));
return $attrib_str;
}
// convert a HTML attribute string attributes to an associative array (name => value)
function parse_attrib_string($str)
{
$attrib = array();
preg_match_all('/\s*([-_a-z]+)=(["\'])([^"]+)\2/Ui', stripslashes($str), $regs, PREG_SET_ORDER);
// convert attributes to an associative array (name => value)
if ($regs)
foreach ($regs as $attr)
$attrib[strtolower($attr[1])] = $attr[3];
return $attrib;
}
function format_date($date, $format=NULL)
{
global $CONFIG, $sess_user_lang;
$ts = NULL;
if (is_numeric($date))
$ts = $date;
else if (!empty($date))
$ts = @strtotime($date);
if (empty($ts))
return '';
// get user's timezone
$tz = $CONFIG['timezone'];
if ($CONFIG['dst_active'])
$tz++;
// convert time to user's timezone
$timestamp = $ts - date('Z', $ts) + ($tz * 3600);
// get current timestamp in user's timezone
$now = time(); // local time
$now -= (int)date('Z'); // make GMT time
$now += ($tz * 3600); // user's time
$now_date = getdate($now);
$today_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday'], $now_date['year']);
$week_limit = mktime(0, 0, 0, $now_date['mon'], $now_date['mday']-6, $now_date['year']);
// define date format depending on current time
if ($CONFIG['prettydate'] && !$format && $timestamp > $today_limit && $timestamp < $now)
return sprintf('%s %s', rcube_label('today'), date($CONFIG['date_today'] ? $CONFIG['date_today'] : 'H:i', $timestamp));
else if ($CONFIG['prettydate'] && !$format && $timestamp > $week_limit && $timestamp < $now)
$format = $CONFIG['date_short'] ? $CONFIG['date_short'] : 'D H:i';
else if (!$format)
$format = $CONFIG['date_long'] ? $CONFIG['date_long'] : 'd.m.Y H:i';
// parse format string manually in order to provide localized weekday and month names
// an alternative would be to convert the date() format string to fit with strftime()
$out = '';
for($i=0; $i<strlen($format); $i++)
{
if ($format{$i}=='\\') // skip escape chars
continue;
// write char "as-is"
if ($format{$i}==' ' || $format{$i-1}=='\\')
$out .= $format{$i};
// weekday (short)
else if ($format{$i}=='D')
$out .= rcube_label(strtolower(date('D', $timestamp)));
// weekday long
else if ($format{$i}=='l')
$out .= rcube_label(strtolower(date('l', $timestamp)));
// month name (short)
else if ($format{$i}=='M')
$out .= rcube_label(strtolower(date('M', $timestamp)));
// month name (long)
else if ($format{$i}=='F')
$out .= rcube_label(strtolower(date('F', $timestamp)));
else
$out .= date($format{$i}, $timestamp);
}
return $out;
}
function format_email_recipient($email, $name='')
{
if ($name && $name != $email)
return sprintf('%s <%s>', strpos($name, ",") ? '"'.$name.'"' : $name, $email);
else
return $email;
}
// ************** functions delivering gui objects **************
function rcmail_message_container($attrib)
{
global $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmMessageContainer';
// allow the following attributes to be added to the <table> tag
$attrib_str = create_attrib_string($attrib, array('style', 'class', 'id'));
$out = '<div' . $attrib_str . "></div>";
$OUTPUT->add_gui_object('message', $attrib['id']);
return $out;
}
// return the IMAP username of the current session
function rcmail_current_username($attrib)
{
global $DB;
static $s_username;
// alread fetched
if (!empty($s_username))
return $s_username;
// get e-mail address form default identity
$sql_result = $DB->query("SELECT email AS mailto
FROM ".get_table_name('identities')."
WHERE user_id=?
AND standard=1
AND del<>1",
$_SESSION['user_id']);
if ($DB->num_rows($sql_result))
{
$sql_arr = $DB->fetch_assoc($sql_result);
$s_username = $sql_arr['mailto'];
}
else if (strstr($_SESSION['username'], '@'))
$s_username = $_SESSION['username'];
else
$s_username = $_SESSION['username'].'@'.$_SESSION['imap_host'];
return $s_username;
}
// return code for the webmail login form
function rcmail_login_form($attrib)
{
global $CONFIG, $OUTPUT, $SESS_HIDDEN_FIELD;
$labels = array();
$labels['user'] = rcube_label('username');
$labels['pass'] = rcube_label('password');
$labels['host'] = rcube_label('server');
$input_user = new textfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30, 'autocomplete' => 'off'));
$input_pass = new passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30));
$input_action = new hiddenfield(array('name' => '_action', 'value' => 'login'));
$fields = array();
$fields['user'] = $input_user->show(get_input_value('_user', RCUBE_INPUT_POST));
$fields['pass'] = $input_pass->show();
$fields['action'] = $input_action->show();
if (is_array($CONFIG['default_host']))
{
$select_host = new select(array('name' => '_host', 'id' => 'rcmloginhost'));
foreach ($CONFIG['default_host'] as $key => $value)
{
if (!is_array($value))
$select_host->add($value, (is_numeric($key) ? $value : $key));
else
{
unset($select_host);
break;
}
}
$fields['host'] = isset($select_host) ? $select_host->show($_POST['_host']) : null;
}
else if (!strlen($CONFIG['default_host']))
{
$input_host = new textfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30));
$fields['host'] = $input_host->show($_POST['_host']);
}
$form_name = strlen($attrib['form']) ? $attrib['form'] : 'form';
$form_start = !strlen($attrib['form']) ? '<form name="form" action="./" method="post">' : '';
$form_end = !strlen($attrib['form']) ? '</form>' : '';
if ($fields['host'])
$form_host = <<<EOF
</tr><tr>
<td class="title"><label for="rcmloginhost">$labels[host]</label></td>
<td>$fields[host]</td>
EOF;
$OUTPUT->add_gui_object('loginform', $form_name);
$out = <<<EOF
$form_start
$SESS_HIDDEN_FIELD
$fields[action]
<table><tr>
<td class="title"><label for="rcmloginuser">$labels[user]</label></td>
<td>$fields[user]</td>
</tr><tr>
<td class="title"><label for="rcmloginpwd">$labels[pass]</label></td>
<td>$fields[pass]</td>
$form_host
</tr></table>
$form_end
EOF;
return $out;
}
function rcmail_charset_selector($attrib)
{
global $OUTPUT;
// pass the following attributes to the form class
$field_attrib = array('name' => '_charset');
foreach ($attrib as $attr => $value)
if (in_array($attr, array('id', 'class', 'style', 'size', 'tabindex')))
$field_attrib[$attr] = $value;
$charsets = array(
'US-ASCII' => 'ASCII (English)',
'EUC-JP' => 'EUC-JP (Japanese)',
'EUC-KR' => 'EUC-KR (Korean)',
'BIG5' => 'BIG5 (Chinese)',
'GB2312' => 'GB2312 (Chinese)',
'ISO-2022-JP' => 'ISO-2022-JP (Japanese)',
'ISO-8859-1' => 'ISO-8859-1 (Latin-1)',
'ISO-8859-2' => 'ISO-8895-2 (Central European)',
'ISO-8859-7' => 'ISO-8859-7 (Greek)',
'ISO-8859-9' => 'ISO-8859-9 (Turkish)',
'Windows-1251' => 'Windows-1251 (Cyrillic)',
'Windows-1252' => 'Windows-1252 (Western)',
'Windows-1255' => 'Windows-1255 (Hebrew)',
'Windows-1256' => 'Windows-1256 (Arabic)',
'Windows-1257' => 'Windows-1257 (Baltic)',
'UTF-8' => 'UTF-8'
);
$select = new select($field_attrib);
$select->add(array_values($charsets), array_keys($charsets));
$set = $_POST['_charset'] ? $_POST['_charset'] : $OUTPUT->get_charset();
return $select->show($set);
}
// return code for search function
function rcmail_search_form($attrib)
{
global $OUTPUT;
// add some labels to client
rcube_add_label('searching');
$attrib['name'] = '_q';
if (empty($attrib['id']))
$attrib['id'] = 'rcmqsearchbox';
$input_q = new textfield($attrib);
$out = $input_q->show();
$OUTPUT->add_gui_object('qsearchbox', $attrib['id']);
// add form tag around text field
if (empty($attrib['form']))
$out = sprintf(
'<form name="rcmqsearchform" action="./" '.
'onsubmit="%s.command(\'search\');return false" style="display:inline;">%s</form>',
JS_OBJECT_NAME,
$out);
return $out;
}
/****** debugging functions ********/
/**
* Print or write debug messages
*
* @param mixed Debug message or data
*/
function console($msg)
{
if (!is_string($msg))
$msg = var_export($msg, true);
if (!($GLOBALS['CONFIG']['debug_level'] & 4))
write_log('console', $msg);
else if ($GLOBALS['REMOTE_REQUEST'])
print "/*\n $msg \n*/\n";
else
{
print '<div style="background:#eee; border:1px solid #ccc; margin-bottom:3px; padding:6px"><pre>';
print $msg;
print "</pre></div>\n";
}
}
/**
* Append a line to a logfile in the logs directory.
* Date will be added automatically to the line.
*
* @param $name Name of logfile
* @param $line Line to append
*/
function write_log($name, $line)
{
global $CONFIG;
if (!is_string($line))
$line = var_export($line, true);
$log_entry = sprintf("[%s]: %s\n",
date("d-M-Y H:i:s O", mktime()),
$line);
if (empty($CONFIG['log_dir']))
$CONFIG['log_dir'] = $INSTALL_PATH.'logs';
// try to open specific log file for writing
if ($fp = @fopen($CONFIG['log_dir'].'/'.$name, 'a'))
{
fwrite($fp, $log_entry);
fclose($fp);
}
}
function rcube_timer()
{
list($usec, $sec) = explode(" ", microtime());
return ((float)$usec + (float)$sec);
}
function rcube_print_time($timer, $label='Timer')
{
static $print_count = 0;
$print_count++;
$now = rcube_timer();
$diff = $now-$timer;
if (empty($label))
$label = 'Timer '.$print_count;
console(sprintf("%s: %0.4f sec", $label, $diff));
}
?>
diff --git a/program/include/rcmail_template.inc b/program/include/rcmail_template.inc
index 6e3fe52b8..3609bec1b 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] . ($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']));
+ $attrib['href'] = Q(rcmail_url(null, null, $attrib['command']));
else if (in_array($attrib['command'], $a_static_commands))
- $attrib['href'] = Q(rcmail_self_url($attrib['command']));
+ $attrib['href'] = Q(rcmail_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/js/list.js b/program/js/list.js
index 719585893..23a9c349c 100644
--- a/program/js/list.js
+++ b/program/js/list.js
@@ -1,710 +1,711 @@
/*
+-----------------------------------------------------------------------+
| RoundCube List Widget |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2006, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
+-----------------------------------------------------------------------+
| Authors: Thomas Bruederli <roundcube@gmail.com> |
| Charles McNulty <charles@charlesmcnulty.com> |
+-----------------------------------------------------------------------+
| Requires: common.js |
+-----------------------------------------------------------------------+
$Id: list.js 344 2006-09-18 03:49:28Z thomasb $
*/
/**
* RoundCube List Widget class
* @contructor
*/
function rcube_list_widget(list, p)
{
// static contants
this.ENTER_KEY = 13;
this.DELETE_KEY = 46;
this.list = list ? list : null;
this.frame = null;
this.rows = [];
this.selection = [];
this.shiftkey = false;
this.multiselect = false;
this.draggable = false;
this.keyboard = false;
this.dont_select = false;
this.drag_active = false;
this.last_selected = 0;
this.in_selection_before = false;
this.focused = false;
this.drag_mouse_start = null;
this.dblclick_time = 600;
this.row_init = function(){};
this.events = { click:[], dblclick:[], select:[], keypress:[], dragstart:[], dragend:[] };
// overwrite default paramaters
if (p && typeof(p)=='object')
for (var n in p)
this[n] = p[n];
}
rcube_list_widget.prototype = {
/**
* get all message rows from HTML table and init each row
*/
init: function()
{
if (this.list && this.list.tBodies[0])
{
this.rows = new Array();
var row;
for(var r=0; r<this.list.tBodies[0].childNodes.length; r++)
{
row = this.list.tBodies[0].childNodes[r];
while (row && (row.nodeType != 1 || row.style.display == 'none'))
{
row = row.nextSibling;
r++;
}
this.init_row(row);
}
this.frame = this.list.parentNode;
// set body events
if (this.keyboard)
rcube_event.add_listener({element:document, event:'keydown', object:this, method:'key_press'});
}
},
/**
*
*/
init_row: function(row)
{
// make references in internal array and set event handlers
if (row && String(row.id).match(/rcmrow([a-z0-9\-_=]+)/i))
{
var p = this;
var uid = RegExp.$1;
row.uid = uid;
this.rows[uid] = {uid:uid, id:row.id, obj:row, classname:row.className};
// set eventhandlers to table row
row.onmousedown = function(e){ return p.drag_row(e, this.uid); };
row.onmouseup = function(e){ return p.click_row(e, this.uid); };
if (document.all)
row.onselectstart = function() { return false; };
this.row_init(this.rows[uid]);
}
},
/**
*
*/
clear: function(sel)
{
var tbody = document.createElement('TBODY');
this.list.insertBefore(tbody, this.list.tBodies[0]);
this.list.removeChild(this.list.tBodies[1]);
this.rows = new Array();
if (sel) this.clear_selection();
},
/**
* 'remove' message row from list (just hide it)
*/
remove_row: function(uid)
{
if (this.rows[uid].obj)
this.rows[uid].obj.style.display = 'none';
this.rows[uid] = null;
},
/**
*
*/
insert_row: function(row, attop)
{
var tbody = this.list.tBodies[0];
if (attop && tbody.rows.length)
tbody.insertBefore(row, tbody.firstChild);
else
tbody.appendChild(row);
this.init_row(row);
},
/**
* Set focur to the list
*/
focus: function(e)
{
this.focused = true;
for (var n=0; n<this.selection.length; n++)
{
id = this.selection[n];
if (this.rows[id].obj)
{
this.set_classname(this.rows[id].obj, 'selected', true);
this.set_classname(this.rows[id].obj, 'unfocused', false);
}
}
if (e || (e = window.event))
rcube_event.cancel(e);
},
/**
* remove focus from the list
*/
blur: function()
{
var id;
this.focused = false;
for (var n=0; n<this.selection.length; n++)
{
id = this.selection[n];
if (this.rows[id] && this.rows[id].obj)
{
this.set_classname(this.rows[id].obj, 'selected', false);
this.set_classname(this.rows[id].obj, 'unfocused', true);
}
}
},
/**
* onmousedown-handler of message list row
*/
drag_row: function(e, id)
{
this.in_selection_before = this.in_selection(id) ? id : false;
// don't do anything (another action processed before)
if (this.dont_select)
return false;
// selects currently unselected row
if (!this.in_selection_before)
{
var mod_key = rcube_event.get_modifier(e);
this.select_row(id, mod_key, false);
}
if (this.draggable && this.selection.length)
{
this.drag_start = true;
this.drag_mouse_start = rcube_event.get_mouse_pos(e);
rcube_event.add_listener({element:document, event:'mousemove', object:this, method:'drag_mouse_move'});
rcube_event.add_listener({element:document, event:'mouseup', object:this, method:'drag_mouse_up'});
}
return false;
},
/**
* onmouseup-handler of message list row
*/
click_row: function(e, id)
{
var now = new Date().getTime();
var mod_key = rcube_event.get_modifier(e);
// don't do anything (another action processed before)
if (this.dont_select)
{
this.dont_select = false;
return false;
}
var dblclicked = now - this.rows[id].clicked < this.dblclick_time;
// unselects currently selected row
if (!this.drag_active && this.in_selection_before == id && !dblclicked)
this.select_row(id, mod_key, false);
this.drag_start = false;
this.in_selection_before = false;
// row was double clicked
if (this.rows && dblclicked && this.in_selection(id))
this.trigger_event('dblclick');
else
this.trigger_event('click');
if (!this.drag_active)
rcube_event.cancel(e);
this.rows[id].clicked = now;
return false;
},
/**
* get next and previous rows that are not hidden
*/
get_next_row: function()
{
if (!this.rows)
return false;
var last_selected_row = this.rows[this.last_selected];
var new_row = last_selected_row ? last_selected_row.obj.nextSibling : null;
while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none'))
new_row = new_row.nextSibling;
return new_row;
},
get_prev_row: function()
{
if (!this.rows)
return false;
var last_selected_row = this.rows[this.last_selected];
var new_row = last_selected_row ? last_selected_row.obj.previousSibling : null;
while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none'))
new_row = new_row.previousSibling;
return new_row;
},
// selects or unselects the proper row depending on the modifier key pressed
select_row: function(id, mod_key, with_mouse)
{
var select_before = this.selection.join(',');
if (!this.multiselect)
mod_key = 0;
if (!mod_key)
{
this.shift_start = id;
this.highlight_row(id, false);
}
else
{
switch (mod_key)
{
case SHIFT_KEY:
this.shift_select(id, false);
break;
case CONTROL_KEY:
this.shift_start = id;
if (!with_mouse)
this.highlight_row(id, true);
break;
case CONTROL_SHIFT_KEY:
this.shift_select(id, true);
break;
default:
this.highlight_row(id, false);
break;
}
}
// trigger event if selection changed
if (this.selection.join(',') != select_before)
this.trigger_event('select');
if (this.last_selected != 0 && this.rows[this.last_selected])
this.set_classname(this.rows[this.last_selected].obj, 'focused', false);
this.last_selected = id;
this.set_classname(this.rows[id].obj, 'focused', true);
},
/**
* Alias method for select_row
*/
select: function(id)
{
this.select_row(id, false);
this.scrollto(id);
},
/**
* Select row next to the last selected one.
* Either below or above.
*/
select_next: function()
{
var next_row = this.get_next_row();
var prev_row = this.get_prev_row();
var new_row = (next_row) ? next_row : prev_row;
if (new_row)
this.select_row(new_row.uid, false, false);
},
/**
* Perform selection when shift key is pressed
*/
shift_select: function(id, control)
{
var from_rowIndex = this.rows[this.shift_start].obj.rowIndex;
var to_rowIndex = this.rows[id].obj.rowIndex;
var i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex);
var j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex);
// iterate through the entire message list
for (var n in this.rows)
{
if ((this.rows[n].obj.rowIndex >= i) && (this.rows[n].obj.rowIndex <= j))
{
if (!this.in_selection(n))
this.highlight_row(n, true);
}
else
{
if (this.in_selection(n) && !control)
this.highlight_row(n, true);
}
}
},
/**
* Check if given id is part of the current selection
*/
in_selection: function(id)
{
for(var n in this.selection)
if (this.selection[n]==id)
return true;
return false;
},
/**
* Select each row in list
*/
select_all: function(filter)
{
if (!this.rows || !this.rows.length)
return false;
// reset selection first
this.clear_selection();
for (var n in this.rows)
{
if (!filter || this.rows[n][filter]==true)
{
this.last_selected = n;
this.highlight_row(n, true);
}
}
return true;
},
/**
* Unselect all selected rows
*/
clear_selection: function()
{
for(var n=0; n<this.selection.length; n++)
if (this.rows[this.selection[n]])
{
this.set_classname(this.rows[this.selection[n]].obj, 'selected', false);
this.set_classname(this.rows[this.selection[n]].obj, 'unfocused', false);
}
this.selection = new Array();
},
/**
* Getter for the selection array
*/
get_selection: function()
{
return this.selection;
},
/**
* Return the ID if only one row is selected
*/
get_single_selection: function()
{
if (this.selection.length == 1)
return this.selection[0];
else
return null;
},
/**
* Highlight/unhighlight a row
*/
highlight_row: function(id, multiple)
{
if (this.rows[id] && !multiple)
{
this.clear_selection();
this.selection[0] = id;
this.set_classname(this.rows[id].obj, 'selected', true)
}
else if (this.rows[id])
{
if (!this.in_selection(id)) // select row
{
this.selection[this.selection.length] = id;
this.set_classname(this.rows[id].obj, 'selected', true);
}
else // unselect row
{
var p = find_in_array(id, this.selection);
var a_pre = this.selection.slice(0, p);
var a_post = this.selection.slice(p+1, this.selection.length);
this.selection = a_pre.concat(a_post);
this.set_classname(this.rows[id].obj, 'selected', false);
this.set_classname(this.rows[id].obj, 'unfocused', false);
}
}
},
/**
* Handler for keyboard events
*/
key_press: function(e)
{
if (this.focused != true)
return true;
this.shiftkey = e.shiftKey;
var keyCode = document.layers ? e.which : document.all ? event.keyCode : document.getElementById ? e.keyCode : 0;
var mod_key = rcube_event.get_modifier(e);
switch (keyCode)
{
case 40:
case 38:
return this.use_arrow_key(keyCode, mod_key);
break;
default:
this.key_pressed = keyCode;
this.trigger_event('keypress');
}
return true;
},
/**
* Special handling method for arrow keys
*/
use_arrow_key: function(keyCode, mod_key)
{
var new_row;
if (keyCode == 40) // down arrow key pressed
new_row = this.get_next_row();
else if (keyCode == 38) // up arrow key pressed
new_row = this.get_prev_row();
if (new_row)
{
this.select_row(new_row.uid, mod_key, true);
this.scrollto(new_row.uid);
}
return false;
},
/**
* Try to scroll the list to make the specified row visible
*/
scrollto: function(id)
{
var row = this.rows[id].obj;
if (row && this.frame)
{
var scroll_to = Number(row.offsetTop);
if (scroll_to < Number(this.frame.scrollTop))
this.frame.scrollTop = scroll_to;
else if (scroll_to + Number(row.offsetHeight) > Number(this.frame.scrollTop) + Number(this.frame.offsetHeight))
this.frame.scrollTop = (scroll_to + Number(row.offsetHeight)) - Number(this.frame.offsetHeight);
}
},
/**
* Handler for mouse move events
*/
drag_mouse_move: function(e)
{
if (this.drag_start)
{
// check mouse movement, of less than 3 pixels, don't start dragging
var m = rcube_event.get_mouse_pos(e);
if (!this.drag_mouse_start || (Math.abs(m.x - this.drag_mouse_start.x) < 3 && Math.abs(m.y - this.drag_mouse_start.y) < 3))
return false;
if (!this.draglayer)
this.draglayer = new rcube_layer('rcmdraglayer', {x:0, y:0, width:300, vis:0, zindex:2000});
// get subjects of selectedd messages
var names = '';
- var c, subject, obj;
+ var c, node, subject, obj;
for(var n=0; n<this.selection.length; n++)
{
if (n>12) // only show 12 lines
{
names += '...';
break;
}
if (this.rows[this.selection[n]].obj)
{
obj = this.rows[this.selection[n]].obj;
subject = '';
for(c=0; c<obj.childNodes.length; c++)
- if (!subject && obj.childNodes[c].nodeName=='TD' && obj.childNodes[c].firstChild && obj.childNodes[c].firstChild.nodeType==3)
+ if (obj.childNodes[c].nodeName=='TD' && (node = obj.childNodes[c].firstChild) && (node.nodeType==3 || node.nodeName=='A'))
{
- subject = obj.childNodes[c].firstChild.data;
+ subject = node.nodeType==3 ? node.data : node.innerHTML;
names += (subject.length > 50 ? subject.substring(0, 50)+'...' : subject) + '<br />';
+ break;
}
}
}
this.draglayer.write(names);
this.draglayer.show(1);
this.drag_active = true;
this.trigger_event('dragstart');
}
if (this.drag_active && this.draglayer)
{
var pos = rcube_event.get_mouse_pos(e);
this.draglayer.move(pos.x+20, pos.y-5);
}
this.drag_start = false;
return false;
},
/**
* Handler for mouse up events
*/
drag_mouse_up: function(e)
{
document.onmousemove = null;
if (this.draglayer && this.draglayer.visible)
this.draglayer.show(0);
this.drag_active = false;
this.trigger_event('dragend');
rcube_event.remove_listener({element:document, event:'mousemove', object:this, method:'drag_mouse_move'});
rcube_event.remove_listener({element:document, event:'mouseup', object:this, method:'drag_mouse_up'});
return rcube_event.cancel(e);
},
/**
* set/unset a specific class name
*/
set_classname: function(obj, classname, set)
{
var reg = new RegExp('\s*'+classname, 'i');
if (!set && obj.className.match(reg))
obj.className = obj.className.replace(reg, '');
else if (set && !obj.className.match(reg))
obj.className += ' '+classname;
},
/**
* Setter for object event handlers
*
* @param {String} Event name
* @param {Function} Handler function
* @return Listener ID (used to remove this handler later on)
*/
addEventListener: function(evt, handler)
{
if (this.events[evt]) {
var handle = this.events[evt].length;
this.events[evt][handle] = handler;
return handle;
}
else
return false;
},
/**
* Removes a specific event listener
*
* @param {String} Event name
* @param {Int} Listener ID to remove
*/
removeEventListener: function(evt, handle)
{
if (this.events[evt] && this.events[evt][handle])
this.events[evt][handle] = null;
},
/**
* This will execute all registered event handlers
* @private
*/
trigger_event: function(evt)
{
if (this.events[evt] && this.events[evt].length) {
for (var i=0; i<this.events[evt].length; i++)
if (typeof(this.events[evt][i]) == 'function')
this.events[evt][i](this);
}
}
};
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 5329270c2..397b0a12d 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -1,239 +1,239 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/addressbook/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 addressbook functionality and GUI objects |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id$
*/
require_once('include/rcube_contacts.inc');
require_once('include/rcube_ldap.inc');
// instantiate a contacts object according to the given source
if (($source = get_input_value('_source', RCUBE_INPUT_GPC)) && isset($CONFIG['ldap_public'][$source]))
$CONTACTS = new rcube_ldap($CONFIG['ldap_public'][$source]);
else
$CONTACTS = new rcube_contacts($DB, $_SESSION['user_id']);
$CONTACTS->set_pagesize($CONFIG['pagesize']);
// set list properties and session vars
if (!empty($_GET['_page']))
{
$CONTACTS->set_page(intval($_GET['_page']));
$_SESSION['page'] = $_GET['_page'];
}
else
$CONTACTS->set_page(isset($_SESSION['page']) ?$_SESSION['page'] : 1);
// set message set for search result
if (!empty($_REQUEST['_search']) && isset($_SESSION['search'][$_REQUEST['_search']]))
$CONTACTS->set_search_set($_SESSION['search'][$_REQUEST['_search']]);
// set data source env
$OUTPUT->set_env('source', $source ? $source : '0');
$OUTPUT->set_env('readonly', $CONTACTS->readonly, false);
function rcmail_directory_list($attrib)
{
global $CONFIG, $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmdirectorylist';
$local_id = '0';
$current = get_input_value('_source', RCUBE_INPUT_GPC);
$line_templ = '<li id="%s" class="%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'.
"</a></li>\n";
$js_list = array("$local_id" => array('id' => $local_id, 'readonly' => false));
// allow the following attributes to be added to the <ul> tag
$out = '<ul' . create_attrib_string($attrib, array('style', 'class', 'id')) . ">\n";
$out .= sprintf($line_templ,
'rcmli'.$local_id,
!$current ? 'selected' : '',
- Q(rcmail_self_url('list', array('_source' => 0))),
+ Q(rcmail_url('list', array('_source' => 0))),
JS_OBJECT_NAME,
$local_id,
JS_OBJECT_NAME,
$local_id,
JS_OBJECT_NAME,
$local_id,
JS_OBJECT_NAME,
$local_id,
rcube_label('personaladrbook'));
foreach ((array)$CONFIG['ldap_public'] as $id => $prop)
{
$js_id = JQ($id);
$dom_id = preg_replace('/[^a-z0-9\-_]/i', '', $id);
$out .= sprintf($line_templ,
'rcmli'.$dom_id,
$current == $id ? 'selected' : '',
- Q(rcmail_self_url('list', array('_source' => $id))),
+ Q(rcmail_url('list', array('_source' => $id))),
JS_OBJECT_NAME,
$js_id,
JS_OBJECT_NAME,
$js_id,
JS_OBJECT_NAME,
$js_id,
JS_OBJECT_NAME,
$js_id,
!empty($prop['name']) ? Q($prop['name']) : Q($id));
$js_list[$id] = array('id' => $id, 'readonly' => !$prop['writeable']);
}
$out .= '</ul>';
$OUTPUT->add_gui_object('folderlist', $attrib['id']);
$OUTPUT->set_env('address_sources', $js_list);
return $out;
}
// return the message list as HTML table
function rcmail_contacts_list($attrib)
{
global $CONTACTS, $OUTPUT;
// count contacts for this user
$result = $CONTACTS->list_records();
// add id to message list table if not specified
if (!strlen($attrib['id']))
$attrib['id'] = 'rcmAddressList';
// define list of cols to be displayed
$a_show_cols = array('name');
// create XHTML table
$out = rcube_table_output($attrib, $result->records, $a_show_cols, $CONTACTS->primary_key);
// set client env
$OUTPUT->add_gui_object('contactslist', $attrib['id']);
$OUTPUT->set_env('current_page', (int)$CONTACTS->list_page);
$OUTPUT->set_env('pagecount', ceil($result->count/$CONTACTS->page_size));
$OUTPUT->include_script('list.js');
// add some labels to client
rcube_add_label('deletecontactconfirm');
return $out;
}
function rcmail_js_contacts_list($result, $prefix='')
{
global $OUTPUT;
if (empty($result) || $result->count == 0)
return;
// define list of cols to be displayed
$a_show_cols = array('name');
while ($row = $result->next())
{
$a_row_cols = array();
// format each col
foreach ($a_show_cols as $col)
$a_row_cols[$col] = $row[$col];
$OUTPUT->command($prefix.'add_contact_row', $row['ID'], $a_row_cols);
}
}
// similar function as /steps/settings/identities.inc::rcmail_identity_frame()
function rcmail_contact_frame($attrib)
{
global $OUTPUT;
if (!$attrib['id'])
$attrib['id'] = 'rcmcontactframe';
$attrib['name'] = $attrib['id'];
$attrib_str = create_attrib_string($attrib, array('name', 'id', 'class', 'style', 'src', 'width', 'height', 'frameborder'));
$OUTPUT->set_env('contentframe', $attrib['name']);
$OUTPUT->set_env('blankpage', $attrib['src'] ? $OUTPUT->abs_url($attrib['src']) : 'program/blank.gif');
return '<iframe'. $attrib_str . '></iframe>';
}
function rcmail_rowcount_display($attrib)
{
global $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_rowcount_text();
$out .= '</span>';
return $out;
}
function rcmail_get_rowcount_text()
{
global $CONTACTS;
// read nr of contacts
$result = $CONTACTS->get_result();
if (!$result)
$result = $CONTACTS->count();
if ($result->count == 0)
$out = rcube_label('nocontactsfound');
else
$out = rcube_label(array(
'name' => 'contactsfromto',
'vars' => array(
'from' => $result->first + 1,
'to' => min($result->count, $result->first + $CONTACTS->page_size),
'count' => $result->count)
));
return $out;
}
// register UI objects
$OUTPUT->add_handlers(array(
'directorylist' => 'rcmail_directory_list',
'addresslist' => 'rcmail_contacts_list',
'addressframe' => 'rcmail_contact_frame',
'recordscountdisplay' => 'rcmail_rowcount_display',
'searchform' => 'rcmail_search_form'
));
?>
diff --git a/program/steps/addressbook/mailto.inc b/program/steps/addressbook/mailto.inc
index ddbec30d0..27217e5c8 100644
--- a/program/steps/addressbook/mailto.inc
+++ b/program/steps/addressbook/mailto.inc
@@ -1,48 +1,48 @@
<?php
/*
+-----------------------------------------------------------------------+
| program/steps/addressbook/mailto.inc |
| |
| This file is part of the RoundCube Webmail client |
| Copyright (C) 2007, RoundCube Dev. - Switzerland |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
| Compose a recipient list with all selected contacts |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+-----------------------------------------------------------------------+
$Id: copy.inc 471 2007-02-09 21:25:50Z thomasb $
*/
$cid = get_input_value('_cid', RCUBE_INPUT_GET);
$recipients = null;
$mailto = array();
if ($cid && preg_match('/^[a-z0-9\-_=]+(,[a-z0-9\-_=]+)*$/i', $cid) && $CONTACTS->ready)
{
$recipients = $CONTACTS->search($CONTACTS->primary_key, $cid);
while (is_object($recipients) && ($rec = $recipients->iterate()))
$mailto[] = format_email_recipient($rec['email'], $rec['name']);
}
if (!empty($mailto))
{
$mailto_str = join(', ', $mailto);
$mailto_id = substr(md5($mailto_str), 0, 16);
$_SESSION['mailto'][$mailto_id] = $mailto_str;
- $OUTPUT->command('redirect', rcmail_self_url('compose', array('_mailto' => $mailto_id), 'mail'));
+ $OUTPUT->command('redirect', rcmail_url('compose', array('_mailto' => $mailto_id), 'mail'));
}
else
$OUTPUT->show_message('nocontactsfound', 'warning');
// send response
$OUTPUT->send();
?>
\ No newline at end of file
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 1848d301a..991c3c168 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -1,1483 +1,1493 @@
<?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));
+ $GET_URL = rcmail_url('get', array('_mbox'=>$IMAP->get_mailbox_name(), '_uid'=>get_input_value('_uid', RCUBE_INPUT_GET)));
// set current mailbox in client environment
$OUTPUT->set_env('mailbox', $IMAP->get_mailbox_name());
$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']))),
+ 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
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');
+
+ $mbox = $IMAP->get_mailbox_name();
// 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))
+ if (($mbox==$CONFIG['sent_mbox'] || $mbox==$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);
+ $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')
{
+ $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
+ $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);
}
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');
+ $mbox = $IMAP->get_mailbox_name();
// show 'to' instead of from in sent messages
- if (($IMAP->get_mailbox_name() == $CONFIG['sent_mbox'] || $IMAP->get_mailbox_name() == $CONFIG['drafts_mbox'])
+ if (($mbox == $CONFIG['sent_mbox'] || $mbox == $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')
{
+ $action = $mbox==$CONFIG['drafts_mbox'] ? 'compose' : 'show';
+ $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);
}
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/common.css b/skins/default/common.css
index 2ce3dffad..32105ef90 100755
--- a/skins/default/common.css
+++ b/skins/default/common.css
@@ -1,426 +1,424 @@
/***** RoundCube|Mail basic styles *****/
body
{
margin: 8px;
background-color: #F6F6F6; /* #EBEBEB; */
color: #000000;
}
body.iframe
{
margin: 0px;
}
body.extwin
{
margin: 10px;
}
body, td, th, span, div, p, h3
{
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
font-size: 12px;
color: #000000;
}
th
{
font-weight: normal;
}
h3
{
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
font-size: 18px;
color: #000000;
}
a, a:active, a:visited
{
color: #000000;
outline: none;
}
a.button, a.button:visited, a.tab, a.tab:visited, a.axislist
{
color: #000000;
text-decoration: none;
}
a.tab
{
width: 80px;
display: block;
text-align: center;
}
hr
{
height: 1px;
background-color: #666666;
border-style: none;
}
input, textarea
{
font-size: 9pt;
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
padding: 1px;
padding-left: 3px;
padding-right: 3px;
background-color: #ffffff;
border: 1px solid #666666;
}
input[type="checkbox"],
input[type="radio"]
{
border: 0;
padding: 0;
}
input.button
{
height: 20px;
color: #333333;
font-size: 12px;
padding-left: 8px;
padding-right: 8px;
background: url(images/buttons/bg.gif) repeat-x #f0f0f0;
border: 1px solid #a4a4a4;
}
input.button:hover
{
color: black;
}
img
{
behavior: url('skins/default/pngbehavior.htc');
}
.alttext
{
font-size: 11px;
}
/** common user interface objects */
#header
{
position: absolute;
top: 10px;
left: 20px;
width: 170px;
height: 40px;
z-index: 100;
}
#taskbar
{
position: absolute;
top: 0px;
right: 0px;
width: 600px;
height: 37px;
background: url(images/taskbar.gif) top right no-repeat;
padding: 10px 14px 10px 0px;
text-align: right;
white-space: nowrap;
z-index: 2;
}
#taskbar a,
#taskbar a:active,
#taskbar a:visited
{
font-size: 11px;
color: #666666;
text-decoration: none;
padding: 6px 16px 6px 30px;
background-repeat: no-repeat;
}
#taskbar a:hover
{
color: #333333;
}
a.button-mail
{
background-image: url(images/buttons/mail.gif);
}
a.button-addressbook
{
background-image: url(images/buttons/addressbook.gif);
}
a.button-settings
{
background-image: url(images/buttons/settings.gif);
}
a.button-logout
{
background-image: url(images/buttons/logout.gif);
}
#message
{
position: absolute;
display: none;
top: -1px;
left: 200px;
right: 200px;
z-index: 5000;
opacity: 0.85;
}
#message div
{
width: 400px;
margin: 0px auto;
height: 24px;
min-height: 24px;
padding: 8px 10px 8px 46px;
}
#message div.notice,
#remote-objects-message
{
background: url(images/display/info.png) 6px 3px no-repeat;
background-color: #F7FDCB;
border: 1px solid #C2D071;
}
#message div.error,
#message div.warning
{
background: url(images/display/warning.png) 6px 3px no-repeat;
background-color: #EF9398;
border: 1px solid #DC5757;
}
#message div.confirmation
{
background: url(images/display/confirm.png) 6px 3px no-repeat;
background-color: #A6EF7B;
border: 1px solid #76C83F;
}
#message div.loading
{
background: url(images/display/loading.gif) 6px 3px no-repeat;
background-color: #EBEBEB;
border: 1px solid #CCCCCC;
}
.splitter
{
position: absolute;
padding: 2px;
background: url(images/dimple.png) center no-repeat;
}
.splitter-h
{
cursor: n-resize;
background-position: center 2px;
}
.splitter-v
{
cursor: e-resize;
background-position: 1px center;
}
.boxtitle
{
height: 12px !important;
padding: 4px 20px 3px 20px;
border-bottom: 1px solid #999;
color: #333;
font-size: 11px;
font-weight: bold;
background-color: #EBEBEB;
background-image: url(images/listheader_aqua.gif);
}
.radios-left label
{
padding-left: 0.3em;
}
/***** common table settings ******/
table.records-table thead tr td
{
height: 20px;
padding: 0px 4px 0px 4px;
vertical-align: middle;
border-bottom: 1px solid #999999;
color: #333333;
background-color: #EBEBEB;
background-image: url(images/listheader_aqua.gif);
font-size: 11px;
font-weight: bold;
}
table.records-table tbody tr td
{
height: 16px;
padding: 2px 4px 2px 4px;
font-size: 11px;
white-space: nowrap;
border-bottom: 1px solid #EBEBEB;
overflow: hidden;
text-align: left;
}
table.records-table tr
{
background-color: #FFFFFF;
}
table.records-table tr.selected td
{
- font-weight: bold;
color: #FFFFFF;
background-color: #CC3333;
}
table.records-table tr.focused td
{
}
table.records-table tr.unfocused td
{
- font-weight: bold;
color: #FFFFFF;
background-color: #929292;
}
/***** mac-style quicksearch field *****/
#quicksearchbar
{
position: absolute;
top: 60px;
right: 30px;
width: 182px;
height: 20px;
text-align: right;
background: url('images/searchfield.gif') top left no-repeat;
}
#quicksearchbar a
{
position: absolute;
top: 3px;
right: 4px;
text-decoration: none;
}
#quicksearchbar img
{
vertical-align: middle;
}
#quicksearchbox
{
position: absolute;
top: 2px;
left: 20px;
width: 140px;
font-size: 11px;
padding: 0px;
border: none;
}
/*\*/
html>body*#quicksearchbar[id$="quicksearchbar"]:not([class="none"]) { background-image: none; }
html>body*#quicksearchbar[id$="quicksearchbar"]:not([class="none"]) a { top: 5px; }
html>body*#quicksearchbar[id$="quicksearchbar"]:not([class="none"]) #quicksearchbox { width: 180px; top:0px; right: 1px; left: auto; }
/**/
/***** roundcube webmail pre-defined classes *****/
#rcversion
{
position: absolute;
top: 67px;
left: 20px;
width: 160px;
text-align: center;
font-weight: normal;
font-size: x-small;
font-variant: small-caps;
color: #999999;
/*border: 1px solid #308014;
background-color: #b4eeb4;*/
}
#rcmdraglayer
{
width: 300px;
border: 1px solid #999999;
background-color: #F9F9F9;
padding-left: 8px;
padding-right: 8px;
padding-top: 3px;
padding-bottom: 3px;
font-size: 11px;
opacity: 0.6;
-moz-opacity: 0.6;
}
a.rcmContactAddress
{
text-decoration: none;
}
a.rcmContactAddress:hover
{
text-decoration: underline;
}
#rcmKSearchpane
{
background-color: #F9F9F9;
border: 1px solid #CCCCCC;
}
#rcmKSearchpane ul
{
margin: 0px;
padding: 2px;
list-style-image: none;
list-style-type: none;
}
#rcmKSearchpane ul li
{
height: 16px;
font-size: 11px;
padding-left: 8px;
padding-top: 2px;
padding-right: 8px;
white-space: nowrap;
}
#rcmKSearchpane ul li.selected
{
color: #ffffff;
background-color: #CC3333;
}
diff --git a/skins/default/mail.css b/skins/default/mail.css
index 67ce7e682..f06049116 100644
--- a/skins/default/mail.css
+++ b/skins/default/mail.css
@@ -1,877 +1,880 @@
/***** RoundCube|Mail mail task styles *****/
#messagetoolbar
{
position: absolute;
top: 45px;
left: 200px;
right: 250px;
height: 35px;
white-space: nowrap;
/* border: 1px solid #cccccc; */
}
#messagetoolbar a
{
padding-right: 10px;
}
#messagetoolbar select
{
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
font-size: 11px;
color: #333333;
}
#messagetoolbar select.mboxlist
{
position: absolute;
left: 375px;
top: 10px;
}
#messagetoolbar select.mboxlist option
{
padding-left: 15px;
}
#messagetoolbar select.mboxlist option[value="0"]
{
padding-left: 2px;
}
#listcontrols
{
position: absolute;
left: 200px;
bottom: 20px;
height: 16px;
width: 500px;
font-size: 11px;
}
#listcontrols a,
#listcontrols a:active,
#listcontrols a:visited,
#mailboxcontrols a,
#mailboxcontrols a:active,
#mailboxcontrols a:visited
{
color: #999999;
font-size: 11px;
text-decoration: none;
}
#listcontrols a.active,
#listcontrols a.active:active,
#listcontrols a.active:visited,
#mailboxcontrols a.active,
#mailboxcontrols a.active:active,
#mailboxcontrols a.active:visited
{
color: #CC0000;
}
#listcontrols a.active:hover,
#mailboxcontrols a.active:hover
{
text-decoration: underline;
}
#messagecountbar
{
position: absolute;
bottom: 16px;
right: 30px;
width: 300px;
height: 20px;
text-align: right;
white-space: nowrap;
}
#messagecountbar span
{
font-size: 11px;
color: #333333;
}
#messagepartcontainer
{
position: absolute;
top: 80px;
left: 20px;
right: 20px;
bottom: 20px;
}
#mailcontframe
{
position: absolute;
top: 85px;
left: 200px;
right: 30px;
bottom: 40px;
border: 1px solid #999999;
background-color: #F9F9F9;
overflow: auto;
/* css hack for IE */
width: expression((parseInt(document.documentElement.clientWidth)-230)+'px');
height: expression((parseInt(document.documentElement.clientHeight)-125)+'px');
}
#mailpreviewframe
{
position: absolute;
top: 305px;
left: 200px;
right: 30px;
bottom: 40px;
border: 1px solid #999999;
background-color: #F9F9F9;
/* css hack for IE */
width: expression((parseInt(document.documentElement.clientWidth)-230)+'px');
height: expression((parseInt(document.documentElement.clientHeight)-135-document.getElementById('mailcontframe').offsetHeight)+'px');
}
#messagecontframe
{
width: 100%;
height: 100%;
border: 0;
}
/*\*/
html>body*#messagecontframe
{
[height: 40%;
height: 40%;
]height: 100%;
}
/**/
#messagepartframe
{
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
width: auto;
height: auto;
border: 1px solid #999999;
background-color: #F9F9F9;
}
#partheader
{
position: absolute;
top: 10px;
left: 220px;
height: 40px;
}
#partheader table td
{
padding-left: 2px;
padding-right: 4px;
vertical-align: middle;
font-size: 11px;
}
#partheader table td.title
{
color: #666666;
font-weight: bold;
}
/** mailbox list styles */
#mailboxlist-header
{
position: absolute;
top: 85px;
left: 20px;
width: 140px !important;
/* width: 162px; */
height: 13px;
padding: 3px 10px 2px 10px;
background-color: #EBEBEB;
background-image: url(images/listheader_aqua.gif);
border: 1px solid #CCCCCC;
color: #333333;
font-size: 11px;
font-weight: bold;
}
#mailboxlist-container
{
position: absolute;
top: 105px;
left: 20px;
width: 160px;
bottom: 40px;
border: 1px solid #CCCCCC;
background-color: #F9F9F9;
overflow: auto;
/* css hack for IE */
height: expression((parseInt(document.documentElement.clientHeight)-145)+'px');
}
#mailboxlist
{
width: 100%;
height: auto;
margin: 0px;
padding: 0px;
list-style-image: none;
list-style-type: none;
overflow: hidden;
white-space: nowrap;
}
#mailboxlist li
{
/* height: 18px; */
font-size: 11px;
background: url(images/icons/folder-closed.png) no-repeat;
background-position: 10px 1px;
border-bottom: 1px solid #EBEBEB;
/* IE 5.5 margin-left: -16px; */
}
#mailboxlist li.inbox
{
background-image: url(images/icons/folder-inbox.png);
}
#mailboxlist li.drafts
{
background-image: url(images/icons/folder-drafts.png);
}
#mailboxlist li.sent
{
background-image: url(images/icons/folder-sent.png);
}
#mailboxlist li.junk
{
background-image: url(images/icons/folder-junk.png);
}
#mailboxlist li.trash
{
background-image: url(images/icons/folder-trash.png);
}
#mailboxlist li a
{
display: block;
padding-left: 32px;
padding-top: 2px;
padding-bottom: 2px;
text-decoration: none;
}
#mailboxlist li, #mailboxlist li.unread
{
/* background-image: url(images/mailbox_list.gif); */
}
#mailboxlist li.unread
{
font-weight: bold;
}
#mailboxlist li.selected
{
background-color: #929292;
border-bottom: 1px solid #898989;
}
#mailboxlist li.selected a
{
color: #FFF;
font-weight: bold;
}
#mailboxlist li.droptarget
{
background-color: #FFFFA6;
}
/* styles for nested folders */
#mailboxlist ul {
list-style: none;
padding: 0;
margin:0;
border-top: 1px solid #EBEBEB;
}
#mailboxlist ul li {
padding-left: 15px;
background-position: 25px 1px;
}
#mailboxlist li.selected li {
background-color: #F9F9F9;
}
#mailboxlist li.unread li {
font-weight: normal;
}
#mailboxlist li.unread li.unread {
font-weight: bold;
}
#mailboxlist li.selected li a{
color: black;
font-weight: normal;
}
#mailboxcontrols
{
position: absolute;
left: 20px;
width: 160px;
bottom: 20px;
height: 16px;
overflow: hidden;
font-size: 11px;
}
/** message list styles */
body.messagelist
{
margin: 0px;
background-color: #F9F9F9;
}
#messagelist
{
width: 100%;
display: table;
table-layout: fixed;
/* css hack for IE */
width: expression(document.getElementById('mailcontframe').clientWidth);
}
#messagelist thead tr td
{
height: 20px;
padding-top: 0px;
padding-bottom: 0px;
padding-left: 2px;
padding-right: 4px;
vertical-align: middle;
border-bottom: 1px solid #999999;
color: #333333;
background-color: #EBEBEB;
background-image: url(images/listheader_aqua.gif);
font-size: 11px;
font-weight: bold;
}
#messagelist thead tr td.sortedASC,
#messagelist thead tr td.sortedDESC
{
background-image: url(images/listheader_dark.gif);
}
#messagelist thead tr td.sortedASC a
{
background: url(images/sort_asc.gif) top right no-repeat;
}
#messagelist thead tr td.sortedDESC a
{
background: url(images/sort_desc.gif) top right no-repeat;
}
#messagelist thead tr td a,
-#messagelist thead tr td a:hover
+#messagelist tbody tr td a
{
display: block;
width: auto !important;
width: 100%;
color: #333333;
text-decoration: none;
}
#messagelist tbody tr td
{
height: 16px;
padding: 2px;
padding-right: 4px;
font-size: 11px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
border-bottom: 1px solid #EBEBEB;
cursor: pointer;
}
+#messagelist tbody tr td a
+{
+ color: #000;
+}
+
#messagelist col
{
display: table-column;
text-align: left;
vertical-align: middle;
}
#messagelist tr td.icon
{
width: 16px;
vertical-align: middle;
}
#messagelist tr td.subject
{
overflow: hidden;
vertical-align: middle;
}
#messagelist tr td.size
{
width: 60px;
text-align: right;
vertical-align: middle;
}
#messagelist tr td.from,
#messagelist tr td.to
{
width: 180px;
vertical-align: middle;
}
#messagelist tr td.date
{
width: 118px;
vertical-align: middle;
}
#messagelist tr.message
{
background-color: #FFFFFF;
}
/*
#messagelist tr.odd
{
background-color: #F9F9F9;
}
*/
#messagelist tr.unread
{
font-weight: bold;
background-color: #FFFFFF;
}
#messagelist tr.selected td
{
- font-weight: bold;
color: #FFFFFF;
background-color: #CC3333;
}
#messagelist tr.unfocused td
{
- font-weight: bold;
color: #FFFFFF;
background-color: #929292;
}
-#messagelist tr.selected td a.rcmContactAddress
+#messagelist tr.selected td a
{
color: #FFFFFF;
}
-#messagelist tr.unfocused td a.rcmContactAddress
+#messagelist tr.unfocused td a
{
color: #FFFFFF;
}
-#messagelist tr.deleted td a.rcmContactAddress
+#messagelist tr.deleted td a
{
color: #CCCCCC;
}
#messagelist tr.deleted td,
#messagelist tr.deleted td a
{
color: #CCCCCC;
}
#quotadisplay
{
color: #666666;
font-size: 11px;
}
#quotadisplay img
{
vertical-align: middle;
margin-left: 4px;
border: 1px solid #666666;
}
/** message view styles */
#messageframe
{
position: absolute;
top: 85px;
left: 200px;
right: 30px;
bottom: 40px;
border: 1px solid #cccccc;
background-color: #FFFFFF;
overflow: auto;
/* css hack for IE */
/* margin-bottom: 10px; */
width: expression((parseInt(document.documentElement.clientWidth)-240)+'px');
height: expression((parseInt(document.documentElement.clientHeight)-125)+'px');
}
div.messageheaderbox
{
margin: 6px 8px 0px 8px;
border: 1px solid #ccc;
}
table.headers-table
{
width: 100%;
background-color: #EBEBEB;
table-layout: fixed;
}
#messagebody table.headers-table
{
width: auto;
margin: 6px 8px;
background-color: #F4F4F4;
border: 1px solid #ccc;
}
table.headers-table tr td
{
font-size: 11px;
border-bottom:1px solid #FFFFFF;
}
table.headers-table td.header-title
{
width: 80px;
color: #666666;
font-weight: bold;
text-align: right;
white-space: nowrap;
padding-right: 4px;
}
table.headers-table tr td.subject
{
width: 95%;
font-weight: bold;
}
#attachment-list
{
margin: 0px;
padding: 0px 0px 0px 68px;
min-height: 18px;
list-style-image: none;
list-style-type: none;
background: url(images/icons/attachment.png) 52px 1px no-repeat #DFDFDF;
/* css hack for IE */
height: expression(Math.min(18, parseInt(this.clientHeight))+'px');
}
#attachment-list:after
{
content: ".";
display: block;
height: 0;
font-size: 0;
clear: both;
visibility: hidden;
}
#attachment-list li
{
float: left;
height: 18px;
font-size: 11px;
padding: 2px 10px 0px 10px;
}
#attachment-list li a
{
text-decoration: none;
}
#attachment-list li a:hover
{
text-decoration: underline;
}
#messagebody
{
position:relative;
min-height: 300px;
padding-top: 10px;
padding-bottom: 10px;
background-color: #FFFFFF;
}
div.message-part
{
padding: 8px;
padding-top: 10px;
overflow: hidden;
}
div.message-part a
{
color: #0000CC;
}
div.message-part div.pre
{
margin: 0px;
padding: 0px;
white-space: pre;
font-family: monospace;
}
div.message-part blockquote
{
color: blue;
border-left: 2px solid blue;
border-right: 2px solid blue;
background-color: #F6F6F6;
margin: 2px 0px 2px 0px;
padding: 1px 8px 1px 10px;
}
div.message-part blockquote blockquote
{
color: green;
border-left: 2px solid green;
border-right: 2px solid green;
}
div.message-part blockquote blockquote blockquote
{
color: #990000;
border-left: 2px solid #bb0000;
border-right: 2px solid #bb0000;
}
#remote-objects-message
{
display: none;
height: 20px;
min-height: 20px;
margin: 8px 8px 0px 8px;
padding: 10px 10px 6px 46px;
}
#remote-objects-message a
{
color: #666666;
padding-left: 10px;
}
#remote-objects-message a:hover
{
color: #333333;
}
/** message compose styles */
#priority-selector
{
position: absolute;
left: 280px;
top: 10px;
}
#receipt-selector
{
position: absolute;
left: 450px;
top: 10px;
}
#compose-container
{
position: absolute;
top: 90px;
left: 200px;
right: 40px;
bottom: 40px;
padding: 0px;
margin: 0px;
/* css hack for IE */
width: expression(document.documentElement.clientWidth-240);
height: expression((parseInt(document.documentElement.clientHeight)-130)+'px');
}
/*
#compose-headers
{
position: absolute;
top: 70px;
left: 200px;
height: 84px;
border-top: 1px solid #cccccc;
overflow: auto;
}
#compose-headers td
{
padding-top: 1px;
padding-bottom: 1px;
border-right: 1px solid #cccccc;
border-bottom: 1px solid #cccccc;
}
*/
#compose-headers
{
width: 100%;
}
/*
#compose-headers td
{
width: 100%;
}
*/
#compose-headers td.top
{
vertical-align: top;
}
#compose-headers td.title,
#compose-subject td.title
{
width: 80px !important;
color: #666666;
font-size: 11px;
font-weight: bold;
padding-right: 10px;
white-space: nowrap;
}
#compose-headers td.add-button
{
width: 40px !important;
text-align: right;
vertical-align: bottom;
}
#compose-headers td.add-button a
{
color: #666666;
font-size: 11px;
text-decoration: none;
}
#compose-headers td textarea
{
width: 100%;
height: 40px;
}
#compose-headers td input
{
width: 100%;
}
#compose-cc,
#compose-bcc,
#compose-replyto
{
display: none;
}
#compose-body
{
margin-top: 5px;
margin-bottom: 10px;
width: 99%;
height: 90%;
min-height: 280px;
font-size: 9pt;
font-family: "Courier New", Courier, monospace;
}
#compose-attachments
{
position: absolute;
top: 100px;
left: 20px;
width: 160px;
}
#compose-attachments ul
{
margin: 0px;
padding: 0px;
border: 1px solid #CCCCCC;
background-color: #F9F9F9;
list-style-image: none;
list-style-type: none;
}
#compose-attachments ul li
{
height: 18px;
font-size: 11px;
padding-left: 2px;
padding-top: 2px;
padding-right: 4px;
border-bottom: 1px solid #EBEBEB;
white-space: nowrap;
overflow: hidden;
}
#attachment-title
{
background: url(images/icons/attachment.png) top left no-repeat;
padding: 0px 0px 3px 22px;
}
#attachment-form
{
position: absolute;
top: 150px;
left: 20px;
z-index: 200;
padding: 8px;
visibility: hidden;
border: 1px solid #CCCCCC;
background-color: #F9F9F9;
}
#attachment-form input.button
{
margin-top: 8px;
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Mar 19, 8:48 AM (21 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
456374
Default Alt Text
(161 KB)
Attached To
Mode
R3 roundcubemail
Attached
Detach File
Event Timeline
Log In to Comment