summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoralecpl <alec@alec.pl>2012-04-13 08:52:02 +0000
committeralecpl <alec@alec.pl>2012-04-13 08:52:02 +0000
commit0c259682f65eaaf23ea4ccb56a706d6baf3007e4 (patch)
treef1491f39189c8a970e7612b9dcc20f9409d7361e
parentce64332e7a9bf2468eabdb4b789270aebb3e7dc7 (diff)
- Merge devel-framework branch, resolved conflicts
-rw-r--r--CHANGELOG11
-rwxr-xr-xbin/msgexport.sh2
-rw-r--r--index.php27
-rw-r--r--installer/index.php2
-rw-r--r--installer/utils.php16
-rw-r--r--program/include/clisetup.php2
-rw-r--r--program/include/html.php66
-rw-r--r--program/include/iniset.php60
-rw-r--r--program/include/main.inc2110
-rw-r--r--program/include/rcmail.php1247
-rw-r--r--program/include/rcube.php1226
-rw-r--r--program/include/rcube_addressbook.php7
-rw-r--r--program/include/rcube_base_replacer.php110
-rw-r--r--program/include/rcube_cache.php14
-rw-r--r--program/include/rcube_config.php14
-rw-r--r--program/include/rcube_contacts.php42
-rw-r--r--program/include/rcube_html_page.php323
-rw-r--r--program/include/rcube_imap.php53
-rw-r--r--program/include/rcube_imap_cache.php69
-rw-r--r--program/include/rcube_imap_generic.php49
-rw-r--r--program/include/rcube_ldap.php32
-rw-r--r--program/include/rcube_mdb2.php345
-rw-r--r--program/include/rcube_message.php18
-rw-r--r--program/include/rcube_message_header.php238
-rw-r--r--program/include/rcube_message_part.php103
-rw-r--r--program/include/rcube_output.php259
-rw-r--r--program/include/rcube_output_html.php (renamed from program/include/rcube_template.php)646
-rw-r--r--program/include/rcube_output_json.php (renamed from program/include/rcube_json_output.php)101
-rw-r--r--program/include/rcube_plugin.php16
-rw-r--r--program/include/rcube_plugin_api.php83
-rw-r--r--program/include/rcube_session.php21
-rw-r--r--program/include/rcube_shared.inc612
-rw-r--r--program/include/rcube_smtp.php6
-rw-r--r--program/include/rcube_spellchecker.php20
-rw-r--r--program/include/rcube_sqlite.inc79
-rw-r--r--program/include/rcube_storage.php92
-rw-r--r--program/include/rcube_string_replacer.php6
-rw-r--r--program/include/rcube_ui.php1468
-rw-r--r--program/include/rcube_user.php36
-rw-r--r--program/include/rcube_vcard.php6
-rw-r--r--program/steps/addressbook/func.inc2
-rw-r--r--program/steps/mail/compose.inc16
-rw-r--r--program/steps/mail/func.inc25
-rw-r--r--program/steps/mail/get.inc25
-rw-r--r--program/steps/mail/show.inc26
-rw-r--r--program/steps/utils/error.inc15
46 files changed, 5335 insertions, 4411 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a074cab36..58612d3f1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,17 @@
CHANGELOG Roundcube Webmail
===========================
+- Roundcube Framework:
+ Add possibility to replace IMAP driver with custom class
+ Add IMAP auto-connection feature, improving performance with caching enabled
+ Replace imap_init hook with storage_init (with additional 'driver' argument)
+ Improved performance by caching IMAP server's capabilities in session
+ Unified global functions naming (rcube_ prefix)
+ Move global functions from main.inc and rcube_shared.inc into classes
+ Better classes separation
+
+RELEASE 0.8-rc
+----------------
- Set flexible width to login form fields (#1488418)
- Fix re-draw bug on list columns change in IE8 (#1487822)
- Allow mass-removal of addresses from a group (#1487748)
diff --git a/bin/msgexport.sh b/bin/msgexport.sh
index c876f5f10..e6c180188 100755
--- a/bin/msgexport.sh
+++ b/bin/msgexport.sh
@@ -34,7 +34,7 @@ function export_mailbox($mbox, $filename)
$IMAP->set_folder($mbox);
$index = $IMAP->index($mbox, null, 'ASC');
- $count = $index->countMessages();
+ $count = $index->count();
$index = $index->get();
vputs("Getting message list of {$mbox}...");
diff --git a/index.php b/index.php
index beed3881d..8a7a79fd2 100644
--- a/index.php
+++ b/index.php
@@ -2,7 +2,7 @@
/*
+-------------------------------------------------------------------------+
| Roundcube Webmail IMAP Client |
- | Version 0.8-svn |
+ | Version 0.9-svn |
| |
| Copyright (C) 2005-2012, The Roundcube Dev Team |
| |
@@ -45,7 +45,7 @@ require_once 'program/include/iniset.php';
$RCMAIL = rcmail::get_instance();
// Make the whole PHP output non-cacheable (#1487797)
-send_nocacheing_headers();
+$RCMAIL->output->nocacheing_headers();
// turn on output buffering
ob_start();
@@ -67,14 +67,14 @@ if ($err_str = $RCMAIL->db->is_error()) {
}
// error steps
-if ($RCMAIL->action=='error' && !empty($_GET['_code'])) {
+if ($RCMAIL->action == 'error' && !empty($_GET['_code'])) {
raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE);
}
// check if https is required (for login) and redirect if necessary
if (empty($_SESSION['user_id']) && ($force_https = $RCMAIL->config->get('force_https', false))) {
$https_port = is_bool($force_https) ? 443 : $force_https;
- if (!rcube_https_check($https_port)) {
+ if (!rcube_ui::https_check($https_port)) {
$host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']);
$host .= ($https_port != 443 ? ':' . $https_port : '');
header('Location: https://' . $host . $_SERVER['REQUEST_URI']);
@@ -89,15 +89,15 @@ $RCMAIL->action = $startup['action'];
// try to log in
if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
- $request_valid = $_SESSION['temp'] && $RCMAIL->check_request(RCUBE_INPUT_POST, 'login');
+ $request_valid = $_SESSION['temp'] && $RCMAIL->check_request(rcube_ui::INPUT_POST, 'login');
// purge the session in case of new login when a session already exists
$RCMAIL->kill_session();
$auth = $RCMAIL->plugins->exec_hook('authenticate', array(
'host' => $RCMAIL->autoselect_host(),
- 'user' => trim(get_input_value('_user', RCUBE_INPUT_POST)),
- 'pass' => get_input_value('_pass', RCUBE_INPUT_POST, true,
+ 'user' => trim(rcube_ui::get_input_value('_user', rcube_ui::INPUT_POST)),
+ 'pass' => rcube_ui::get_input_value('_pass', rcube_ui::INPUT_POST, true,
$RCMAIL->config->get('password_charset', 'ISO-8859-1')),
'cookiecheck' => true,
'valid' => $request_valid,
@@ -119,11 +119,11 @@ if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
$RCMAIL->session->set_auth_cookie();
// log successful login
- rcmail_log_login();
+ $RCMAIL->log_login();
// restore original request parameters
$query = array();
- if ($url = get_input_value('_url', RCUBE_INPUT_POST)) {
+ if ($url = rcube_ui::get_input_value('_url', rcube_ui::INPUT_POST)) {
parse_str($url, $query);
// prevent endless looping on login page
@@ -149,7 +149,7 @@ if ($RCMAIL->task == 'login' && $RCMAIL->action == 'login') {
}
// end session (after optional referer check)
-else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id']) && (!$RCMAIL->config->get('referer_check') || rcube_check_referer())) {
+else if ($RCMAIL->task == 'logout' && isset($_SESSION['user_id']) && (!$RCMAIL->config->get('referer_check') || rcmail::check_referer())) {
$userdata = array(
'user' => $_SESSION['username'],
'host' => $_SESSION['storage_host'],
@@ -172,7 +172,8 @@ else if ($RCMAIL->task != 'login' && $_SESSION['user_id'] && $RCMAIL->action !=
// not logged in -> show login page
if (empty($RCMAIL->user->ID)) {
// log session failures
- if (($task = get_input_value('_task', RCUBE_INPUT_GPC)) && !in_array($task, array('login','logout')) && !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')])) {
+ $task = rcube_ui::get_input_value('_task', rcube_ui::INPUT_GPC);
+ if ($task && !in_array($task, array('login','logout')) && !$session_error && ($sess_id = $_COOKIE[ini_get('session.name')])) {
$RCMAIL->session->log("Aborted session " . $sess_id . "; no valid session data found");
$session_error = true;
}
@@ -208,7 +209,7 @@ else {
// check client X-header to verify request origin
if ($OUTPUT->ajax_call) {
- if (rc_request_header('X-Roundcube-Request') != $RCMAIL->get_request_token() && !$RCMAIL->config->get('devel_mode')) {
+ if (rcube_request_header('X-Roundcube-Request') != $RCMAIL->get_request_token() && !$RCMAIL->config->get('devel_mode')) {
header('HTTP/1.1 403 Forbidden');
die("Invalid Request");
}
@@ -220,7 +221,7 @@ else {
}
// check referer if configured
- if (!$request_check_whitelist[$RCMAIL->action] && $RCMAIL->config->get('referer_check') && !rcube_check_referer()) {
+ if (!$request_check_whitelist[$RCMAIL->action] && $RCMAIL->config->get('referer_check') && !rcmail::check_referer()) {
raise_error(array(
'code' => 403,
'type' => 'php',
diff --git a/installer/index.php b/installer/index.php
index 65e84a3b4..842b90054 100644
--- a/installer/index.php
+++ b/installer/index.php
@@ -53,6 +53,8 @@ $include_path .= ini_get('include_path');
set_include_path($include_path);
require_once 'utils.php';
+require_once 'rcube_shared.inc';
+// deprecated aliases (to be removed)
require_once 'main.inc';
session_start();
diff --git a/installer/utils.php b/installer/utils.php
index d559df14e..ca2577c14 100644
--- a/installer/utils.php
+++ b/installer/utils.php
@@ -45,26 +45,16 @@ function __autoload($classname)
include_once $filename. '.php';
}
-
-/**
- * Fake internal error handler to catch errors
- */
-function raise_error($p)
-{
- $rci = rcube_install::get_instance();
- $rci->raise_error($p);
-}
-
/**
* Local callback function for PEAR errors
*/
-function rcube_pear_error($err)
+function __pear_error($err)
{
- raise_error(array(
+ rcmail::raise_error(array(
'code' => $err->getCode(),
'message' => $err->getMessage(),
));
}
// set PEAR error handling (will also load the PEAR main class)
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
+PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, '__pear_error');
diff --git a/program/include/clisetup.php b/program/include/clisetup.php
index c5f8dd1cc..22ffbbc92 100644
--- a/program/include/clisetup.php
+++ b/program/include/clisetup.php
@@ -55,7 +55,7 @@ function get_opt($aliases=array())
continue;
$args[$key] = preg_replace(array('/^["\']/', '/["\']$/'), '', $value);
-
+
if ($alias = $aliases[$key])
$args[$alias] = $args[$key];
}
diff --git a/program/include/html.php b/program/include/html.php
index 0e89d778f..305a39781 100644
--- a/program/include/html.php
+++ b/program/include/html.php
@@ -277,7 +277,7 @@ class html
$attrib_arr = array();
foreach ($attrib as $key => $value) {
// skip size if not numeric
- if (($key=='size' && !is_numeric($value))) {
+ if ($key == 'size' && !is_numeric($value)) {
continue;
}
@@ -297,17 +297,57 @@ class html
$attrib_arr[] = $key . '="' . $key . '"';
}
}
- else if ($key=='value') {
- $attrib_arr[] = $key . '="' . Q($value, 'strict', false) . '"';
- }
else {
- $attrib_arr[] = $key . '="' . Q($value) . '"';
+ $attrib_arr[] = $key . '="' . self::quote($value) . '"';
}
}
+
return count($attrib_arr) ? ' '.implode(' ', $attrib_arr) : '';
}
+
+ /**
+ * Convert a HTML attribute string attributes to an associative array (name => value)
+ *
+ * @param string Input string
+ * @return array Key-value pairs of parsed attributes
+ */
+ public static function parse_attrib_string($str)
+ {
+ $attrib = array();
+ $regexp = '/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/Ui';
+
+ preg_match_all($regexp, stripslashes($str), $regs, PREG_SET_ORDER);
+
+ // convert attributes to an associative array (name => value)
+ if ($regs) {
+ foreach ($regs as $attr) {
+ $attrib[strtolower($attr[1])] = html_entity_decode($attr[3] . $attr[4]);
+ }
+ }
+
+ return $attrib;
+ }
+
+ /**
+ * Replacing specials characters in html attribute value
+ *
+ * @param string $str Input string
+ *
+ * @return string The quoted string
+ */
+ public static function quote($str)
+ {
+ $str = htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
+
+ // avoid douple quotation of &
+ // @TODO: get rid of it?
+ $str = preg_replace('/&amp;([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $str);
+
+ return $str;
+ }
}
+
/**
* Class to create an HTML input field
*
@@ -317,9 +357,11 @@ class html_inputfield extends html
{
protected $tagname = 'input';
protected $type = 'text';
- protected $allowed = array('type','name','value','size','tabindex',
+ protected $allowed = array(
+ 'type','name','value','size','tabindex',
'autocomplete','checked','onchange','onclick','disabled','readonly',
- 'spellcheck','results','maxlength','src','multiple','placeholder');
+ 'spellcheck','results','maxlength','src','multiple','placeholder',
+ );
/**
* Object constructor
@@ -517,11 +559,11 @@ class html_textarea extends html
}
if (!empty($value) && !preg_match('/mce_editor/', $this->attrib['class'])) {
- $value = Q($value, 'strict', false);
+ $value = self::quote($value);
}
return self::tag($this->tagname, $this->attrib, $value,
- array_merge(self::$common_attrib, $this->allowed));
+ array_merge(self::$common_attrib, $this->allowed));
}
}
@@ -550,7 +592,7 @@ class html_select extends html
protected $options = array();
protected $allowed = array('name','size','tabindex','autocomplete',
'multiple','onchange','disabled','rel');
-
+
/**
* Add a new option to this drop-down
*
@@ -591,8 +633,9 @@ class html_select extends html
'selected' => (in_array($option['value'], $select, true) ||
in_array($option['text'], $select, true)) ? 1 : null);
- $this->content .= self::tag('option', $attr, Q($option['text']));
+ $this->content .= self::tag('option', $attr, self::quote($option['text']));
}
+
return parent::show();
}
}
@@ -803,4 +846,3 @@ class html_table extends html
}
}
-
diff --git a/program/include/iniset.php b/program/include/iniset.php
index 5feca7d9c..3715c21ef 100644
--- a/program/include/iniset.php
+++ b/program/include/iniset.php
@@ -40,7 +40,7 @@ foreach ($crit_opts as $optname => $optval) {
}
// application constants
-define('RCMAIL_VERSION', '0.8-svn');
+define('RCMAIL_VERSION', '0.9-svn');
define('RCMAIL_CHARSET', 'UTF-8');
define('JS_OBJECT_NAME', 'rcmail');
define('RCMAIL_START', microtime(true));
@@ -53,11 +53,6 @@ if (!defined('RCMAIL_CONFIG_DIR')) {
define('RCMAIL_CONFIG_DIR', INSTALL_PATH . 'config');
}
-// make sure path_separator is defined
-if (!defined('PATH_SEPARATOR')) {
- define('PATH_SEPARATOR', (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') ? ';' : ':');
-}
-
// RC include folders MUST be included FIRST to avoid other
// possible not compatible libraries (i.e PEAR) to be included
// instead the ones provided by RC
@@ -80,59 +75,14 @@ if (extension_loaded('mbstring')) {
@mb_regex_encoding(RCMAIL_CHARSET);
}
-/**
- * Use PHP5 autoload for dynamic class loading
- *
- * @todo Make Zend, PEAR etc play with this
- * @todo Make our classes conform to a more straight forward CS.
- */
-function rcube_autoload($classname)
-{
- $filename = preg_replace(
- array(
- '/MDB2_(.+)/',
- '/Mail_(.+)/',
- '/Net_(.+)/',
- '/Auth_(.+)/',
- '/^html_.+/',
- '/^utf8$/',
- ),
- array(
- 'MDB2/\\1',
- 'Mail/\\1',
- 'Net/\\1',
- 'Auth/\\1',
- 'html',
- 'utf8.class',
- ),
- $classname
- );
-
- if ($fp = @fopen("$filename.php", 'r', true)) {
- fclose($fp);
- include_once("$filename.php");
- return true;
- }
-
- return false;
-}
+// include global functions
+require_once INSTALL_PATH . 'program/include/rcube_shared.inc';
+// Register autoloader
spl_autoload_register('rcube_autoload');
-/**
- * Local callback function for PEAR errors
- */
-function rcube_pear_error($err)
-{
- error_log(sprintf("%s (%s): %s",
- $err->getMessage(),
- $err->getCode(),
- $err->getUserinfo()), 0);
-}
-
// set PEAR error handling (will also load the PEAR main class)
PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
-// include global functions
+// backward compatybility (to be removed)
require_once INSTALL_PATH . 'program/include/main.inc';
-require_once INSTALL_PATH . 'program/include/rcube_shared.inc';
diff --git a/program/include/main.inc b/program/include/main.inc
index 3f502753e..791e657b4 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -5,14 +5,14 @@
| program/include/main.inc |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2011, The Roundcube Dev Team |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
- | Provide basic functions for the webmail package |
+ | Provide deprecated functions aliases for backward compatibility |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
@@ -23,2224 +23,324 @@
*/
/**
- * Roundcube Webmail common functions
+ * Roundcube Webmail deprecated functions
*
* @package Core
* @author Thomas Bruederli <roundcube@gmail.com>
*/
-require_once INSTALL_PATH . 'program/include/rcube_shared.inc';
+// constants for input reading
+define('RCUBE_INPUT_GET', rcube_ui::INPUT_GET);
+define('RCUBE_INPUT_POST', rcube_ui::INPUT_POST);
+define('RCUBE_INPUT_GPC', rcube_ui::INPUT_GPC);
-// define constannts for input reading
-define('RCUBE_INPUT_GET', 0x0101);
-define('RCUBE_INPUT_POST', 0x0102);
-define('RCUBE_INPUT_GPC', 0x0103);
-
-
-/**
- * Return correct name for a specific database table
- *
- * @param string Table name
- * @return string Translated table name
- */
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 rcmail::get_instance()->db->table_name($table);
+}
-/**
- * Return correct name for a specific database sequence
- * (used for Postgres only)
- *
- * @param string Secuence name
- * @return string Translated sequence name
- */
function get_sequence_name($sequence)
- {
- // return sequence name if configured
- $config_key = 'db_sequence_'.$sequence;
- $opt = rcmail::get_instance()->config->get($config_key);
-
- if (!empty($opt))
- return $opt;
-
- return $sequence;
- }
-
+{
+ return rcmail::get_instance()->db->sequence_name($sequence);
+}
-/**
- * Get localized text in the desired language
- * It's a global wrapper for rcmail::gettext()
- *
- * @param mixed Named parameters array or label name
- * @param string Domain to search in (e.g. plugin name)
- * @return string Localized text
- * @see rcmail::gettext()
- */
function rcube_label($p, $domain=null)
{
- return rcmail::get_instance()->gettext($p, $domain);
+ return rcmail::get_instance()->gettext($p, $domain);
}
-
-/**
- * Global wrapper of rcmail::text_exists()
- * to check whether a text label is defined
- *
- * @see rcmail::text_exists()
- */
function rcube_label_exists($name, $domain=null, &$ref_domain = null)
{
- return rcmail::get_instance()->text_exists($name, $domain, $ref_domain);
+ return rcmail::get_instance()->text_exists($name, $domain, $ref_domain);
}
-
-/**
- * Overwrite action variable
- *
- * @param string New action value
- */
function rcmail_overwrite_action($action)
- {
- $app = rcmail::get_instance();
- $app->action = $action;
- $app->output->set_env('action', $action);
- }
-
+{
+ rcmail::get_instance()->overwrite_action($action);
+}
-/**
- * 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)
{
- $app = rcmail::get_instance();
- return $app->url((array)$p + array('_action' => $action, 'task' => $task));
+ return rcube_ui::url($action, $p, $task);
}
-
-/**
- * Garbage collector function for temp files.
- * Remove temp files older than two days
- */
function rcmail_temp_gc()
{
- $rcmail = rcmail::get_instance();
-
- $tmp = unslashify($rcmail->config->get('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);
- }
+ $rcmail = rcmail::get_instance()->temp_gc();
}
-
-// Deprecated
function rcube_charset_convert($str, $from, $to=NULL)
{
return rcube_charset::convert($str, $from, $to);
}
-
-// Deprecated
function rc_detect_encoding($string, $failover='')
{
return rcube_charset::detect($string, $failover);
}
-
-// Deprecated
function rc_utf8_clean($input)
{
return rcube_charset::clean($input);
}
-
-/**
- * Convert a variable into a javascript object notation
- *
- * @param mixed Input value
- * @return string Serialized JSON string
- */
function json_serialize($input)
{
- $input = rcube_charset::clean($input);
-
- // sometimes even using rcube_charset::clean() the input contains invalid UTF-8 sequences
- // that's why we have @ here
- return @json_encode($input);
+ return rcube_output::json_serialize($input);
}
-
-/**
- * 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 string The quoted string
- */
function rep_specialchars_output($str, $enctype='', $mode='', $newlines=TRUE)
- {
- static $html_encode_arr = false;
- static $js_rep_table = false;
- static $xml_rep_table = false;
-
- if (!$enctype)
- $enctype = $OUTPUT->type;
-
- // 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);
-
- $out = strtr($str, $encode_arr);
-
- // avoid douple quotation of &
- $out = preg_replace('/&amp;([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $out);
-
- return $newlines ? nl2br($out) : $out;
- }
-
- // if the replace tables for XML and JS are not yet defined
- if ($js_rep_table===false)
- {
- $js_rep_table = $xml_rep_table = array();
- $xml_rep_table['&'] = '&amp;';
-
- for ($c=160; $c<256; $c++) // can be increased to support more charsets
- $xml_rep_table[chr($c)] = "&#$c;";
-
- $xml_rep_table['"'] = '&quot;';
- $js_rep_table['"'] = '\\"';
- $js_rep_table["'"] = "\\'";
- $js_rep_table["\\"] = "\\\\";
- // Unicode line and paragraph separators (#1486310)
- $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A8))] = '&#8232;';
- $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A9))] = '&#8233;';
- }
-
- // encode for javascript use
- if ($enctype=='js')
- return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
-
- // encode for plaintext
- if ($enctype=='text')
- return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
-
- if ($enctype=='url')
- return rawurlencode($str);
-
- // encode for XML
- if ($enctype=='xml')
- return strtr($str, $xml_rep_table);
-
- // no encoding given -> return original string
- return $str;
- }
-
-/**
- * Quote a given string.
- * Shortcut function for rep_specialchars_output
- *
- * @return string HTML-quoted string
- * @see rep_specialchars_output()
- */
-function Q($str, $mode='strict', $newlines=TRUE)
- {
- return rep_specialchars_output($str, 'html', $mode, $newlines);
- }
-
-/**
- * Quote a given string for javascript output.
- * Shortcut function for rep_specialchars_output
- *
- * @return string JS-quoted string
- * @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)
{
- $value = NULL;
-
- if ($source == RCUBE_INPUT_GET) {
- if (isset($_GET[$fname]))
- $value = $_GET[$fname];
- }
- else if ($source == RCUBE_INPUT_POST) {
- if (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];
- }
-
- return parse_input_value($value, $allow_html, $charset);
+ return rcube_ui::rep_specialchars_output($str, $enctype, $mode, $newlines);
}
-/**
- * Parse/validate input value. See get_input_value()
- * Performs stripslashes() and charset conversion if necessary
- *
- * @param string Input value
- * @param boolean Allow HTML tags in field value
- * @param string Charset to convert into
- * @return string Parsed value
- */
-function parse_input_value($value, $allow_html=FALSE, $charset=NULL)
+function Q($str, $mode='strict', $newlines=TRUE)
{
- global $OUTPUT;
-
- if (empty($value))
- return $value;
-
- if (is_array($value)) {
- foreach ($value as $idx => $val)
- $value[$idx] = parse_input_value($val, $allow_html, $charset);
- return $value;
- }
-
- // strip single quotes if magic_quotes_sybase is enabled
- if (ini_get('magic_quotes_sybase'))
- $value = str_replace("''", "'", $value);
- // strip slashes if magic_quotes enabled
- else if (get_magic_quotes_gpc() || get_magic_quotes_runtime())
- $value = stripslashes($value);
-
- // remove HTML tags if not allowed
- if (!$allow_html)
- $value = strip_tags($value);
-
- $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null;
-
- // remove invalid characters (#1488124)
- if ($output_charset == 'UTF-8')
- $value = rc_utf8_clean($value);
-
- // convert to internal charset
- if ($charset && $output_charset)
- $value = rcube_charset_convert($value, $output_charset, $charset);
-
- return $value;
+ return rcube_ui::Q($str, $mode, $newlines);
}
-/**
- * Convert array of request parameters (prefixed with _)
- * to a regular array with non-prefixed keys.
- *
- * @param int Source to get value from (GPC)
- * @return array Hash array with all request parameters
- */
-function request2param($mode = RCUBE_INPUT_GPC, $ignore = 'task|action')
+function JQ($str)
{
- $out = array();
- $src = $mode == RCUBE_INPUT_GET ? $_GET : ($mode == RCUBE_INPUT_POST ? $_POST : $_REQUEST);
- foreach ($src as $key => $value) {
- $fname = $key[0] == '_' ? substr($key, 1) : $key;
- if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname))
- $out[$fname] = get_input_value($key, $mode);
- }
-
- return $out;
+ return rcube_ui::JQ($str);
}
-/**
- * Remove all non-ascii and non-word chars
- * except ., -, _
- */
-function asciiwords($str, $css_id = false, $replace_with = '')
+function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
{
- $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : '');
- return preg_replace("/[^$allowed]/i", $replace_with, $str);
+ return rcube_ui::get_input_value($fname, $source, $allow_html, $charset);
}
-/**
- * Convert the given string into a valid HTML identifier
- * Same functionality as done in app.js with rcube_webmail.html_identifier()
- */
-function html_identifier($str, $encode=false)
+function parse_input_value($value, $allow_html=FALSE, $charset=NULL)
{
- if ($encode)
- return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
- else
- return asciiwords($str, true, '_');
+ return rcube_ui::parse_input_value($value, $allow_html, $charset);
}
-/**
- * Remove single and double quotes from given string
- *
- * @param string Input value
- * @return string Dequoted string
- */
-function strip_quotes($str)
+function request2param($mode = RCUBE_INPUT_GPC, $ignore = 'task|action')
{
- return str_replace(array("'", '"'), '', $str);
+ return rcube_ui::request2param($mode, $ignore);
}
-
-/**
- * Remove new lines characters from given string
- *
- * @param string Input value
- * @return string Stripped string
- */
-function strip_newlines($str)
+function html_identifier($str, $encode=false)
{
- return preg_replace('/[\r\n]/', '', $str);
+ return rcube_ui::html_identifier($str, $encode);
}
-
-/**
- * Create a HTML table based on the given data
- *
- * @param array Named table attributes
- * @param mixed Table row data. Either a two-dimensional array or a valid SQL result set
- * @param array List of cols to show
- * @param string Name of the identifier col
- * @return string HTML table code
- */
function rcube_table_output($attrib, $table_data, $a_show_cols, $id_col)
{
- global $RCMAIL;
-
- $table = new html_table(/*array('cols' => count($a_show_cols))*/);
-
- // add table header
- if (!$attrib['noheader'])
- foreach ($a_show_cols as $col)
- $table->add_header($col, Q(rcube_label($col)));
-
- $c = 0;
- if (!is_array($table_data))
- {
- $db = $RCMAIL->get_dbh();
- while ($table_data && ($sql_arr = $db->fetch_assoc($table_data)))
- {
- $table->add_row(array('id' => 'rcmrow' . html_identifier($sql_arr[$id_col])));
-
- // format each col
- foreach ($a_show_cols as $col)
- $table->add($col, Q($sql_arr[$col]));
-
- $c++;
- }
- }
- else {
- foreach ($table_data as $row_data)
- {
- $class = !empty($row_data['class']) ? $row_data['class'] : '';
-
- $table->add_row(array('id' => 'rcmrow' . html_identifier($row_data[$id_col]), 'class' => $class));
-
- // format each col
- foreach ($a_show_cols as $col)
- $table->add($col, Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col]));
-
- $c++;
- }
- }
-
- return $table->show($attrib);
+ return rcube_ui::table_output($attrib, $table_data, $a_show_cols, $id_col);
}
-
-/**
- * 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')
{
- static $colcounts = array();
-
- $fname = '_'.$col;
- $attrib['name'] = $fname . ($attrib['array'] ? '[]' : '');
- $attrib['class'] = trim($attrib['class'] . ' ff_' . $col);
-
- if ($type == 'checkbox') {
- $attrib['value'] = '1';
- $input = new html_checkbox($attrib);
- }
- else if ($type == 'textarea') {
- $attrib['cols'] = $attrib['size'];
- $input = new html_textarea($attrib);
- }
- else if ($type == 'select') {
- $input = new html_select($attrib);
- $input->add('---', '');
- $input->add(array_values($attrib['options']), array_keys($attrib['options']));
- }
- else if ($attrib['type'] == 'password') {
- $input = new html_passwordfield($attrib);
- }
- else {
- if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden')
- $attrib['type'] = 'text';
- $input = new html_inputfield($attrib);
- }
-
- // use value from post
- if (isset($_POST[$fname])) {
- $postvalue = get_input_value($fname, RCUBE_INPUT_POST, true);
- $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue;
- }
-
- $out = $input->show($value);
-
- return $out;
+ return rcube_ui::get_edit_field($col, $value, $attrib, $type);
}
-
-/**
- * Replace all css definitions with #container [def]
- * and remove css-inlined scripting
- *
- * @param string CSS source code
- * @param string Container ID to use as prefix
- * @return string Modified CSS source
- */
function rcmail_mod_css_styles($source, $container_id, $allow_remote=false)
- {
- $last_pos = 0;
- $replacements = new rcube_string_replacer;
-
- // ignore the whole block if evil styles are detected
- $source = rcmail_xss_entity_decode($source);
- $stripped = preg_replace('/[^a-z\(:;]/i', '', $source);
- $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : '');
- if (preg_match("/$evilexpr/i", $stripped))
- return '/* evil! */';
-
- // cut out all contents between { and }
- while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) {
- $styles = substr($source, $pos+1, $pos2-($pos+1));
-
- // check every line of a style block...
- if ($allow_remote) {
- $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY);
- foreach ($a_styles as $line) {
- $stripped = preg_replace('/[^a-z\(:;]/i', '', $line);
- // ... and only allow strict url() values
- if (stripos($stripped, 'url(') && !preg_match('!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims', $line)) {
- $a_styles = array('/* evil! */');
- break;
- }
- }
- $styles = join(";\n", $a_styles);
- }
-
- $key = $replacements->add($styles);
- $source = substr($source, 0, $pos+1) . $replacements->get_replacement($key) . substr($source, $pos2, strlen($source)-$pos2);
- $last_pos = $pos+2;
- }
-
- // remove html comments 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',
- '/'.preg_quote($container_id, '/').'\s+body/i',
- ),
- array(
- '',
- "\\1#$container_id \\2",
- $container_id,
- ),
- $source);
-
- // put block contents back in
- $styles = $replacements->resolve($styles);
-
- return $styles;
- }
-
-
-/**
- * Decode escaped entities used by known XSS exploits.
- * See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples
- *
- * @param string CSS content to decode
- * @return string Decoded string
- */
-function rcmail_xss_entity_decode($content)
{
- $out = html_entity_decode(html_entity_decode($content));
- $out = preg_replace_callback('/\\\([0-9a-f]{4})/i', 'rcmail_xss_entity_decode_callback', $out);
- $out = preg_replace('#/\*.*\*/#Ums', '', $out);
- return $out;
+ return rcube_ui::mod_css_styles($source, $container_id, $allow_remote);
}
-
-/**
- * preg_replace_callback callback for rcmail_xss_entity_decode_callback
- *
- * @param array matches result from preg_replace_callback
- * @return string decoded entity
- */
-function rcmail_xss_entity_decode_callback($matches)
-{
- return chr(hexdec($matches[1]));
+function rcmail_xss_entity_decode($content)
+{
+ return rcube_ui::xss_entity_decode($content);
}
-/**
- * Compose a valid attribute string for HTML tags
- *
- * @param array Named tag attributes
- * @param array List of allowed attributes
- * @return string HTML formatted attribute string
- */
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('"', '&quot;', $attrib[$a]));
-
- return $attrib_str;
- }
-
-
-/**
- * Convert a HTML attribute string attributes to an associative array (name => value)
- *
- * @param string Input string
- * @return array Key-value pairs of parsed attributes
- */
-function parse_attrib_string($str)
- {
- $attrib = array();
- preg_match_all('/\s*([-_a-z]+)=(["\'])??(?(2)([^\2]*)\2|(\S+?))/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])] = html_entity_decode($attr[3] . $attr[4]);
- }
- }
-
- return $attrib;
- }
-
-
-/**
- * Improved equivalent to strtotime()
- *
- * @param string Date string
- * @return int
- */
-function rcube_strtotime($date)
{
- // check for MS Outlook vCard date format YYYYMMDD
- if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) {
- return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1]));
- }
- else if (is_numeric($date))
- return $date;
-
- // support non-standard "GMTXXXX" literal
- $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date);
-
- // if date parsing fails, we have a date in non-rfc format.
- // remove token from the end and try again
- while ((($ts = @strtotime($date)) === false) || ($ts < 0)) {
- $d = explode(' ', $date);
- array_pop($d);
- if (!$d) break;
- $date = implode(' ', $d);
- }
-
- return $ts;
+ return html::attrib_string($attrib, $allowed_attribs);
}
-
-/**
- * Convert the given date to a human readable form
- * This uses the date formatting properties from config
- *
- * @param mixed Date representation (string, timestamp or DateTime object)
- * @param string Date format to use
- * @param bool Enables date convertion according to user timezone
- *
- * @return string Formatted date string
- */
-function format_date($date, $format=NULL, $convert=true)
+function parse_attrib_string($str)
{
- global $RCMAIL, $CONFIG;
-
- if (is_object($date) && is_a($date, 'DateTime')) {
- $timestamp = $date->format('U');
- }
- else {
- if (!empty($date))
- $timestamp = rcube_strtotime($date);
-
- if (empty($timestamp))
- return '';
-
- try {
- $date = new DateTime("@".$timestamp);
- }
- catch (Exception $e) {
- return '';
- }
- }
-
- if ($convert) {
- try {
- // convert to the right timezone
- $stz = date_default_timezone_get();
- $tz = new DateTimeZone($RCMAIL->config->get('timezone'));
- $date->setTimezone($tz);
- date_default_timezone_set($tz->getName());
-
- $timestamp = $date->format('U');
- }
- catch (Exception $e) {
- }
- }
-
- // define date format depending on current time
- if (!$format) {
- $now = 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']);
-
- if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now) {
- $format = $RCMAIL->config->get('date_today', $RCMAIL->config->get('time_format', 'H:i'));
- $today = true;
- }
- else if ($CONFIG['prettydate'] && $timestamp > $week_limit && $timestamp < $now)
- $format = $RCMAIL->config->get('date_short', 'D H:i');
- else
- $format = $RCMAIL->config->get('date_long', 'Y-m-d H:i');
- }
-
- // strftime() format
- if (preg_match('/%[a-z]+/i', $format)) {
- $format = strftime($format, $timestamp);
-
- if ($convert && $stz) {
- date_default_timezone_set($stz);
- }
-
- return $today ? (rcube_label('today') . ' ' . $format) : $format;
- }
-
- // 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('long'.strtolower(date('M', $timestamp)));
- else if ($format[$i]=='x')
- $out .= strftime('%x %X', $timestamp);
- else
- $out .= date($format[$i], $timestamp);
- }
-
- if ($today) {
- $label = rcube_label('today');
- // replcae $ character with "Today" label (#1486120)
- if (strpos($out, '$') !== false) {
- $out = preg_replace('/\$/', $label, $out, 1);
- }
- else {
- $out = $label . ' ' . $out;
- }
- }
-
- if ($convert && $stz) {
- date_default_timezone_set($stz);
- }
-
- return $out;
+ return html::parse_attrib_string($str);
}
-
-/**
- * Compose a valid representation of name and e-mail address
- *
- * @param string E-mail address
- * @param string Person name
- * @return string Formatted string
- */
-function format_email_recipient($email, $name='')
+function format_date($date, $format=NULL, $convert=true)
{
- if ($name && $name != $email) {
- // Special chars as defined by RFC 822 need to in quoted string (or escaped).
- return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email));
- }
-
- return trim($email);
+ return rcube_ui::format_date($date, $format, $convert);
}
-
-/**
- * Return the mailboxlist in HTML
- *
- * @param array Named parameters
- * @return string HTML code for the gui object
- */
function rcmail_mailbox_list($attrib)
{
- global $RCMAIL;
- static $a_mailboxes;
-
- $attrib += array('maxlength' => 100, 'realnames' => false, 'unreadwrap' => ' (%s)');
-
- // add some labels to client
- $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm');
-
- $type = $attrib['type'] ? $attrib['type'] : 'ul';
- unset($attrib['type']);
-
- if ($type=='ul' && !$attrib['id'])
- $attrib['id'] = 'rcmboxlist';
-
- if (empty($attrib['folder_name']))
- $attrib['folder_name'] = '*';
-
- // get mailbox list
- $mbox_name = $RCMAIL->storage->get_folder();
-
- // build the folders tree
- if (empty($a_mailboxes)) {
- // get mailbox list
- $a_folders = $RCMAIL->storage->list_folders_subscribed('', $attrib['folder_name'], $attrib['folder_filter']);
- $delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
- $a_mailboxes = array();
-
- foreach ($a_folders as $folder)
- rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter);
- }
-
- // allow plugins to alter the folder tree or to localize folder names
- $hook = $RCMAIL->plugins->exec_hook('render_mailboxlist', array(
- 'list' => $a_mailboxes,
- 'delimiter' => $delimiter,
- 'type' => $type,
- 'attribs' => $attrib,
- ));
-
- $a_mailboxes = $hook['list'];
- $attrib = $hook['attribs'];
-
- if ($type == 'select') {
- $select = new html_select($attrib);
-
- // add no-selection option
- if ($attrib['noselection'])
- $select->add(rcube_label($attrib['noselection']), '');
-
- rcmail_render_folder_tree_select($a_mailboxes, $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']);
- $out = $select->show($attrib['default']);
- }
- else {
- $js_mailboxlist = array();
- $out = html::tag('ul', $attrib, rcmail_render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib);
-
- $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']);
- $RCMAIL->output->set_env('mailboxes', $js_mailboxlist);
- $RCMAIL->output->set_env('unreadwrap', $attrib['unreadwrap']);
- $RCMAIL->output->set_env('collapsed_folders', (string)$RCMAIL->config->get('collapsed_folders'));
- }
-
- return $out;
+ return rcube_ui::folder_list($attrib);
}
-
-/**
- * Return the mailboxlist as html_select object
- *
- * @param array Named parameters
- * @return html_select HTML drop-down object
- */
-function rcmail_mailbox_select($p = array())
+function rcmail_mailbox_select($attrib = array())
{
- global $RCMAIL;
-
- $p += array('maxlength' => 100, 'realnames' => false);
- $a_mailboxes = array();
- $storage = $RCMAIL->get_storage();
-
- if (empty($p['folder_name'])) {
- $p['folder_name'] = '*';
- }
-
- if ($p['unsubscribed'])
- $list = $storage->list_folders('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']);
- else
- $list = $storage->list_folders_subscribed('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']);
-
- $delimiter = $storage->get_hierarchy_delimiter();
-
- foreach ($list as $folder) {
- if (empty($p['exceptions']) || !in_array($folder, $p['exceptions']))
- rcmail_build_folder_tree($a_mailboxes, $folder, $delimiter);
- }
-
- $select = new html_select($p);
-
- if ($p['noselection'])
- $select->add($p['noselection'], '');
-
- rcmail_render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p);
-
- return $select;
-}
-
-
-/**
- * Create a hierarchical array of the mailbox list
- * @access private
- * @return void
- */
-function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
-{
- global $RCMAIL;
-
- // Handle namespace prefix
- $prefix = '';
- if (!$path) {
- $n_folder = $folder;
- $folder = $RCMAIL->storage->mod_folder($folder);
-
- if ($n_folder != $folder) {
- $prefix = substr($n_folder, 0, -strlen($folder));
- }
- }
-
- $pos = strpos($folder, $delm);
-
- if ($pos !== false) {
- $subFolders = substr($folder, $pos+1);
- $currentFolder = substr($folder, 0, $pos);
-
- // sometimes folder has a delimiter as the last character
- if (!strlen($subFolders))
- $virtual = false;
- else if (!isset($arrFolders[$currentFolder]))
- $virtual = true;
- else
- $virtual = $arrFolders[$currentFolder]['virtual'];
- }
- else {
- $subFolders = false;
- $currentFolder = $folder;
- $virtual = false;
- }
-
- $path .= $prefix.$currentFolder;
-
- if (!isset($arrFolders[$currentFolder])) {
- $arrFolders[$currentFolder] = array(
- 'id' => $path,
- 'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'),
- 'virtual' => $virtual,
- 'folders' => array());
- }
- else
- $arrFolders[$currentFolder]['virtual'] = $virtual;
-
- if (strlen($subFolders))
- rcmail_build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm);
-}
-
-
-/**
- * Return html for a structured list &lt;ul&gt; for the mailbox tree
- * @access private
- * @return string
- */
-function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel=0)
-{
- global $RCMAIL, $CONFIG;
-
- $maxlength = intval($attrib['maxlength']);
- $realnames = (bool)$attrib['realnames'];
- $msgcounts = $RCMAIL->storage->get_cache('messagecount');
-
- $out = '';
- foreach ($arrFolders as $key => $folder) {
- $title = null;
- $folder_class = rcmail_folder_classname($folder['id']);
- $collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false;
- $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0;
-
- if ($folder_class && !$realnames) {
- $foldername = rcube_label($folder_class);
- }
- else {
- $foldername = $folder['name'];
-
- // shorten the folder name to a given length
- if ($maxlength && $maxlength > 1) {
- $fname = abbreviate_string($foldername, $maxlength);
- if ($fname != $foldername)
- $title = $foldername;
- $foldername = $fname;
- }
- }
-
- // make folder name safe for ids and class names
- $folder_id = html_identifier($folder['id'], true);
- $classes = array('mailbox');
-
- // set special class for Sent, Drafts, Trash and Junk
- if ($folder_class)
- $classes[] = $folder_class;
-
- if ($folder['id'] == $mbox_name)
- $classes[] = 'selected';
-
- if ($folder['virtual'])
- $classes[] = 'virtual';
- else if ($unread)
- $classes[] = 'unread';
-
- $js_name = JQ($folder['id']);
- $html_name = Q($foldername) . ($unread ? html::span('unreadcount', sprintf($attrib['unreadwrap'], $unread)) : '');
- $link_attrib = $folder['virtual'] ? array() : array(
- 'href' => rcmail_url('', array('_mbox' => $folder['id'])),
- 'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name),
- 'rel' => $folder['id'],
- 'title' => $title,
- );
-
- $out .= html::tag('li', array(
- 'id' => "rcmli".$folder_id,
- 'class' => join(' ', $classes),
- 'noclose' => true),
- html::a($link_attrib, $html_name) .
- (!empty($folder['folders']) ? html::div(array(
- 'class' => ($collapsed ? 'collapsed' : 'expanded'),
- 'style' => "position:absolute",
- 'onclick' => sprintf("%s.command('collapse-folder', '%s')", JS_OBJECT_NAME, $js_name)
- ), '&nbsp;') : ''));
-
- $jslist[$folder_id] = array('id' => $folder['id'], 'name' => $foldername, 'virtual' => $folder['virtual']);
-
- if (!empty($folder['folders'])) {
- $out .= html::tag('ul', array('style' => ($collapsed ? "display:none;" : null)),
- rcmail_render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1));
- }
-
- $out .= "</li>\n";
- }
-
- return $out;
-}
-
-
-/**
- * Return html for a flat list <select> for the mailbox tree
- * @access private
- * @return string
- */
-function rcmail_render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames=false, $nestLevel=0, $opts=array())
-{
- global $RCMAIL;
-
- $out = '';
-
- foreach ($arrFolders as $key => $folder) {
- // skip exceptions (and its subfolders)
- if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) {
- continue;
- }
-
- // skip folders in which it isn't possible to create subfolders
- if (!empty($opts['skip_noinferiors']) && ($attrs = $RCMAIL->storage->folder_attributes($folder['id']))
- && in_array('\\Noinferiors', $attrs)
- ) {
- continue;
- }
-
- if (!$realnames && ($folder_class = rcmail_folder_classname($folder['id'])))
- $foldername = rcube_label($folder_class);
- else {
- $foldername = $folder['name'];
-
- // shorten the folder name to a given length
- if ($maxlength && $maxlength>1)
- $foldername = abbreviate_string($foldername, $maxlength);
- }
-
- $select->add(str_repeat('&nbsp;', $nestLevel*4) . $foldername, $folder['id']);
-
- if (!empty($folder['folders']))
- $out .= rcmail_render_folder_tree_select($folder['folders'], $mbox_name, $maxlength,
- $select, $realnames, $nestLevel+1, $opts);
- }
-
- return $out;
+ return rcube_ui::folder_selector($attrib);
}
-
-/**
- * Return internal name for the given folder if it matches the configured special folders
- * @access private
- * @return string
- */
-function rcmail_folder_classname($folder_id)
-{
- global $CONFIG;
-
- if ($folder_id == 'INBOX')
- return 'inbox';
-
- // for these mailboxes we have localized labels and css classes
- foreach (array('sent', 'drafts', 'trash', 'junk') as $smbx)
- {
- if ($folder_id == $CONFIG[$smbx.'_mbox'])
- return $smbx;
- }
-}
-
-
-/**
- * Try to localize the given IMAP folder name.
- * UTF-7 decode it in case no localized text was found
- *
- * @param string Folder name
- * @return string Localized folder name in UTF-8 encoding
- */
function rcmail_localize_foldername($name)
{
- if ($folder_class = rcmail_folder_classname($name))
- return rcube_label($folder_class);
- else
- return rcube_charset_convert($name, 'UTF7-IMAP');
+ return rcube_ui::localize_foldername($name);
}
-
function rcmail_localize_folderpath($path)
{
- global $RCMAIL;
-
- $protect_folders = $RCMAIL->config->get('protect_default_folders');
- $default_folders = (array) $RCMAIL->config->get('default_folders');
- $delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
- $path = explode($delimiter, $path);
- $result = array();
-
- foreach ($path as $idx => $dir) {
- $directory = implode($delimiter, array_slice($path, 0, $idx+1));
- if ($protect_folders && in_array($directory, $default_folders)) {
- unset($result);
- $result[] = rcmail_localize_foldername($directory);
- }
- else {
- $result[] = rcube_charset_convert($dir, 'UTF7-IMAP');
- }
- }
-
- return implode($delimiter, $result);
+ return rcube_ui::localize_folderpath($path);
}
-
function rcmail_quota_display($attrib)
{
- global $OUTPUT;
-
- if (!$attrib['id'])
- $attrib['id'] = 'rcmquotadisplay';
-
- $_SESSION['quota_display'] = !empty($attrib['display']) ? $attrib['display'] : 'text';
-
- $OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
-
- $quota = rcmail_quota_content($attrib);
-
- $OUTPUT->add_script('rcmail.set_quota('.json_serialize($quota).');', 'docready');
-
- return html::span($attrib, '');
+ return rcube_ui::quota_display($attrib);
}
-
-function rcmail_quota_content($attrib=NULL)
+function rcmail_quota_content($attrib = null)
{
- global $RCMAIL;
-
- $quota = $RCMAIL->storage->get_quota();
- $quota = $RCMAIL->plugins->exec_hook('quota', $quota);
-
- $quota_result = (array) $quota;
- $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : '';
-
- if (!$quota['total'] && $RCMAIL->config->get('quota_zero_as_unlimited')) {
- $quota_result['title'] = rcube_label('unlimited');
- $quota_result['percent'] = 0;
- }
- else if ($quota['total']) {
- if (!isset($quota['percent']))
- $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100));
-
- $title = sprintf('%s / %s (%.0f%%)',
- show_bytes($quota['used'] * 1024), show_bytes($quota['total'] * 1024),
- $quota_result['percent']);
-
- $quota_result['title'] = $title;
-
- if ($attrib['width'])
- $quota_result['width'] = $attrib['width'];
- if ($attrib['height'])
- $quota_result['height'] = $attrib['height'];
- }
- else {
- $quota_result['title'] = rcube_label('unknown');
- $quota_result['percent'] = 0;
- }
-
- return $quota_result;
+ return rcube_ui::quota_content($attrib);
}
-
-/**
- * Outputs error message according to server error/response codes
- *
- * @param string Fallback message label
- * @param string Fallback message label arguments
- *
- * @return void
- */
function rcmail_display_server_error($fallback=null, $fallback_args=null)
{
- global $RCMAIL;
-
- $err_code = $RCMAIL->storage->get_error_code();
- $res_code = $RCMAIL->storage->get_response_code();
-
- if ($err_code < 0) {
- $RCMAIL->output->show_message('storageerror', 'error');
- }
- else if ($res_code == rcube_storage::NOPERM) {
- $RCMAIL->output->show_message('errornoperm', 'error');
- }
- else if ($res_code == rcube_storage::READONLY) {
- $RCMAIL->output->show_message('errorreadonly', 'error');
- }
- else if ($err_code && ($err_str = $RCMAIL->storage->get_error_str())) {
- // try to detect access rights problem and display appropriate message
- if (stripos($err_str, 'Permission denied') !== false)
- $RCMAIL->output->show_message('errornoperm', 'error');
- else
- $RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str));
- }
- else if ($fallback) {
- $RCMAIL->output->show_message($fallback, 'error', $fallback_args);
- }
-
- return true;
+ rcube_ui::display_server_error($fallback, $fallback_args);
}
-
-/**
- * Generate CSS classes from mimetype and filename extension
- *
- * @param string Mimetype
- * @param string The filename
- * @return string CSS classes separated by space
- */
function rcmail_filetype2classname($mimetype, $filename)
{
- list($primary, $secondary) = explode('/', $mimetype);
-
- $classes = array($primary ? $primary : 'unknown');
- if ($secondary) {
- $classes[] = $secondary;
- }
- if (preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) {
- $classes[] = $m[1];
- }
-
- return strtolower(join(" ", $classes));
+ return rcube_ui::file2class($mimetype, $filename);
}
-/**
- * Output HTML editor scripts
- *
- * @param string Editor mode
- * @return void
- */
function rcube_html_editor($mode='')
{
- global $RCMAIL;
-
- $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode));
-
- if ($hook['abort'])
- return;
-
- $lang = strtolower($_SESSION['language']);
-
- // TinyMCE uses two-letter lang codes, with exception of Chinese
- if (strpos($lang, 'zh_') === 0)
- $lang = str_replace('_', '-', $lang);
- else
- $lang = substr($lang, 0, 2);
-
- if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js'))
- $lang = 'en';
-
- $RCMAIL->output->include_script('tiny_mce/tiny_mce.js');
- $RCMAIL->output->include_script('editor.js');
- $RCMAIL->output->add_script(sprintf("rcmail_editor_init(%s)",
- json_encode(array(
- 'mode' => $mode,
- 'lang' => $lang,
- 'skin_path' => $RCMAIL->output->get_skin_path(),
- 'spellcheck' => intval($RCMAIL->config->get('enable_spellcheck')),
- 'spelldict' => intval($RCMAIL->config->get('spellcheck_dictionary')),
- ))), 'docready');
+ rcube_ui::html_editor($mode);
}
-
-/**
- * Replaces TinyMCE's emoticon images with plain-text representation
- *
- * @param string HTML content
- * @return string HTML content
- */
function rcmail_replace_emoticons($html)
{
- $emoticons = array(
- '8-)' => 'smiley-cool',
- ':-#' => 'smiley-foot-in-mouth',
- ':-*' => 'smiley-kiss',
- ':-X' => 'smiley-sealed',
- ':-P' => 'smiley-tongue-out',
- ':-@' => 'smiley-yell',
- ":'(" => 'smiley-cry',
- ':-(' => 'smiley-frown',
- ':-D' => 'smiley-laughing',
- ':-)' => 'smiley-smile',
- ':-S' => 'smiley-undecided',
- ':-$' => 'smiley-embarassed',
- 'O:-)' => 'smiley-innocent',
- ':-|' => 'smiley-money-mouth',
- ':-O' => 'smiley-surprised',
- ';-)' => 'smiley-wink',
- );
-
- foreach ($emoticons as $idx => $file) {
- // <img title="Cry" src="http://.../program/js/tiny_mce/plugins/emotions/img/smiley-cry.gif" border="0" alt="Cry" />
- $search[] = '/<img title="[a-z ]+" src="https?:\/\/[a-z0-9_.\/-]+\/tiny_mce\/plugins\/emotions\/img\/'.$file.'.gif"[^>]+\/>/i';
- $replace[] = $idx;
- }
-
- return preg_replace($search, $replace, $html);
+ return rcube_ui::replace_emoticons($html);
}
-
-/**
- * Send the given message using the configured method
- *
- * @param object $message Reference to Mail_MIME object
- * @param string $from Sender address string
- * @param array $mailto Array of recipient address strings
- * @param array $smtp_error SMTP error array (reference)
- * @param string $body_file Location of file with saved message body (reference),
- * used when delay_file_io is enabled
- * @param array $smtp_opts SMTP options (e.g. DSN request)
- *
- * @return boolean Send status.
- */
function rcmail_deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file=null, $smtp_opts=null)
{
- global $CONFIG, $RCMAIL;
-
- $headers = $message->headers();
-
- // send thru SMTP server using custom SMTP library
- if ($CONFIG['smtp_server']) {
- // generate list of recipients
- $a_recipients = array($mailto);
-
- if (strlen($headers['Cc']))
- $a_recipients[] = $headers['Cc'];
- if (strlen($headers['Bcc']))
- $a_recipients[] = $headers['Bcc'];
-
- // clean Bcc from header for recipients
- $send_headers = $headers;
- unset($send_headers['Bcc']);
- // here too, it because txtHeaders() below use $message->_headers not only $send_headers
- unset($message->_headers['Bcc']);
-
- $smtp_headers = $message->txtHeaders($send_headers, true);
-
- if ($message->getParam('delay_file_io')) {
- // use common temp dir
- $temp_dir = $RCMAIL->config->get('temp_dir');
- $body_file = tempnam($temp_dir, 'rcmMsg');
- if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) {
- raise_error(array('code' => 650, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not create message: ".$mime_result->getMessage()),
- TRUE, FALSE);
- return false;
- }
- $msg_body = fopen($body_file, 'r');
- } else {
- $msg_body = $message->get();
- }
-
- // send message
- if (!is_object($RCMAIL->smtp))
- $RCMAIL->smtp_init(true);
-
- $sent = $RCMAIL->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts);
- $smtp_response = $RCMAIL->smtp->get_response();
- $smtp_error = $RCMAIL->smtp->get_error();
-
- // log error
- if (!$sent)
- raise_error(array('code' => 800, 'type' => 'smtp', 'line' => __LINE__, 'file' => __FILE__,
- 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE);
- }
- // send mail using PHP's mail() function
- else {
- // unset some headers because they will be added by the mail() function
- $headers_enc = $message->headers($headers);
- $headers_php = $message->_headers;
- unset($headers_php['To'], $headers_php['Subject']);
-
- // reset stored headers and overwrite
- $message->_headers = array();
- $header_str = $message->txtHeaders($headers_php);
-
- // #1485779
- if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
- if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) {
- $headers_enc['To'] = implode(', ', $m[1]);
- }
- }
-
- $msg_body = $message->get();
-
- if (PEAR::isError($msg_body))
- raise_error(array('code' => 650, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not create message: ".$msg_body->getMessage()),
- TRUE, FALSE);
- else {
- $delim = $RCMAIL->config->header_delimiter();
- $to = $headers_enc['To'];
- $subject = $headers_enc['Subject'];
- $header_str = rtrim($header_str);
-
- if ($delim != "\r\n") {
- $header_str = str_replace("\r\n", $delim, $header_str);
- $msg_body = str_replace("\r\n", $delim, $msg_body);
- $to = str_replace("\r\n", $delim, $to);
- $subject = str_replace("\r\n", $delim, $subject);
- }
-
- if (ini_get('safe_mode'))
- $sent = mail($to, $subject, $msg_body, $header_str);
- else
- $sent = mail($to, $subject, $msg_body, $header_str, "-f$from");
- }
- }
-
- if ($sent) {
- $RCMAIL->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body));
-
- // remove MDN headers after sending
- unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);
-
- // get all recipients
- if ($headers['Cc'])
- $mailto .= $headers['Cc'];
- if ($headers['Bcc'])
- $mailto .= $headers['Bcc'];
- if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m))
- $mailto = implode(', ', array_unique($m[1]));
-
- if ($CONFIG['smtp_log']) {
- write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s",
- $RCMAIL->user->get_username(),
- $_SERVER['REMOTE_ADDR'],
- $mailto,
- !empty($smtp_response) ? join('; ', $smtp_response) : ''));
- }
- }
-
- if (is_resource($msg_body)) {
- fclose($msg_body);
- }
-
- $message->_headers = array();
- $message->headers($headers);
-
- return $sent;
+ return rcmail::get_instance()->deliver_message($message, $from, $mailto, $smtp_error, $body_file, $smtp_opts);
}
-
-// Returns unique Message-ID
function rcmail_gen_message_id()
{
- global $RCMAIL;
-
- $local_part = md5(uniqid('rcmail'.mt_rand(),true));
- $domain_part = $RCMAIL->user->get_username('domain');
-
- // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924)
- if (!preg_match('/\.[a-z]+$/i', $domain_part)) {
- if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['HTTP_HOST']))
- && preg_match('/\.[a-z]+$/i', $host)) {
- $domain_part = $host;
- }
- else if (($host = preg_replace('/:[0-9]+$/', '', $_SERVER['SERVER_NAME']))
- && preg_match('/\.[a-z]+$/i', $host)) {
- $domain_part = $host;
- }
- }
-
- return sprintf('<%s@%s>', $local_part, $domain_part);
+ return rcmail::get_instance()->gen_message_id();
}
-
-// Returns RFC2822 formatted current date in user's timezone
function rcmail_user_date()
{
- global $RCMAIL;
-
- // get user's timezone
- try {
- $tz = new DateTimeZone($RCMAIL->config->get('timezone'));
- $date = new DateTime('now', $tz);
- }
- catch (Exception $e) {
- $date = new DateTime();
- }
-
- return $date->format('r');
+ return rcmail::get_instance()->user_date();
}
-
-/**
- * Check if we can process not exceeding memory_limit
- *
- * @param integer Required amount of memory
- * @return boolean
- */
function rcmail_mem_check($need)
{
- $mem_limit = parse_bytes(ini_get('memory_limit'));
- $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
-
- return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true;
+ return rcube_ui::mem_check($need);
}
-
-/**
- * Check if working in SSL mode
- *
- * @param integer HTTPS port number
- * @param boolean Enables 'use_https' option checking
- * @return boolean
- */
function rcube_https_check($port=null, $use_https=true)
{
- global $RCMAIL;
-
- if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off')
- return true;
- if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https')
- return true;
- if ($port && $_SERVER['SERVER_PORT'] == $port)
- return true;
- if ($use_https && isset($RCMAIL) && $RCMAIL->config->get('use_https'))
- return true;
-
- return false;
+ return rcube_ui::https_check($port, $use_https);
}
-
-/**
- * For backward compatibility.
- *
- * @global rcmail $RCMAIL
- * @param string $var_name Variable name.
- * @return void
- */
function rcube_sess_unset($var_name=null)
{
- global $RCMAIL;
-
- $RCMAIL->session->remove($var_name);
+ rcmail::get_instance()->session->remove($var_name);
}
-
-/**
- * Replaces hostname variables
- *
- * @param string $name Hostname
- * @param string $host Optional IMAP hostname
- * @return string
- */
function rcube_parse_host($name, $host='')
{
- // %n - host
- $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']);
- // %d - domain name without first part, e.g. %n=mail.domain.tld, %d=domain.tld
- $d = preg_replace('/^[^\.]+\./', '', $n);
- // %h - IMAP host
- $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host;
- // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld
- $z = preg_replace('/^[^\.]+\./', '', $h);
- // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided
- if ( strpos($name, '%s') !== false ){
- $user_email = rcube_idn_convert(get_input_value('_user', RCUBE_INPUT_POST), true);
- if ( preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s) < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false )
- return false;
- }
-
- $name = str_replace(array('%n', '%d', '%h', '%z', '%s'), array($n, $d, $h, $z, $s[2]), $name);
- return $name;
+ return rcmail::parse_host($name, $host);
}
-
-/**
- * E-mail address validation
- *
- * @param string $email Email address
- * @param boolean $dns_check True to check dns
- * @return boolean
- */
function check_email($email, $dns_check=true)
{
- // Check for invalid characters
- if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email))
- return false;
-
- // Check for length limit specified by RFC 5321 (#1486453)
- if (strlen($email) > 254)
- return false;
-
- $email_array = explode('@', $email);
-
- // Check that there's one @ symbol
- if (count($email_array) < 2)
- return false;
-
- $domain_part = array_pop($email_array);
- $local_part = implode('@', $email_array);
-
- // from PEAR::Validate
- $regexp = '&^(?:
- ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name
- ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322)
- $&xi';
-
- if (!preg_match($regexp, $local_part))
- return false;
-
- // Check domain part
- if (preg_match('/^\[*(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]*$/', $domain_part))
- return true; // IP address
- else {
- // If not an IP address
- $domain_array = explode('.', $domain_part);
- if (sizeof($domain_array) < 2)
- return false; // Not enough parts to be a valid domain
-
- foreach ($domain_array as $part)
- if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part))
- return false;
-
- if (!$dns_check || !rcmail::get_instance()->config->get('email_dns_check'))
- return true;
-
- if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) {
- $lookup = array();
- @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup);
- foreach ($lookup as $line) {
- if (strpos($line, 'MX preference'))
- return true;
- }
- return false;
- }
-
- // find MX record(s)
- if (getmxrr($domain_part, $mx_records))
- return true;
-
- // find any DNS record
- if (checkdnsrr($domain_part, 'ANY'))
- return true;
- }
-
- return false;
+ return rcmail::get_instance()->check_email($email, $dns_check);
}
-/*
- * Idn_to_ascii wrapper.
- * Intl/Idn modules version of this function doesn't work with e-mail address
- */
-function rcube_idn_to_ascii($str)
-{
- return rcube_idn_convert($str, true);
-}
-
-/*
- * Idn_to_ascii wrapper.
- * Intl/Idn modules version of this function doesn't work with e-mail address
- */
-function rcube_idn_to_utf8($str)
-{
- return rcube_idn_convert($str, false);
-}
-
-function rcube_idn_convert($input, $is_utf=false)
-{
- if ($at = strpos($input, '@')) {
- $user = substr($input, 0, $at);
- $domain = substr($input, $at+1);
- }
- else {
- $domain = $input;
- }
-
- $domain = $is_utf ? idn_to_ascii($domain) : idn_to_utf8($domain);
-
- if ($domain === false) {
- return '';
- }
-
- return $at ? $user . '@' . $domain : $domain;
-}
-
-
-/**
- * Helper class to turn relative urls into absolute ones
- * using a predefined base
- */
-class rcube_base_replacer
-{
- private $base_url;
-
- public function __construct($base)
- {
- $this->base_url = $base;
- }
-
- public function callback($matches)
- {
- return $matches[1] . '="' . self::absolute_url($matches[3], $this->base_url) . '"';
- }
-
- public function replace($body)
- {
- return preg_replace_callback(array(
- '/(src|background|href)=(["\']?)([^"\'\s]+)(\2|\s|>)/Ui',
- '/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui',
- ),
- array($this, 'callback'), $body);
- }
-
- /**
- * Convert paths like ../xxx to an absolute path using a base url
- *
- * @param string $path Relative path
- * @param string $base_url Base URL
- *
- * @return string Absolute URL
- */
- public static function absolute_url($path, $base_url)
- {
- $host_url = $base_url;
- $abs_path = $path;
-
- // check if path is an absolute URL
- if (preg_match('/^[fhtps]+:\/\//', $path)) {
- return $path;
- }
-
- // check if path is a content-id scheme
- if (strpos($path, 'cid:') === 0) {
- return $path;
- }
-
- // cut base_url to the last directory
- if (strrpos($base_url, '/') > 7) {
- $host_url = substr($base_url, 0, strpos($base_url, '/', 7));
- $base_url = substr($base_url, 0, strrpos($base_url, '/'));
- }
-
- // $path is absolute
- if ($path[0] == '/') {
- $abs_path = $host_url.$path;
- }
- else {
- // strip './' because its the same as ''
- $path = preg_replace('/^\.\//', '', $path);
-
- if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) {
- foreach ($matches as $a_match) {
- if (strrpos($base_url, '/')) {
- $base_url = substr($base_url, 0, strrpos($base_url, '/'));
- }
- $path = substr($path, 3);
- }
- }
-
- $abs_path = $base_url.'/'.$path;
- }
-
- return $abs_path;
- }
-}
-
-
-/****** debugging and logging functions ********/
-
-/**
- * Print or write debug messages
- *
- * @param mixed Debug message or data
- * @return void
- */
function console()
{
- $args = func_get_args();
-
- if (class_exists('rcmail', false)) {
- $rcmail = rcmail::get_instance();
- if (is_object($rcmail->plugins)) {
- $plugin = $rcmail->plugins->exec_hook('console', array('args' => $args));
- if ($plugin['abort'])
- return;
- $args = $plugin['args'];
- }
- }
-
- $msg = array();
- foreach ($args as $arg)
- $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
-
- write_log('console', join(";\n", $msg));
+ call_user_func_array(array('rcmail', 'console'), func_get_args());
}
-
-/**
- * Append a line to a logfile in the logs directory.
- * Date will be added automatically to the line.
- *
- * @param $name name of log file
- * @param line Line to append
- * @return void
- */
function write_log($name, $line)
{
- global $CONFIG, $RCMAIL;
-
- if (!is_string($line))
- $line = var_export($line, true);
-
- if (empty($CONFIG['log_date_format']))
- $CONFIG['log_date_format'] = 'd-M-Y H:i:s O';
-
- $date = date($CONFIG['log_date_format']);
-
- // trigger logging hook
- if (is_object($RCMAIL) && is_object($RCMAIL->plugins)) {
- $log = $RCMAIL->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line));
- $name = $log['name'];
- $line = $log['line'];
- $date = $log['date'];
- if ($log['abort'])
- return true;
- }
-
- if ($CONFIG['log_driver'] == 'syslog') {
- $prio = $name == 'errors' ? LOG_ERR : LOG_INFO;
- syslog($prio, $line);
- return true;
- }
- else {
- $line = sprintf("[%s]: %s\n", $date, $line);
-
- // log_driver == 'file' is assumed here
- if (empty($CONFIG['log_dir']))
- $CONFIG['log_dir'] = INSTALL_PATH.'logs';
-
- // try to open specific log file for writing
- $logfile = $CONFIG['log_dir'].'/'.$name;
- if ($fp = @fopen($logfile, 'a')) {
- fwrite($fp, $line);
- fflush($fp);
- fclose($fp);
- return true;
- }
- else
- trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING);
- }
-
- return false;
+ return rcmail::write_log($name, $line);
}
-
-/**
- * Write login data (name, ID, IP address) to the 'userlogins' log file.
- *
- * @return void
- */
function rcmail_log_login()
{
- global $RCMAIL;
-
- if (!$RCMAIL->config->get('log_logins') || !$RCMAIL->user)
- return;
-
- write_log('userlogins', sprintf('Successful login for %s (ID: %d) from %s in session %s',
- $RCMAIL->user->get_username(), $RCMAIL->user->ID, rcmail_remote_ip(), session_id()));
+ return rcmail::get_instance()->log_login();
}
-
-/**
- * Returns remote IP address and forwarded addresses if found
- *
- * @return string Remote IP address(es)
- */
function rcmail_remote_ip()
{
- $address = $_SERVER['REMOTE_ADDR'];
-
- // append the NGINX X-Real-IP header, if set
- if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
- $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP'];
- }
- // append the X-Forwarded-For header, if set
- if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
- $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
- }
-
- if (!empty($remote_ip))
- $address .= '(' . implode(',', $remote_ip) . ')';
-
- return $address;
+ return rcmail::remote_ip();
}
-
-/**
- * Check whether the HTTP referer matches the current request
- *
- * @return boolean True if referer is the same host+path, false if not
- */
function rcube_check_referer()
{
- $uri = parse_url($_SERVER['REQUEST_URI']);
- $referer = parse_url(rc_request_header('Referer'));
- return $referer['host'] == rc_request_header('Host') && $referer['path'] == $uri['path'];
+ return rcmail::check_referer();
}
-
-/**
- * @access private
- * @return mixed
- */
function rcube_timer()
{
- return microtime(true);
+ return rcmail::timer();
}
-
-/**
- * @access private
- * @return void
- */
function rcube_print_time($timer, $label='Timer', $dest='console')
{
- static $print_count = 0;
-
- $print_count++;
- $now = rcube_timer();
- $diff = $now-$timer;
-
- if (empty($label))
- $label = 'Timer '.$print_count;
-
- write_log($dest, sprintf("%s: %0.4f sec", $label, $diff));
+ rcmail::print_timer($timer, $label, $dest);
}
-
-/**
- * Throw system error and show error page
- *
- * @param array Named parameters
- * - code: Error code (required)
- * - type: Error type [php|db|imap|javascript] (required)
- * - message: Error message
- * - file: File where error occured
- * - line: Line where error occured
- * @param boolean True to log the error
- * @param boolean Terminate script execution
- */
-// may be defined in Installer
-if (!function_exists('raise_error')) {
function raise_error($arg=array(), $log=false, $terminate=false)
{
- global $__page_content, $CONFIG, $OUTPUT, $ERROR_CODE, $ERROR_MESSAGE;
-
- // report bug (if not incompatible browser)
- if ($log && $arg['type'] && $arg['message'])
- rcube_log_bug($arg);
-
- // display error page and terminate script
- if ($terminate) {
- $ERROR_CODE = $arg['code'];
- $ERROR_MESSAGE = $arg['message'];
- include INSTALL_PATH . 'program/steps/utils/error.inc';
- exit;
- }
-}
+ rcmail::raise_error($arg, $log, $terminate);
}
-
-/**
- * Report error according to configured debug_level
- *
- * @param array Named parameters
- * @return void
- * @see raise_error()
- */
function rcube_log_bug($arg_arr)
{
- global $CONFIG;
-
- $program = strtoupper($arg_arr['type']);
- $level = $CONFIG['debug_level'];
-
- // disable errors for ajax requests, write to log instead (#1487831)
- if (($level & 4) && !empty($_REQUEST['_remote'])) {
- $level = ($level ^ 4) | 1;
- }
-
- // write error to local log file
- if ($level & 1) {
- $post_query = ($_SERVER['REQUEST_METHOD'] == 'POST' ? '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']) : '');
- $log_entry = sprintf("%s Error: %s%s (%s %s)",
- $program,
- $arg_arr['message'],
- $arg_arr['file'] ? sprintf(' in %s on line %d', $arg_arr['file'], $arg_arr['line']) : '',
- $_SERVER['REQUEST_METHOD'],
- $_SERVER['REQUEST_URI'] . $post_query);
-
- if (!write_log('errors', $log_entry)) {
- // send error to PHPs error handler if write_log didn't succeed
- trigger_error($arg_arr['message']);
- }
- }
-
- // report the bug to the global bug reporting system
- if ($level & 2) {
- // TODO: Send error via HTTP
- }
-
- // show error if debug_mode is on
- if ($level & 4) {
- print "<b>$program Error";
-
- if (!empty($arg_arr['file']) && !empty($arg_arr['line']))
- print " in $arg_arr[file] ($arg_arr[line])";
-
- print ':</b>&nbsp;';
- print nl2br($arg_arr['message']);
- print '<br />';
- flush();
- }
+ rcmail::log_bug($arg_arr);
}
function rcube_upload_progress()
{
- global $RCMAIL;
-
- $prefix = ini_get('apc.rfc1867_prefix');
- $params = array(
- 'action' => $RCMAIL->action,
- 'name' => get_input_value('_progress', RCUBE_INPUT_GET),
- );
-
- if (function_exists('apc_fetch')) {
- $status = apc_fetch($prefix . $params['name']);
-
- if (!empty($status)) {
- $status['percent'] = round($status['current']/$status['total']*100);
- $params = array_merge($status, $params);
- }
- }
-
- if (isset($params['percent']))
- $params['text'] = rcube_label(array('name' => 'uploadprogress', 'vars' => array(
- 'percent' => $params['percent'] . '%',
- 'current' => show_bytes($params['current']),
- 'total' => show_bytes($params['total'])
- )));
-
- $RCMAIL->output->command('upload_progress_update', $params);
- $RCMAIL->output->send();
+ rcube_ui::upload_progress();
}
function rcube_upload_init()
{
- global $RCMAIL;
-
- // Enable upload progress bar
- if (($seconds = $RCMAIL->config->get('upload_progress')) && ini_get('apc.rfc1867')) {
- if ($field_name = ini_get('apc.rfc1867_name')) {
- $RCMAIL->output->set_env('upload_progress_name', $field_name);
- $RCMAIL->output->set_env('upload_progress_time', (int) $seconds);
- }
- }
-
- // find max filesize value
- $max_filesize = parse_bytes(ini_get('upload_max_filesize'));
- $max_postsize = parse_bytes(ini_get('post_max_size'));
- if ($max_postsize && $max_postsize < $max_filesize)
- $max_filesize = $max_postsize;
-
- $RCMAIL->output->set_env('max_filesize', $max_filesize);
- $max_filesize = show_bytes($max_filesize);
- $RCMAIL->output->set_env('filesizeerror', rcube_label(array(
- 'name' => 'filesizeerror', 'vars' => array('size' => $max_filesize))));
-
- return $max_filesize;
+ return rcube_ui::upload_init();
}
-/**
- * Initializes client-side autocompletion
- */
function rcube_autocomplete_init()
{
- global $RCMAIL;
- static $init;
+ rcube_ui::autocomplete_init();
+}
+
+function rcube_fontdefs($font = null)
+{
+ return rcube_ui::font_defs($font);
+}
+
+function send_nocacheing_headers()
+{
+ return rcmail::get_instance()->output->nocacheing_headers();
+}
- if ($init)
- return;
+function show_bytes($bytes)
+{
+ return rcube_ui::show_bytes($bytes);
+}
- $init = 1;
+function rc_wordwrap($string, $width=75, $break="\n", $cut=false)
+{
+ return rcube_mime::wordwrap($string, $width, $break, $cut);
+}
- if (($threads = (int)$RCMAIL->config->get('autocomplete_threads')) > 0) {
- $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql');
- if (count($book_types) > 1) {
- $RCMAIL->output->set_env('autocomplete_threads', $threads);
- $RCMAIL->output->set_env('autocomplete_sources', $book_types);
- }
- }
+function rc_request_header($name)
+{
+ return rcube_request_header($name);
+}
- $RCMAIL->output->set_env('autocomplete_max', (int)$RCMAIL->config->get('autocomplete_max', 15));
- $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length'));
- $RCMAIL->output->add_label('autocompletechars', 'autocompletemore');
+function rc_mime_content_type($path, $name, $failover = 'application/octet-stream', $is_stream=false)
+{
+ return rcube_mime::file_content_type($path, $name, $failover, $is_stream);
}
-function rcube_fontdefs($font = null)
+function rc_image_content_type($data)
{
- $fonts = array(
- 'Andale Mono' => '"Andale Mono",Times,monospace',
- 'Arial' => 'Arial,Helvetica,sans-serif',
- 'Arial Black' => '"Arial Black","Avant Garde",sans-serif',
- 'Book Antiqua' => '"Book Antiqua",Palatino,serif',
- 'Courier New' => '"Courier New",Courier,monospace',
- 'Georgia' => 'Georgia,Palatino,serif',
- 'Helvetica' => 'Helvetica,Arial,sans-serif',
- 'Impact' => 'Impact,Chicago,sans-serif',
- 'Tahoma' => 'Tahoma,Arial,Helvetica,sans-serif',
- 'Terminal' => 'Terminal,Monaco,monospace',
- 'Times New Roman' => '"Times New Roman",Times,serif',
- 'Trebuchet MS' => '"Trebuchet MS",Geneva,sans-serif',
- 'Verdana' => 'Verdana,Geneva,sans-serif',
- );
-
- if ($font)
- return $fonts[$font];
-
- return $fonts;
+ return rcube_mime::image_content_type($data);
}
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index a86729156..bca91e1a8 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -5,8 +5,8 @@
| program/include/rcmail.php |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2011, The Roundcube Dev Team |
- | Copyright (C) 2011, Kolab Systems AG |
+ | Copyright (C) 2008-2012, The Roundcube Dev Team |
+ | Copyright (C) 2011-2012, Kolab Systems AG |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -30,7 +30,7 @@
*
* @package Core
*/
-class rcmail
+class rcmail extends rcube
{
/**
* Main tasks.
@@ -40,76 +40,6 @@ class rcmail
static public $main_tasks = array('mail','settings','addressbook','login','logout','utils','dummy');
/**
- * Singleton instace of rcmail
- *
- * @var rcmail
- */
- static private $instance;
-
- /**
- * Stores instance of rcube_config.
- *
- * @var rcube_config
- */
- public $config;
-
- /**
- * Stores rcube_user instance.
- *
- * @var rcube_user
- */
- public $user;
-
- /**
- * Instace of database class.
- *
- * @var rcube_mdb2
- */
- public $db;
-
- /**
- * Instace of Memcache class.
- *
- * @var rcube_mdb2
- */
- public $memcache;
-
- /**
- * Instace of rcube_session class.
- *
- * @var rcube_session
- */
- public $session;
-
- /**
- * Instance of rcube_smtp class.
- *
- * @var rcube_smtp
- */
- public $smtp;
-
- /**
- * Instance of rcube_storage class.
- *
- * @var rcube_storage
- */
- public $storage;
-
- /**
- * Instance of rcube_template class.
- *
- * @var rcube_template
- */
- public $output;
-
- /**
- * Instance of rcube_plugin_api.
- *
- * @var rcube_plugin_api
- */
- public $plugins;
-
- /**
* Current task.
*
* @var string
@@ -124,12 +54,8 @@ class rcmail
public $action = '';
public $comm_path = './';
- private $texts;
private $address_books = array();
- private $caches = array();
private $action_map = array();
- private $shutdown_functions = array();
- private $expunge_cache = false;
/**
@@ -139,7 +65,7 @@ class rcmail
*/
static function get_instance()
{
- if (!self::$instance) {
+ if (!self::$instance || !is_a(self::$instance, 'rcmail')) {
self::$instance = new rcmail();
self::$instance->startup(); // init AFTER object was linked with self::$instance
}
@@ -149,32 +75,12 @@ class rcmail
/**
- * Private constructor
- */
- private function __construct()
- {
- // load configuration
- $this->config = new rcube_config();
-
- register_shutdown_function(array($this, 'shutdown'));
- }
-
-
- /**
* Initial startup function
* to register session, create database and imap connections
*/
- private function startup()
+ protected function startup()
{
- // initialize syslog
- if ($this->config->get('log_driver') == 'syslog') {
- $syslog_id = $this->config->get('syslog_id', 'roundcube');
- $syslog_facility = $this->config->get('syslog_facility', LOG_USER);
- openlog($syslog_id, LOG_ODELAY, $syslog_facility);
- }
-
- // connect to database
- $this->get_dbh();
+ $this->init(self::INIT_WITH_DB | self::INIT_WITH_PLUGINS);
// start session
$this->session_init();
@@ -186,8 +92,8 @@ class rcmail
$this->session_configure();
// set task and action properties
- $this->set_task(get_input_value('_task', RCUBE_INPUT_GPC));
- $this->action = asciiwords(get_input_value('_action', RCUBE_INPUT_GPC));
+ $this->set_task(rcube_ui::get_input_value('_task', rcube_ui::INPUT_GPC));
+ $this->action = asciiwords(rcube_ui::get_input_value('_action', rcube_ui::INPUT_GPC));
// reset some session parameters when changing task
if ($this->task != 'utils') {
@@ -203,11 +109,9 @@ class rcmail
else
$GLOBALS['OUTPUT'] = $this->load_gui(!empty($_REQUEST['_framed']));
- // create plugin API and load plugins
- $this->plugins = rcube_plugin_api::get_instance();
-
- // init plugins
- $this->plugins->init();
+ // load plugins
+ $this->plugins->init($this, $this->task);
+ $this->plugins->load_plugins((array)$this->config->get('plugins', array()), array('filesystem_attachments', 'jqueryui'));
}
@@ -259,144 +163,6 @@ class rcmail
/**
- * Check the given string and return a valid language code
- *
- * @param string Language code
- * @return string Valid language code
- */
- private function language_prop($lang)
- {
- static $rcube_languages, $rcube_language_aliases;
-
- // user HTTP_ACCEPT_LANGUAGE if no language is specified
- if (empty($lang) || $lang == 'auto') {
- $accept_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
- $lang = str_replace('-', '_', $accept_langs[0]);
- }
-
- 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
- else if (!isset($rcube_languages[$lang])) {
- $short = substr($lang, 0, 2);
-
- // check if we have an alias for the short language code
- if (!isset($rcube_languages[$short]) && isset($rcube_language_aliases[$short])) {
- $lang = $rcube_language_aliases[$short];
- }
- // expand 'nn' to 'nn_NN'
- else if (!isset($rcube_languages[$short])) {
- $lang = $short.'_'.strtoupper($short);
- }
- }
-
- if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
- $lang = 'en_US';
- }
-
- return $lang;
- }
-
-
- /**
- * Get the current database connection
- *
- * @return rcube_mdb2 Database connection object
- */
- public function get_dbh()
- {
- if (!$this->db) {
- $config_all = $this->config->all();
-
- $this->db = new rcube_mdb2($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']);
- $this->db->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql';
- $this->db->set_debug((bool)$config_all['sql_debug']);
- }
-
- return $this->db;
- }
-
-
- /**
- * Get global handle for memcache access
- *
- * @return object Memcache
- */
- public function get_memcache()
- {
- if (!isset($this->memcache)) {
- // no memcache support in PHP
- if (!class_exists('Memcache')) {
- $this->memcache = false;
- return false;
- }
-
- $this->memcache = new Memcache;
- $this->mc_available = 0;
-
- // add alll configured hosts to pool
- $pconnect = $this->config->get('memcache_pconnect', true);
- foreach ($this->config->get('memcache_hosts', array()) as $host) {
- list($host, $port) = explode(':', $host);
- if (!$port) $port = 11211;
- $this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure')));
- }
-
- // test connection and failover (will result in $this->mc_available == 0 on complete failure)
- $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist
-
- if (!$this->mc_available)
- $this->memcache = false;
- }
-
- return $this->memcache;
- }
-
- /**
- * Callback for memcache failure
- */
- public function memcache_failure($host, $port)
- {
- static $seen = array();
-
- // only report once
- if (!$seen["$host:$port"]++) {
- $this->mc_available--;
- raise_error(array('code' => 604, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => "Memcache failure on host $host:$port"),
- true, false);
- }
- }
-
-
- /**
- * Initialize and get cache object
- *
- * @param string $name Cache identifier
- * @param string $type Cache type ('db', 'apc' or 'memcache')
- * @param int $ttl Expiration time for cache items in seconds
- * @param bool $packed Enables/disables data serialization
- *
- * @return rcube_cache Cache object
- */
- public function get_cache($name, $type='db', $ttl=0, $packed=true)
- {
- if (!isset($this->caches[$name])) {
- $this->caches[$name] = new rcube_cache($type, $_SESSION['user_id'], $name, $ttl, $packed);
- }
-
- return $this->caches[$name];
- }
-
-
- /**
* Return instance of the internal address book class
*
* @param string Address book identifier
@@ -425,7 +191,7 @@ class rcmail
$contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['storage_host']));
}
else if ($id === '0') {
- $contacts = new rcube_contacts($this->db, $this->user->ID);
+ $contacts = new rcube_contacts($this->db, $this->get_user_id());
}
else {
$plugin = $this->plugins->exec_hook('addressbook_get', array('id' => $id, 'writeable' => $writeable));
@@ -446,7 +212,7 @@ class rcmail
}
if (!$contacts) {
- raise_error(array(
+ self::raise_error(array(
'code' => 700, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Addressbook source ($id) not found!"),
@@ -481,10 +247,10 @@ class rcmail
// We are using the DB address book
if ($abook_type != 'ldap') {
if (!isset($this->address_books['0']))
- $this->address_books['0'] = new rcube_contacts($this->db, $this->user->ID);
+ $this->address_books['0'] = new rcube_contacts($this->db, $this->get_user_id());
$list['0'] = array(
'id' => '0',
- 'name' => rcube_label('personaladrbook'),
+ 'name' => $this->gettext('personaladrbook'),
'groups' => $this->address_books['0']->groups,
'readonly' => $this->address_books['0']->readonly,
'autocomplete' => in_array('sql', $autocomplete),
@@ -532,13 +298,13 @@ class rcmail
* environment vars according to the current session and configuration
*
* @param boolean True if this request is loaded in a (i)frame
- * @return rcube_template Reference to HTML output object
+ * @return rcube_output_html Reference to HTML output object
*/
public function load_gui($framed = false)
{
// init output page
- if (!($this->output instanceof rcube_template))
- $this->output = new rcube_template($this->task, $framed);
+ if (!($this->output instanceof rcube_output_html))
+ $this->output = new rcube_output_html($this->task, $framed);
// set keep-alive/check-recent interval
if ($this->session && ($keep_alive = $this->session->get_keep_alive())) {
@@ -565,177 +331,18 @@ class rcmail
/**
* Create an output object for JSON responses
*
- * @return rcube_json_output Reference to JSON output object
+ * @return rcube_output_json Reference to JSON output object
*/
public function json_init()
{
- if (!($this->output instanceof rcube_json_output))
- $this->output = new rcube_json_output($this->task);
+ if (!($this->output instanceof rcube_output_json))
+ $this->output = new rcube_output_json($this->task);
return $this->output;
}
/**
- * Create SMTP object and connect to server
- *
- * @param boolean True if connection should be established
- */
- public function smtp_init($connect = false)
- {
- $this->smtp = new rcube_smtp();
-
- if ($connect)
- $this->smtp->connect();
- }
-
-
- /**
- * Initialize and get storage object
- *
- * @return rcube_storage Storage object
- */
- public function get_storage()
- {
- // already initialized
- if (!is_object($this->storage)) {
- $this->storage_init();
- }
-
- return $this->storage;
- }
-
-
- /**
- * Connect to the IMAP server with stored session data.
- *
- * @return bool True on success, False on error
- * @deprecated
- */
- public function imap_connect()
- {
- return $this->storage_connect();
- }
-
-
- /**
- * Initialize IMAP object.
- *
- * @deprecated
- */
- public function imap_init()
- {
- $this->storage_init();
- }
-
-
- /**
- * Initialize storage object
- */
- public function storage_init()
- {
- // already initialized
- if (is_object($this->storage)) {
- return;
- }
-
- $driver = $this->config->get('storage_driver', 'imap');
- $driver_class = "rcube_{$driver}";
-
- if (!class_exists($driver_class)) {
- raise_error(array(
- 'code' => 700, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Storage driver class ($driver) not found!"),
- true, true);
- }
-
- // Initialize storage object
- $this->storage = new $driver_class;
-
- // for backward compat. (deprecated, will be removed)
- $this->imap = $this->storage;
-
- // enable caching of mail data
- $storage_cache = $this->config->get("{$driver}_cache");
- $messages_cache = $this->config->get('messages_cache');
- // for backward compatybility
- if ($storage_cache === null && $messages_cache === null && $this->config->get('enable_caching')) {
- $storage_cache = 'db';
- $messages_cache = true;
- }
-
- if ($storage_cache)
- $this->storage->set_caching($storage_cache);
- if ($messages_cache)
- $this->storage->set_messages_caching(true);
-
- // set pagesize from config
- $pagesize = $this->config->get('mail_pagesize');
- if (!$pagesize) {
- $pagesize = $this->config->get('pagesize', 50);
- }
- $this->storage->set_pagesize($pagesize);
-
- // set class options
- $options = array(
- 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'),
- 'auth_cid' => $this->config->get("{$driver}_auth_cid"),
- 'auth_pw' => $this->config->get("{$driver}_auth_pw"),
- 'debug' => (bool) $this->config->get("{$driver}_debug"),
- 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"),
- 'timeout' => (int) $this->config->get("{$driver}_timeout"),
- 'skip_deleted' => (bool) $this->config->get('skip_deleted'),
- 'driver' => $driver,
- );
-
- if (!empty($_SESSION['storage_host'])) {
- $options['host'] = $_SESSION['storage_host'];
- $options['user'] = $_SESSION['username'];
- $options['port'] = $_SESSION['storage_port'];
- $options['ssl'] = $_SESSION['storage_ssl'];
- $options['password'] = $this->decrypt($_SESSION['password']);
- // set 'imap_host' for backwards compatibility
- $_SESSION[$driver.'_host'] = &$_SESSION['storage_host'];
- }
-
- $options = $this->plugins->exec_hook("storage_init", $options);
-
- $this->storage->set_options($options);
- $this->set_storage_prop();
- }
-
-
- /**
- * Connect to the mail storage server with stored session data
- *
- * @return bool True on success, False on error
- */
- public function storage_connect()
- {
- $storage = $this->get_storage();
-
- if ($_SESSION['storage_host'] && !$storage->is_connected()) {
- $host = $_SESSION['storage_host'];
- $user = $_SESSION['username'];
- $port = $_SESSION['storage_port'];
- $ssl = $_SESSION['storage_ssl'];
- $pass = $this->decrypt($_SESSION['password']);
-
- if (!$storage->connect($host, $user, $pass, $port, $ssl)) {
- if ($this->output)
- $this->output->show_message($storage->get_error_code() == -1 ? 'storageerror' : 'sessionerror', 'error');
- }
- else {
- $this->set_storage_prop();
- }
- }
-
- return $storage->is_connected();
- }
-
-
- /**
* Create session object and start the session.
*/
public function session_init()
@@ -757,7 +364,7 @@ class rcmail
ini_set('session.gc_maxlifetime', $lifetime * 2);
}
- ini_set('session.cookie_secure', rcube_https_check());
+ ini_set('session.cookie_secure', rcube_ui::https_check());
ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid');
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
@@ -766,7 +373,7 @@ class rcmail
// use database for storing session data
$this->session = new rcube_session($this->get_dbh(), $this->config);
- $this->session->register_gc_handler('rcmail_temp_gc');
+ $this->session->register_gc_handler(array($this, 'temp_gc'));
$this->session->register_gc_handler(array($this, 'cache_gc'));
// start PHP session (if not in CLI mode)
@@ -842,7 +449,7 @@ class rcmail
if (!$allowed)
return false;
}
- else if (!empty($config['default_host']) && $host != rcube_parse_host($config['default_host']))
+ else if (!empty($config['default_host']) && $host != self::parse_host($config['default_host']))
return false;
// parse $host URL
@@ -866,9 +473,9 @@ class rcmail
// Check if we need to add domain
if (!empty($config['username_domain']) && strpos($username, '@') === false) {
if (is_array($config['username_domain']) && isset($config['username_domain'][$host]))
- $username .= '@'.rcube_parse_host($config['username_domain'][$host], $host);
+ $username .= '@'.self::parse_host($config['username_domain'][$host], $host);
else if (is_string($config['username_domain']))
- $username .= '@'.rcube_parse_host($config['username_domain'], $host);
+ $username .= '@'.self::parse_host($config['username_domain'], $host);
}
// Convert username to lowercase. If storage backend
@@ -929,7 +536,7 @@ class rcmail
$user = $created;
}
else {
- raise_error(array(
+ self::raise_error(array(
'code' => 620, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Failed to create a user record. Maybe aborted by a plugin?"
@@ -937,7 +544,7 @@ class rcmail
}
}
else {
- raise_error(array(
+ self::raise_error(array(
'code' => 621, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Access denied for new user $username. 'auto_create_user' is disabled"
@@ -984,28 +591,6 @@ class rcmail
/**
- * Set storage parameters.
- * This must be done AFTER connecting to the server!
- */
- private function set_storage_prop()
- {
- $storage = $this->get_storage();
-
- $storage->set_charset($this->config->get('default_charset', RCMAIL_CHARSET));
-
- if ($default_folders = $this->config->get('default_folders')) {
- $storage->set_default_folders($default_folders);
- }
- if (isset($_SESSION['mbox'])) {
- $storage->set_folder($_SESSION['mbox']);
- }
- if (isset($_SESSION['page'])) {
- $storage->set_page($_SESSION['page']);
- }
- }
-
-
- /**
* Auto-select IMAP host based on the posted login information
*
* @return string Selected IMAP host
@@ -1016,7 +601,7 @@ class rcmail
$host = null;
if (is_array($default_host)) {
- $post_host = get_input_value('_host', RCUBE_INPUT_POST);
+ $post_host = rcube_ui::get_input_value('_host', rcube_ui::INPUT_POST);
// direct match in default_host array
if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) {
@@ -1024,7 +609,7 @@ class rcmail
}
// try to select host by mail domain
- list($user, $domain) = explode('@', get_input_value('_user', RCUBE_INPUT_POST));
+ list($user, $domain) = explode('@', rcube_ui::get_input_value('_user', rcube_ui::INPUT_POST));
if (!empty($domain)) {
foreach ($default_host as $storage_host => $mail_domains) {
if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) {
@@ -1045,178 +630,16 @@ class rcmail
}
}
else if (empty($default_host)) {
- $host = get_input_value('_host', RCUBE_INPUT_POST);
+ $host = rcube_ui::get_input_value('_host', rcube_ui::INPUT_POST);
}
else
- $host = rcube_parse_host($default_host);
+ $host = self::parse_host($default_host);
return $host;
}
/**
- * Get localized text in the desired language
- *
- * @param mixed $attrib Named parameters array or label name
- * @param string $domain Label domain (plugin) name
- *
- * @return string Localized text
- */
- public function gettext($attrib, $domain=null)
- {
- // load localization files if not done yet
- if (empty($this->texts))
- $this->load_language();
-
- // extract attributes
- if (is_string($attrib))
- $attrib = array('name' => $attrib);
-
- $name = $attrib['name'] ? $attrib['name'] : '';
-
- // attrib contain text values: use them from now
- if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us']))
- $this->texts[$name] = $setval;
-
- // check for text with domain
- if ($domain && ($text = $this->texts[$domain.'.'.$name]))
- ;
- // text does not exist
- else if (!($text = $this->texts[$name])) {
- return "[$name]";
- }
-
- // replace vars in text
- if (is_array($attrib['vars'])) {
- foreach ($attrib['vars'] as $var_key => $var_value)
- $text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text);
- }
-
- // format output
- if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
- return ucfirst($text);
- else if ($attrib['uppercase'])
- return mb_strtoupper($text);
- else if ($attrib['lowercase'])
- return mb_strtolower($text);
-
- return strtr($text, array('\n' => "\n"));
- }
-
-
- /**
- * Check if the given text label exists
- *
- * @param string $name Label name
- * @param string $domain Label domain (plugin) name or '*' for all domains
- * @param string $ref_domain Sets domain name if label is found
- *
- * @return boolean True if text exists (either in the current language or in en_US)
- */
- public function text_exists($name, $domain = null, &$ref_domain = null)
- {
- // load localization files if not done yet
- if (empty($this->texts))
- $this->load_language();
-
- if (isset($this->texts[$name])) {
- $ref_domain = '';
- return true;
- }
-
- // any of loaded domains (plugins)
- if ($domain == '*') {
- foreach ($this->plugins->loaded_plugins() as $domain)
- if (isset($this->texts[$domain.'.'.$name])) {
- $ref_domain = $domain;
- return true;
- }
- }
- // specified domain
- else if ($domain) {
- $ref_domain = $domain;
- return isset($this->texts[$domain.'.'.$name]);
- }
-
- return false;
- }
-
- /**
- * Load a localization package
- *
- * @param string Language ID
- */
- public function load_language($lang = null, $add = array())
- {
- $lang = $this->language_prop(($lang ? $lang : $_SESSION['language']));
-
- // load localized texts
- if (empty($this->texts) || $lang != $_SESSION['language']) {
- $this->texts = array();
-
- // handle empty lines after closing PHP tag in localization files
- ob_start();
-
- // get english labels (these should be complete)
- @include(INSTALL_PATH . 'program/localization/en_US/labels.inc');
- @include(INSTALL_PATH . 'program/localization/en_US/messages.inc');
-
- if (is_array($labels))
- $this->texts = $labels;
- if (is_array($messages))
- $this->texts = array_merge($this->texts, $messages);
-
- // include user language files
- if ($lang != 'en' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
- include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');
- include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');
-
- if (is_array($labels))
- $this->texts = array_merge($this->texts, $labels);
- if (is_array($messages))
- $this->texts = array_merge($this->texts, $messages);
- }
-
- ob_end_clean();
-
- $_SESSION['language'] = $lang;
- }
-
- // append additional texts (from plugin)
- if (is_array($add) && !empty($add))
- $this->texts += $add;
- }
-
-
- /**
- * Read directory program/localization and return a list of available languages
- *
- * @return array List of available localizations
- */
- public function list_languages()
- {
- 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;
- }
- closedir($dh);
- }
- }
-
- return $sa_languages;
- }
-
-
- /**
* Destroy session data and remove cookie
*/
public function kill_session()
@@ -1260,68 +683,6 @@ class rcmail
/**
- * Function to be executed in script shutdown
- * Registered with register_shutdown_function()
- */
- public function shutdown()
- {
- foreach ($this->shutdown_functions as $function)
- call_user_func($function);
-
- if (is_object($this->smtp))
- $this->smtp->disconnect();
-
- foreach ($this->address_books as $book) {
- if (is_object($book) && is_a($book, 'rcube_addressbook'))
- $book->close();
- }
-
- foreach ($this->caches as $cache) {
- if (is_object($cache))
- $cache->close();
- }
-
- if (is_object($this->storage)) {
- if ($this->expunge_cache)
- $this->storage->expunge_cache();
- $this->storage->close();
- }
-
- // before closing the database connection, write session data
- if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) {
- session_write_close();
- }
-
- // write performance stats to logs/console
- if ($this->config->get('devel_mode')) {
- if (function_exists('memory_get_usage'))
- $mem = show_bytes(memory_get_usage());
- if (function_exists('memory_get_peak_usage'))
- $mem .= '/'.show_bytes(memory_get_peak_usage());
-
- $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : '');
- if (defined('RCMAIL_START'))
- rcube_print_time(RCMAIL_START, $log);
- else
- console($log);
- }
- }
-
-
- /**
- * Registers shutdown function to be executed on shutdown.
- * The functions will be executed before destroying any
- * objects like smtp, imap, session, etc.
- *
- * @param callback Function callback
- */
- public function add_shutdown_function($function)
- {
- $this->shutdown_functions[] = $function;
- }
-
-
- /**
* Garbage collector for cache entries.
* Set flag to expunge caches on shutdown
*/
@@ -1342,7 +703,7 @@ class rcmail
{
$sess_id = $_COOKIE[ini_get('session.name')];
if (!$sess_id) $sess_id = session_id();
- $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->user->ID . $this->config->get('des_key') . $sess_id)));
+ $plugin = $this->plugins->exec_hook('request_token', array('value' => md5('RT' . $this->get_user_id() . $this->config->get('des_key') . $sess_id)));
return $plugin['value'];
}
@@ -1353,9 +714,9 @@ class rcmail
* @param int Request method
* @return boolean True if request token is valid false if not
*/
- public function check_request($mode = RCUBE_INPUT_POST)
+ public function check_request($mode = rcube_ui::INPUT_POST)
{
- $token = get_input_value('_token', $mode);
+ $token = rcube_ui::get_input_value('_token', $mode);
$sess_id = $_COOKIE[ini_get('session.name')];
return !empty($sess_id) && $token == $this->get_request_token();
}
@@ -1384,130 +745,6 @@ class rcmail
/**
- * Encrypt using 3DES
- *
- * @param string $clear clear text input
- * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key'
- * @param boolean $base64 whether or not to base64_encode() the result before returning
- *
- * @return string encrypted text
- */
- public function encrypt($clear, $key = 'des_key', $base64 = true)
- {
- if (!$clear)
- return '';
- /*-
- * Add a single canary byte to the end of the clear text, which
- * will help find out how much of padding will need to be removed
- * upon decryption; see http://php.net/mcrypt_generic#68082
- */
- $clear = pack("a*H2", $clear, "80");
-
- if (function_exists('mcrypt_module_open') &&
- ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, "")))
- {
- $iv = $this->create_iv(mcrypt_enc_get_iv_size($td));
- mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
- $cipher = $iv . mcrypt_generic($td, $clear);
- mcrypt_generic_deinit($td);
- mcrypt_module_close($td);
- }
- else {
- @include_once 'des.inc';
-
- if (function_exists('des')) {
- $des_iv_size = 8;
- $iv = $this->create_iv($des_iv_size);
- $cipher = $iv . des($this->config->get_crypto_key($key), $clear, 1, 1, $iv);
- }
- else {
- raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not perform encryption; make sure Mcrypt is installed or lib/des.inc is available"
- ), true, true);
- }
- }
-
- return $base64 ? base64_encode($cipher) : $cipher;
- }
-
- /**
- * Decrypt 3DES-encrypted string
- *
- * @param string $cipher encrypted text
- * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key'
- * @param boolean $base64 whether or not input is base64-encoded
- *
- * @return string decrypted text
- */
- public function decrypt($cipher, $key = 'des_key', $base64 = true)
- {
- if (!$cipher)
- return '';
-
- $cipher = $base64 ? base64_decode($cipher) : $cipher;
-
- if (function_exists('mcrypt_module_open') &&
- ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, "")))
- {
- $iv_size = mcrypt_enc_get_iv_size($td);
- $iv = substr($cipher, 0, $iv_size);
-
- // session corruption? (#1485970)
- if (strlen($iv) < $iv_size)
- return '';
-
- $cipher = substr($cipher, $iv_size);
- mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
- $clear = mdecrypt_generic($td, $cipher);
- mcrypt_generic_deinit($td);
- mcrypt_module_close($td);
- }
- else {
- @include_once 'des.inc';
-
- if (function_exists('des')) {
- $des_iv_size = 8;
- $iv = substr($cipher, 0, $des_iv_size);
- $cipher = substr($cipher, $des_iv_size);
- $clear = des($this->config->get_crypto_key($key), $cipher, 0, 1, $iv);
- }
- else {
- raise_error(array(
- 'code' => 500, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Could not perform decryption; make sure Mcrypt is installed or lib/des.inc is available"
- ), true, true);
- }
- }
-
- /*-
- * Trim PHP's padding and the canary byte; see note in
- * rcmail::encrypt() and http://php.net/mcrypt_generic#68082
- */
- $clear = substr(rtrim($clear, "\0"), 0, -1);
-
- return $clear;
- }
-
- /**
- * Generates encryption initialization vector (IV)
- *
- * @param int Vector size
- * @return string Vector string
- */
- private function create_iv($size)
- {
- // mcrypt_create_iv() can be slow when system lacks entrophy
- // we'll generate IV vector manually
- $iv = '';
- for ($i = 0; $i < $size; $i++)
- $iv .= chr(mt_rand(0, 255));
- return $iv;
- }
-
- /**
* Build a valid URL to this instance of Roundcube
*
* @param mixed Either a string with the action or url parameters as key-value pairs
@@ -1536,50 +773,36 @@ class rcmail
/**
- * Construct shell command, execute it and return output as string.
- * Keywords {keyword} are replaced with arguments
- *
- * @param $cmd Format string with {keywords} to be replaced
- * @param $values (zero, one or more arrays can be passed)
- * @return output of command. shell errors not detectable
+ * Function to be executed in script shutdown
*/
- public static function exec(/* $cmd, $values1 = array(), ... */)
+ public function shutdown()
{
- $args = func_get_args();
- $cmd = array_shift($args);
- $values = $replacements = array();
-
- // merge values into one array
- foreach ($args as $arg)
- $values += (array)$arg;
-
- preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER);
- foreach ($matches as $tags) {
- list(, $tag, $option, $key) = $tags;
- $parts = array();
-
- if ($option) {
- foreach ((array)$values["-$key"] as $key => $value) {
- if ($value === true || $value === false || $value === null)
- $parts[] = $value ? $key : "";
- else foreach ((array)$value as $val)
- $parts[] = "$key " . escapeshellarg($val);
- }
- }
- else {
- foreach ((array)$values[$key] as $value)
- $parts[] = escapeshellarg($value);
- }
+ parent::shutdown();
- $replacements[$tag] = join(" ", $parts);
+ foreach ($this->address_books as $book) {
+ if (is_object($book) && is_a($book, 'rcube_addressbook'))
+ $book->close();
}
- // use strtr behaviour of going through source string once
- $cmd = strtr($cmd, $replacements);
+ // before closing the database connection, write session data
+ if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) {
+ session_write_close();
+ }
- return (string)shell_exec($cmd);
- }
+ // write performance stats to logs/console
+ if ($this->config->get('devel_mode')) {
+ if (function_exists('memory_get_usage'))
+ $mem = rcube_ui::show_bytes(memory_get_usage());
+ if (function_exists('memory_get_peak_usage'))
+ $mem .= '/'.rcube_ui::show_bytes(memory_get_peak_usage());
+ $log = $this->task . ($this->action ? '/'.$this->action : '') . ($mem ? " [$mem]" : '');
+ if (defined('RCMAIL_START'))
+ self::print_timer(RCMAIL_START, $log);
+ else
+ self::console($log);
+ }
+ }
/**
* Helper method to set a cookie with the current path and host settings
@@ -1596,7 +819,7 @@ class rcmail
$cookie = session_get_cookie_params();
setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'],
- rcube_https_check(), true);
+ rcube_ui::https_check(), true);
}
/**
@@ -1727,4 +950,356 @@ class rcmail
$this->set_storage_prop();
}
+
+ /**
+ * Overwrite action variable
+ *
+ * @param string New action value
+ */
+ public function overwrite_action($action)
+ {
+ $this->action = $action;
+ $this->output->set_env('action', $action);
+ }
+
+
+ /**
+ * Send the given message using the configured method.
+ *
+ * @param object $message Reference to Mail_MIME object
+ * @param string $from Sender address string
+ * @param array $mailto Array of recipient address strings
+ * @param array $smtp_error SMTP error array (reference)
+ * @param string $body_file Location of file with saved message body (reference),
+ * used when delay_file_io is enabled
+ * @param array $smtp_opts SMTP options (e.g. DSN request)
+ *
+ * @return boolean Send status.
+ */
+ public function deliver_message(&$message, $from, $mailto, &$smtp_error, &$body_file = null, $smtp_opts = null)
+ {
+ $headers = $message->headers();
+
+ // send thru SMTP server using custom SMTP library
+ if ($this->config->get('smtp_server')) {
+ // generate list of recipients
+ $a_recipients = array($mailto);
+
+ if (strlen($headers['Cc']))
+ $a_recipients[] = $headers['Cc'];
+ if (strlen($headers['Bcc']))
+ $a_recipients[] = $headers['Bcc'];
+
+ // clean Bcc from header for recipients
+ $send_headers = $headers;
+ unset($send_headers['Bcc']);
+ // here too, it because txtHeaders() below use $message->_headers not only $send_headers
+ unset($message->_headers['Bcc']);
+
+ $smtp_headers = $message->txtHeaders($send_headers, true);
+
+ if ($message->getParam('delay_file_io')) {
+ // use common temp dir
+ $temp_dir = $this->config->get('temp_dir');
+ $body_file = tempnam($temp_dir, 'rcmMsg');
+ if (PEAR::isError($mime_result = $message->saveMessageBody($body_file))) {
+ self::raise_error(array('code' => 650, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Could not create message: ".$mime_result->getMessage()),
+ TRUE, FALSE);
+ return false;
+ }
+ $msg_body = fopen($body_file, 'r');
+ }
+ else {
+ $msg_body = $message->get();
+ }
+
+ // send message
+ if (!is_object($this->smtp)) {
+ $this->smtp_init(true);
+ }
+
+ $sent = $this->smtp->send_mail($from, $a_recipients, $smtp_headers, $msg_body, $smtp_opts);
+ $smtp_response = $this->smtp->get_response();
+ $smtp_error = $this->smtp->get_error();
+
+ // log error
+ if (!$sent) {
+ self::raise_error(array('code' => 800, 'type' => 'smtp',
+ 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => "SMTP error: ".join("\n", $smtp_response)), TRUE, FALSE);
+ }
+ }
+ // send mail using PHP's mail() function
+ else {
+ // unset some headers because they will be added by the mail() function
+ $headers_enc = $message->headers($headers);
+ $headers_php = $message->_headers;
+ unset($headers_php['To'], $headers_php['Subject']);
+
+ // reset stored headers and overwrite
+ $message->_headers = array();
+ $header_str = $message->txtHeaders($headers_php);
+
+ // #1485779
+ if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
+ if (preg_match_all('/<([^@]+@[^>]+)>/', $headers_enc['To'], $m)) {
+ $headers_enc['To'] = implode(', ', $m[1]);
+ }
+ }
+
+ $msg_body = $message->get();
+
+ if (PEAR::isError($msg_body)) {
+ self::raise_error(array('code' => 650, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Could not create message: ".$msg_body->getMessage()),
+ TRUE, FALSE);
+ }
+ else {
+ $delim = $this->config->header_delimiter();
+ $to = $headers_enc['To'];
+ $subject = $headers_enc['Subject'];
+ $header_str = rtrim($header_str);
+
+ if ($delim != "\r\n") {
+ $header_str = str_replace("\r\n", $delim, $header_str);
+ $msg_body = str_replace("\r\n", $delim, $msg_body);
+ $to = str_replace("\r\n", $delim, $to);
+ $subject = str_replace("\r\n", $delim, $subject);
+ }
+
+ if (ini_get('safe_mode'))
+ $sent = mail($to, $subject, $msg_body, $header_str);
+ else
+ $sent = mail($to, $subject, $msg_body, $header_str, "-f$from");
+ }
+ }
+
+ if ($sent) {
+ $this->plugins->exec_hook('message_sent', array('headers' => $headers, 'body' => $msg_body));
+
+ // remove MDN headers after sending
+ unset($headers['Return-Receipt-To'], $headers['Disposition-Notification-To']);
+
+ // get all recipients
+ if ($headers['Cc'])
+ $mailto .= $headers['Cc'];
+ if ($headers['Bcc'])
+ $mailto .= $headers['Bcc'];
+ if (preg_match_all('/<([^@]+@[^>]+)>/', $mailto, $m))
+ $mailto = implode(', ', array_unique($m[1]));
+
+ if ($this->config->get('smtp_log')) {
+ self::write_log('sendmail', sprintf("User %s [%s]; Message for %s; %s",
+ $this->user->get_username(),
+ $_SERVER['REMOTE_ADDR'],
+ $mailto,
+ !empty($smtp_response) ? join('; ', $smtp_response) : ''));
+ }
+ }
+
+ if (is_resource($msg_body)) {
+ fclose($msg_body);
+ }
+
+ $message->_headers = array();
+ $message->headers($headers);
+
+ return $sent;
+ }
+
+
+ /**
+ * Unique Message-ID generator.
+ *
+ * @return string Message-ID
+ */
+ public function gen_message_id()
+ {
+ $local_part = md5(uniqid('rcmail'.mt_rand(),true));
+ $domain_part = $this->user->get_username('domain');
+
+ // Try to find FQDN, some spamfilters doesn't like 'localhost' (#1486924)
+ if (!preg_match('/\.[a-z]+$/i', $domain_part)) {
+ foreach (array($_SERVER['HTTP_HOST'], $_SERVER['SERVER_NAME']) as $host) {
+ $host = preg_replace('/:[0-9]+$/', '', $host);
+ if ($host && preg_match('/\.[a-z]+$/i', $host)) {
+ $domain_part = $host;
+ }
+ }
+ }
+
+ return sprintf('<%s@%s>', $local_part, $domain_part);
+ }
+
+
+ /**
+ * Returns RFC2822 formatted current date in user's timezone
+ *
+ * @return string Date
+ */
+ public function user_date()
+ {
+ // get user's timezone
+ try {
+ $tz = new DateTimeZone($this->config->get('timezone'));
+ $date = new DateTime('now', $tz);
+ }
+ catch (Exception $e) {
+ $date = new DateTime();
+ }
+
+ return $date->format('r');
+ }
+
+
+ /**
+ * E-mail address validation.
+ *
+ * @param string $email Email address
+ * @param boolean $dns_check True to check dns
+ *
+ * @return boolean True on success, False if address is invalid
+ */
+ public function check_email($email, $dns_check=true)
+ {
+ // Check for invalid characters
+ if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) {
+ return false;
+ }
+
+ // Check for length limit specified by RFC 5321 (#1486453)
+ if (strlen($email) > 254) {
+ return false;
+ }
+
+ $email_array = explode('@', $email);
+
+ // Check that there's one @ symbol
+ if (count($email_array) < 2) {
+ return false;
+ }
+
+ $domain_part = array_pop($email_array);
+ $local_part = implode('@', $email_array);
+
+ // from PEAR::Validate
+ $regexp = '&^(?:
+ ("\s*(?:[^"\f\n\r\t\v\b\s]+\s*)+")| #1 quoted name
+ ([-\w!\#\$%\&\'*+~/^`|{}=]+(?:\.[-\w!\#\$%\&\'*+~/^`|{}=]+)*)) #2 OR dot-atom (RFC5322)
+ $&xi';
+
+ if (!preg_match($regexp, $local_part)) {
+ return false;
+ }
+
+ // Check domain part
+ if (preg_match('/^\[*(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]*$/', $domain_part)) {
+ return true; // IP address
+ }
+ else {
+ // If not an IP address
+ $domain_array = explode('.', $domain_part);
+ // Not enough parts to be a valid domain
+ if (sizeof($domain_array) < 2) {
+ return false;
+ }
+
+ foreach ($domain_array as $part) {
+ if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $part)) {
+ return false;
+ }
+ }
+
+ if (!$dns_check || !$this->config->get('email_dns_check')) {
+ return true;
+ }
+
+ if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) {
+ $lookup = array();
+ @exec("nslookup -type=MX " . escapeshellarg($domain_part) . " 2>&1", $lookup);
+ foreach ($lookup as $line) {
+ if (strpos($line, 'MX preference')) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // find MX record(s)
+ if (getmxrr($domain_part, $mx_records)) {
+ return true;
+ }
+
+ // find any DNS record
+ if (checkdnsrr($domain_part, 'ANY')) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Write login data (name, ID, IP address) to the 'userlogins' log file.
+ */
+ public function log_login()
+ {
+ if (!$this->config->get('log_logins')) {
+ return;
+ }
+
+ $user_name = $this->get_user_name();
+ $user_id = $this->get_user_id();
+
+ if (!$user_id) {
+ return;
+ }
+
+ self::write_log('userlogins',
+ sprintf('Successful login for %s (ID: %d) from %s in session %s',
+ $user_name, $user_id, self::remote_ip(), session_id()));
+ }
+
+
+ /**
+ * Check whether the HTTP referer matches the current request
+ *
+ * @return boolean True if referer is the same host+path, false if not
+ */
+ public static function check_referer()
+ {
+ $uri = parse_url($_SERVER['REQUEST_URI']);
+ $referer = parse_url(rcube_request_header('Referer'));
+ return $referer['host'] == rcube_request_header('Host') && $referer['path'] == $uri['path'];
+ }
+
+
+ /**
+ * Garbage collector function for temp files.
+ * Remove temp files older than two days
+ */
+ public function temp_gc()
+ {
+ $tmp = unslashify($this->config->get('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);
+ }
+ }
+
}
diff --git a/program/include/rcube.php b/program/include/rcube.php
new file mode 100644
index 000000000..bee298620
--- /dev/null
+++ b/program/include/rcube.php
@@ -0,0 +1,1226 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcmail.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2008-2012, The Roundcube Dev Team |
+ | Copyright (C) 2011-2012, Kolab Systems AG |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Framework base class providing core functions and holding |
+ | instances of all 'global' objects like db- and storage-connections |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+
+/**
+ * Base class of the Roundcube Framework
+ * implemented as singleton
+ *
+ * @package Core
+ */
+class rcube
+{
+ const INIT_WITH_DB = 1;
+ const INIT_WITH_PLUGINS = 2;
+
+ /**
+ * Singleton instace of rcmail
+ *
+ * @var rcmail
+ */
+ static protected $instance;
+
+ /**
+ * Stores instance of rcube_config.
+ *
+ * @var rcube_config
+ */
+ public $config;
+
+ /**
+ * Instace of database class.
+ *
+ * @var rcube_mdb2
+ */
+ public $db;
+
+ /**
+ * Instace of Memcache class.
+ *
+ * @var rcube_mdb2
+ */
+ public $memcache;
+
+ /**
+ * Instace of rcube_session class.
+ *
+ * @var rcube_session
+ */
+ public $session;
+
+ /**
+ * Instance of rcube_smtp class.
+ *
+ * @var rcube_smtp
+ */
+ public $smtp;
+
+ /**
+ * Instance of rcube_storage class.
+ *
+ * @var rcube_storage
+ */
+ public $storage;
+
+ /**
+ * Instance of rcube_output class.
+ *
+ * @var rcube_output
+ */
+ public $output;
+
+ /**
+ * Instance of rcube_plugin_api.
+ *
+ * @var rcube_plugin_api
+ */
+ public $plugins;
+
+
+ /* private/protected vars */
+ protected $texts;
+ protected $caches = array();
+ protected $shutdown_functions = array();
+ protected $expunge_cache = false;
+
+
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return rcmail The one and only instance
+ */
+ static function get_instance()
+ {
+ if (!self::$instance) {
+ self::$instance = new rcube();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Private constructor
+ */
+ protected function __construct()
+ {
+ // load configuration
+ $this->config = new rcube_config();
+ $this->plugins = new rcube_dummy_plugin_api;
+
+ register_shutdown_function(array($this, 'shutdown'));
+ }
+
+
+ /**
+ * Initial startup function
+ */
+ protected function init($mode = 0)
+ {
+ // initialize syslog
+ if ($this->config->get('log_driver') == 'syslog') {
+ $syslog_id = $this->config->get('syslog_id', 'roundcube');
+ $syslog_facility = $this->config->get('syslog_facility', LOG_USER);
+ openlog($syslog_id, LOG_ODELAY, $syslog_facility);
+ }
+
+ // connect to database
+ if ($mode & self::INIT_WITH_DB) {
+ $this->get_dbh();
+ }
+
+ // create plugin API and load plugins
+ if ($mode & self::INIT_WITH_PLUGINS) {
+ $this->plugins = rcube_plugin_api::get_instance();
+ }
+ }
+
+
+ /**
+ * Get the current database connection
+ *
+ * @return rcube_mdb2 Database connection object
+ */
+ public function get_dbh()
+ {
+ if (!$this->db) {
+ $config_all = $this->config->all();
+
+ $this->db = new rcube_mdb2($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']);
+ $this->db->sqlite_initials = INSTALL_PATH . 'SQL/sqlite.initial.sql';
+ $this->db->set_debug((bool)$config_all['sql_debug']);
+ }
+
+ return $this->db;
+ }
+
+
+ /**
+ * Get global handle for memcache access
+ *
+ * @return object Memcache
+ */
+ public function get_memcache()
+ {
+ if (!isset($this->memcache)) {
+ // no memcache support in PHP
+ if (!class_exists('Memcache')) {
+ $this->memcache = false;
+ return false;
+ }
+
+ $this->memcache = new Memcache;
+ $this->mc_available = 0;
+
+ // add alll configured hosts to pool
+ $pconnect = $this->config->get('memcache_pconnect', true);
+ foreach ($this->config->get('memcache_hosts', array()) as $host) {
+ list($host, $port) = explode(':', $host);
+ if (!$port) $port = 11211;
+ $this->mc_available += intval($this->memcache->addServer($host, $port, $pconnect, 1, 1, 15, false, array($this, 'memcache_failure')));
+ }
+
+ // test connection and failover (will result in $this->mc_available == 0 on complete failure)
+ $this->memcache->increment('__CONNECTIONTEST__', 1); // NOP if key doesn't exist
+
+ if (!$this->mc_available)
+ $this->memcache = false;
+ }
+
+ return $this->memcache;
+ }
+
+
+ /**
+ * Callback for memcache failure
+ */
+ public function memcache_failure($host, $port)
+ {
+ static $seen = array();
+
+ // only report once
+ if (!$seen["$host:$port"]++) {
+ $this->mc_available--;
+ self::raise_error(array('code' => 604, 'type' => 'db',
+ 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => "Memcache failure on host $host:$port"),
+ true, false);
+ }
+ }
+
+
+ /**
+ * Initialize and get cache object
+ *
+ * @param string $name Cache identifier
+ * @param string $type Cache type ('db', 'apc' or 'memcache')
+ * @param int $ttl Expiration time for cache items in seconds
+ * @param bool $packed Enables/disables data serialization
+ *
+ * @return rcube_cache Cache object
+ */
+ public function get_cache($name, $type='db', $ttl=0, $packed=true)
+ {
+ if (!isset($this->caches[$name])) {
+ $this->caches[$name] = new rcube_cache($type, $_SESSION['user_id'], $name, $ttl, $packed);
+ }
+
+ return $this->caches[$name];
+ }
+
+
+ /**
+ * Create SMTP object and connect to server
+ *
+ * @param boolean True if connection should be established
+ */
+ public function smtp_init($connect = false)
+ {
+ $this->smtp = new rcube_smtp();
+
+ if ($connect)
+ $this->smtp->connect();
+ }
+
+
+ /**
+ * Initialize and get storage object
+ *
+ * @return rcube_storage Storage object
+ */
+ public function get_storage()
+ {
+ // already initialized
+ if (!is_object($this->storage)) {
+ $this->storage_init();
+ }
+
+ return $this->storage;
+ }
+
+
+ /**
+ * Initialize storage object
+ */
+ public function storage_init()
+ {
+ // already initialized
+ if (is_object($this->storage)) {
+ return;
+ }
+
+ $driver = $this->config->get('storage_driver', 'imap');
+ $driver_class = "rcube_{$driver}";
+
+ if (!class_exists($driver_class)) {
+ self::raise_error(array(
+ 'code' => 700, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Storage driver class ($driver) not found!"),
+ true, true);
+ }
+
+ // Initialize storage object
+ $this->storage = new $driver_class;
+
+ // for backward compat. (deprecated, will be removed)
+ $this->imap = $this->storage;
+
+ // enable caching of mail data
+ $storage_cache = $this->config->get("{$driver}_cache");
+ $messages_cache = $this->config->get('messages_cache');
+ // for backward compatybility
+ if ($storage_cache === null && $messages_cache === null && $this->config->get('enable_caching')) {
+ $storage_cache = 'db';
+ $messages_cache = true;
+ }
+
+ if ($storage_cache)
+ $this->storage->set_caching($storage_cache);
+ if ($messages_cache)
+ $this->storage->set_messages_caching(true);
+
+ // set pagesize from config
+ $pagesize = $this->config->get('mail_pagesize');
+ if (!$pagesize) {
+ $pagesize = $this->config->get('pagesize', 50);
+ }
+ $this->storage->set_pagesize($pagesize);
+
+ // set class options
+ $options = array(
+ 'auth_type' => $this->config->get("{$driver}_auth_type", 'check'),
+ 'auth_cid' => $this->config->get("{$driver}_auth_cid"),
+ 'auth_pw' => $this->config->get("{$driver}_auth_pw"),
+ 'debug' => (bool) $this->config->get("{$driver}_debug"),
+ 'force_caps' => (bool) $this->config->get("{$driver}_force_caps"),
+ 'timeout' => (int) $this->config->get("{$driver}_timeout"),
+ 'skip_deleted' => (bool) $this->config->get('skip_deleted'),
+ 'driver' => $driver,
+ );
+
+ if (!empty($_SESSION['storage_host'])) {
+ $options['host'] = $_SESSION['storage_host'];
+ $options['user'] = $_SESSION['username'];
+ $options['port'] = $_SESSION['storage_port'];
+ $options['ssl'] = $_SESSION['storage_ssl'];
+ $options['password'] = $this->decrypt($_SESSION['password']);
+ }
+
+ $options = $this->plugins->exec_hook("storage_init", $options);
+
+ // for backward compat. (deprecated, to be removed)
+ $options = $this->plugins->exec_hook("imap_init", $options);
+
+ $this->storage->set_options($options);
+ $this->set_storage_prop();
+ }
+
+
+ /**
+ * Connect to the mail storage server with stored session data
+ *
+ * @return bool True on success, False on error
+ */
+ public function storage_connect()
+ {
+ $storage = $this->get_storage();
+
+ if ($_SESSION['storage_host'] && !$storage->is_connected()) {
+ $host = $_SESSION['storage_host'];
+ $user = $_SESSION['username'];
+ $port = $_SESSION['storage_port'];
+ $ssl = $_SESSION['storage_ssl'];
+ $pass = $this->decrypt($_SESSION['password']);
+
+ if (!$storage->connect($host, $user, $pass, $port, $ssl)) {
+ if (is_object($this->output))
+ $this->output->show_message($storage->get_error_code() == -1 ? 'storageerror' : 'sessionerror', 'error');
+ }
+ else {
+ $this->set_storage_prop();
+ return $storage->is_connected();
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Set storage parameters.
+ * This must be done AFTER connecting to the server!
+ */
+ protected function set_storage_prop()
+ {
+ $storage = $this->get_storage();
+
+ $storage->set_charset($this->config->get('default_charset', RCMAIL_CHARSET));
+
+ if ($default_folders = $this->config->get('default_folders')) {
+ $storage->set_default_folders($default_folders);
+ }
+ if (isset($_SESSION['mbox'])) {
+ $storage->set_folder($_SESSION['mbox']);
+ }
+ if (isset($_SESSION['page'])) {
+ $storage->set_page($_SESSION['page']);
+ }
+ }
+
+
+ /**
+ * Get localized text in the desired language
+ *
+ * @param mixed $attrib Named parameters array or label name
+ * @param string $domain Label domain (plugin) name
+ *
+ * @return string Localized text
+ */
+ public function gettext($attrib, $domain=null)
+ {
+ // load localization files if not done yet
+ if (empty($this->texts))
+ $this->load_language();
+
+ // extract attributes
+ if (is_string($attrib))
+ $attrib = array('name' => $attrib);
+
+ $name = $attrib['name'] ? $attrib['name'] : '';
+
+ // attrib contain text values: use them from now
+ if (($setval = $attrib[strtolower($_SESSION['language'])]) || ($setval = $attrib['en_us']))
+ $this->texts[$name] = $setval;
+
+ // check for text with domain
+ if ($domain && ($text = $this->texts[$domain.'.'.$name]))
+ ;
+ // text does not exist
+ else if (!($text = $this->texts[$name])) {
+ return "[$name]";
+ }
+
+ // replace vars in text
+ if (is_array($attrib['vars'])) {
+ foreach ($attrib['vars'] as $var_key => $var_value)
+ $text = str_replace($var_key[0]!='$' ? '$'.$var_key : $var_key, $var_value, $text);
+ }
+
+ // format output
+ if (($attrib['uppercase'] && strtolower($attrib['uppercase']=='first')) || $attrib['ucfirst'])
+ return ucfirst($text);
+ else if ($attrib['uppercase'])
+ return mb_strtoupper($text);
+ else if ($attrib['lowercase'])
+ return mb_strtolower($text);
+
+ return strtr($text, array('\n' => "\n"));
+ }
+
+
+ /**
+ * Check if the given text label exists
+ *
+ * @param string $name Label name
+ * @param string $domain Label domain (plugin) name or '*' for all domains
+ * @param string $ref_domain Sets domain name if label is found
+ *
+ * @return boolean True if text exists (either in the current language or in en_US)
+ */
+ public function text_exists($name, $domain = null, &$ref_domain = null)
+ {
+ // load localization files if not done yet
+ if (empty($this->texts))
+ $this->load_language();
+
+ if (isset($this->texts[$name])) {
+ $ref_domain = '';
+ return true;
+ }
+
+ // any of loaded domains (plugins)
+ if ($domain == '*') {
+ foreach ($this->plugins->loaded_plugins() as $domain)
+ if (isset($this->texts[$domain.'.'.$name])) {
+ $ref_domain = $domain;
+ return true;
+ }
+ }
+ // specified domain
+ else if ($domain) {
+ $ref_domain = $domain;
+ return isset($this->texts[$domain.'.'.$name]);
+ }
+
+ return false;
+ }
+
+ /**
+ * Load a localization package
+ *
+ * @param string Language ID
+ */
+ public function load_language($lang = null, $add = array())
+ {
+ $lang = $this->language_prop(($lang ? $lang : $_SESSION['language']));
+
+ // load localized texts
+ if (empty($this->texts) || $lang != $_SESSION['language']) {
+ $this->texts = array();
+
+ // handle empty lines after closing PHP tag in localization files
+ ob_start();
+
+ // get english labels (these should be complete)
+ @include(INSTALL_PATH . 'program/localization/en_US/labels.inc');
+ @include(INSTALL_PATH . 'program/localization/en_US/messages.inc');
+
+ if (is_array($labels))
+ $this->texts = $labels;
+ if (is_array($messages))
+ $this->texts = array_merge($this->texts, $messages);
+
+ // include user language files
+ if ($lang != 'en' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
+ include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');
+ include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');
+
+ if (is_array($labels))
+ $this->texts = array_merge($this->texts, $labels);
+ if (is_array($messages))
+ $this->texts = array_merge($this->texts, $messages);
+ }
+
+ ob_end_clean();
+
+ $_SESSION['language'] = $lang;
+ }
+
+ // append additional texts (from plugin)
+ if (is_array($add) && !empty($add))
+ $this->texts += $add;
+ }
+
+
+ /**
+ * Check the given string and return a valid language code
+ *
+ * @param string Language code
+ * @return string Valid language code
+ */
+ protected function language_prop($lang)
+ {
+ static $rcube_languages, $rcube_language_aliases;
+
+ // user HTTP_ACCEPT_LANGUAGE if no language is specified
+ if (empty($lang) || $lang == 'auto') {
+ $accept_langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
+ $lang = str_replace('-', '_', $accept_langs[0]);
+ }
+
+ 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
+ else if (!isset($rcube_languages[$lang])) {
+ $short = substr($lang, 0, 2);
+
+ // check if we have an alias for the short language code
+ if (!isset($rcube_languages[$short]) && isset($rcube_language_aliases[$short])) {
+ $lang = $rcube_language_aliases[$short];
+ }
+ // expand 'nn' to 'nn_NN'
+ else if (!isset($rcube_languages[$short])) {
+ $lang = $short.'_'.strtoupper($short);
+ }
+ }
+
+ if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
+ $lang = 'en_US';
+ }
+
+ return $lang;
+ }
+
+
+ /**
+ * Read directory program/localization and return a list of available languages
+ *
+ * @return array List of available localizations
+ */
+ public function list_languages()
+ {
+ 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;
+ }
+ closedir($dh);
+ }
+ }
+
+ return $sa_languages;
+ }
+
+
+ /**
+ * Encrypt using 3DES
+ *
+ * @param string $clear clear text input
+ * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key'
+ * @param boolean $base64 whether or not to base64_encode() the result before returning
+ *
+ * @return string encrypted text
+ */
+ public function encrypt($clear, $key = 'des_key', $base64 = true)
+ {
+ if (!$clear)
+ return '';
+
+ /*-
+ * Add a single canary byte to the end of the clear text, which
+ * will help find out how much of padding will need to be removed
+ * upon decryption; see http://php.net/mcrypt_generic#68082
+ */
+ $clear = pack("a*H2", $clear, "80");
+
+ if (function_exists('mcrypt_module_open') &&
+ ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) {
+ $iv = $this->create_iv(mcrypt_enc_get_iv_size($td));
+ mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
+ $cipher = $iv . mcrypt_generic($td, $clear);
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+ }
+ else {
+ @include_once 'des.inc';
+
+ if (function_exists('des')) {
+ $des_iv_size = 8;
+ $iv = $this->create_iv($des_iv_size);
+ $cipher = $iv . des($this->config->get_crypto_key($key), $clear, 1, 1, $iv);
+ }
+ else {
+ self::raise_error(array(
+ 'code' => 500, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Could not perform encryption; make sure Mcrypt is installed or lib/des.inc is available"
+ ), true, true);
+ }
+ }
+
+ return $base64 ? base64_encode($cipher) : $cipher;
+ }
+
+ /**
+ * Decrypt 3DES-encrypted string
+ *
+ * @param string $cipher encrypted text
+ * @param string $key encryption key to retrieve from the configuration, defaults to 'des_key'
+ * @param boolean $base64 whether or not input is base64-encoded
+ *
+ * @return string decrypted text
+ */
+ public function decrypt($cipher, $key = 'des_key', $base64 = true)
+ {
+ if (!$cipher)
+ return '';
+
+ $cipher = $base64 ? base64_decode($cipher) : $cipher;
+
+ if (function_exists('mcrypt_module_open') &&
+ ($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, ""))) {
+ $iv_size = mcrypt_enc_get_iv_size($td);
+ $iv = substr($cipher, 0, $iv_size);
+
+ // session corruption? (#1485970)
+ if (strlen($iv) < $iv_size)
+ return '';
+
+ $cipher = substr($cipher, $iv_size);
+ mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
+ $clear = mdecrypt_generic($td, $cipher);
+ mcrypt_generic_deinit($td);
+ mcrypt_module_close($td);
+ }
+ else {
+ @include_once 'des.inc';
+
+ if (function_exists('des')) {
+ $des_iv_size = 8;
+ $iv = substr($cipher, 0, $des_iv_size);
+ $cipher = substr($cipher, $des_iv_size);
+ $clear = des($this->config->get_crypto_key($key), $cipher, 0, 1, $iv);
+ }
+ else {
+ self::raise_error(array(
+ 'code' => 500, 'type' => 'php',
+ 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Could not perform decryption; make sure Mcrypt is installed or lib/des.inc is available"
+ ), true, true);
+ }
+ }
+
+ /*-
+ * Trim PHP's padding and the canary byte; see note in
+ * rcmail::encrypt() and http://php.net/mcrypt_generic#68082
+ */
+ $clear = substr(rtrim($clear, "\0"), 0, -1);
+
+ return $clear;
+ }
+
+ /**
+ * Generates encryption initialization vector (IV)
+ *
+ * @param int Vector size
+ * @return string Vector string
+ */
+ private function create_iv($size)
+ {
+ // mcrypt_create_iv() can be slow when system lacks entrophy
+ // we'll generate IV vector manually
+ $iv = '';
+ for ($i = 0; $i < $size; $i++)
+ $iv .= chr(mt_rand(0, 255));
+ return $iv;
+ }
+
+
+ /**
+ * Build a valid URL to this instance of Roundcube
+ *
+ * @param mixed Either a string with the action or url parameters as key-value pairs
+ * @return string Valid application URL
+ */
+ public function url($p)
+ {
+ // STUB: should be overloaded by the application
+ return '';
+ }
+
+
+ /**
+ * Function to be executed in script shutdown
+ * Registered with register_shutdown_function()
+ */
+ public function shutdown()
+ {
+ foreach ($this->shutdown_functions as $function)
+ call_user_func($function);
+
+ if (is_object($this->smtp))
+ $this->smtp->disconnect();
+
+ foreach ($this->caches as $cache) {
+ if (is_object($cache))
+ $cache->close();
+ }
+
+ if (is_object($this->storage)) {
+ if ($this->expunge_cache)
+ $this->storage->expunge_cache();
+ $this->storage->close();
+ }
+ }
+
+
+ /**
+ * Registers shutdown function to be executed on shutdown.
+ * The functions will be executed before destroying any
+ * objects like smtp, imap, session, etc.
+ *
+ * @param callback Function callback
+ */
+ public function add_shutdown_function($function)
+ {
+ $this->shutdown_functions[] = $function;
+ }
+
+
+ /**
+ * Use imagemagick or GD lib to read image properties
+ *
+ * @param string Absolute file path
+ * @return mixed Hash array with image props like type, width, height or False on error
+ */
+ public static function imageprops($filepath)
+ {
+ $rcube = self::get_instance();
+ if ($cmd = $rcube->config->get('im_identify_path', false)) {
+ list(, $type, $size) = explode(' ', strtolower(self::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath))));
+ if ($size)
+ list($width, $height) = explode('x', $size);
+ }
+ else if (function_exists('getimagesize')) {
+ $imsize = @getimagesize($filepath);
+ $width = $imsize[0];
+ $height = $imsize[1];
+ $type = preg_replace('!image/!', '', $imsize['mime']);
+ }
+
+ return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false;
+ }
+
+
+ /**
+ * Convert an image to a given size and type using imagemagick (ensures input is an image)
+ *
+ * @param $p['in'] Input filename (mandatory)
+ * @param $p['out'] Output filename (mandatory)
+ * @param $p['size'] Width x height of resulting image, e.g. "160x60"
+ * @param $p['type'] Output file type, e.g. "jpg"
+ * @param $p['-opts'] Custom command line options to ImageMagick convert
+ * @return Success of convert as true/false
+ */
+ public static function imageconvert($p)
+ {
+ $result = false;
+ $rcube = self::get_instance();
+ $convert = $rcube->config->get('im_convert_path', false);
+ $identify = $rcube->config->get('im_identify_path', false);
+
+ // imagemagick is required for this
+ if (!$convert)
+ return false;
+
+ if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false))))
+ list(, $type) = explode(' ', strtolower(self::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps
+
+ $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
+ $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
+ $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts'];
+
+ if (in_array($type, explode(',', $p['types']))) # Valid type?
+ $result = self::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === "";
+
+ return $result;
+ }
+
+
+ /**
+ * Construct shell command, execute it and return output as string.
+ * Keywords {keyword} are replaced with arguments
+ *
+ * @param $cmd Format string with {keywords} to be replaced
+ * @param $values (zero, one or more arrays can be passed)
+ * @return output of command. shell errors not detectable
+ */
+ public static function exec(/* $cmd, $values1 = array(), ... */)
+ {
+ $args = func_get_args();
+ $cmd = array_shift($args);
+ $values = $replacements = array();
+
+ // merge values into one array
+ foreach ($args as $arg)
+ $values += (array)$arg;
+
+ preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER);
+ foreach ($matches as $tags) {
+ list(, $tag, $option, $key) = $tags;
+ $parts = array();
+
+ if ($option) {
+ foreach ((array)$values["-$key"] as $key => $value) {
+ if ($value === true || $value === false || $value === null)
+ $parts[] = $value ? $key : "";
+ else foreach ((array)$value as $val)
+ $parts[] = "$key " . escapeshellarg($val);
+ }
+ }
+ else {
+ foreach ((array)$values[$key] as $value)
+ $parts[] = escapeshellarg($value);
+ }
+
+ $replacements[$tag] = join(" ", $parts);
+ }
+
+ // use strtr behaviour of going through source string once
+ $cmd = strtr($cmd, $replacements);
+
+ return (string)shell_exec($cmd);
+ }
+
+
+ /**
+ * Replaces hostname variables.
+ *
+ * @param string $name Hostname
+ * @param string $host Optional IMAP hostname
+ *
+ * @return string Hostname
+ */
+ public static function parse_host($name, $host = '')
+ {
+ // %n - host
+ $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']);
+ // %d - domain name without first part, e.g. %n=mail.domain.tld, %d=domain.tld
+ $d = preg_replace('/^[^\.]+\./', '', $n);
+ // %h - IMAP host
+ $h = $_SESSION['storage_host'] ? $_SESSION['storage_host'] : $host;
+ // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld
+ $z = preg_replace('/^[^\.]+\./', '', $h);
+ // %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided
+ if (strpos($name, '%s') !== false) {
+ $user_email = rcube_ui::get_input_value('_user', rcube_ui::INPUT_POST);
+ $user_email = rcube_idn_convert($user_email, true);
+ $matches = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s);
+ if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) {
+ return false;
+ }
+ }
+
+ $name = str_replace(array('%n', '%d', '%h', '%z', '%s'), array($n, $d, $h, $z, $s[2]), $name);
+ return $name;
+ }
+
+
+ /**
+ * Print or write debug messages
+ *
+ * @param mixed Debug message or data
+ */
+ public static function console()
+ {
+ $args = func_get_args();
+
+ if (class_exists('rcmail', false)) {
+ $rcube = self::get_instance();
+ if (is_object($rcube->plugins)) {
+ $plugin = $rcube->plugins->exec_hook('console', array('args' => $args));
+ if ($plugin['abort']) {
+ return;
+ }
+ $args = $plugin['args'];
+ }
+ }
+
+ $msg = array();
+ foreach ($args as $arg) {
+ $msg[] = !is_string($arg) ? var_export($arg, true) : $arg;
+ }
+
+ self::write_log('console', join(";\n", $msg));
+ }
+
+
+ /**
+ * Append a line to a logfile in the logs directory.
+ * Date will be added automatically to the line.
+ *
+ * @param $name name of log file
+ * @param line Line to append
+ */
+ public static function write_log($name, $line)
+ {
+ if (!is_string($line)) {
+ $line = var_export($line, true);
+ }
+
+ $date_format = self::$instance ? self::$instance->config->get('log_date_format') : null;
+ $log_driver = self::$instance ? self::$instance->config->get('log_driver') : null;
+
+ if (empty($date_format)) {
+ $date_format = 'd-M-Y H:i:s O';
+ }
+
+ $date = date($date_format);
+
+ // trigger logging hook
+ if (is_object(self::$instance) && is_object(self::$instance->plugins)) {
+ $log = self::$instance->plugins->exec_hook('write_log', array('name' => $name, 'date' => $date, 'line' => $line));
+ $name = $log['name'];
+ $line = $log['line'];
+ $date = $log['date'];
+ if ($log['abort'])
+ return true;
+ }
+
+ if ($log_driver == 'syslog') {
+ $prio = $name == 'errors' ? LOG_ERR : LOG_INFO;
+ syslog($prio, $line);
+ return true;
+ }
+
+ // log_driver == 'file' is assumed here
+
+ $line = sprintf("[%s]: %s\n", $date, $line);
+ $log_dir = self::$instance ? self::$instance->config->get('log_dir') : null;
+
+ if (empty($log_dir)) {
+ $log_dir = INSTALL_PATH . 'logs';
+ }
+
+ // try to open specific log file for writing
+ $logfile = $log_dir.'/'.$name;
+
+ if ($fp = @fopen($logfile, 'a')) {
+ fwrite($fp, $line);
+ fflush($fp);
+ fclose($fp);
+ return true;
+ }
+
+ trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING);
+ return false;
+ }
+
+
+ /**
+ * Throw system error (and show error page).
+ *
+ * @param array Named parameters
+ * - code: Error code (required)
+ * - type: Error type [php|db|imap|javascript] (required)
+ * - message: Error message
+ * - file: File where error occured
+ * - line: Line where error occured
+ * @param boolean True to log the error
+ * @param boolean Terminate script execution
+ */
+ public static function raise_error($arg = array(), $log = false, $terminate = false)
+ {
+ // installer
+ if (class_exists('rcube_install', false)) {
+ $rci = rcube_install::get_instance();
+ $rci->raise_error($arg);
+ return;
+ }
+
+ if ($log && $arg['type'] && $arg['message']) {
+ self::log_bug($arg);
+ }
+
+ // display error page and terminate script
+ if ($terminate && is_object(self::$instance->output)) {
+ self::$instance->output->raise_error($arg['code'], $arg['message']);
+ }
+ }
+
+
+ /**
+ * Report error according to configured debug_level
+ *
+ * @param array Named parameters
+ * @see self::raise_error()
+ */
+ public static function log_bug($arg_arr)
+ {
+ $program = strtoupper($arg_arr['type']);
+ $level = self::get_instance()->config->get('debug_level');
+
+ // disable errors for ajax requests, write to log instead (#1487831)
+ if (($level & 4) && !empty($_REQUEST['_remote'])) {
+ $level = ($level ^ 4) | 1;
+ }
+
+ // write error to local log file
+ if ($level & 1) {
+ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+ $post_query = '?_task='.urlencode($_POST['_task']).'&_action='.urlencode($_POST['_action']);
+ }
+ else {
+ $post_query = '';
+ }
+
+ $log_entry = sprintf("%s Error: %s%s (%s %s)",
+ $program,
+ $arg_arr['message'],
+ $arg_arr['file'] ? sprintf(' in %s on line %d', $arg_arr['file'], $arg_arr['line']) : '',
+ $_SERVER['REQUEST_METHOD'],
+ $_SERVER['REQUEST_URI'] . $post_query);
+
+ if (!self::write_log('errors', $log_entry)) {
+ // send error to PHPs error handler if write_log didn't succeed
+ trigger_error($arg_arr['message']);
+ }
+ }
+
+ // report the bug to the global bug reporting system
+ if ($level & 2) {
+ // TODO: Send error via HTTP
+ }
+
+ // show error if debug_mode is on
+ if ($level & 4) {
+ print "<b>$program Error";
+
+ if (!empty($arg_arr['file']) && !empty($arg_arr['line'])) {
+ print " in $arg_arr[file] ($arg_arr[line])";
+ }
+
+ print ':</b>&nbsp;';
+ print nl2br($arg_arr['message']);
+ print '<br />';
+ flush();
+ }
+ }
+
+
+ /**
+ * Returns remote IP address and forwarded addresses if found
+ *
+ * @return string Remote IP address(es)
+ */
+ public static function remote_ip()
+ {
+ $address = $_SERVER['REMOTE_ADDR'];
+
+ // append the NGINX X-Real-IP header, if set
+ if (!empty($_SERVER['HTTP_X_REAL_IP'])) {
+ $remote_ip[] = 'X-Real-IP: ' . $_SERVER['HTTP_X_REAL_IP'];
+ }
+ // append the X-Forwarded-For header, if set
+ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $remote_ip[] = 'X-Forwarded-For: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
+ }
+
+ if (!empty($remote_ip)) {
+ $address .= '(' . implode(',', $remote_ip) . ')';
+ }
+
+ return $address;
+ }
+
+
+ /**
+ * Returns current time (with microseconds).
+ *
+ * @return float Current time in seconds since the Unix
+ */
+ public static function timer()
+ {
+ return microtime(true);
+ }
+
+
+ /**
+ * Logs time difference according to provided timer
+ *
+ * @param float $timer Timer (self::timer() result)
+ * @param string $label Log line prefix
+ * @param string $dest Log file name
+ *
+ * @see self::timer()
+ */
+ public static function print_timer($timer, $label = 'Timer', $dest = 'console')
+ {
+ static $print_count = 0;
+
+ $print_count++;
+ $now = self::timer();
+ $diff = $now - $timer;
+
+ if (empty($label)) {
+ $label = 'Timer '.$print_count;
+ }
+
+ self::write_log($dest, sprintf("%s: %0.4f sec", $label, $diff));
+ }
+
+
+ /**
+ * Getter for logged user ID.
+ *
+ * @return mixed User identifier
+ */
+ public function get_user_id()
+ {
+ if (is_object($this->user)) {
+ return $this->user->ID;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Getter for logged user name.
+ *
+ * @return string User name
+ */
+ public function get_user_name()
+ {
+ if (is_object($this->user)) {
+ return $this->user->get_username();
+ }
+
+ return null;
+ }
+}
+
+
+/**
+ * Lightweight plugin API class serving as a dummy if plugins are not enabled
+ *
+ * @package Core
+ */
+class rcube_dummy_plugin_api
+{
+ /**
+ * Triggers a plugin hook.
+ * @see rcube_plugin_api::exec_hook()
+ */
+ public function exec_hook($hook, $args = array())
+ {
+ return $args;
+ }
+}
+
diff --git a/program/include/rcube_addressbook.php b/program/include/rcube_addressbook.php
index b56b58a65..ca2f1e71c 100644
--- a/program/include/rcube_addressbook.php
+++ b/program/include/rcube_addressbook.php
@@ -211,11 +211,14 @@ abstract class rcube_addressbook
*/
public function validate(&$save_data, $autofix = false)
{
+ $rcmail = rcmail::get_instance();
+
// check validity of email addresses
foreach ($this->get_col_values('email', $save_data, true) as $email) {
if (strlen($email)) {
- if (!check_email(rcube_idn_to_ascii($email))) {
- $this->set_error(self::ERROR_VALIDATE, rcube_label(array('name' => 'emailformaterror', 'vars' => array('email' => $email))));
+ if (!$rcmail->check_email(rcube_idn_to_ascii($email))) {
+ $error = $rcmail->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email)));
+ $this->set_error(self::ERROR_VALIDATE, $error);
return false;
}
}
diff --git a/program/include/rcube_base_replacer.php b/program/include/rcube_base_replacer.php
new file mode 100644
index 000000000..f97a2ee29
--- /dev/null
+++ b/program/include/rcube_base_replacer.php
@@ -0,0 +1,110 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_base_replacer.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Provide basic functions for base URL replacement |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+/**
+ * Helper class to turn relative urls into absolute ones
+ * using a predefined base
+ *
+ * @package Core
+ * @author Thomas Bruederli <roundcube@gmail.com>
+ */
+class rcube_base_replacer
+{
+ private $base_url;
+
+
+ public function __construct($base)
+ {
+ $this->base_url = $base;
+ }
+
+
+ public function callback($matches)
+ {
+ return $matches[1] . '="' . self::absolute_url($matches[3], $this->base_url) . '"';
+ }
+
+
+ public function replace($body)
+ {
+ return preg_replace_callback(array(
+ '/(src|background|href)=(["\']?)([^"\'\s]+)(\2|\s|>)/Ui',
+ '/(url\s*\()(["\']?)([^"\'\)\s]+)(\2)\)/Ui',
+ ),
+ array($this, 'callback'), $body);
+ }
+
+
+ /**
+ * Convert paths like ../xxx to an absolute path using a base url
+ *
+ * @param string $path Relative path
+ * @param string $base_url Base URL
+ *
+ * @return string Absolute URL
+ */
+ public static function absolute_url($path, $base_url)
+ {
+ $host_url = $base_url;
+ $abs_path = $path;
+
+ // check if path is an absolute URL
+ if (preg_match('/^[fhtps]+:\/\//', $path)) {
+ return $path;
+ }
+
+ // check if path is a content-id scheme
+ if (strpos($path, 'cid:') === 0) {
+ return $path;
+ }
+
+ // cut base_url to the last directory
+ if (strrpos($base_url, '/') > 7) {
+ $host_url = substr($base_url, 0, strpos($base_url, '/', 7));
+ $base_url = substr($base_url, 0, strrpos($base_url, '/'));
+ }
+
+ // $path is absolute
+ if ($path[0] == '/') {
+ $abs_path = $host_url.$path;
+ }
+ else {
+ // strip './' because its the same as ''
+ $path = preg_replace('/^\.\//', '', $path);
+
+ if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) {
+ foreach ($matches as $a_match) {
+ if (strrpos($base_url, '/')) {
+ $base_url = substr($base_url, 0, strrpos($base_url, '/'));
+ }
+ $path = substr($path, 3);
+ }
+ }
+
+ $abs_path = $base_url.'/'.$path;
+ }
+
+ return $abs_path;
+ }
+}
diff --git a/program/include/rcube_cache.php b/program/include/rcube_cache.php
index e5011854b..3e6bc0f32 100644
--- a/program/include/rcube_cache.php
+++ b/program/include/rcube_cache.php
@@ -66,7 +66,7 @@ class rcube_cache
*/
function __construct($type, $userid, $prefix='', $ttl=0, $packed=true)
{
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
$type = strtolower($type);
if ($type == 'memcache') {
@@ -197,7 +197,7 @@ class rcube_cache
{
if ($this->type == 'db' && $this->db) {
$this->db->query(
- "DELETE FROM ".get_table_name('cache').
+ "DELETE FROM ".$this->db->table_name('cache').
" WHERE user_id = ?".
" AND cache_key LIKE ?".
" AND " . $this->db->unixtimestamp('created')." < ?",
@@ -274,7 +274,7 @@ class rcube_cache
else {
$sql_result = $this->db->limitquery(
"SELECT cache_id, data, cache_key".
- " FROM ".get_table_name('cache').
+ " FROM ".$this->db->table_name('cache').
" WHERE user_id = ?".
" AND cache_key = ?".
// for better performance we allow more records for one key
@@ -330,7 +330,7 @@ class rcube_cache
// Remove NULL rows (here we don't need to check if the record exist)
if ($data == 'N;') {
$this->db->query(
- "DELETE FROM ".get_table_name('cache').
+ "DELETE FROM ".$this->db->table_name('cache').
" WHERE user_id = ?".
" AND cache_key = ?",
$this->userid, $key);
@@ -341,7 +341,7 @@ class rcube_cache
// update existing cache record
if ($key_exists) {
$result = $this->db->query(
- "UPDATE ".get_table_name('cache').
+ "UPDATE ".$this->db->table_name('cache').
" SET created = ". $this->db->now().", data = ?".
" WHERE user_id = ?".
" AND cache_key = ?",
@@ -352,7 +352,7 @@ class rcube_cache
// for better performance we allow more records for one key
// so, no need to check if record exist (see rcube_cache::read_record())
$result = $this->db->query(
- "INSERT INTO ".get_table_name('cache').
+ "INSERT INTO ".$this->db->table_name('cache').
" (created, user_id, cache_key, data)".
" VALUES (".$this->db->now().", ?, ?, ?)",
$this->userid, $key, $data);
@@ -416,7 +416,7 @@ class rcube_cache
}
$this->db->query(
- "DELETE FROM ".get_table_name('cache').
+ "DELETE FROM ".$this->db->table_name('cache').
" WHERE user_id = ?" . $where,
$this->userid);
}
diff --git a/program/include/rcube_config.php b/program/include/rcube_config.php
index 46906dde1..e14dcb85a 100644
--- a/program/include/rcube_config.php
+++ b/program/include/rcube_config.php
@@ -85,11 +85,11 @@ class rcube_config
// fix default imap folders encoding
foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
- $this->prop[$folder] = rcube_charset_convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP');
+ $this->prop[$folder] = rcube_charset::convert($this->prop[$folder], RCMAIL_CHARSET, 'UTF7-IMAP');
if (!empty($this->prop['default_folders']))
foreach ($this->prop['default_folders'] as $n => $folder)
- $this->prop['default_folders'][$n] = rcube_charset_convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
+ $this->prop['default_folders'][$n] = rcube_charset::convert($folder, RCMAIL_CHARSET, 'UTF7-IMAP');
// set PHP error logging according to config
if ($this->prop['debug_level'] & 1) {
@@ -186,7 +186,7 @@ class rcube_config
$result = $def;
}
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
if ($name == 'timezone' && isset($this->prop['_timezone_value']))
$result = $this->prop['_timezone_value'];
@@ -300,7 +300,7 @@ class rcube_config
{
// Bomb out if the requested key does not exist
if (!array_key_exists($key, $this->prop)) {
- raise_error(array(
+ rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Request for unconfigured crypto key \"$key\""
@@ -311,7 +311,7 @@ class rcube_config
// Bomb out if the configured key is not exactly 24 bytes long
if (strlen($key) != 24) {
- raise_error(array(
+ rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Configured crypto key '$key' is not exactly 24 bytes long"
@@ -335,7 +335,7 @@ class rcube_config
if ($delim == "\n" || $delim == "\r\n")
return $delim;
else
- raise_error(array(
+ rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Invalid mail_header_delimiter setting"
@@ -370,7 +370,7 @@ class rcube_config
$domain = $this->prop['mail_domain'][$host];
}
else if (!empty($this->prop['mail_domain']))
- $domain = rcube_parse_host($this->prop['mail_domain']);
+ $domain = rcmail::parse_host($this->prop['mail_domain']);
if ($encode)
$domain = rcube_idn_to_ascii($domain);
diff --git a/program/include/rcube_contacts.php b/program/include/rcube_contacts.php
index c30751faf..8834a7dbc 100644
--- a/program/include/rcube_contacts.php
+++ b/program/include/rcube_contacts.php
@@ -153,7 +153,7 @@ class rcube_contacts extends rcube_addressbook
$sql_filter = $search ? " AND " . $this->db->ilike('name', '%'.$search.'%') : '';
$sql_result = $this->db->query(
- "SELECT * FROM ".get_table_name($this->db_groups).
+ "SELECT * FROM ".$this->db->table_name($this->db_groups).
" WHERE del<>1".
" AND user_id=?".
$sql_filter.
@@ -178,7 +178,7 @@ class rcube_contacts extends rcube_addressbook
function get_group($group_id)
{
$sql_result = $this->db->query(
- "SELECT * FROM ".get_table_name($this->db_groups).
+ "SELECT * FROM ".$this->db->table_name($this->db_groups).
" WHERE del<>1".
" AND contactgroup_id=?".
" AND user_id=?",
@@ -214,7 +214,7 @@ class rcube_contacts extends rcube_addressbook
$length = $subset != 0 ? abs($subset) : $this->page_size;
if ($this->group_id)
- $join = " LEFT JOIN ".get_table_name($this->db_groupmembers)." AS m".
+ $join = " LEFT JOIN ".$this->db->table_name($this->db_groupmembers)." AS m".
" ON (m.contact_id = c.".$this->primary_key.")";
$order_col = (in_array($this->sort_col, $this->table_cols) ? $this->sort_col : 'name');
@@ -228,7 +228,7 @@ class rcube_contacts extends rcube_addressbook
$order_cols[] = 'c.email';
$sql_result = $this->db->limitquery(
- "SELECT * FROM ".get_table_name($this->db_name)." AS c" .
+ "SELECT * FROM ".$this->db->table_name($this->db_name)." AS c" .
$join .
" WHERE c.del<>1" .
" AND c.user_id=?" .
@@ -488,13 +488,13 @@ class rcube_contacts extends rcube_addressbook
private function _count()
{
if ($this->group_id)
- $join = " LEFT JOIN ".get_table_name($this->db_groupmembers)." AS m".
+ $join = " LEFT JOIN ".$this->db->table_name($this->db_groupmembers)." AS m".
" ON (m.contact_id=c.".$this->primary_key.")";
// count contacts for this user
$sql_result = $this->db->query(
"SELECT COUNT(c.contact_id) AS rows".
- " FROM ".get_table_name($this->db_name)." AS c".
+ " FROM ".$this->db->table_name($this->db_name)." AS c".
$join.
" WHERE c.del<>1".
" AND c.user_id=?".
@@ -536,7 +536,7 @@ class rcube_contacts extends rcube_addressbook
return $assoc ? $first : $this->result;
$this->db->query(
- "SELECT * FROM ".get_table_name($this->db_name).
+ "SELECT * FROM ".$this->db->table_name($this->db_name).
" WHERE contact_id=?".
" AND user_id=?".
" AND del<>1",
@@ -568,8 +568,8 @@ class rcube_contacts extends rcube_addressbook
return $results;
$sql_result = $this->db->query(
- "SELECT cgm.contactgroup_id, cg.name FROM " . get_table_name($this->db_groupmembers) . " AS cgm" .
- " LEFT JOIN " . get_table_name($this->db_groups) . " AS cg ON (cgm.contactgroup_id = cg.contactgroup_id AND cg.del<>1)" .
+ "SELECT cgm.contactgroup_id, cg.name FROM " . $this->db->table_name($this->db_groupmembers) . " AS cgm" .
+ " LEFT JOIN " . $this->db->table_name($this->db_groups) . " AS cg ON (cgm.contactgroup_id = cg.contactgroup_id AND cg.del<>1)" .
" WHERE cgm.contact_id=?",
$id
);
@@ -638,7 +638,7 @@ class rcube_contacts extends rcube_addressbook
if (!$existing->count && !empty($a_insert_cols)) {
$this->db->query(
- "INSERT INTO ".get_table_name($this->db_name).
+ "INSERT INTO ".$this->db->table_name($this->db_name).
" (user_id, changed, del, ".join(', ', $a_insert_cols).")".
" VALUES (".intval($this->user_id).", ".$this->db->now().", 0, ".join(', ', $a_insert_values).")"
);
@@ -676,7 +676,7 @@ class rcube_contacts extends rcube_addressbook
if (!empty($write_sql)) {
$this->db->query(
- "UPDATE ".get_table_name($this->db_name).
+ "UPDATE ".$this->db->table_name($this->db_name).
" SET changed=".$this->db->now().", ".join(', ', $write_sql).
" WHERE contact_id=?".
" AND user_id=?".
@@ -772,7 +772,7 @@ class rcube_contacts extends rcube_addressbook
// flag record as deleted (always)
$this->db->query(
- "UPDATE ".get_table_name($this->db_name).
+ "UPDATE ".$this->db->table_name($this->db_name).
" SET del=1, changed=".$this->db->now().
" WHERE user_id=?".
" AND contact_id IN ($ids)",
@@ -799,7 +799,7 @@ class rcube_contacts extends rcube_addressbook
// clear deleted flag
$this->db->query(
- "UPDATE ".get_table_name($this->db_name).
+ "UPDATE ".$this->db->table_name($this->db_name).
" SET del=0, changed=".$this->db->now().
" WHERE user_id=?".
" AND contact_id IN ($ids)",
@@ -819,7 +819,7 @@ class rcube_contacts extends rcube_addressbook
{
$this->cache = null;
- $this->db->query("UPDATE ".get_table_name($this->db_name).
+ $this->db->query("UPDATE ".$this->db->table_name($this->db_name).
" SET del=1, changed=".$this->db->now().
" WHERE user_id = ?", $this->user_id);
@@ -841,7 +841,7 @@ class rcube_contacts extends rcube_addressbook
$name = $this->unique_groupname($name);
$this->db->query(
- "INSERT INTO ".get_table_name($this->db_groups).
+ "INSERT INTO ".$this->db->table_name($this->db_groups).
" (user_id, changed, name)".
" VALUES (".intval($this->user_id).", ".$this->db->now().", ".$this->db->quote($name).")"
);
@@ -863,7 +863,7 @@ class rcube_contacts extends rcube_addressbook
{
// flag group record as deleted
$sql_result = $this->db->query(
- "UPDATE ".get_table_name($this->db_groups).
+ "UPDATE ".$this->db->table_name($this->db_groups).
" SET del=1, changed=".$this->db->now().
" WHERE contactgroup_id=?".
" AND user_id=?",
@@ -889,7 +889,7 @@ class rcube_contacts extends rcube_addressbook
$name = $this->unique_groupname($newname);
$sql_result = $this->db->query(
- "UPDATE ".get_table_name($this->db_groups).
+ "UPDATE ".$this->db->table_name($this->db_groups).
" SET name=?, changed=".$this->db->now().
" WHERE contactgroup_id=?".
" AND user_id=?",
@@ -917,7 +917,7 @@ class rcube_contacts extends rcube_addressbook
// get existing assignments ...
$sql_result = $this->db->query(
- "SELECT contact_id FROM ".get_table_name($this->db_groupmembers).
+ "SELECT contact_id FROM ".$this->db->table_name($this->db_groupmembers).
" WHERE contactgroup_id=?".
" AND contact_id IN (".$this->db->array2list($ids, 'integer').")",
$group_id
@@ -930,7 +930,7 @@ class rcube_contacts extends rcube_addressbook
foreach ($ids as $contact_id) {
$this->db->query(
- "INSERT INTO ".get_table_name($this->db_groupmembers).
+ "INSERT INTO ".$this->db->table_name($this->db_groupmembers).
" (contactgroup_id, contact_id, created)".
" VALUES (?, ?, ".$this->db->now().")",
$group_id,
@@ -960,7 +960,7 @@ class rcube_contacts extends rcube_addressbook
$ids = $this->db->array2list($ids, 'integer');
$sql_result = $this->db->query(
- "DELETE FROM ".get_table_name($this->db_groupmembers).
+ "DELETE FROM ".$this->db->table_name($this->db_groupmembers).
" WHERE contactgroup_id=?".
" AND contact_id IN ($ids)",
$group_id
@@ -983,7 +983,7 @@ class rcube_contacts extends rcube_addressbook
do {
$sql_result = $this->db->query(
- "SELECT 1 FROM ".get_table_name($this->db_groups).
+ "SELECT 1 FROM ".$this->db->table_name($this->db_groups).
" WHERE del<>1".
" AND user_id=?".
" AND name=?",
diff --git a/program/include/rcube_html_page.php b/program/include/rcube_html_page.php
deleted file mode 100644
index fffe49094..000000000
--- a/program/include/rcube_html_page.php
+++ /dev/null
@@ -1,323 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcube_html_page.php |
- | |
- | This file is part of the Roundcube PHP suite |
- | Copyright (C) 2005-2011 The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | CONTENTS: |
- | Class to build XHTML page output |
- | |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-
- $Id$
-
-*/
-
-/**
- * Class for HTML page creation
- *
- * @package HTML
- */
-class rcube_html_page
-{
- protected $scripts_path = '';
- protected $script_files = array();
- protected $css_files = array();
- protected $scripts = array();
- protected $charset = RCMAIL_CHARSET;
- protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
-
- protected $title = '';
- protected $header = '';
- protected $footer = '';
- protected $body = '';
- protected $base_path = '';
-
-
- /** Constructor */
- public function __construct() {}
-
- /**
- * Link an external script file
- *
- * @param string File URL
- * @param string Target position [head|foot]
- */
- public function include_script($file, $position='head')
- {
- static $sa_files = array();
-
- if (!preg_match('|^https?://|i', $file) && $file[0] != '/') {
- $file = $this->scripts_path . $file;
- if ($fs = @filemtime($file)) {
- $file .= '?s=' . $fs;
- }
- }
-
- if (in_array($file, $sa_files)) {
- return;
- }
-
- $sa_files[] = $file;
-
- if (!is_array($this->script_files[$position])) {
- $this->script_files[$position] = array();
- }
-
- $this->script_files[$position][] = $file;
- }
-
- /**
- * Add inline javascript code
- *
- * @param string JS code snippet
- * @param string Target position [head|head_top|foot]
- */
- public function add_script($script, $position='head')
- {
- if (!isset($this->scripts[$position])) {
- $this->scripts[$position] = "\n" . rtrim($script);
- }
- else {
- $this->scripts[$position] .= "\n" . rtrim($script);
- }
- }
-
- /**
- * Link an external css file
- *
- * @param string File URL
- */
- public function include_css($file)
- {
- $this->css_files[] = $file;
- }
-
- /**
- * Add HTML code to the page header
- *
- * @param string $str HTML code
- */
- public function add_header($str)
- {
- $this->header .= "\n" . $str;
- }
-
- /**
- * Add HTML code to the page footer
- * To be added right befor </body>
- *
- * @param string $str HTML code
- */
- public function add_footer($str)
- {
- $this->footer .= "\n" . $str;
- }
-
- /**
- * Setter for page title
- *
- * @param string $t Page title
- */
- public function set_title($t)
- {
- $this->title = $t;
- }
-
- /**
- * Setter for output charset.
- * To be specified in a meta tag and sent as http-header
- *
- * @param string $charset Charset
- */
- public function set_charset($charset)
- {
- $this->charset = $charset;
- }
-
- /**
- * Getter for output charset
- *
- * @return string Output charset
- */
- public function get_charset()
- {
- return $this->charset;
- }
-
- /**
- * Reset all saved properties
- */
- public function reset()
- {
- $this->script_files = array();
- $this->scripts = array();
- $this->title = '';
- $this->header = '';
- $this->footer = '';
- $this->body = '';
- }
-
- /**
- * Process template and write to stdOut
- *
- * @param string HTML template
- * @param string Base for absolute paths
- */
- public function write($templ='', $base_path='')
- {
- $output = empty($templ) ? $this->default_template : trim($templ);
-
- // set default page title
- if (empty($this->title)) {
- $this->title = 'Roundcube Mail';
- }
-
- // replace specialchars in content
- $page_title = Q($this->title, 'show', FALSE);
- $page_header = '';
- $page_footer = '';
-
- // include meta tag with charset
- if (!empty($this->charset)) {
- if (!headers_sent()) {
- header('Content-Type: text/html; charset=' . $this->charset);
- }
- $page_header = '<meta http-equiv="content-type"';
- $page_header.= ' content="text/html; charset=';
- $page_header.= $this->charset . '" />'."\n";
- }
-
- // definition of the code to be placed in the document header and footer
- if (is_array($this->script_files['head'])) {
- foreach ($this->script_files['head'] as $file) {
- $page_header .= html::script($file);
- }
- }
-
- $head_script = $this->scripts['head_top'] . $this->scripts['head'];
- if (!empty($head_script)) {
- $page_header .= html::script(array(), $head_script);
- }
-
- if (!empty($this->header)) {
- $page_header .= $this->header;
- }
-
- // put docready commands into page footer
- if (!empty($this->scripts['docready'])) {
- $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
- }
-
- if (is_array($this->script_files['foot'])) {
- foreach ($this->script_files['foot'] as $file) {
- $page_footer .= html::script($file);
- }
- }
-
- if (!empty($this->footer)) {
- $page_footer .= $this->footer . "\n";
- }
-
- if (!empty($this->scripts['foot'])) {
- $page_footer .= html::script(array(), $this->scripts['foot']);
- }
-
- // find page header
- if ($hpos = stripos($output, '</head>')) {
- $page_header .= "\n";
- }
- else {
- if (!is_numeric($hpos)) {
- $hpos = stripos($output, '<body');
- }
- if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
- while ($output[$hpos] != '>') {
- $hpos++;
- }
- $hpos++;
- }
- $page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
- }
-
- // add page hader
- if ($hpos) {
- $output = substr_replace($output, $page_header, $hpos, 0);
- }
- else {
- $output = $page_header . $output;
- }
-
- // add page footer
- if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
- $output = substr_replace($output, $page_footer."\n", $fpos, 0);
- }
- else {
- $output .= "\n".$page_footer;
- }
-
- // add css files in head, before scripts, for speed up with parallel downloads
- if (!empty($this->css_files) &&
- (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
- ) {
- $css = '';
- foreach ($this->css_files as $file) {
- $css .= html::tag('link', array('rel' => 'stylesheet',
- 'type' => 'text/css', 'href' => $file, 'nl' => true));
- }
- $output = substr_replace($output, $css, $pos, 0);
- }
-
- $this->base_path = $base_path;
-
- // correct absolute paths in images and other tags
- // add timestamp to .js and .css filename
- $output = preg_replace_callback(
- '!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
- array($this, 'file_callback'), $output);
-
- // trigger hook with final HTML content to be sent
- $hook = rcmail::get_instance()->plugins->exec_hook("send_page", array('content' => $output));
- if (!$hook['abort']) {
- if ($this->charset != RCMAIL_CHARSET) {
- echo rcube_charset_convert($hook['content'], RCMAIL_CHARSET, $this->charset);
- }
- else {
- echo $hook['content'];
- }
- }
- }
-
- /**
- * Callback function for preg_replace_callback in write()
- *
- * @return string Parsed string
- */
- private function file_callback($matches)
- {
- $file = $matches[3];
-
- // correct absolute paths
- if ($file[0] == '/') {
- $file = $this->base_path . $file;
- }
-
- // add file modification timestamp
- if (preg_match('/\.(js|css)$/', $file)) {
- if ($fs = @filemtime($file)) {
- $file .= '?s=' . $fs;
- }
- }
-
- return $matches[1] . '=' . $matches[2] . $file . $matches[4];
- }
-}
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index bd8f35176..966fc54b6 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -132,7 +132,7 @@ class rcube_imap extends rcube_storage
$this->options['ssl_mode'] = $use_ssl == 'imaps' ? 'ssl' : $use_ssl;
}
else if ($use_ssl) {
- raise_error(array('code' => 403, 'type' => 'imap',
+ rcube::raise_error(array('code' => 403, 'type' => 'imap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "OpenSSL not available"), true, false);
$port = 143;
@@ -154,7 +154,7 @@ class rcube_imap extends rcube_storage
$attempt = 0;
do {
- $data = rcmail::get_instance()->plugins->exec_hook('imap_connect',
+ $data = rcube::get_instance()->plugins->exec_hook('imap_connect',
array_merge($this->options, array('host' => $host, 'user' => $user,
'attempt' => ++$attempt)));
@@ -185,9 +185,9 @@ class rcube_imap extends rcube_storage
else if ($this->conn->error) {
if ($pass && $user) {
$message = sprintf("Login failed for %s from %s. %s",
- $user, rcmail_remote_ip(), $this->conn->error);
+ $user, rcmail::remote_ip(), $this->conn->error);
- raise_error(array('code' => 403, 'type' => 'imap',
+ rcube::raise_error(array('code' => 403, 'type' => 'imap',
'file' => __FILE__, 'line' => __LINE__,
'message' => $message), true, false);
}
@@ -457,7 +457,7 @@ class rcube_imap extends rcube_storage
return;
}
- $config = rcmail::get_instance()->config;
+ $config = rcube::get_instance()->config;
$imap_personal = $config->get('imap_ns_personal');
$imap_other = $config->get('imap_ns_other');
$imap_shared = $config->get('imap_ns_shared');
@@ -546,7 +546,7 @@ class rcube_imap extends rcube_storage
$folder = $this->folder;
}
- return $this->messagecount($folder, $mode, $force, $status);
+ return $this->countmessages($folder, $mode, $force, $status);
}
@@ -562,7 +562,7 @@ class rcube_imap extends rcube_storage
* @return int Number of messages
* @see rcube_imap::count()
*/
- protected function messagecount($folder, $mode='ALL', $force=false, $status=true)
+ protected function countmessages($folder, $mode='ALL', $force=false, $status=true)
{
$mode = strtoupper($mode);
@@ -834,8 +834,8 @@ class rcube_imap extends rcube_storage
* protected method for setting threaded messages flags:
* depth, has_children and unread_children
*
- * @param array $headers Reference to headers array indexed by message UID
- * @param rcube_imap_result $threads Threads data object
+ * @param array $headers Reference to headers array indexed by message UID
+ * @param rcube_result_thread $threads Threads data object
*
* @return array Message headers array indexed by message UID
*/
@@ -1048,7 +1048,7 @@ class rcube_imap extends rcube_storage
if ($sort) {
// use this class for message sorting
- $sorter = new rcube_header_sorter();
+ $sorter = new rcube_message_header_sorter();
$sorter->set_index($msgs);
$sorter->sort_headers($a_msg_headers);
}
@@ -1075,7 +1075,7 @@ class rcube_imap extends rcube_storage
$old = $this->get_folder_stats($folder);
// refresh message count -> will update
- $this->messagecount($folder, 'ALL', true);
+ $this->countmessages($folder, 'ALL', true);
$result = 0;
@@ -1456,7 +1456,7 @@ class rcube_imap extends rcube_storage
foreach ($matches[1] as $m) {
$string_offset = $m[1] + strlen($m[0]) + 4; // {}\r\n
$string = substr($str, $string_offset - 1, $m[0]);
- $string = rcube_charset_convert($string, $charset, $dest_charset);
+ $string = rcube_charset::convert($string, $charset, $dest_charset);
if ($string === false) {
continue;
}
@@ -1498,7 +1498,7 @@ class rcube_imap extends rcube_storage
* @param string $folder Folder to read from
* @param bool $force True to skip cache
*
- * @return rcube_mail_header Message headers
+ * @return rcube_message_header Message headers
*/
public function get_message_headers($uid, $folder = null, $force = false)
{
@@ -1529,7 +1529,7 @@ class rcube_imap extends rcube_storage
* @param int $uid Message UID to fetch
* @param string $folder Folder to read from
*
- * @return object rcube_mail_header Message data
+ * @return object rcube_message_header Message data
*/
public function get_message($uid, $folder = null)
{
@@ -1948,7 +1948,7 @@ class rcube_imap extends rcube_storage
$charset = $this->struct_charset;
}
else {
- $charset = rc_detect_encoding($filename_mime, $this->default_charset);
+ $charset = rcube_charset::detect($filename_mime, $this->default_charset);
}
$part->filename = rcube_mime::decode_mime_string($filename_mime, $charset);
@@ -1960,7 +1960,7 @@ class rcube_imap extends rcube_storage
$filename_encoded = $fmatches[2];
}
- $part->filename = rcube_charset_convert(urldecode($filename_encoded), $filename_charset);
+ $part->filename = rcube_charset::convert(urldecode($filename_encoded), $filename_charset);
}
}
@@ -2039,7 +2039,7 @@ class rcube_imap extends rcube_storage
$o_part->charset = $this->default_charset;
}
}
- $body = rcube_charset_convert($body, $o_part->charset);
+ $body = rcube_charset::convert($body, $o_part->charset);
}
}
@@ -2227,7 +2227,7 @@ class rcube_imap extends rcube_storage
}
}
- $config = rcmail::get_instance()->config;
+ $config = rcube::get_instance()->config;
$to_trash = $to_mbox == $config->get('trash_mbox');
// flag messages as read before moving them
@@ -2510,7 +2510,7 @@ class rcube_imap extends rcube_storage
$a_defaults = $a_out = array();
// Give plugins a chance to provide a list of folders
- $data = rcmail::get_instance()->plugins->exec_hook('storage_folders',
+ $data = rcube::get_instance()->plugins->exec_hook('storage_folders',
array('root' => $root, 'name' => $name, 'filter' => $filter, 'mode' => 'LSUB'));
if (isset($data['folders'])) {
@@ -2521,7 +2521,7 @@ class rcube_imap extends rcube_storage
}
else {
// Server supports LIST-EXTENDED, we can use selection options
- $config = rcmail::get_instance()->config;
+ $config = rcube::get_instance()->config;
// #1486225: Some dovecot versions returns wrong result using LIST-EXTENDED
if (!$config->get('imap_force_lsub') && $this->get_capability('LIST-EXTENDED')) {
// This will also set folder options, LSUB doesn't do that
@@ -3530,7 +3530,7 @@ class rcube_imap extends rcube_storage
protected function get_cache_engine()
{
if ($this->caching && !$this->cache) {
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
$ttl = $rcmail->config->get('message_cache_lifetime', '10d') - mktime();
$this->cache = $rcmail->get_cache('IMAP', $this->caching, $ttl);
}
@@ -3589,8 +3589,9 @@ class rcube_imap extends rcube_storage
$this->mcache->expunge($ttl);
}
- if ($this->cache)
+ if ($this->cache) {
$this->cache->expunge();
+ }
}
@@ -3624,10 +3625,10 @@ class rcube_imap extends rcube_storage
protected function get_mcache_engine()
{
if ($this->messages_caching && !$this->mcache) {
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
if ($dbh = $rcmail->get_dbh()) {
$this->mcache = new rcube_imap_cache(
- $dbh, $this, $rcmail->user->ID, $this->options['skip_deleted']);
+ $dbh, $this, $rcmail->get_user_id(), $this->options['skip_deleted']);
}
}
@@ -3691,7 +3692,7 @@ class rcube_imap extends rcube_storage
$a_defaults[$p] = $folder;
}
else {
- $folders[$folder] = rcube_charset_convert($folder, 'UTF7-IMAP');
+ $folders[$folder] = rcube_charset::convert($folder, 'UTF7-IMAP');
}
}
@@ -3851,7 +3852,7 @@ class rcube_imap extends rcube_storage
*/
public function debug_handler(&$imap, $message)
{
- write_log('imap', $message);
+ rcmail::write_log('imap', $message);
}
diff --git a/program/include/rcube_imap_cache.php b/program/include/rcube_imap_cache.php
index ee53dc25c..eaa8a805f 100644
--- a/program/include/rcube_imap_cache.php
+++ b/program/include/rcube_imap_cache.php
@@ -95,7 +95,7 @@ class rcube_imap_cache
{
$this->db = $db;
$this->imap = $imap;
- $this->userid = (int)$userid;
+ $this->userid = $userid;
$this->skip_deleted = $skip_deleted;
}
@@ -290,7 +290,7 @@ class rcube_imap_cache
* @param string $mailbox Folder name
* @param array $msgs Message UIDs
*
- * @return array The list of messages (rcube_mail_header) indexed by UID
+ * @return array The list of messages (rcube_message_header) indexed by UID
*/
function get_messages($mailbox, $msgs = array())
{
@@ -301,7 +301,7 @@ class rcube_imap_cache
// Fetch messages from cache
$sql_result = $this->db->query(
"SELECT uid, data, flags"
- ." FROM ".get_table_name('cache_messages')
+ ." FROM ".$this->db->table_name('cache_messages')
." WHERE user_id = ?"
." AND mailbox = ?"
." AND uid IN (".$this->db->array2list($msgs, 'integer').")",
@@ -348,7 +348,7 @@ class rcube_imap_cache
* from IMAP server
* @param bool $no_cache Enables internal cache usage
*
- * @return rcube_mail_header Message data
+ * @return rcube_message_header Message data
*/
function get_message($mailbox, $uid, $update = true, $cache = true)
{
@@ -362,7 +362,7 @@ class rcube_imap_cache
$sql_result = $this->db->query(
"SELECT flags, data"
- ." FROM ".get_table_name('cache_messages')
+ ." FROM ".$this->db->table_name('cache_messages')
." WHERE user_id = ?"
." AND mailbox = ?"
." AND uid = ?",
@@ -404,9 +404,9 @@ class rcube_imap_cache
/**
* Saves the message in cache.
*
- * @param string $mailbox Folder name
- * @param rcube_mail_header $message Message data
- * @param bool $force Skips message in-cache existance check
+ * @param string $mailbox Folder name
+ * @param rcube_message_header $message Message data
+ * @param bool $force Skips message in-cache existance check
*/
function add_message($mailbox, $message, $force = false)
{
@@ -430,7 +430,7 @@ class rcube_imap_cache
// here will work as select, assume row exist if affected_rows=0)
if (!$force) {
$res = $this->db->query(
- "UPDATE ".get_table_name('cache_messages')
+ "UPDATE ".$this->db->table_name('cache_messages')
." SET flags = ?, data = ?, changed = ".$this->db->now()
." WHERE user_id = ?"
." AND mailbox = ?"
@@ -444,7 +444,7 @@ class rcube_imap_cache
// insert new record
$this->db->query(
- "INSERT INTO ".get_table_name('cache_messages')
+ "INSERT INTO ".$this->db->table_name('cache_messages')
." (user_id, mailbox, uid, flags, changed, data)"
." VALUES (?, ?, ?, ?, ".$this->db->now().", ?)",
$this->userid, $mailbox, (int) $message->uid, $flags, $msg);
@@ -479,7 +479,7 @@ class rcube_imap_cache
}
$this->db->query(
- "UPDATE ".get_table_name('cache_messages')
+ "UPDATE ".$this->db->table_name('cache_messages')
." SET changed = ".$this->db->now()
.", flags = flags ".($enabled ? "+ $idx" : "- $idx")
." WHERE user_id = ?"
@@ -500,7 +500,7 @@ class rcube_imap_cache
{
if (!strlen($mailbox)) {
$this->db->query(
- "DELETE FROM ".get_table_name('cache_messages')
+ "DELETE FROM ".$this->db->table_name('cache_messages')
." WHERE user_id = ?",
$this->userid);
}
@@ -513,11 +513,11 @@ class rcube_imap_cache
}
$this->db->query(
- "DELETE FROM ".get_table_name('cache_messages')
+ "DELETE FROM ".$this->db->table_name('cache_messages')
." WHERE user_id = ?"
- ." AND mailbox = ".$this->db->quote($mailbox)
+ ." AND mailbox = ?"
.($uids !== null ? " AND uid IN (".$this->db->array2list((array)$uids, 'integer').")" : ""),
- $this->userid);
+ $this->userid, $mailbox);
}
}
@@ -536,17 +536,19 @@ class rcube_imap_cache
// otherwise use 'valid' flag to not loose HIGHESTMODSEQ value
if ($remove) {
$this->db->query(
- "DELETE FROM ".get_table_name('cache_index')
- ." WHERE user_id = ".intval($this->userid)
- .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "")
+ "DELETE FROM ".$this->db->table_name('cache_index')
+ ." WHERE user_id = ?"
+ .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""),
+ $this->userid
);
}
else {
$this->db->query(
- "UPDATE ".get_table_name('cache_index')
+ "UPDATE ".$this->db->table_name('cache_index')
." SET valid = 0"
- ." WHERE user_id = ".intval($this->userid)
- .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "")
+ ." WHERE user_id = ?"
+ .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""),
+ $this->userid
);
}
@@ -569,9 +571,10 @@ class rcube_imap_cache
function remove_thread($mailbox = null)
{
$this->db->query(
- "DELETE FROM ".get_table_name('cache_thread')
- ." WHERE user_id = ".intval($this->userid)
- .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : "")
+ "DELETE FROM ".$this->db->table_name('cache_thread')
+ ." WHERE user_id = ?"
+ .(strlen($mailbox) ? " AND mailbox = ".$this->db->quote($mailbox) : ""),
+ $this->userid
);
if (strlen($mailbox)) {
@@ -628,7 +631,7 @@ class rcube_imap_cache
// Get index from DB
$sql_result = $this->db->query(
"SELECT data, valid"
- ." FROM ".get_table_name('cache_index')
+ ." FROM ".$this->db->table_name('cache_index')
." WHERE user_id = ?"
." AND mailbox = ?",
$this->userid, $mailbox);
@@ -665,7 +668,7 @@ class rcube_imap_cache
// Get thread from DB
$sql_result = $this->db->query(
"SELECT data"
- ." FROM ".get_table_name('cache_thread')
+ ." FROM ".$this->db->table_name('cache_thread')
." WHERE user_id = ?"
." AND mailbox = ?",
$this->userid, $mailbox);
@@ -709,7 +712,7 @@ class rcube_imap_cache
if ($exists) {
$sql_result = $this->db->query(
- "UPDATE ".get_table_name('cache_index')
+ "UPDATE ".$this->db->table_name('cache_index')
." SET data = ?, valid = 1, changed = ".$this->db->now()
." WHERE user_id = ?"
." AND mailbox = ?",
@@ -717,7 +720,7 @@ class rcube_imap_cache
}
else {
$sql_result = $this->db->query(
- "INSERT INTO ".get_table_name('cache_index')
+ "INSERT INTO ".$this->db->table_name('cache_index')
." (user_id, mailbox, data, valid, changed)"
." VALUES (?, ?, ?, 1, ".$this->db->now().")",
$this->userid, $mailbox, $data);
@@ -740,7 +743,7 @@ class rcube_imap_cache
if ($exists) {
$sql_result = $this->db->query(
- "UPDATE ".get_table_name('cache_thread')
+ "UPDATE ".$this->db->table_name('cache_thread')
." SET data = ?, changed = ".$this->db->now()
." WHERE user_id = ?"
." AND mailbox = ?",
@@ -748,7 +751,7 @@ class rcube_imap_cache
}
else {
$sql_result = $this->db->query(
- "INSERT INTO ".get_table_name('cache_thread')
+ "INSERT INTO ".$this->db->table_name('cache_thread')
." (user_id, mailbox, data, changed)"
." VALUES (?, ?, ?, ".$this->db->now().")",
$this->userid, $mailbox, $data);
@@ -956,7 +959,7 @@ class rcube_imap_cache
$uids = array();
$sql_result = $this->db->query(
"SELECT uid"
- ." FROM ".get_table_name('cache_messages')
+ ." FROM ".$this->db->table_name('cache_messages')
." WHERE user_id = ?"
." AND mailbox = ?",
$this->userid, $mailbox);
@@ -1003,7 +1006,7 @@ class rcube_imap_cache
}
$this->db->query(
- "UPDATE ".get_table_name('cache_messages')
+ "UPDATE ".$this->db->table_name('cache_messages')
." SET flags = ?, changed = ".$this->db->now()
." WHERE user_id = ?"
." AND mailbox = ?"
@@ -1058,7 +1061,7 @@ class rcube_imap_cache
*
* @param array $sql_arr Message row data
*
- * @return rcube_mail_header Message object
+ * @return rcube_message_header Message object
*/
private function build_message($sql_arr)
{
diff --git a/program/include/rcube_imap_generic.php b/program/include/rcube_imap_generic.php
index a664c5b57..fb2ded1d3 100644
--- a/program/include/rcube_imap_generic.php
+++ b/program/include/rcube_imap_generic.php
@@ -29,42 +29,9 @@
*/
-/**
- * Struct representing an e-mail message header
- *
- * @package Mail
- * @author Aleksander Machniak <alec@alec.pl>
- */
-class rcube_mail_header
-{
- public $id;
- public $uid;
- public $subject;
- public $from;
- public $to;
- public $cc;
- public $replyto;
- public $in_reply_to;
- public $date;
- public $messageID;
- public $size;
- public $encoding;
- public $charset;
- public $ctype;
- public $timestamp;
- public $bodystructure;
- public $internaldate;
- public $references;
- public $priority;
- public $mdn_to;
- public $others = array();
- public $flags = array();
-}
+// for backward copat.
+class rcube_mail_header extends rcube_message_header { }
-// For backward compatibility with cached messages (#1486602)
-class iilBasicHeader extends rcube_mail_header
-{
-}
/**
* PHP based wrapper class to connect to an IMAP server
@@ -1545,8 +1512,6 @@ class rcube_imap_generic
*/
function sort($mailbox, $field, $add='', $return_uid=false, $encoding = 'US-ASCII')
{
- require_once dirname(__FILE__) . '/rcube_result_index.php';
-
$field = strtoupper($field);
if ($field == 'INTERNALDATE') {
$field = 'ARRIVAL';
@@ -1595,8 +1560,6 @@ class rcube_imap_generic
*/
function thread($mailbox, $algorithm='REFERENCES', $criteria='', $return_uid=false, $encoding='US-ASCII')
{
- require_once dirname(__FILE__) . '/rcube_result_thread.php';
-
$old_sel = $this->selected;
if (!$this->select($mailbox)) {
@@ -1635,8 +1598,6 @@ class rcube_imap_generic
*/
function search($mailbox, $criteria, $return_uid=false, $items=array())
{
- require_once dirname(__FILE__) . '/rcube_result_index.php';
-
$old_sel = $this->selected;
if (!$this->select($mailbox)) {
@@ -1696,8 +1657,6 @@ class rcube_imap_generic
function index($mailbox, $message_set, $index_field='', $skip_deleted=true,
$uidfetch=false, $return_uid=false)
{
- require_once dirname(__FILE__) . '/rcube_result_index.php';
-
$msg_index = $this->fetchHeaderIndex($mailbox, $message_set,
$index_field, $skip_deleted, $uidfetch, $return_uid);
@@ -2034,7 +1993,7 @@ class rcube_imap_generic
* @param string $mod_seq Modification sequence for CHANGEDSINCE (RFC4551) query
* @param bool $vanished Enables VANISHED parameter (RFC5162) for CHANGEDSINCE query
*
- * @return array List of rcube_mail_header elements, False on error
+ * @return array List of rcube_message_header elements, False on error
* @since 0.6
*/
function fetch($mailbox, $message_set, $is_uid = false, $query_items = array(),
@@ -2074,7 +2033,7 @@ class rcube_imap_generic
if (preg_match('/^\* ([0-9]+) FETCH/', $line, $m)) {
$id = intval($m[1]);
- $result[$id] = new rcube_mail_header;
+ $result[$id] = new rcube_message_header;
$result[$id]->id = $id;
$result[$id]->subject = '';
$result[$id]->messageID = 'mid:' . $id;
diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php
index 08b7cd99c..545fef9a5 100644
--- a/program/include/rcube_ldap.php
+++ b/program/include/rcube_ldap.php
@@ -63,12 +63,11 @@ class rcube_ldap extends rcube_addressbook
/**
* Object constructor
*
- * @param array LDAP connection properties
- * @param boolean Enables debug mode
- * @param string Current user mail domain name
- * @param integer User-ID
+ * @param array $p LDAP connection properties
+ * @param boolean $debug Enables debug mode
+ * @param string $mail_domain Current user mail domain name
*/
- function __construct($p, $debug=false, $mail_domain=NULL)
+ function __construct($p, $debug = false, $mail_domain = null)
{
$this->prop = $p;
@@ -176,10 +175,10 @@ class rcube_ldap extends rcube_addressbook
*/
private function _connect()
{
- global $RCMAIL;
+ $RCMAIL = rcmail::get_instance();
if (!function_exists('ldap_connect'))
- raise_error(array('code' => 100, 'type' => 'ldap',
+ rcube::raise_error(array('code' => 100, 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "No ldap support in this installation of PHP"),
true, true);
@@ -195,7 +194,7 @@ class rcube_ldap extends rcube_addressbook
foreach ($this->prop['hosts'] as $host)
{
- $host = idn_to_ascii(rcube_parse_host($host));
+ $host = idn_to_ascii(rcmail::parse_host($host));
$hostname = $host.($this->prop['port'] ? ':'.$this->prop['port'] : '');
$this->_debug("C: Connect [$hostname] [{$this->prop['name']}]");
@@ -225,7 +224,7 @@ class rcube_ldap extends rcube_addressbook
}
if (!is_resource($this->conn)) {
- raise_error(array('code' => 100, 'type' => 'ldap',
+ rcube::raise_error(array('code' => 100, 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Could not connect to any LDAP server, last tried $hostname"), true);
@@ -248,7 +247,7 @@ class rcube_ldap extends rcube_addressbook
}
// Get the pieces needed for variable replacement.
- if ($fu = $RCMAIL->user->get_username())
+ if ($fu = $RCMAIL->get_user_name())
list($u, $d) = explode('@', $fu);
else
$d = $this->mail_domain;
@@ -287,7 +286,7 @@ class rcube_ldap extends rcube_addressbook
if (!empty($this->prop['search_dn_default']))
$replaces['%dn'] = $this->prop['search_dn_default'];
else {
- raise_error(array(
+ rcube::raise_error(array(
'code' => 100, 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "DN not found using LDAP search."), true);
@@ -341,7 +340,7 @@ class rcube_ldap extends rcube_addressbook
}
if (!function_exists('ldap_sasl_bind')) {
- raise_error(array('code' => 100, 'type' => 'ldap',
+ rcube::raise_error(array('code' => 100, 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Unable to bind: ldap_sasl_bind() not exists"),
true, true);
@@ -367,7 +366,7 @@ class rcube_ldap extends rcube_addressbook
$this->_debug("S: ".ldap_error($this->conn));
- raise_error(array(
+ rcube::raise_error(array(
'code' => ldap_errno($this->conn), 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Bind failed for authcid=$authc ".ldap_error($this->conn)),
@@ -400,7 +399,7 @@ class rcube_ldap extends rcube_addressbook
$this->_debug("S: ".ldap_error($this->conn));
- raise_error(array(
+ rcube::raise_error(array(
'code' => ldap_errno($this->conn), 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Bind failed for dn=$dn: ".ldap_error($this->conn)),
@@ -1562,8 +1561,9 @@ class rcube_ldap extends rcube_addressbook
*/
private function _debug($str)
{
- if ($this->debug)
- write_log('ldap', $str);
+ if ($this->debug) {
+ rcmail::write_log('ldap', $str);
+ }
}
diff --git a/program/include/rcube_mdb2.php b/program/include/rcube_mdb2.php
index c103f9a61..0139bdc65 100644
--- a/program/include/rcube_mdb2.php
+++ b/program/include/rcube_mdb2.php
@@ -59,10 +59,11 @@ class rcube_mdb2
* @param string $db_dsnw DSN for read/write operations
* @param string $db_dsnr Optional DSN for read only operations
*/
- function __construct($db_dsnw, $db_dsnr='', $pconn=false)
+ public function __construct($db_dsnw, $db_dsnr='', $pconn=false)
{
- if (empty($db_dsnr))
+ if (empty($db_dsnr)) {
$db_dsnr = $db_dsnw;
+ }
$this->db_dsnw = $db_dsnw;
$this->db_dsnr = $db_dsnr;
@@ -88,7 +89,8 @@ class rcube_mdb2
'emulate_prepared' => $this->debug_mode,
'debug' => $this->debug_mode,
'debug_handler' => array($this, 'debug_handler'),
- 'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL);
+ 'portability' => MDB2_PORTABILITY_ALL ^ MDB2_PORTABILITY_EMPTY_TO_NULL,
+ );
if ($this->db_provider == 'pgsql') {
$db_options['disable_smart_seqname'] = true;
@@ -103,17 +105,19 @@ class rcube_mdb2
$this->db_error = true;
$this->db_error_msg = $dbh->getMessage();
- raise_error(array('code' => 500, 'type' => 'db',
+ rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $dbh->getUserInfo()), true, false);
}
else if ($this->db_provider == 'sqlite') {
$dsn_array = MDB2::parseDSN($dsn);
- if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials))
- $this->_sqlite_create_database($dbh, $this->sqlite_initials);
+ if (!filesize($dsn_array['database']) && !empty($this->sqlite_initials)) {
+ $this->sqlite_create_database($dbh, $this->sqlite_initials);
+ }
}
- else if ($this->db_provider!='mssql' && $this->db_provider!='sqlsrv')
+ else if ($this->db_provider != 'mssql' && $this->db_provider != 'sqlsrv') {
$dbh->setCharset('utf8');
+ }
return $dbh;
}
@@ -123,9 +127,8 @@ class rcube_mdb2
* Connect to appropiate database depending on the operation
*
* @param string $mode Connection mode (r|w)
- * @access public
*/
- function db_connect($mode)
+ public function db_connect($mode)
{
// previous connection failed, don't attempt to connect again
if ($this->conn_failure) {
@@ -157,10 +160,12 @@ class rcube_mdb2
$this->db_connected = !PEAR::isError($this->db_handle);
}
- if ($this->db_connected)
+ if ($this->db_connected) {
$this->db_mode = $mode;
- else
+ }
+ else {
$this->conn_failure = true;
+ }
}
@@ -168,9 +173,8 @@ class rcube_mdb2
* Activate/deactivate debug mode
*
* @param boolean $dbg True if SQL queries should be logged
- * @access public
*/
- function set_debug($dbg = true)
+ public function set_debug($dbg = true)
{
$this->debug_mode = $dbg;
if ($this->db_connected) {
@@ -184,9 +188,8 @@ class rcube_mdb2
* Getter for error state
*
* @param boolean True on error
- * @access public
*/
- function is_error()
+ public function is_error()
{
return $this->db_error ? $this->db_error_msg : false;
}
@@ -196,9 +199,8 @@ class rcube_mdb2
* Connection state checker
*
* @param boolean True if in connected state
- * @access public
*/
- function is_connected()
+ public function is_connected()
{
return PEAR::isError($this->db_handle) ? false : $this->db_connected;
}
@@ -208,7 +210,7 @@ class rcube_mdb2
* Is database replication configured?
* This returns true if dsnw != dsnr
*/
- function is_replicated()
+ public function is_replicated()
{
return !empty($this->db_dsnr) && $this->db_dsnw != $this->db_dsnr;
}
@@ -219,17 +221,18 @@ class rcube_mdb2
*
* @param string SQL query to execute
* @param mixed Values to be inserted in query
+ *
* @return number Query handle identifier
- * @access public
*/
- function query()
+ public function query()
{
$params = func_get_args();
$query = array_shift($params);
// Support one argument of type array, instead of n arguments
- if (count($params) == 1 && is_array($params[0]))
+ if (count($params) == 1 && is_array($params[0])) {
$params = $params[0];
+ }
return $this->_query($query, 0, 0, $params);
}
@@ -242,10 +245,10 @@ class rcube_mdb2
* @param number Offset for LIMIT statement
* @param number Number of rows for LIMIT statement
* @param mixed Values to be inserted in query
+ *
* @return number Query handle identifier
- * @access public
*/
- function limitquery()
+ public function limitquery()
{
$params = func_get_args();
$query = array_shift($params);
@@ -274,17 +277,21 @@ class rcube_mdb2
$this->db_connect($mode);
// check connection before proceeding
- if (!$this->is_connected())
+ if (!$this->is_connected()) {
return null;
+ }
- if ($this->db_provider == 'sqlite')
- $this->_sqlite_prepare();
+ if ($this->db_provider == 'sqlite') {
+ $this->sqlite_prepare();
+ }
- if ($numrows || $offset)
+ if ($numrows || $offset) {
$result = $this->db_handle->setLimit($numrows,$offset);
+ }
- if (empty($params))
+ if (empty($params)) {
$result = $mode == 'r' ? $this->db_handle->query($query) : $this->db_handle->exec($query);
+ }
else {
$params = (array)$params;
$q = $this->db_handle->prepare($query, null, $mode=='w' ? MDB2_PREPARE_MANIP : null);
@@ -292,7 +299,7 @@ class rcube_mdb2
$this->db_error = true;
$this->db_error_msg = $q->userinfo;
- raise_error(array('code' => 500, 'type' => 'db',
+ rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $this->db_error_msg), true, false);
@@ -315,17 +322,18 @@ class rcube_mdb2
*
* @param number $res_id Optional query handle identifier
* @return mixed Number of rows or false on failure
- * @access public
*/
- function num_rows($res_id=null)
+ public function num_rows($res_id=null)
{
- if (!$this->db_connected)
+ if (!$this->db_connected) {
return false;
+ }
- if ($result = $this->_get_result($res_id))
+ if ($result = $this->_get_result($res_id)) {
return $result->numRows();
- else
- return false;
+ }
+
+ return false;
}
@@ -334,12 +342,12 @@ class rcube_mdb2
*
* @param number $res_id Optional query handle identifier
* @return mixed Number of rows or false on failure
- * @access public
*/
- function affected_rows($res_id = null)
+ public function affected_rows($res_id = null)
{
- if (!$this->db_connected)
+ if (!$this->db_connected) {
return false;
+ }
return $this->_get_result($res_id);
}
@@ -350,21 +358,24 @@ class rcube_mdb2
* For Postgres databases, a sequence name is required
*
* @param string $table Table name (to find the incremented sequence)
+ *
* @return mixed ID or false on failure
- * @access public
*/
- function insert_id($table = '')
+ public function insert_id($table = '')
{
- if (!$this->db_connected || $this->db_mode == 'r')
+ if (!$this->db_connected || $this->db_mode == 'r') {
return false;
+ }
if ($table) {
- if ($this->db_provider == 'pgsql')
+ if ($this->db_provider == 'pgsql') {
// find sequence name
- $table = get_sequence_name($table);
- else
+ $table = $this->sequence_name($table);
+ }
+ else {
// resolve table name
- $table = get_table_name($table);
+ $table = $this->table_name($table);
+ }
}
$id = $this->db_handle->lastInsertID($table);
@@ -378,10 +389,10 @@ class rcube_mdb2
* If no query handle is specified, the last query will be taken as reference
*
* @param number $res_id Optional query handle identifier
+ *
* @return mixed Array with col values or false on failure
- * @access public
*/
- function fetch_assoc($res_id=null)
+ public function fetch_assoc($res_id = null)
{
$result = $this->_get_result($res_id);
return $this->_fetch_row($result, MDB2_FETCHMODE_ASSOC);
@@ -393,10 +404,10 @@ class rcube_mdb2
* If no query handle is specified, the last query will be taken as reference
*
* @param number $res_id Optional query handle identifier
+ *
* @return mixed Array with col values or false on failure
- * @access public
*/
- function fetch_array($res_id=null)
+ public function fetch_array($res_id = null)
{
$result = $this->_get_result($res_id);
return $this->_fetch_row($result, MDB2_FETCHMODE_ORDERED);
@@ -408,13 +419,14 @@ class rcube_mdb2
*
* @param MDB2_Result_Common Query $result result handle
* @param number $mode Fetch mode identifier
- * @return mixed Array with col values or false on failure
- * @access private
+ *
+ * @return mixed Array with col values or false on failure
*/
private function _fetch_row($result, $mode)
{
- if ($result === false || PEAR::isError($result) || !$this->is_connected())
+ if ($result === false || PEAR::isError($result) || !$this->is_connected()) {
return false;
+ }
return $result->fetchRow($mode);
}
@@ -424,18 +436,19 @@ class rcube_mdb2
* Wrapper for the SHOW TABLES command
*
* @return array List of all tables of the current database
- * @access public
* @since 0.4-beta
*/
- function list_tables()
+ public function list_tables()
{
// get tables if not cached
if (!$this->tables) {
$this->db_handle->loadModule('Manager');
- if (!PEAR::isError($result = $this->db_handle->listTables()))
+ if (!PEAR::isError($result = $this->db_handle->listTables())) {
$this->tables = $result;
- else
+ }
+ else {
$this->tables = array();
+ }
}
return $this->tables;
@@ -446,9 +459,10 @@ class rcube_mdb2
* Wrapper for SHOW COLUMNS command
*
* @param string Table name
+ *
* @return array List of table cols
*/
- function list_cols($table)
+ public function list_cols($table)
{
$this->db_handle->loadModule('Manager');
if (!PEAR::isError($result = $this->db_handle->listTableFields($table))) {
@@ -464,18 +478,20 @@ class rcube_mdb2
*
* @param mixed $input Value to quote
* @param string $type Type of data
+ *
* @return string Quoted/converted string for use in query
- * @access public
*/
- function quote($input, $type = null)
+ public function quote($input, $type = null)
{
// handle int directly for better performance
- if ($type == 'integer')
+ if ($type == 'integer') {
return intval($input);
+ }
// create DB handle if not available
- if (!$this->db_handle)
+ if (!$this->db_handle) {
$this->db_connect('r');
+ }
return $this->db_connected ? $this->db_handle->quote($input, $type) : addslashes($input);
}
@@ -485,12 +501,12 @@ class rcube_mdb2
* Quotes a string so it can be safely used as a table or column name
*
* @param string $str Value to quote
+ *
* @return string Quoted string for use in query
* @deprecated Replaced by rcube_MDB2::quote_identifier
* @see rcube_mdb2::quote_identifier
- * @access public
*/
- function quoteIdentifier($str)
+ public function quoteIdentifier($str)
{
return $this->quote_identifier($str);
}
@@ -500,13 +516,14 @@ class rcube_mdb2
* Quotes a string so it can be safely used as a table or column name
*
* @param string $str Value to quote
+ *
* @return string Quoted string for use in query
- * @access public
*/
- function quote_identifier($str)
+ public function quote_identifier($str)
{
- if (!$this->db_handle)
+ if (!$this->db_handle) {
$this->db_connect('r');
+ }
return $this->db_connected ? $this->db_handle->quoteIdentifier($str) : $str;
}
@@ -516,14 +533,15 @@ class rcube_mdb2
* Escapes a string
*
* @param string $str The string to be escaped
+ *
* @return string The escaped string
- * @access public
* @since 0.1.1
*/
- function escapeSimple($str)
+ public function escapeSimple($str)
{
- if (!$this->db_handle)
+ if (!$this->db_handle) {
$this->db_connect('r');
+ }
return $this->db_handle->escape($str);
}
@@ -533,9 +551,8 @@ class rcube_mdb2
* Return SQL function for current time and date
*
* @return string SQL function to use in query
- * @access public
*/
- function now()
+ public function now()
{
switch ($this->db_provider) {
case 'mssql':
@@ -553,16 +570,18 @@ class rcube_mdb2
*
* @param array $arr Input array
* @param string $type Type of data
+ *
* @return string Comma-separated list of quoted values for use in query
- * @access public
*/
- function array2list($arr, $type = null)
+ public function array2list($arr, $type = null)
{
- if (!is_array($arr))
+ if (!is_array($arr)) {
return $this->quote($arr, $type);
+ }
- foreach ($arr as $idx => $item)
+ foreach ($arr as $idx => $item) {
$arr[$idx] = $this->quote($item, $type);
+ }
return implode(',', $arr);
}
@@ -575,10 +594,11 @@ class rcube_mdb2
* of timestamp functions in Mysql (year 2038 problem)
*
* @param string $field Field name
+ *
* @return string SQL statement to use in query
* @deprecated
*/
- function unixtimestamp($field)
+ public function unixtimestamp($field)
{
switch($this->db_provider) {
case 'pgsql':
@@ -598,10 +618,10 @@ class rcube_mdb2
* Return SQL statement to convert from a unix timestamp
*
* @param string $timestamp Field name
+ *
* @return string SQL statement to use in query
- * @access public
*/
- function fromunixtime($timestamp)
+ public function fromunixtime($timestamp)
{
return date("'Y-m-d H:i:s'", $timestamp);
}
@@ -612,13 +632,13 @@ class rcube_mdb2
*
* @param string $column Field name
* @param string $value Search value
+ *
* @return string SQL statement to use in query
- * @access public
*/
- function ilike($column, $value)
+ public function ilike($column, $value)
{
// TODO: use MDB2's matchPattern() function
- switch($this->db_provider) {
+ switch ($this->db_provider) {
case 'pgsql':
return $this->quote_identifier($column).' ILIKE '.$this->quote($value);
default:
@@ -626,20 +646,20 @@ class rcube_mdb2
}
}
+
/**
* Abstract SQL statement for value concatenation
*
* @return string SQL statement to be used in query
- * @access public
*/
- function concat(/* col1, col2, ... */)
+ public function concat(/* col1, col2, ... */)
{
$func = '';
$args = func_get_args();
if (is_array($args[0]))
$args = $args[0];
- switch($this->db_provider) {
+ switch ($this->db_provider) {
case 'mysql':
case 'mysqli':
$func = 'CONCAT';
@@ -661,20 +681,22 @@ class rcube_mdb2
* Encodes non-UTF-8 characters in string/array/object (recursive)
*
* @param mixed $input Data to fix
+ *
* @return mixed Properly UTF-8 encoded data
- * @access public
*/
- function encode($input)
+ public static function encode($input)
{
if (is_object($input)) {
- foreach (get_object_vars($input) as $idx => $value)
- $input->$idx = $this->encode($value);
+ foreach (get_object_vars($input) as $idx => $value) {
+ $input->$idx = self::encode($value);
+ }
return $input;
}
else if (is_array($input)) {
- foreach ($input as $idx => $value)
- $input[$idx] = $this->encode($value);
- return $input;
+ foreach ($input as $idx => $value) {
+ $input[$idx] = self::encode($value);
+ }
+ return $input;
}
return utf8_encode($input);
@@ -685,20 +707,22 @@ class rcube_mdb2
* Decodes encoded UTF-8 string/object/array (recursive)
*
* @param mixed $input Input data
+ *
* @return mixed Decoded data
- * @access public
*/
- function decode($input)
+ public static function decode($input)
{
if (is_object($input)) {
- foreach (get_object_vars($input) as $idx => $value)
- $input->$idx = $this->decode($value);
+ foreach (get_object_vars($input) as $idx => $value) {
+ $input->$idx = self::decode($value);
+ }
return $input;
}
else if (is_array($input)) {
- foreach ($input as $idx => $value)
- $input[$idx] = $this->decode($value);
- return $input;
+ foreach ($input as $idx => $value) {
+ $input[$idx] = self::decode($value);
+ }
+ return $input;
}
return utf8_decode($input);
@@ -709,8 +733,8 @@ class rcube_mdb2
* Adds a query result and returns a handle ID
*
* @param object $res Query handle
+ *
* @return mixed Handle ID
- * @access private
*/
private function _add_result($res)
{
@@ -718,7 +742,7 @@ class rcube_mdb2
if (PEAR::isError($res)) {
$this->db_error = true;
$this->db_error_msg = $res->getMessage();
- raise_error(array('code' => 500, 'type' => 'db',
+ rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => $res->getMessage() . " Query: "
. substr(preg_replace('/[\r\n]+\s*/', ' ', $res->userinfo), 0, 512)),
@@ -737,17 +761,20 @@ class rcube_mdb2
* If no ID is specified, the last resource handle will be returned
*
* @param number $res_id Handle ID
+ *
* @return mixed Resource handle or false on failure
- * @access private
*/
private function _get_result($res_id = null)
{
- if ($res_id == null)
+ if ($res_id == null) {
$res_id = $this->last_res_id;
+ }
- if (isset($this->a_query_results[$res_id]))
- if (!PEAR::isError($this->a_query_results[$res_id]))
+ if (isset($this->a_query_results[$res_id])) {
+ if (!PEAR::isError($this->a_query_results[$res_id])) {
return $this->a_query_results[$res_id];
+ }
+ }
return false;
}
@@ -758,42 +785,36 @@ class rcube_mdb2
*
* @param MDB2 $dbh SQLite database handle
* @param string $file_name File path to use for DB creation
- * @access private
*/
- private function _sqlite_create_database($dbh, $file_name)
+ private function sqlite_create_database($dbh, $file_name)
{
- if (empty($file_name) || !is_string($file_name))
+ if (empty($file_name) || !is_string($file_name)) {
return;
+ }
$data = file_get_contents($file_name);
- if (strlen($data))
- if (!sqlite_exec($dbh->connection, $data, $error) || MDB2::isError($dbh))
- raise_error(array('code' => 500, 'type' => 'db',
+ if (strlen($data)) {
+ if (!sqlite_exec($dbh->connection, $data, $error) || MDB2::isError($dbh)) {
+ rcube::raise_error(array('code' => 500, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
- 'message' => $error), true, false);
+ 'message' => $error), true, false);
+ }
+ }
}
/**
* Add some proprietary database functions to the current SQLite handle
* in order to make it MySQL compatible
- *
- * @access private
*/
- private function _sqlite_prepare()
+ private function sqlite_prepare()
{
- include_once(INSTALL_PATH . 'program/include/rcube_sqlite.inc');
-
- // we emulate via callback some missing MySQL function
- sqlite_create_function($this->db_handle->connection,
- 'from_unixtime', 'rcube_sqlite_from_unixtime');
+ // we emulate via callback some missing MySQL functions
sqlite_create_function($this->db_handle->connection,
- 'unix_timestamp', 'rcube_sqlite_unix_timestamp');
+ 'unix_timestamp', array('rcube_mdb2', 'sqlite_unix_timestamp'));
sqlite_create_function($this->db_handle->connection,
- 'now', 'rcube_sqlite_now');
- sqlite_create_function($this->db_handle->connection,
- 'md5', 'rcube_sqlite_md5');
+ 'now', array('rcube_mdb2', 'sqlite_now'));
}
@@ -805,8 +826,82 @@ class rcube_mdb2
if ($scope != 'prepare') {
$debug_output = sprintf('%s(%d): %s;',
$scope, $db->db_index, rtrim($message, ';'));
- write_log('sql', $debug_output);
+ rcmail::write_log('sql', $debug_output);
}
}
-} // end class rcube_db
+
+ /**
+ * Return correct name for a specific database table
+ *
+ * @param string $table Table name
+ *
+ * @return string Translated table name
+ */
+ public function table_name($table)
+ {
+ $rcmail = rcube::get_instance();
+
+ // return table name if configured
+ $config_key = 'db_table_'.$table;
+
+ if ($name = $rcmail->config->get($config_key)) {
+ return $name;
+ }
+
+ return $table;
+ }
+
+
+ /**
+ * Return correct name for a specific database sequence
+ * (used for Postgres only)
+ *
+ * @param string $sequence Secuence name
+ *
+ * @return string Translated sequence name
+ */
+ public function sequence_name($sequence)
+ {
+ $rcmail = rcube::get_instance();
+
+ // return sequence name if configured
+ $config_key = 'db_sequence_'.$sequence;
+
+ if ($name = $rcmail->config->get($config_key)) {
+ return $name;
+ }
+
+ return $sequence;
+ }
+
+
+ /**
+ * Callback for sqlite: unix_timestamp()
+ */
+ public static function sqlite_unix_timestamp($timestamp = '')
+ {
+ $timestamp = trim($timestamp);
+ if (!$timestamp) {
+ $ret = time();
+ }
+ else if (!preg_match('/^[0-9]+$/s', $timestamp)) {
+ $ret = strtotime($timestamp);
+ }
+ else {
+ $ret = $timestamp;
+ }
+
+ return $ret;
+ }
+
+
+ /**
+ * Callback for sqlite: now()
+ */
+ public static function sqlite_now()
+ {
+ return date("Y-m-d H:i:s");
+ }
+
+}
diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php
index 76246a2d8..295b06ee6 100644
--- a/program/include/rcube_message.php
+++ b/program/include/rcube_message.php
@@ -78,7 +78,7 @@ class rcube_message
function __construct($uid)
{
$this->uid = $uid;
- $this->app = rcmail::get_instance();
+ $this->app = rcube::get_instance();
$this->storage = $this->app->get_storage();
$this->storage->set_options(array('all_headers' => true));
@@ -96,8 +96,10 @@ class rcube_message
$this->opt = array(
'safe' => $this->is_safe,
'prefer_html' => $this->app->config->get('prefer_html'),
- 'get_url' => rcmail_url('get', array(
- '_mbox' => $this->storage->get_folder(), '_uid' => $uid))
+ 'get_url' => $this->app->url(array(
+ 'action' => 'get',
+ 'mbox' => $this->storage->get_folder(),
+ 'uid' => $uid))
);
if (!empty($this->headers->structure)) {
@@ -380,7 +382,8 @@ class rcube_message
$c->type = 'content';
$c->ctype_primary = 'text';
$c->ctype_secondary = 'plain';
- $c->body = rcube_label('htmlmessage');
+ $c->mimetype = 'text/plain';
+ $c->realtype = 'text/html';
$this->parts[] = $c;
}
@@ -388,7 +391,6 @@ class rcube_message
// 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';
$this->attachments[] = $html_part;
@@ -400,8 +402,8 @@ class rcube_message
$p->type = 'content';
$p->ctype_primary = 'text';
$p->ctype_secondary = 'plain';
- $p->body = rcube_label('encryptedmessage');
- $p->size = strlen($p->body);
+ $p->mimetype = 'text/plain';
+ $p->realtype = 'multipart/encrypted';
$this->parts[] = $p;
}
@@ -671,7 +673,7 @@ class rcube_message
$uupart->size = strlen($uupart->body);
$uupart->mime_id = 'uu.' . $part->mime_id . '.' . $pid;
- $ctype = rc_mime_content_type($uupart->body, $uupart->filename, 'application/octet-stream', true);
+ $ctype = rcube_mime::content_type($uupart->body, $uupart->filename, 'application/octet-stream', true);
$uupart->mimetype = $ctype;
list($uupart->ctype_primary, $uupart->ctype_secondary) = explode('/', $ctype);
diff --git a/program/include/rcube_message_header.php b/program/include/rcube_message_header.php
new file mode 100644
index 000000000..ee7e1e34b
--- /dev/null
+++ b/program/include/rcube_message_header.php
@@ -0,0 +1,238 @@
+<?php
+
+/**
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_message_header.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
+ | Copyright (C) 2011-2012, Kolab Systems AG |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | E-mail message headers representation |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Aleksander Machniak <alec@alec.pl> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+/**
+ * Struct representing an e-mail message header
+ *
+ * @package Mail
+ * @author Aleksander Machniak <alec@alec.pl>
+ */
+class rcube_message_header
+{
+ /**
+ * Message sequence number
+ *
+ * @var int
+ */
+ public $id;
+
+ /**
+ * Message unique identifier
+ *
+ * @var int
+ */
+ public $uid;
+
+ /**
+ * Message subject
+ *
+ * @var string
+ */
+ public $subject;
+
+ /**
+ * Message sender (From)
+ *
+ * @var string
+ */
+ public $from;
+
+ /**
+ * Message recipient (To)
+ *
+ * @var string
+ */
+ public $to;
+
+ /**
+ * Message additional recipients (Cc)
+ *
+ * @var string
+ */
+ public $cc;
+
+ /**
+ * Message Reply-To header
+ *
+ * @var string
+ */
+ public $replyto;
+
+ /**
+ * Message In-Reply-To header
+ *
+ * @var string
+ */
+ public $in_reply_to;
+
+ /**
+ * Message date (Date)
+ *
+ * @var string
+ */
+ public $date;
+
+ /**
+ * Message identifier (Message-ID)
+ *
+ * @var string
+ */
+ public $messageID;
+
+ /**
+ * Message size
+ *
+ * @var int
+ */
+ public $size;
+
+ /**
+ * Message encoding
+ *
+ * @var string
+ */
+ public $encoding;
+
+ /**
+ * Message charset
+ *
+ * @var string
+ */
+ public $charset;
+
+ /**
+ * Message Content-type
+ *
+ * @var string
+ */
+ public $ctype;
+
+ /**
+ * Message timestamp (based on message date)
+ *
+ * @var int
+ */
+ public $timestamp;
+
+ /**
+ * IMAP bodystructure string
+ *
+ * @var string
+ */
+ public $bodystructure;
+
+ /**
+ * IMAP internal date
+ *
+ * @var string
+ */
+ public $internaldate;
+
+ /**
+ * Message References header
+ *
+ * @var string
+ */
+ public $references;
+
+ /**
+ * Message priority (X-Priority)
+ *
+ * @var int
+ */
+ public $priority;
+
+ /**
+ * Message receipt recipient
+ *
+ * @var string
+ */
+ public $mdn_to;
+
+ /**
+ * Other message headers
+ *
+ * @var array
+ */
+ public $others = array();
+
+ /**
+ * Message flags
+ *
+ * @var array
+ */
+ public $flags = array();
+}
+
+
+/**
+ * Class for sorting an array of rcube_message_header objects in a predetermined order.
+ *
+ * @package Mail
+ * @author Aleksander Machniak <alec@alec.pl>
+ */
+class rcube_message_header_sorter
+{
+ private $uids = array();
+
+
+ /**
+ * Set the predetermined sort order.
+ *
+ * @param array $index Numerically indexed array of IMAP UIDs
+ */
+ function set_index($index)
+ {
+ $index = array_flip($index);
+
+ $this->uids = $index;
+ }
+
+ /**
+ * Sort the array of header objects
+ *
+ * @param array $headers Array of rcube_message_header objects indexed by UID
+ */
+ function sort_headers(&$headers)
+ {
+ uksort($headers, array($this, "compare_uids"));
+ }
+
+ /**
+ * Sort method called by uksort()
+ *
+ * @param int $a Array key (UID)
+ * @param int $b Array key (UID)
+ */
+ function compare_uids($a, $b)
+ {
+ // then find each sequence number in my ordered list
+ $posa = isset($this->uids[$a]) ? intval($this->uids[$a]) : -1;
+ $posb = isset($this->uids[$b]) ? intval($this->uids[$b]) : -1;
+
+ // return the relative position as the comparison value
+ return $posa - $posb;
+ }
+}
diff --git a/program/include/rcube_message_part.php b/program/include/rcube_message_part.php
new file mode 100644
index 000000000..799dc0f99
--- /dev/null
+++ b/program/include/rcube_message_part.php
@@ -0,0 +1,103 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_message_part.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
+ | Copyright (C) 2011-2012, Kolab Systems AG |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Class representing a message part |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ | Author: Aleksander Machniak <alec@alec.pl> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+
+/**
+ * Class representing a message part
+ *
+ * @package Mail
+ * @author Thomas Bruederli <roundcube@gmail.com>
+ * @author Aleksander Machniak <alec@alec.pl>
+ * @version 2.0
+ */
+class rcube_message_part
+{
+ /**
+ * Part MIME identifier
+ *
+ * @var string
+ */
+ public $mime_id = '';
+
+ /**
+ * Content main type
+ *
+ * @var string
+ */
+ public $ctype_primary = 'text';
+
+ /**
+ * Content subtype
+ *
+ * @var string
+ */
+ public $ctype_secondary = 'plain';
+
+ /**
+ * Complete content type
+ *
+ * @var string
+ */
+ public $mimetype = 'text/plain';
+
+ public $disposition = '';
+ public $filename = '';
+ public $encoding = '8bit';
+ public $charset = '';
+
+ /**
+ * Part size in bytes
+ *
+ * @var int
+ */
+ public $size = 0;
+
+ /**
+ * Part headers
+ *
+ * @var array
+ */
+ public $headers = array();
+
+ public $d_parameters = array();
+ public $ctype_parameters = array();
+
+
+ /**
+ * Clone handler.
+ */
+ function __clone()
+ {
+ if (isset($this->parts)) {
+ foreach ($this->parts as $idx => $part) {
+ if (is_object($part)) {
+ $this->parts[$idx] = clone $part;
+ }
+ }
+ }
+ }
+
+}
diff --git a/program/include/rcube_output.php b/program/include/rcube_output.php
new file mode 100644
index 000000000..575f1062d
--- /dev/null
+++ b/program/include/rcube_output.php
@@ -0,0 +1,259 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_output.php |
+ | |
+ | This file is part of the Roundcube PHP suite |
+ | Copyright (C) 2005-2012 The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | CONTENTS: |
+ | Abstract class for output generation |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ | Author: Aleksander Machniak <alec@alec.pl> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+/**
+ * Class for output generation
+ *
+ * @package HTML
+ */
+abstract class rcube_output
+{
+ public $browser;
+ public $type = 'html';
+ public $ajax_call = false;
+ public $framed = false;
+
+ protected $app;
+ protected $config;
+ protected $charset = RCMAIL_CHARSET;
+ protected $env = array();
+ protected $pagetitle = '';
+ protected $object_handlers = array();
+
+
+ /**
+ * Object constructor
+ */
+ public function __construct($task = null, $framed = false)
+ {
+ $this->app = rcmail::get_instance();
+ $this->config = $this->app->config;
+ $this->browser = new rcube_browser();
+ }
+
+
+ /**
+ * Setter for page title
+ *
+ * @param string $title Page title
+ */
+ public function set_pagetitle($title)
+ {
+ $this->pagetitle = $title;
+ }
+
+
+ /**
+ * Setter for output charset.
+ * To be specified in a meta tag and sent as http-header
+ *
+ * @param string $charset Charset name
+ */
+ public function set_charset($charset)
+ {
+ $this->charset = $charset;
+ }
+
+
+ /**
+ * Getter for output charset
+ *
+ * @return string Output charset name
+ */
+ public function get_charset()
+ {
+ return $this->charset;
+ }
+
+
+ /**
+ * Getter for the current skin path property
+ */
+ public function get_skin_path()
+ {
+ return $this->config->get('skin_path');
+ }
+
+
+ /**
+ * Set environment variable
+ *
+ * @param string $name Property name
+ * @param mixed $value Property value
+ */
+ public function set_env($name, $value)
+ {
+ $this->env[$name] = $value;
+ }
+
+
+ /**
+ * Environment variable getter.
+ *
+ * @param string $name Property name
+ *
+ * @return mixed Property value
+ */
+ public function get_env($name)
+ {
+ return $this->env[$name];
+ }
+
+
+ /**
+ * Delete all stored env variables and commands
+ */
+ public function reset()
+ {
+ $this->env = array();
+ $this->object_handlers = array();
+ $this->pagetitle = '';
+ }
+
+
+ /**
+ * Call a client method
+ *
+ * @param string Method to call
+ * @param ... Additional arguments
+ */
+ abstract function command();
+
+
+ /**
+ * Add a localized label to the client environment
+ */
+ abstract function add_label();
+
+
+ /**
+ * Invoke display_message command
+ *
+ * @param string $message Message to display
+ * @param string $type Message type [notice|confirm|error]
+ * @param array $vars Key-value pairs to be replaced in localized text
+ * @param boolean $override Override last set message
+ * @param int $timeout Message displaying time in seconds
+ */
+ abstract function show_message($message, $type = 'notice', $vars = null, $override = true, $timeout = 0);
+
+
+ /**
+ * Redirect to a certain url.
+ *
+ * @param mixed $p Either a string with the action or url parameters as key-value pairs
+ * @param int $delay Delay in seconds
+ */
+ abstract function redirect($p = array(), $delay = 1);
+
+
+ /**
+ * Send output to the client.
+ */
+ abstract function send();
+
+
+ /**
+ * Register a template object handler
+ *
+ * @param string Object name
+ * @param string Function name to call
+ * @return void
+ */
+ public 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
+ * @return void
+ */
+ public function add_handlers($arr)
+ {
+ $this->object_handlers = array_merge($this->object_handlers, $arr);
+ }
+
+
+ /**
+ * Send HTTP headers to prevent caching a page
+ */
+ public function nocacheing_headers()
+ {
+ if (headers_sent()) {
+ return;
+ }
+
+ header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
+ header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
+
+ // Request browser to disable DNS prefetching (CVE-2010-0464)
+ header("X-DNS-Prefetch-Control: off");
+
+ // We need to set the following headers to make downloads work using IE in HTTPS mode.
+ if ($this->browser->ie && rcube_ui::https_check()) {
+ header('Pragma: private');
+ header("Cache-Control: private, must-revalidate");
+ }
+ else {
+ header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0");
+ header("Pragma: no-cache");
+ }
+ }
+
+
+ /**
+ * Show error page and terminate script execution
+ *
+ * @param int $code Error code
+ * @param string $message Error message
+ */
+ public function raise_error($code, $message)
+ {
+ // STUB: to be overloaded by specific output classes
+ fputs(STDERR, "Error $code: $message\n");
+ exit(-1);
+ }
+
+
+ /**
+ * Convert a variable into a javascript object notation
+ *
+ * @param mixed Input value
+ *
+ * @return string Serialized JSON string
+ */
+ public static function json_serialize($input)
+ {
+ $input = rcube_charset::clean($input);
+
+ // sometimes even using rcube_charset::clean() the input contains invalid UTF-8 sequences
+ // that's why we have @ here
+ return @json_encode($input);
+ }
+
+}
diff --git a/program/include/rcube_template.php b/program/include/rcube_output_html.php
index b2bdda488..a047aba45 100644
--- a/program/include/rcube_template.php
+++ b/program/include/rcube_output_html.php
@@ -2,10 +2,10 @@
/*
+-----------------------------------------------------------------------+
- | program/include/rcube_template.php |
+ | program/include/rcubeoutput_html.php |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2011, The Roundcube Dev Team |
+ | Copyright (C) 2006-2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -13,7 +13,6 @@
| |
| 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> |
@@ -28,33 +27,32 @@
* Class to create HTML page output using a skin template
*
* @package View
- * @todo Documentation
- * @uses rcube_html_page
*/
-class rcube_template extends rcube_html_page
+class rcube_output_html extends rcube_output
{
- private $app;
- private $config;
- private $pagetitle = '';
- private $message = null;
- private $js_env = array();
- private $js_labels = array();
- private $js_commands = array();
- private $object_handlers = array();
- private $plugin_skin_path;
- private $template_name;
-
- public $browser;
- public $framed = false;
- public $env = array();
public $type = 'html';
- public $ajax_call = false;
+
+ protected $message = null;
+ protected $js_env = array();
+ protected $js_labels = array();
+ protected $js_commands = array();
+ protected $plugin_skin_path;
+ protected $template_name;
+ protected $scripts_path = '';
+ protected $script_files = array();
+ protected $css_files = array();
+ protected $scripts = array();
+ protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
+ protected $header = '';
+ protected $footer = '';
+ protected $body = '';
+ protected $base_path = '';
// deprecated names of templates used before 0.5
- private $deprecated_templates = array(
- 'contact' => 'showcontact',
- 'contactadd' => 'addcontact',
- 'contactedit' => 'editcontact',
+ protected $deprecated_templates = array(
+ 'contact' => 'showcontact',
+ 'contactadd' => 'addcontact',
+ 'contactedit' => 'editcontact',
'identityedit' => 'editidentity',
'messageprint' => 'printmessage',
);
@@ -64,20 +62,16 @@ class rcube_template extends rcube_html_page
*
* @todo Replace $this->config with the real rcube_config object
*/
- public function __construct($task, $framed = false)
+ public function __construct($task = null, $framed = false)
{
parent::__construct();
- $this->app = rcmail::get_instance();
- $this->config = $this->app->config->all();
- $this->browser = new rcube_browser();
-
//$this->framed = $framed;
$this->set_env('task', $task);
- $this->set_env('x_frame_options', $this->app->config->get('x_frame_options', 'sameorigin'));
+ $this->set_env('x_frame_options', $this->config->get('x_frame_options', 'sameorigin'));
// load the correct skin (in case user-defined)
- $this->set_skin($this->config['skin']);
+ $this->set_skin($this->config->get('skin'));
// add common javascripts
$this->add_script('var '.JS_OBJECT_NAME.' = new rcube_webmail();', 'head_top');
@@ -101,6 +95,7 @@ class rcube_template extends rcube_html_page
));
}
+
/**
* Set environment variable
*
@@ -116,26 +111,22 @@ class rcube_template extends rcube_html_page
}
}
- /**
- * Set page title variable
- */
- public function set_pagetitle($title)
- {
- $this->pagetitle = $title;
- }
/**
* Getter for the current page title
*
* @return string The page title
*/
- public function get_pagetitle()
+ protected function get_pagetitle()
{
if (!empty($this->pagetitle)) {
$title = $this->pagetitle;
}
else if ($this->env['task'] == 'login') {
- $title = rcube_label(array('name' => 'welcome', 'vars' => array('product' => $this->config['product_name'])));
+ $title = $this->app->gettext(array(
+ 'name' => 'welcome',
+ 'vars' => array('product' => $this->config->get('product_name')
+ )));
}
else {
$title = ucfirst($this->env['task']);
@@ -144,6 +135,7 @@ class rcube_template extends rcube_html_page
return $title;
}
+
/**
* Set skin
*/
@@ -156,23 +148,18 @@ class rcube_template extends rcube_html_page
$valid = true;
}
else {
- $skin_path = $this->config['skin_path'] ? $this->config['skin_path'] : 'skins/default';
+ $skin_path = $this->config->get('skin_path');
+ if (!$skin_path) {
+ $skin_path = 'skins/default';
+ }
$valid = !$skin;
}
- $this->app->config->set('skin_path', $skin_path);
- $this->config['skin_path'] = $skin_path;
+ $this->config->set('skin_path', $skin_path);
return $valid;
}
- /**
- * Getter for the current skin path property
- */
- public function get_skin_path()
- {
- return $this->config['skin_path'];
- }
/**
* Check if a specific template exists
@@ -182,32 +169,10 @@ class rcube_template extends rcube_html_page
*/
public function template_exists($name)
{
- $filename = $this->config['skin_path'] . '/templates/' . $name . '.html';
+ $filename = $this->config->get('skin_path') . '/templates/' . $name . '.html';
return (is_file($filename) && is_readable($filename)) || ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name]));
}
- /**
- * Register a template object handler
- *
- * @param string Object name
- * @param string Function name to call
- * @return void
- */
- public 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
- * @return void
- */
- public function add_handlers($arr)
- {
- $this->object_handlers = array_merge($this->object_handlers, $arr);
- }
/**
* Register a GUI object to the client script
@@ -221,6 +186,7 @@ class rcube_template extends rcube_html_page
$this->add_script(JS_OBJECT_NAME.".gui_object('$obj', '$id');");
}
+
/**
* Call a client method
*
@@ -236,6 +202,7 @@ class rcube_template extends rcube_html_page
$this->js_commands[] = $cmd;
}
+
/**
* Add a localized label to the client environment
*/
@@ -246,10 +213,11 @@ class rcube_template extends rcube_html_page
$args = $args[0];
foreach ($args as $name) {
- $this->js_labels[$name] = rcube_label($name);
+ $this->js_labels[$name] = $this->app->gettext($name);
}
}
+
/**
* Invoke display_message command
*
@@ -263,10 +231,10 @@ class rcube_template extends rcube_html_page
public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
{
if ($override || !$this->message) {
- if (rcube_label_exists($message)) {
+ if ($this->app->text_exists($message)) {
if (!empty($vars))
$vars = array_map('Q', $vars);
- $msgtext = rcube_label(array('name' => $message, 'vars' => $vars));
+ $msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
}
else
$msgtext = $message;
@@ -276,39 +244,38 @@ class rcube_template extends rcube_html_page
}
}
+
/**
* Delete all stored env variables and commands
- *
- * @return void
- * @uses rcube_html::reset()
- * @uses self::$env
- * @uses self::$js_env
- * @uses self::$js_commands
- * @uses self::$object_handlers
*/
public function reset()
{
- $this->env = array();
+ parent::reset();
$this->js_env = array();
$this->js_labels = array();
$this->js_commands = array();
- $this->object_handlers = array();
- parent::reset();
+ $this->script_files = array();
+ $this->scripts = array();
+ $this->header = '';
+ $this->footer = '';
+ $this->body = '';
}
+
/**
* Redirect to a certain url
*
- * @param mixed Either a string with the action or url parameters as key-value pairs
- * @see rcmail::url()
+ * @param mixed $p Either a string with the action or url parameters as key-value pairs
+ * @param int $delay Delay in seconds
*/
- public function redirect($p = array())
+ public function redirect($p = array(), $delay = 1)
{
$location = $this->app->url($p);
header('Location: ' . $location);
exit;
}
+
/**
* Send the request output to the client.
* This will either parse a skin tempalte or send an AJAX response
@@ -321,7 +288,7 @@ class rcube_template extends rcube_html_page
if ($templ != 'iframe') {
// prevent from endless loops
if ($exit != 'recur' && $this->app->plugins->is_processing('render_page')) {
- raise_error(array('code' => 505, 'type' => 'php',
+ rcube::raise_error(array('code' => 505, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => 'Recursion alert: ignoring output->send()'), true, false);
return;
@@ -342,12 +309,11 @@ class rcube_template extends rcube_html_page
}
}
+
/**
* Process template and write to stdOut
*
- * @param string HTML template
- * @see rcube_html_page::write()
- * @override
+ * @param string $template HTML template content
*/
public function write($template = '')
{
@@ -374,9 +340,10 @@ class rcube_template extends rcube_html_page
header('X-Frame-Options: ' . ($iframe && $xframe == 'deny' ? 'sameorigin' : $xframe));
// call super method
- parent::write($template, $this->config['skin_path']);
+ $this->_write($template, $this->config->get('skin_path'));
}
+
/**
* Parse a specific skin template and deliver to stdout (or return)
*
@@ -388,7 +355,7 @@ class rcube_template extends rcube_html_page
*/
function parse($name = 'main', $exit = true, $write = true)
{
- $skin_path = $this->config['skin_path'];
+ $skin_path = $this->config->get('skin_path');
$plugin = false;
$realname = $name;
$temp = explode('.', $name, 2);
@@ -399,7 +366,7 @@ class rcube_template extends rcube_html_page
if (count($temp) > 1) {
$plugin = $temp[0];
$name = $temp[1];
- $skin_dir = $plugin . '/skins/' . $this->config['skin'];
+ $skin_dir = $plugin . '/skins/' . $this->config->get('skin');
$skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
// fallback to default skin
@@ -414,16 +381,16 @@ class rcube_template extends rcube_html_page
if (!is_readable($path) && $this->deprecated_templates[$realname]) {
$path = "$skin_path/templates/".$this->deprecated_templates[$realname].".html";
if (is_readable($path))
- raise_error(array('code' => 502, 'type' => 'php',
+ rcube::raise_error(array('code' => 502, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Using deprecated template '".$this->deprecated_templates[$realname]
- ."' in ".$this->config['skin_path']."/templates. Please rename to '".$realname."'"),
+ ."' in $skin_path/templates. Please rename to '".$realname."'"),
true, false);
}
// read template file
if (($templ = @file_get_contents($path)) === false) {
- raise_error(array(
+ rcube::raise_error(array(
'code' => 501,
'type' => 'php',
'line' => __LINE__,
@@ -458,7 +425,7 @@ class rcube_template extends rcube_html_page
if ($write) {
// add debug console
- if ($realname != 'error' && ($this->config['debug_level'] & 8)) {
+ if ($realname != 'error' && ($this->config->get('debug_level') & 8)) {
$this->add_footer('<div id="console" style="position:absolute;top:5px;left:5px;width:405px;padding:2px;background:white;z-index:9000;display:none">
<a href="#toggle" onclick="con=$(\'#dbgconsole\');con[con.is(\':visible\')?\'hide\':\'show\']();return false">console</a>
<textarea name="console" id="dbgconsole" rows="20" cols="40" style="display:none;width:400px;border:none;font-size:10px" spellcheck="false"></textarea></div>'
@@ -480,16 +447,17 @@ class rcube_template extends rcube_html_page
}
}
+
/**
* Return executable javascript code for all registered commands
*
* @return string $out
*/
- private function get_js_commands()
+ protected function get_js_commands()
{
$out = '';
if (!$this->framed && !empty($this->js_env)) {
- $out .= JS_OBJECT_NAME . '.set_env('.json_serialize($this->js_env).");\n";
+ $out .= JS_OBJECT_NAME . '.set_env('.self::json_serialize($this->js_env).");\n";
}
if (!empty($this->js_labels)) {
$this->command('add_label', $this->js_labels);
@@ -497,7 +465,7 @@ class rcube_template extends rcube_html_page
foreach ($this->js_commands as $i => $args) {
$method = array_shift($args);
foreach ($args as $i => $arg) {
- $args[$i] = json_serialize($arg);
+ $args[$i] = self::json_serialize($arg);
}
$parent = $this->framed || preg_match('/^parent\./', $method);
$out .= sprintf(
@@ -511,6 +479,7 @@ class rcube_template extends rcube_html_page
return $out;
}
+
/**
* Make URLs starting with a slash point to skin directory
*
@@ -520,41 +489,62 @@ class rcube_template extends rcube_html_page
public function abs_url($str)
{
if ($str[0] == '/')
- return $this->config['skin_path'] . $str;
+ return $this->config->get('skin_path') . $str;
else
return $str;
}
+ /**
+ * Show error page and terminate script execution
+ *
+ * @param int $code Error code
+ * @param string $message Error message
+ */
+ public function raise_error($code, $message)
+ {
+ global $__page_content, $ERROR_CODE, $ERROR_MESSAGE;
+
+ $ERROR_CODE = $code;
+ $ERROR_MESSAGE = $message;
+
+ include INSTALL_PATH . 'program/steps/utils/error.inc';
+ exit;
+ }
+
+
/***** Template parsing methods *****/
/**
* Replace all strings ($varname)
* with the content of the according global variable.
*/
- private function parse_with_globals($input)
+ protected function parse_with_globals($input)
{
- $GLOBALS['__version'] = Q(RCMAIL_VERSION);
- $GLOBALS['__comm_path'] = Q($this->app->comm_path);
- $GLOBALS['__skin_path'] = Q($this->config['skin_path']);
+ $GLOBALS['__version'] = html::quote(RCMAIL_VERSION);
+ $GLOBALS['__comm_path'] = html::quote($this->app->comm_path);
+ $GLOBALS['__skin_path'] = Q($this->config->get('skin_path'));
+
return preg_replace_callback('/\$(__[a-z0-9_\-]+)/',
- array($this, 'globals_callback'), $input);
+ array($this, 'globals_callback'), $input);
}
+
/**
* Callback funtion for preg_replace_callback() in parse_with_globals()
*/
- private function globals_callback($matches)
+ protected function globals_callback($matches)
{
return $GLOBALS[$matches[1]];
}
+
/**
* Public wrapper to dipp into template parsing.
*
* @param string $input
* @return string
- * @uses rcube_template::parse_xml()
+ * @uses rcube_output_html::parse_xml()
* @since 0.1-rc1
*/
public function just_parse($input)
@@ -562,20 +552,21 @@ class rcube_template extends rcube_html_page
return $this->parse_xml($input);
}
+
/**
* Parse for conditional tags
*
* @param string $input
* @return string
*/
- private function parse_conditions($input)
+ protected function parse_conditions($input)
{
$matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>\n?/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE);
if ($matches && count($matches) == 4) {
if (preg_match('/^(else|endif)$/i', $matches[1])) {
return $matches[0] . $this->parse_conditions($matches[3]);
}
- $attrib = parse_attrib_string($matches[2]);
+ $attrib = html::parse_attrib_string($matches[2]);
if (isset($attrib['condition'])) {
$condmet = $this->check_condition($attrib['condition']);
$submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>\n?/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
@@ -588,7 +579,7 @@ class rcube_template extends rcube_html_page
}
return $matches[0] . $this->parse_conditions($result);
}
- raise_error(array(
+ rcube::raise_error(array(
'code' => 500,
'type' => 'php',
'line' => __LINE__,
@@ -608,7 +599,7 @@ class rcube_template extends rcube_html_page
* @param string Condition statement
* @return boolean True if condition is met, False if not
*/
- private function check_condition($condition)
+ protected function check_condition($condition)
{
return eval("return (".$this->parse_expression($condition).");");
}
@@ -617,10 +608,10 @@ class rcube_template extends rcube_html_page
/**
* Inserts hidden field with CSRF-prevention-token into POST forms
*/
- private function alter_form_tag($matches)
+ protected function alter_form_tag($matches)
{
- $out = $matches[0];
- $attrib = parse_attrib_string($matches[1]);
+ $out = $matches[0];
+ $attrib = html::parse_attrib_string($matches[1]);
if (strtolower($attrib['method']) == 'post') {
$hidden = new html_hiddenfield(array('name' => '_token', 'value' => $this->app->get_request_token()));
@@ -637,7 +628,7 @@ class rcube_template extends rcube_html_page
* @param string Expression statement
* @return string Expression value
*/
- private function parse_expression($expression)
+ protected function parse_expression($expression)
{
return preg_replace(
array(
@@ -653,7 +644,7 @@ class rcube_template extends rcube_html_page
"\$_SESSION['\\1']",
"\$this->app->config->get('\\1',get_boolean('\\3'))",
"\$this->env['\\1']",
- "get_input_value('\\1', RCUBE_INPUT_GPC)",
+ "rcube_ui::get_input_value('\\1', rcube_ui::INPUT_GPC)",
"\$_COOKIE['\\1']",
"\$this->browser->{'\\1'}",
$this->template_name,
@@ -671,7 +662,7 @@ class rcube_template extends rcube_html_page
* @todo Use DOM-parser to traverse template HTML
* @todo Maybe a cache.
*/
- private function parse_xml($input)
+ protected function parse_xml($input)
{
return preg_replace_callback('/<roundcube:([-_a-z]+)\s+((?:[^>]|\\\\>)+)(?<!\\\\)>/Ui', array($this, 'xml_command'), $input);
}
@@ -684,10 +675,10 @@ class rcube_template extends rcube_html_page
* @param array Matches array of preg_replace_callback
* @return string Tag/Object content
*/
- private function xml_command($matches)
+ protected function xml_command($matches)
{
$command = strtolower($matches[1]);
- $attrib = parse_attrib_string($matches[2]);
+ $attrib = html::parse_attrib_string($matches[2]);
// empty output if required condition is not met
if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
@@ -706,20 +697,20 @@ class rcube_template extends rcube_html_page
// show a label
case 'label':
if ($attrib['name'] || $attrib['command']) {
- $vars = $attrib + array('product' => $this->config['product_name']);
+ $vars = $attrib + array('product' => $this->config->get('product_name'));
unset($vars['name'], $vars['command']);
- $label = rcube_label($attrib + array('vars' => $vars));
- return !$attrib['noshow'] ? (get_boolean((string)$attrib['html']) ? $label : Q($label)) : '';
+ $label = $this->app->gettext($attrib + array('vars' => $vars));
+ return !$attrib['noshow'] ? (get_boolean((string)$attrib['html']) ? $label : html::quote($label)) : '';
}
break;
// include a file
case 'include':
if (!$this->plugin_skin_path || !is_file($path = realpath($this->plugin_skin_path . $attrib['file'])))
- $path = realpath(($attrib['skin_path'] ? $attrib['skin_path'] : $this->config['skin_path']).$attrib['file']);
-
+ $path = realpath(($attrib['skin_path'] ? $attrib['skin_path'] : $this->config->get('skin_path')).$attrib['file']);
+
if (is_readable($path)) {
- if ($this->config['skin_include_php']) {
+ if ($this->config->get('skin_include_php')) {
$incl = $this->include_php($path);
}
else {
@@ -765,13 +756,13 @@ class rcube_template extends rcube_html_page
}
else if ($object == 'logo') {
$attrib += array('alt' => $this->xml_command(array('', 'object', 'name="productname"')));
- if ($this->config['skin_logo'])
- $attrib['src'] = $this->config['skin_logo'];
+ if ($logo = $this->config->get('skin_logo'))
+ $attrib['src'] = $logo;
$content = html::img($attrib);
}
else if ($object == 'productname') {
- $name = !empty($this->config['product_name']) ? $this->config['product_name'] : 'Roundcube Webmail';
- $content = Q($name);
+ $name = $this->config->get('product_name', 'Roundcube Webmail');
+ $content = html::quote($name);
}
else if ($object == 'version') {
$ver = (string)RCMAIL_VERSION;
@@ -779,20 +770,20 @@ class rcube_template extends rcube_html_page
if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs))
$ver .= ' [SVN r'.$regs[1].']';
}
- $content = Q($ver);
+ $content = html::quote($ver);
}
else if ($object == 'steptitle') {
- $content = Q($this->get_pagetitle());
+ $content = html::quote($this->get_pagetitle());
}
else if ($object == 'pagetitle') {
- if (!empty($this->config['devel_mode']) && !empty($_SESSION['username']))
- $title = $_SESSION['username'].' :: ';
- else if (!empty($this->config['product_name']))
- $title = $this->config['product_name'].' :: ';
+ if ($this->config->get('devel_mode') && !empty($_SESSION['username']))
+ $title = $_SESSION['username'].' :: ';
+ else if ($prod_name = $this->config->get('product_name'))
+ $title = $prod_name . ' :: ';
else
- $title = '';
+ $title = '';
$title .= $this->get_pagetitle();
- $content = Q($title);
+ $content = html::quote($title);
}
// exec plugin hooks for this template object
@@ -802,7 +793,7 @@ class rcube_template extends rcube_html_page
// return code for a specified eval expression
case 'exp':
$value = $this->parse_expression($attrib['expression']);
- return eval("return Q($value);");
+ return eval("return html::quote($value);");
// return variable
case 'var':
@@ -815,13 +806,13 @@ class rcube_template extends rcube_html_page
$value = $this->env[$name];
break;
case 'config':
- $value = $this->config[$name];
+ $value = $this->config->get($name);
if (is_array($value) && $value[$_SESSION['storage_host']]) {
$value = $value[$_SESSION['storage_host']];
}
break;
case 'request':
- $value = get_input_value($name, RCUBE_INPUT_GPC);
+ $value = rcube_ui::get_input_value($name, rcube_ui::INPUT_GPC);
break;
case 'session':
$value = $_SESSION[$name];
@@ -838,19 +829,20 @@ class rcube_template extends rcube_html_page
$value = implode(', ', $value);
}
- return Q($value);
+ return html::quote($value);
break;
}
return '';
}
+
/**
* Include a specific file and return it's contents
*
* @param string File path
* @return string Contents of the processed file
*/
- private function include_php($file)
+ protected function include_php($file)
{
ob_start();
include $file;
@@ -860,6 +852,7 @@ class rcube_template extends rcube_html_page
return $out;
}
+
/**
* Create and register a button
*
@@ -901,13 +894,13 @@ class rcube_template extends rcube_html_page
}
// get localized text for labels and titles
if ($attrib['title']) {
- $attrib['title'] = Q(rcube_label($attrib['title'], $attrib['domain']));
+ $attrib['title'] = html::quote($this->app->gettext($attrib['title'], $attrib['domain']));
}
if ($attrib['label']) {
- $attrib['label'] = Q(rcube_label($attrib['label'], $attrib['domain']));
+ $attrib['label'] = html::quote($this->app->gettext($attrib['label'], $attrib['domain']));
}
if ($attrib['alt']) {
- $attrib['alt'] = Q(rcube_label($attrib['alt'], $attrib['domain']));
+ $attrib['alt'] = html::quote($this->app->gettext($attrib['alt'], $attrib['domain']));
}
// set title to alt attribute for IE browsers
@@ -935,14 +928,14 @@ class rcube_template extends rcube_html_page
// make valid href to specific buttons
if (in_array($attrib['command'], rcmail::$main_tasks)) {
- $attrib['href'] = rcmail_url(null, null, $attrib['command']);
+ $attrib['href'] = $this->app->url(array('task' => $attrib['command']));
$attrib['onclick'] = sprintf("%s.command('switch-task','%s');return false", JS_OBJECT_NAME, $attrib['command']);
}
else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) {
- $attrib['href'] = rcmail_url($attrib['command'], null, $attrib['task']);
+ $attrib['href'] = $this->app->url(array('action' => $attrib['command'], 'task' => $attrib['task']));
}
else if (in_array($attrib['command'], $a_static_commands)) {
- $attrib['href'] = rcmail_url($attrib['command']);
+ $attrib['href'] = $this->app->url(array('action' => $attrib['command']));
}
else if ($attrib['command'] == 'permaurl' && !empty($this->env['permaurl'])) {
$attrib['href'] = $this->env['permaurl'];
@@ -969,7 +962,7 @@ class rcube_template extends rcube_html_page
$out = '';
// generate image tag
- if ($attrib['type']=='image') {
+ if ($attrib['type'] == 'image') {
$attrib_str = html::attrib_string(
$attrib,
array(
@@ -983,13 +976,13 @@ class rcube_template extends rcube_html_page
}
$link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'target');
}
- else if ($attrib['type']=='link') {
+ else if ($attrib['type'] == 'link') {
$btn_content = isset($attrib['content']) ? $attrib['content'] : ($attrib['label'] ? $attrib['label'] : $attrib['command']);
$link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style', 'tabindex', 'target');
if ($attrib['innerclass'])
$btn_content = html::span($attrib['innerclass'], $btn_content);
}
- else if ($attrib['type']=='input') {
+ else if ($attrib['type'] == 'input') {
$attrib['type'] = 'button';
if ($attrib['label']) {
@@ -1012,6 +1005,244 @@ class rcube_template extends rcube_html_page
}
+ /**
+ * Link an external script file
+ *
+ * @param string File URL
+ * @param string Target position [head|foot]
+ */
+ public function include_script($file, $position='head')
+ {
+ static $sa_files = array();
+
+ if (!preg_match('|^https?://|i', $file) && $file[0] != '/') {
+ $file = $this->scripts_path . $file;
+ if ($fs = @filemtime($file)) {
+ $file .= '?s=' . $fs;
+ }
+ }
+
+ if (in_array($file, $sa_files)) {
+ return;
+ }
+
+ $sa_files[] = $file;
+
+ if (!is_array($this->script_files[$position])) {
+ $this->script_files[$position] = array();
+ }
+
+ $this->script_files[$position][] = $file;
+ }
+
+
+ /**
+ * Add inline javascript code
+ *
+ * @param string JS code snippet
+ * @param string Target position [head|head_top|foot]
+ */
+ public function add_script($script, $position='head')
+ {
+ if (!isset($this->scripts[$position])) {
+ $this->scripts[$position] = "\n" . rtrim($script);
+ }
+ else {
+ $this->scripts[$position] .= "\n" . rtrim($script);
+ }
+ }
+
+
+ /**
+ * Link an external css file
+ *
+ * @param string File URL
+ */
+ public function include_css($file)
+ {
+ $this->css_files[] = $file;
+ }
+
+
+ /**
+ * Add HTML code to the page header
+ *
+ * @param string $str HTML code
+ */
+ public function add_header($str)
+ {
+ $this->header .= "\n" . $str;
+ }
+
+
+ /**
+ * Add HTML code to the page footer
+ * To be added right befor </body>
+ *
+ * @param string $str HTML code
+ */
+ public function add_footer($str)
+ {
+ $this->footer .= "\n" . $str;
+ }
+
+
+ /**
+ * Process template and write to stdOut
+ *
+ * @param string HTML template
+ * @param string Base for absolute paths
+ */
+ public function _write($templ = '', $base_path = '')
+ {
+ $output = empty($templ) ? $this->default_template : trim($templ);
+
+ // set default page title
+ if (empty($this->pagetitle)) {
+ $this->pagetitle = 'Roundcube Mail';
+ }
+
+ // replace specialchars in content
+ $page_title = html::quote($this->pagetitle);
+ $page_header = '';
+ $page_footer = '';
+
+ // include meta tag with charset
+ if (!empty($this->charset)) {
+ if (!headers_sent()) {
+ header('Content-Type: text/html; charset=' . $this->charset);
+ }
+ $page_header = '<meta http-equiv="content-type"';
+ $page_header.= ' content="text/html; charset=';
+ $page_header.= $this->charset . '" />'."\n";
+ }
+
+ // definition of the code to be placed in the document header and footer
+ if (is_array($this->script_files['head'])) {
+ foreach ($this->script_files['head'] as $file) {
+ $page_header .= html::script($file);
+ }
+ }
+
+ $head_script = $this->scripts['head_top'] . $this->scripts['head'];
+ if (!empty($head_script)) {
+ $page_header .= html::script(array(), $head_script);
+ }
+
+ if (!empty($this->header)) {
+ $page_header .= $this->header;
+ }
+
+ // put docready commands into page footer
+ if (!empty($this->scripts['docready'])) {
+ $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
+ }
+
+ if (is_array($this->script_files['foot'])) {
+ foreach ($this->script_files['foot'] as $file) {
+ $page_footer .= html::script($file);
+ }
+ }
+
+ if (!empty($this->footer)) {
+ $page_footer .= $this->footer . "\n";
+ }
+
+ if (!empty($this->scripts['foot'])) {
+ $page_footer .= html::script(array(), $this->scripts['foot']);
+ }
+
+ // find page header
+ if ($hpos = stripos($output, '</head>')) {
+ $page_header .= "\n";
+ }
+ else {
+ if (!is_numeric($hpos)) {
+ $hpos = stripos($output, '<body');
+ }
+ if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
+ while ($output[$hpos] != '>') {
+ $hpos++;
+ }
+ $hpos++;
+ }
+ $page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
+ }
+
+ // add page hader
+ if ($hpos) {
+ $output = substr_replace($output, $page_header, $hpos, 0);
+ }
+ else {
+ $output = $page_header . $output;
+ }
+
+ // add page footer
+ if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
+ $output = substr_replace($output, $page_footer."\n", $fpos, 0);
+ }
+ else {
+ $output .= "\n".$page_footer;
+ }
+
+ // add css files in head, before scripts, for speed up with parallel downloads
+ if (!empty($this->css_files) &&
+ (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
+ ) {
+ $css = '';
+ foreach ($this->css_files as $file) {
+ $css .= html::tag('link', array('rel' => 'stylesheet',
+ 'type' => 'text/css', 'href' => $file, 'nl' => true));
+ }
+ $output = substr_replace($output, $css, $pos, 0);
+ }
+
+ $this->base_path = $base_path;
+
+ // correct absolute paths in images and other tags
+ // add timestamp to .js and .css filename
+ $output = preg_replace_callback(
+ '!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
+ array($this, 'file_callback'), $output);
+
+ // trigger hook with final HTML content to be sent
+ $hook = rcmail::get_instance()->plugins->exec_hook("send_page", array('content' => $output));
+ if (!$hook['abort']) {
+ if ($this->charset != RCMAIL_CHARSET) {
+ echo rcube_charset::convert($hook['content'], RCMAIL_CHARSET, $this->charset);
+ }
+ else {
+ echo $hook['content'];
+ }
+ }
+ }
+
+
+ /**
+ * Callback function for preg_replace_callback in write()
+ *
+ * @return string Parsed string
+ */
+ protected function file_callback($matches)
+ {
+ $file = $matches[3];
+
+ // correct absolute paths
+ if ($file[0] == '/') {
+ $file = $this->base_path . $file;
+ }
+
+ // add file modification timestamp
+ if (preg_match('/\.(js|css)$/', $file)) {
+ if ($fs = @filemtime($file)) {
+ $file .= '?s=' . $fs;
+ }
+ }
+
+ return $matches[1] . '=' . $matches[2] . $file . $matches[4];
+ }
+
+
/* ************* common functions delivering gui objects ************** */
@@ -1108,15 +1339,15 @@ class rcube_template extends rcube_html_page
* @param array Named parameters
* @return string HTML code for the gui object
*/
- private function login_form($attrib)
+ protected function login_form($attrib)
{
- $default_host = $this->config['default_host'];
- $autocomplete = (int) $this->config['login_autocomplete'];
+ $default_host = $this->config->get('default_host');
+ $autocomplete = (int) $this->config->get('login_autocomplete');
$_SESSION['temp'] = true;
// save original url
- $url = get_input_value('_url', RCUBE_INPUT_POST);
+ $url = rcube_ui::get_input_value('_url', rcube_ui::INPUT_POST);
if (empty($url) && !preg_match('/_(task|action)=logout/', $_SERVER['QUERY_STRING']))
$url = $_SERVER['QUERY_STRING'];
@@ -1165,16 +1396,16 @@ class rcube_template extends rcube_html_page
// create HTML table with two cols
$table = new html_table(array('cols' => 2));
- $table->add('title', html::label('rcmloginuser', Q(rcube_label('username'))));
- $table->add('input', $input_user->show(get_input_value('_user', RCUBE_INPUT_GPC)));
+ $table->add('title', html::label('rcmloginuser', html::quote($this->app->gettext('username'))));
+ $table->add('input', $input_user->show(rcube_ui::get_input_value('_user', rcube_ui::INPUT_GPC)));
- $table->add('title', html::label('rcmloginpwd', Q(rcube_label('password'))));
+ $table->add('title', html::label('rcmloginpwd', html::quote($this->app->gettext('password'))));
$table->add('input', $input_pass->show());
// add host selection row
if (is_object($input_host) && !$hide_host) {
- $table->add('title', html::label('rcmloginhost', Q(rcube_label('server'))));
- $table->add('input', $input_host->show(get_input_value('_host', RCUBE_INPUT_GPC)));
+ $table->add('title', html::label('rcmloginhost', html::quote($this->app->gettext('server'))));
+ $table->add('input', $input_host->show(rcube_ui::get_input_value('_host', rcube_ui::INPUT_GPC)));
}
$out = $input_task->show();
@@ -1204,7 +1435,7 @@ class rcube_template extends rcube_html_page
* @param array Named parameters
* @return void
*/
- private function preloader($attrib)
+ protected function preloader($attrib)
{
$images = preg_split('/[\s\t\n,]+/', $attrib['images'], -1, PREG_SPLIT_NO_EMPTY);
$images = array_map(array($this, 'abs_url'), $images);
@@ -1212,7 +1443,7 @@ class rcube_template extends rcube_html_page
if (empty($images) || $this->app->task == 'logout')
return;
- $this->add_script('var images = ' . json_serialize($images) .';
+ $this->add_script('var images = ' . self::json_serialize($images) .';
for (var i=0; i<images.length; i++) {
img = new Image();
img.src = images[i];
@@ -1227,7 +1458,7 @@ class rcube_template extends rcube_html_page
* @param array Named parameters
* @return string HTML code for the gui object
*/
- private function search_form($attrib)
+ protected function search_form($attrib)
{
// add some labels to client
$this->add_label('searching');
@@ -1265,14 +1496,15 @@ class rcube_template extends rcube_html_page
* @param array Named tag parameters
* @return string HTML code for the gui object
*/
- private function message_container($attrib)
+ protected function message_container($attrib)
{
if (isset($attrib['id']) === false) {
$attrib['id'] = 'rcmMessageContainer';
}
$this->add_gui_object('message', $attrib['id']);
- return html::div($attrib, "");
+
+ return html::div($attrib, '');
}
@@ -1282,7 +1514,7 @@ class rcube_template extends rcube_html_page
* @param array Named parameters for the select tag
* @return string HTML code for the gui object
*/
- function charset_selector($attrib)
+ public function charset_selector($attrib)
{
// pass the following attributes to the form class
$field_attrib = array('name' => '_charset');
@@ -1293,39 +1525,39 @@ class rcube_template extends rcube_html_page
}
$charsets = array(
- 'UTF-8' => 'UTF-8 ('.rcube_label('unicode').')',
- 'US-ASCII' => 'ASCII ('.rcube_label('english').')',
- 'ISO-8859-1' => 'ISO-8859-1 ('.rcube_label('westerneuropean').')',
- 'ISO-8859-2' => 'ISO-8859-2 ('.rcube_label('easterneuropean').')',
- 'ISO-8859-4' => 'ISO-8859-4 ('.rcube_label('baltic').')',
- 'ISO-8859-5' => 'ISO-8859-5 ('.rcube_label('cyrillic').')',
- 'ISO-8859-6' => 'ISO-8859-6 ('.rcube_label('arabic').')',
- 'ISO-8859-7' => 'ISO-8859-7 ('.rcube_label('greek').')',
- 'ISO-8859-8' => 'ISO-8859-8 ('.rcube_label('hebrew').')',
- 'ISO-8859-9' => 'ISO-8859-9 ('.rcube_label('turkish').')',
- 'ISO-8859-10' => 'ISO-8859-10 ('.rcube_label('nordic').')',
- 'ISO-8859-11' => 'ISO-8859-11 ('.rcube_label('thai').')',
- 'ISO-8859-13' => 'ISO-8859-13 ('.rcube_label('baltic').')',
- 'ISO-8859-14' => 'ISO-8859-14 ('.rcube_label('celtic').')',
- 'ISO-8859-15' => 'ISO-8859-15 ('.rcube_label('westerneuropean').')',
- 'ISO-8859-16' => 'ISO-8859-16 ('.rcube_label('southeasterneuropean').')',
- 'WINDOWS-1250' => 'Windows-1250 ('.rcube_label('easterneuropean').')',
- 'WINDOWS-1251' => 'Windows-1251 ('.rcube_label('cyrillic').')',
- 'WINDOWS-1252' => 'Windows-1252 ('.rcube_label('westerneuropean').')',
- 'WINDOWS-1253' => 'Windows-1253 ('.rcube_label('greek').')',
- 'WINDOWS-1254' => 'Windows-1254 ('.rcube_label('turkish').')',
- 'WINDOWS-1255' => 'Windows-1255 ('.rcube_label('hebrew').')',
- 'WINDOWS-1256' => 'Windows-1256 ('.rcube_label('arabic').')',
- 'WINDOWS-1257' => 'Windows-1257 ('.rcube_label('baltic').')',
- 'WINDOWS-1258' => 'Windows-1258 ('.rcube_label('vietnamese').')',
- 'ISO-2022-JP' => 'ISO-2022-JP ('.rcube_label('japanese').')',
- 'ISO-2022-KR' => 'ISO-2022-KR ('.rcube_label('korean').')',
- 'ISO-2022-CN' => 'ISO-2022-CN ('.rcube_label('chinese').')',
- 'EUC-JP' => 'EUC-JP ('.rcube_label('japanese').')',
- 'EUC-KR' => 'EUC-KR ('.rcube_label('korean').')',
- 'EUC-CN' => 'EUC-CN ('.rcube_label('chinese').')',
- 'BIG5' => 'BIG5 ('.rcube_label('chinese').')',
- 'GB2312' => 'GB2312 ('.rcube_label('chinese').')',
+ 'UTF-8' => 'UTF-8 ('.$this->app->gettext('unicode').')',
+ 'US-ASCII' => 'ASCII ('.$this->app->gettext('english').')',
+ 'ISO-8859-1' => 'ISO-8859-1 ('.$this->app->gettext('westerneuropean').')',
+ 'ISO-8859-2' => 'ISO-8859-2 ('.$this->app->gettext('easterneuropean').')',
+ 'ISO-8859-4' => 'ISO-8859-4 ('.$this->app->gettext('baltic').')',
+ 'ISO-8859-5' => 'ISO-8859-5 ('.$this->app->gettext('cyrillic').')',
+ 'ISO-8859-6' => 'ISO-8859-6 ('.$this->app->gettext('arabic').')',
+ 'ISO-8859-7' => 'ISO-8859-7 ('.$this->app->gettext('greek').')',
+ 'ISO-8859-8' => 'ISO-8859-8 ('.$this->app->gettext('hebrew').')',
+ 'ISO-8859-9' => 'ISO-8859-9 ('.$this->app->gettext('turkish').')',
+ 'ISO-8859-10' => 'ISO-8859-10 ('.$this->app->gettext('nordic').')',
+ 'ISO-8859-11' => 'ISO-8859-11 ('.$this->app->gettext('thai').')',
+ 'ISO-8859-13' => 'ISO-8859-13 ('.$this->app->gettext('baltic').')',
+ 'ISO-8859-14' => 'ISO-8859-14 ('.$this->app->gettext('celtic').')',
+ 'ISO-8859-15' => 'ISO-8859-15 ('.$this->app->gettext('westerneuropean').')',
+ 'ISO-8859-16' => 'ISO-8859-16 ('.$this->app->gettext('southeasterneuropean').')',
+ 'WINDOWS-1250' => 'Windows-1250 ('.$this->app->gettext('easterneuropean').')',
+ 'WINDOWS-1251' => 'Windows-1251 ('.$this->app->gettext('cyrillic').')',
+ 'WINDOWS-1252' => 'Windows-1252 ('.$this->app->gettext('westerneuropean').')',
+ 'WINDOWS-1253' => 'Windows-1253 ('.$this->app->gettext('greek').')',
+ 'WINDOWS-1254' => 'Windows-1254 ('.$this->app->gettext('turkish').')',
+ 'WINDOWS-1255' => 'Windows-1255 ('.$this->app->gettext('hebrew').')',
+ 'WINDOWS-1256' => 'Windows-1256 ('.$this->app->gettext('arabic').')',
+ 'WINDOWS-1257' => 'Windows-1257 ('.$this->app->gettext('baltic').')',
+ 'WINDOWS-1258' => 'Windows-1258 ('.$this->app->gettext('vietnamese').')',
+ 'ISO-2022-JP' => 'ISO-2022-JP ('.$this->app->gettext('japanese').')',
+ 'ISO-2022-KR' => 'ISO-2022-KR ('.$this->app->gettext('korean').')',
+ 'ISO-2022-CN' => 'ISO-2022-CN ('.$this->app->gettext('chinese').')',
+ 'EUC-JP' => 'EUC-JP ('.$this->app->gettext('japanese').')',
+ 'EUC-KR' => 'EUC-KR ('.$this->app->gettext('korean').')',
+ 'EUC-CN' => 'EUC-CN ('.$this->app->gettext('chinese').')',
+ 'BIG5' => 'BIG5 ('.$this->app->gettext('chinese').')',
+ 'GB2312' => 'GB2312 ('.$this->app->gettext('chinese').')',
);
if (!empty($_POST['_charset']))
@@ -1348,7 +1580,7 @@ class rcube_template extends rcube_html_page
/**
* Include content from config/about.<LANG>.html if available
*/
- private function about_content($attrib)
+ protected function about_content($attrib)
{
$content = '';
$filenames = array(
@@ -1369,6 +1601,4 @@ class rcube_template extends rcube_html_page
return $content;
}
-} // end class rcube_template
-
-
+}
diff --git a/program/include/rcube_json_output.php b/program/include/rcube_output_json.php
index f062d4b71..73cf76795 100644
--- a/program/include/rcube_json_output.php
+++ b/program/include/rcube_output_json.php
@@ -2,21 +2,20 @@
/*
+-----------------------------------------------------------------------+
- | program/include/rcube_json_output.php |
+ | program/include/rcube_output_json.php |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2010, The Roundcube Dev Team |
+ | Copyright (C) 2008-2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| PURPOSE: |
- | Class to handle HTML page output using a skin template. |
- | Extends rcube_html_page class from rcube_shared.inc |
- | |
+ | Class to handle JSON (AJAX) output |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
+ | Author: Aleksander Machniak <alec@alec.pl> |
+-----------------------------------------------------------------------+
$Id$
@@ -29,37 +28,18 @@
*
* @package View
*/
-class rcube_json_output
+class rcube_output_json extends rcube_output
{
- /**
- * Stores configuration object.
- *
- * @var rcube_config
- */
- private $config;
- private $charset = RCMAIL_CHARSET;
- private $texts = array();
- private $commands = array();
- private $callbacks = array();
- private $message = null;
-
- public $browser;
- public $env = array();
+ protected $texts = array();
+ protected $commands = array();
+ protected $callbacks = array();
+ protected $message = null;
+
public $type = 'js';
public $ajax_call = true;
/**
- * Constructor
- */
- public function __construct($task=null)
- {
- $this->config = rcmail::get_instance()->config;
- $this->browser = new rcube_browser();
- }
-
-
- /**
* Set environment variable
*
* @param string $name Property name
@@ -88,31 +68,10 @@ class rcube_json_output
/**
- * @ignore
- */
- function set_charset($charset)
- {
- // ignore: $this->charset = $charset;
- }
-
-
- /**
- * Get charset for output
- *
- * @return string Output charset
- */
- function get_charset()
- {
- return $this->charset;
- }
-
-
- /**
* Register a template object handler
*
* @param string $obj Object name
* @param string $func Function name to call
- * @return void
*/
public function add_handler($obj, $func)
{
@@ -124,7 +83,6 @@ class rcube_json_output
* Register a list of template object handlers
*
* @param array $arr Hash array with object=>handler pairs
- * @return void
*/
public function add_handlers($arr)
{
@@ -159,7 +117,7 @@ class rcube_json_output
$args = $args[0];
foreach ($args as $name) {
- $this->texts[$name] = rcube_label($name);
+ $this->texts[$name] = $this->app->gettext($name);
}
}
@@ -177,10 +135,11 @@ class rcube_json_output
public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
{
if ($override || !$this->message) {
- if (rcube_label_exists($message)) {
- if (!empty($vars))
- $vars = array_map('Q', $vars);
- $msgtext = rcube_label(array('name' => $message, 'vars' => $vars));
+ if ($this->app->text_exists($message)) {
+ if (!empty($vars)) {
+ $vars = array_map(array('rcube_ui', 'Q'), $vars);
+ }
+ $msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
}
else
$msgtext = $message;
@@ -196,7 +155,7 @@ class rcube_json_output
*/
public function reset()
{
- $this->env = array();
+ parent::reset();
$this->texts = array();
$this->commands = array();
}
@@ -228,6 +187,20 @@ class rcube_json_output
/**
+ * Show error page and terminate script execution
+ *
+ * @param int $code Error code
+ * @param string $message Error message
+ */
+ public function raise_error($code, $message)
+ {
+ $this->show_message("Application Error ($code): $message", 'error');
+ $this->remote_response();
+ exit;
+ }
+
+
+ /**
* Send an AJAX response with executable JS code
*
* @param string $add Additional JS code
@@ -235,13 +208,13 @@ class rcube_json_output
* @return void
* @deprecated
*/
- public function remote_response($add='')
+ protected function remote_response($add='')
{
static $s_header_sent = false;
if (!$s_header_sent) {
$s_header_sent = true;
- send_nocacheing_headers();
+ $this->nocacheing_headers();
header('Content-Type: text/plain; charset=' . $this->get_charset());
}
@@ -251,7 +224,7 @@ class rcube_json_output
$rcmail = rcmail::get_instance();
$response['action'] = $rcmail->action;
- if ($unlock = get_input_value('_unlock', RCUBE_INPUT_GPC)) {
+ if ($unlock = rcube_ui::get_input_value('_unlock', rcube_ui::INPUT_GPC)) {
$response['unlock'] = $unlock;
}
@@ -267,7 +240,7 @@ class rcube_json_output
if (!empty($this->callbacks))
$response['callbacks'] = $this->callbacks;
- echo json_serialize($response);
+ echo self::json_serialize($response);
}
@@ -276,14 +249,14 @@ class rcube_json_output
*
* @return string $out
*/
- private function get_js_commands()
+ protected function get_js_commands()
{
$out = '';
foreach ($this->commands as $i => $args) {
$method = array_shift($args);
foreach ($args as $i => $arg) {
- $args[$i] = json_serialize($arg);
+ $args[$i] = self::json_serialize($arg);
}
$out .= sprintf(
diff --git a/program/include/rcube_plugin.php b/program/include/rcube_plugin.php
index aeb05afa1..e20f7ce6a 100644
--- a/program/include/rcube_plugin.php
+++ b/program/include/rcube_plugin.php
@@ -110,9 +110,10 @@ abstract class rcube_plugin
public function load_config($fname = 'config.inc.php')
{
$fpath = $this->home.'/'.$fname;
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
if (is_file($fpath) && !$rcmail->config->load_from_file($fpath)) {
- raise_error(array('code' => 527, 'type' => 'php',
+ rcube::raise_error(array(
+ 'code' => 527, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Failed to load config from $fpath"), true, false);
return false;
@@ -176,7 +177,7 @@ abstract class rcube_plugin
foreach ($texts as $key => $value)
$add[$domain.'.'.$key] = $value;
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
$rcmail->load_language($lang, $add);
// add labels to client
@@ -196,7 +197,7 @@ abstract class rcube_plugin
*/
public function gettext($p)
{
- return rcmail::get_instance()->gettext($p, $this->ID);
+ return rcube::get_instance()->gettext($p, $this->ID);
}
/**
@@ -309,9 +310,10 @@ abstract class rcube_plugin
*/
public function local_skin_path()
{
- $skin_path = 'skins/'.$this->api->config->get('skin');
- if (!is_dir(realpath(slashify($this->home) . $skin_path)))
- $skin_path = 'skins/default';
+ $rcmail = rcube::get_instance();
+ $skin_path = 'skins/' . $rcmail->config->get('skin');
+ if (!is_dir(realpath(slashify($this->home) . $skin_path)))
+ $skin_path = 'skins/default';
return $skin_path;
}
diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php
index be12f11b5..95fd3b66a 100644
--- a/program/include/rcube_plugin_api.php
+++ b/program/include/rcube_plugin_api.php
@@ -22,6 +22,11 @@
*/
+// location where plugins are loade from
+if (!defined('RCMAIL_PLUGINS_DIR'))
+ define('RCMAIL_PLUGINS_DIR', INSTALL_PATH . 'plugins/');
+
+
/**
* The plugin loader and global API
*
@@ -33,8 +38,8 @@ class rcube_plugin_api
public $dir;
public $url = 'plugins/';
+ public $task = '';
public $output;
- public $config;
public $handlers = array();
private $plugins = array();
@@ -43,7 +48,6 @@ class rcube_plugin_api
private $actionmap = array();
private $objectsmap = array();
private $template_contents = array();
- private $required_plugins = array('filesystem_attachments', 'jqueryui');
private $active_hook = false;
// Deprecated names of hooks, will be removed after 0.5-stable release
@@ -99,29 +103,48 @@ class rcube_plugin_api
*/
private function __construct()
{
- $this->dir = INSTALL_PATH . $this->url;
+ $this->dir = slashify(RCMAIL_PLUGINS_DIR);
}
/**
- * Load and init all enabled plugins
+ * Initialize plugin engine
*
* This has to be done after rcmail::load_gui() or rcmail::json_init()
* was called because plugins need to have access to rcmail->output
+ *
+ * @param object rcube Instance of the rcube base class
+ * @param string Current application task (used for conditional plugin loading)
*/
- public function init()
+ public function init($app, $task = '')
{
- $rcmail = rcmail::get_instance();
- $this->output = $rcmail->output;
- $this->config = $rcmail->config;
+ $this->task = $task;
+ $this->output = $app->output;
+
+ // register an internal hook
+ $this->register_hook('template_container', array($this, 'template_container_hook'));
- $plugins_enabled = (array)$rcmail->config->get('plugins', array());
+ // maybe also register a shudown function which triggers shutdown functions of all plugin objects
+ }
+
+
+ /**
+ * Load and init all enabled plugins
+ *
+ * This has to be done after rcmail::load_gui() or rcmail::json_init()
+ * was called because plugins need to have access to rcmail->output
+ *
+ * @param array List of configured plugins to load
+ * @param array List of plugins required by the application
+ */
+ public function load_plugins($plugins_enabled, $required_plugins = array())
+ {
foreach ($plugins_enabled as $plugin_name) {
$this->load_plugin($plugin_name);
}
// check existance of all required core plugins
- foreach ($this->required_plugins as $plugin_name) {
+ foreach ($required_plugins as $plugin_name) {
$loaded = false;
foreach ($this->plugins as $plugin) {
if ($plugin instanceof $plugin_name) {
@@ -136,19 +159,13 @@ class rcube_plugin_api
// trigger fatal error if still not loaded
if (!$loaded) {
- raise_error(array('code' => 520, 'type' => 'php',
+ rcube::raise_error(array('code' => 520, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Requried plugin $plugin_name was not loaded"), true, true);
}
}
-
- // register an internal hook
- $this->register_hook('template_container', array($this, 'template_container_hook'));
-
- // maybe also register a shudown function which triggers shutdown functions of all plugin objects
}
-
/**
* Load the specified plugin
*
@@ -159,8 +176,6 @@ class rcube_plugin_api
{
static $plugins_dir;
- $rcmail = rcmail::get_instance();
-
if (!$plugins_dir) {
$dir = dir($this->dir);
$plugins_dir = unslashify($dir->path);
@@ -181,8 +196,8 @@ class rcube_plugin_api
// check inheritance...
if (is_subclass_of($plugin, 'rcube_plugin')) {
// ... task, request type and framed mode
- if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $rcmail->task))
- && (!$plugin->noajax || (is_object($rcmail->output) && is_a($rcmail->output, 'rcube_template')))
+ if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $this->task))
+ && (!$plugin->noajax || (is_object($this->output) && $this->output->type == 'html'))
&& (!$plugin->noframe || empty($_REQUEST['_framed']))
) {
$plugin->init();
@@ -192,13 +207,13 @@ class rcube_plugin_api
}
}
else {
- raise_error(array('code' => 520, 'type' => 'php',
+ rcube::raise_error(array('code' => 520, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "No plugin class $plugin_name found in $fn"), true, false);
}
}
else {
- raise_error(array('code' => 520, 'type' => 'php',
+ rcube::raise_error(array('code' => 520, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Failed to load plugin file $fn"), true, false);
}
@@ -217,7 +232,7 @@ class rcube_plugin_api
{
if (is_callable($callback)) {
if (isset($this->deprecated_hooks[$hook])) {
- raise_error(array('code' => 522, 'type' => 'php',
+ rcube::raise_error(array('code' => 522, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Deprecated hook name. ".$hook.' -> '.$this->deprecated_hooks[$hook]), true, false);
$hook = $this->deprecated_hooks[$hook];
@@ -225,7 +240,7 @@ class rcube_plugin_api
$this->handlers[$hook][] = $callback;
}
else
- raise_error(array('code' => 521, 'type' => 'php',
+ rcube::raise_error(array('code' => 521, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Invalid callback function for $hook"), true, false);
}
@@ -297,7 +312,7 @@ class rcube_plugin_api
$this->actionmap[$action] = $owner;
}
else {
- raise_error(array('code' => 523, 'type' => 'php',
+ rcube::raise_error(array('code' => 523, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Cannot register action $action; already taken by another plugin"), true, false);
}
@@ -316,7 +331,7 @@ class rcube_plugin_api
call_user_func($this->actions[$action]);
}
else {
- raise_error(array('code' => 524, 'type' => 'php',
+ rcube::raise_error(array('code' => 524, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "No handler found for action $action"), true, true);
}
@@ -337,14 +352,14 @@ class rcube_plugin_api
$name = 'plugin.'.$name;
// can register handler only if it's not taken or registered by myself
- if (!isset($this->objectsmap[$name]) || $this->objectsmap[$name] == $owner) {
+ if (is_object($this->output) && (!isset($this->objectsmap[$name]) || $this->objectsmap[$name] == $owner)) {
$this->output->add_handler($name, $callback);
$this->objectsmap[$name] = $owner;
}
else {
- raise_error(array('code' => 525, 'type' => 'php',
+ rcube::raise_error(array('code' => 525, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Cannot register template handler $name; already taken by another plugin"), true, false);
+ 'message' => "Cannot register template handler $name; already taken by another plugin or no output object available"), true, false);
}
}
@@ -358,12 +373,12 @@ class rcube_plugin_api
public function register_task($task, $owner)
{
if ($task != asciiwords($task)) {
- raise_error(array('code' => 526, 'type' => 'php',
+ rcube::raise_error(array('code' => 526, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Invalid task name: $task. Only characters [a-z0-9_.-] are allowed"), true, false);
}
else if (in_array($task, rcmail::$main_tasks)) {
- raise_error(array('code' => 526, 'type' => 'php',
+ rcube::raise_error(array('code' => 526, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Cannot register taks $task; already taken by another plugin or the application itself"), true, false);
}
@@ -408,7 +423,7 @@ class rcube_plugin_api
*/
public function include_script($fn)
{
- if ($this->output->type == 'html') {
+ if (is_object($this->output) && $this->output->type == 'html') {
$src = $this->resource_url($fn);
$this->output->add_header(html::tag('script', array('type' => "text/javascript", 'src' => $src)));
}
@@ -422,7 +437,7 @@ class rcube_plugin_api
*/
public function include_stylesheet($fn)
{
- if ($this->output->type == 'html') {
+ if (is_object($this->output) && $this->output->type == 'html') {
$src = $this->resource_url($fn);
$this->output->include_css($src);
}
diff --git a/program/include/rcube_session.php b/program/include/rcube_session.php
index e6e636e18..da221c30e 100644
--- a/program/include/rcube_session.php
+++ b/program/include/rcube_session.php
@@ -78,7 +78,7 @@ class rcube_session
array($this, 'gc'));
}
else {
- raise_error(array('code' => 604, 'type' => 'db',
+ rcube::raise_error(array('code' => 604, 'type' => 'db',
'line' => __LINE__, 'file' => __FILE__,
'message' => "Failed to connect to memcached. Please check configuration"),
true, true);
@@ -129,7 +129,7 @@ class rcube_session
public function db_read($key)
{
$sql_result = $this->db->query(
- "SELECT vars, ip, changed FROM ".get_table_name('session')
+ "SELECT vars, ip, changed FROM ".$this->db->table_name('session')
." WHERE sess_id = ?", $key);
if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) {
@@ -177,18 +177,18 @@ class rcube_session
if ($newvars !== $oldvars) {
$this->db->query(
sprintf("UPDATE %s SET vars=?, changed=%s WHERE sess_id=?",
- get_table_name('session'), $now),
+ $this->db->table_name('session'), $now),
base64_encode($newvars), $key);
}
else if ($ts - $this->changed > $this->lifetime / 2) {
- $this->db->query("UPDATE ".get_table_name('session')." SET changed=$now WHERE sess_id=?", $key);
+ $this->db->query("UPDATE ".$this->db->table_name('session')." SET changed=$now WHERE sess_id=?", $key);
}
}
else {
$this->db->query(
sprintf("INSERT INTO %s (sess_id, vars, ip, created, changed) ".
"VALUES (?, ?, ?, %s, %s)",
- get_table_name('session'), $now, $now),
+ $this->db->table_name('session'), $now, $now),
$key, base64_encode($vars), (string)$this->ip);
}
@@ -228,7 +228,7 @@ class rcube_session
public function db_destroy($key)
{
$this->db->query(
- sprintf("DELETE FROM %s WHERE sess_id = ?", get_table_name('session')),
+ sprintf("DELETE FROM %s WHERE sess_id = ?", $this->db->table_name('session')),
$key);
return true;
@@ -246,7 +246,7 @@ class rcube_session
// just delete all expired sessions
$this->db->query(
sprintf("DELETE FROM %s WHERE changed < %s",
- get_table_name('session'), $this->db->fromunixtime(time() - $maxlifetime)));
+ $this->db->table_name('session'), $this->db->fromunixtime(time() - $maxlifetime)));
$this->gc();
@@ -322,8 +322,9 @@ class rcube_session
*/
public function gc()
{
- foreach ($this->gc_handlers as $fct)
+ foreach ($this->gc_handlers as $fct) {
call_user_func($fct);
+ }
}
@@ -624,14 +625,14 @@ class rcube_session
$auth_string = "$this->key,$this->secret,$timeslot";
return "S" . (function_exists('sha1') ? sha1($auth_string) : md5($auth_string));
}
-
+
/**
*
*/
function log($line)
{
if ($this->logging)
- write_log('session', $line);
+ rcmail::write_log('session', $line);
}
}
diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc
index 9340091bb..2e9444717 100644
--- a/program/include/rcube_shared.inc
+++ b/program/include/rcube_shared.inc
@@ -2,17 +2,17 @@
/*
+-----------------------------------------------------------------------+
- | rcube_shared.inc |
+ | program/include/rcube_shared.inc |
| |
| This file is part of the Roundcube PHP suite |
- | Copyright (C) 2005-2007, The Roundcube Dev Team |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
| See the README file for a full license statement. |
| |
| CONTENTS: |
- | Shared functions and classes used in PHP projects |
+ | Shared functions used by Roundcube Framework |
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube@gmail.com> |
@@ -31,213 +31,95 @@
/**
- * Send HTTP headers to prevent caching this page
- */
-function send_nocacheing_headers()
-{
- global $OUTPUT;
-
- if (headers_sent())
- return;
-
- header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
- header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
- // Request browser to disable DNS prefetching (CVE-2010-0464)
- header("X-DNS-Prefetch-Control: off");
-
- // We need to set the following headers to make downloads work using IE in HTTPS mode.
- if ($OUTPUT->browser->ie && rcube_https_check()) {
- header('Pragma: private');
- header("Cache-Control: private, must-revalidate");
- } else {
- header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0");
- header("Pragma: no-cache");
- }
-}
-
-
-/**
- * Send header with expire date 30 days in future
- *
- * @param int Expiration time in seconds
- */
-function send_future_expire_header($offset=2600000)
-{
- if (headers_sent())
- return;
-
- header("Expires: ".gmdate("D, d M Y H:i:s", mktime()+$offset)." GMT");
- header("Cache-Control: max-age=$offset");
- header("Pragma: ");
-}
-
-
-/**
* Similar function as in_array() but case-insensitive
*
- * @param mixed Needle value
- * @param array Array to search in
+ * @param string $needle Needle value
+ * @param array $heystack Array to search in
+ *
* @return boolean True if found, False if not
*/
function in_array_nocase($needle, $haystack)
{
- $needle = mb_strtolower($needle);
- foreach ($haystack as $value)
- if ($needle===mb_strtolower($value))
- return true;
+ $needle = mb_strtolower($needle);
+ foreach ($haystack as $value) {
+ if ($needle === mb_strtolower($value)) {
+ return true;
+ }
+ }
- return false;
+ return false;
}
/**
- * Find out if the string content means TRUE or FALSE
+ * Find out if the string content means true or false
*
- * @param string Input value
- * @return boolean Imagine what!
+ * @param string $str Input value
+ *
+ * @return boolean Boolean value
*/
function get_boolean($str)
{
- $str = strtolower($str);
- if (in_array($str, array('false', '0', 'no', 'off', 'nein', ''), TRUE))
- return FALSE;
- else
- return TRUE;
+ $str = strtolower($str);
+
+ return !in_array($str, array('false', '0', 'no', 'off', 'nein', ''), true);
}
/**
- * Parse a human readable string for a number of bytes
+ * Parse a human readable string for a number of bytes.
+ *
+ * @param string $str Input string
*
- * @param string Input string
* @return float Number of bytes
*/
function parse_bytes($str)
{
- if (is_numeric($str))
- return floatval($str);
-
- if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs))
- {
- $bytes = floatval($regs[1]);
- switch (strtolower($regs[2]))
- {
- case 'g':
- case 'gb':
- $bytes *= 1073741824;
- break;
- case 'm':
- case 'mb':
- $bytes *= 1048576;
- break;
- case 'k':
- case 'kb':
- $bytes *= 1024;
- break;
+ if (is_numeric($str)) {
+ return floatval($str);
}
- }
- return floatval($bytes);
-}
-
-/**
- * Create a human readable string for a number of bytes
- *
- * @param int Number of bytes
- * @return string Byte string
- */
-function show_bytes($bytes)
-{
- if ($bytes >= 1073741824)
- {
- $gb = $bytes/1073741824;
- $str = sprintf($gb>=10 ? "%d " : "%.1f ", $gb) . rcube_label('GB');
- }
- else if ($bytes >= 1048576)
- {
- $mb = $bytes/1048576;
- $str = sprintf($mb>=10 ? "%d " : "%.1f ", $mb) . rcube_label('MB');
- }
- else if ($bytes >= 1024)
- $str = sprintf("%d ", round($bytes/1024)) . rcube_label('KB');
- else
- $str = sprintf('%d ', $bytes) . rcube_label('B');
-
- return $str;
-}
-
-/**
- * Wrapper function for wordwrap
- */
-function rc_wordwrap($string, $width=75, $break="\n", $cut=false)
-{
- $para = explode($break, $string);
- $string = '';
- while (count($para)) {
- $line = array_shift($para);
- if ($line[0] == '>') {
- $string .= $line.$break;
- continue;
- }
- $list = explode(' ', $line);
- $len = 0;
- while (count($list)) {
- $line = array_shift($list);
- $l = mb_strlen($line);
- $newlen = $len + $l + ($len ? 1 : 0);
-
- if ($newlen <= $width) {
- $string .= ($len ? ' ' : '').$line;
- $len += (1 + $l);
- } else {
- if ($l > $width) {
- if ($cut) {
- $start = 0;
- while ($l) {
- $str = mb_substr($line, $start, $width);
- $strlen = mb_strlen($str);
- $string .= ($len ? $break : '').$str;
- $start += $strlen;
- $l -= $strlen;
- $len = $strlen;
- }
- } else {
- $string .= ($len ? $break : '').$line;
- if (count($list)) $string .= $break;
- $len = 0;
- }
- } else {
- $string .= $break.$line;
- $len = $l;
+ if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs)) {
+ $bytes = floatval($regs[1]);
+ switch (strtolower($regs[2])) {
+ case 'g':
+ case 'gb':
+ $bytes *= 1073741824;
+ break;
+ case 'm':
+ case 'mb':
+ $bytes *= 1048576;
+ break;
+ case 'k':
+ case 'kb':
+ $bytes *= 1024;
+ break;
}
- }
}
- if (count($para)) $string .= $break;
- }
- return $string;
+
+ return floatval($bytes);
}
+
/**
- * Read a specific HTTP request header
+ * Read a specific HTTP request header.
*
- * @access static
* @param string $name Header name
+ *
* @return mixed Header value or null if not available
*/
-function rc_request_header($name)
+function rcube_request_header($name)
{
- if (function_exists('getallheaders'))
- {
- $hdrs = array_change_key_case(getallheaders(), CASE_UPPER);
- $key = strtoupper($name);
- }
- else
- {
- $key = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
- $hdrs = array_change_key_case($_SERVER, CASE_UPPER);
- }
-
- return $hdrs[$key];
+ if (function_exists('getallheaders')) {
+ $hdrs = array_change_key_case(getallheaders(), CASE_UPPER);
+ $key = strtoupper($name);
+ }
+ else {
+ $key = 'HTTP_' . strtoupper(strtr($name, '-', '_'));
+ $hdrs = array_change_key_case($_SERVER, CASE_UPPER);
+ }
+
+ return $hdrs[$key];
}
@@ -263,219 +145,251 @@ function unslashify($str)
* Delete all files within a folder
*
* @param string Path to directory
+ *
* @return boolean True on success, False if directory was not found
*/
function clear_directory($dir_path)
{
- $dir = @opendir($dir_path);
- if(!$dir) return FALSE;
+ $dir = @opendir($dir_path);
+ if (!$dir) {
+ return false;
+ }
- while ($file = readdir($dir))
- if (strlen($file)>2)
- unlink("$dir_path/$file");
+ while ($file = readdir($dir)) {
+ if (strlen($file) > 2) {
+ unlink("$dir_path/$file");
+ }
+ }
- closedir($dir);
- return TRUE;
+ closedir($dir);
+
+ return true;
}
/**
- * Create a unix timestamp with a specified offset from now
+ * Create a unix timestamp with a specified offset from now.
+ *
+ * @param string $offset_str String representation of the offset (e.g. 20min, 5h, 2days)
+ * @param int $factor Factor to multiply with the offset
*
- * @param string String representation of the offset (e.g. 20min, 5h, 2days)
- * @param int Factor to multiply with the offset
* @return int Unix timestamp
*/
function get_offset_time($offset_str, $factor=1)
{
- if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs))
- {
- $amount = (int)$regs[1];
- $unit = strtolower($regs[2]);
- }
- else
- {
- $amount = (int)$offset_str;
- $unit = 's';
- }
-
- $ts = mktime();
- switch ($unit)
- {
+ if (preg_match('/^([0-9]+)\s*([smhdw])/i', $offset_str, $regs)) {
+ $amount = (int)$regs[1];
+ $unit = strtolower($regs[2]);
+ }
+ else {
+ $amount = (int)$offset_str;
+ $unit = 's';
+ }
+
+ $ts = mktime();
+ switch ($unit) {
case 'w':
- $amount *= 7;
+ $amount *= 7;
case 'd':
- $amount *= 24;
+ $amount *= 24;
case 'h':
- $amount *= 60;
+ $amount *= 60;
case 'm':
- $amount *= 60;
+ $amount *= 60;
case 's':
- $ts += $amount * $factor;
- }
+ $ts += $amount * $factor;
+ }
- return $ts;
+ return $ts;
}
/**
- * Truncate string if it is longer than the allowed length
- * Replace the middle or the ending part of a string with a placeholder
+ * Truncate string if it is longer than the allowed length.
+ * Replace the middle or the ending part of a string with a placeholder.
+ *
+ * @param string $str Input string
+ * @param int $maxlength Max. length
+ * @param string $placeholder Replace removed chars with this
+ * @param bool $ending Set to True if string should be truncated from the end
*
- * @param string Input string
- * @param int Max. length
- * @param string Replace removed chars with this
- * @param bool Set to True if string should be truncated from the end
* @return string Abbreviated string
*/
-function abbreviate_string($str, $maxlength, $place_holder='...', $ending=false)
+function abbreviate_string($str, $maxlength, $placeholder='...', $ending=false)
{
- $length = mb_strlen($str);
+ $length = mb_strlen($str);
- if ($length > $maxlength)
- {
- if ($ending)
- return mb_substr($str, 0, $maxlength) . $place_holder;
+ if ($length > $maxlength) {
+ if ($ending) {
+ return mb_substr($str, 0, $maxlength) . $placeholder;
+ }
+
+ $placeholder_length = mb_strlen($placeholder);
+ $first_part_length = floor(($maxlength - $placeholder_length)/2);
+ $second_starting_location = $length - $maxlength + $first_part_length + $placeholder_length;
- $place_holder_length = mb_strlen($place_holder);
- $first_part_length = floor(($maxlength - $place_holder_length)/2);
- $second_starting_location = $length - $maxlength + $first_part_length + $place_holder_length;
- $str = mb_substr($str, 0, $first_part_length) . $place_holder . mb_substr($str, $second_starting_location);
- }
+ $str = mb_substr($str, 0, $first_part_length) . $placeholder . mb_substr($str, $second_starting_location);
+ }
- return $str;
+ return $str;
}
/**
- * A method to guess the mime_type of an attachment.
- *
- * @param string $path Path to the file.
- * @param string $name File name (with suffix)
- * @param string $failover Mime type supplied for failover.
- * @param string $is_stream Set to True if $path contains file body
+ * Explode quoted string
*
- * @return string
- * @author Till Klampaeckel <till@php.net>
- * @see http://de2.php.net/manual/en/ref.fileinfo.php
- * @see http://de2.php.net/mime_content_type
+ * @param string Delimiter expression string for preg_match()
+ * @param string Input string
*/
-function rc_mime_content_type($path, $name, $failover = 'application/octet-stream', $is_stream=false)
+function rcube_explode_quoted_string($delimiter, $string)
{
- $mime_type = null;
- $mime_magic = rcmail::get_instance()->config->get('mime_magic');
- $mime_ext = @include(RCMAIL_CONFIG_DIR . '/mimetypes.php');
-
- // use file name suffix with hard-coded mime-type map
- if (is_array($mime_ext) && $name) {
- if ($suffix = substr($name, strrpos($name, '.')+1)) {
- $mime_type = $mime_ext[strtolower($suffix)];
+ $result = array();
+ $strlen = strlen($string);
+
+ for ($q=$p=$i=0; $i < $strlen; $i++) {
+ if ($string[$i] == "\"" && $string[$i-1] != "\\") {
+ $q = $q ? false : true;
+ }
+ else if (!$q && preg_match("/$delimiter/", $string[$i])) {
+ $result[] = substr($string, $p, $i - $p);
+ $p = $i + 1;
}
}
- // try fileinfo extension if available
- if (!$mime_type && function_exists('finfo_open')) {
- if ($finfo = finfo_open(FILEINFO_MIME, $mime_magic)) {
- if ($is_stream)
- $mime_type = finfo_buffer($finfo, $path);
- else
- $mime_type = finfo_file($finfo, $path);
- finfo_close($finfo);
+ $result[] = substr($string, $p);
+
+ return $result;
+}
+
+
+/**
+ * Get all keys from array (recursive).
+ *
+ * @param array $array Input array
+ *
+ * @return array List of array keys
+ */
+function array_keys_recursive($array)
+{
+ $keys = array();
+
+ if (!empty($array)) {
+ foreach ($array as $key => $child) {
+ $keys[] = $key;
+ foreach (array_keys_recursive($child) as $val) {
+ $keys[] = $val;
+ }
}
}
- // try PHP's mime_content_type
- if (!$mime_type && !$is_stream && function_exists('mime_content_type')) {
- $mime_type = @mime_content_type($path);
- }
+ return $keys;
+}
- // fall back to user-submitted string
- if (!$mime_type) {
- $mime_type = $failover;
- }
- else {
- // Sometimes (PHP-5.3?) content-type contains charset definition,
- // Remove it (#1487122) also "charset=binary" is useless
- $mime_type = array_shift(preg_split('/[; ]/', $mime_type));
- }
- return $mime_type;
+/**
+ * Remove all non-ascii and non-word chars except ., -, _
+ */
+function asciiwords($str, $css_id = false, $replace_with = '')
+{
+ $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : '');
+ return preg_replace("/[^$allowed]/i", $replace_with, $str);
}
/**
- * Detect image type of the given binary data by checking magic numbers
+ * Remove single and double quotes from given string
*
- * @param string Binary file content
- * @return string Detected mime-type or jpeg as fallback
+ * @param string Input value
+ *
+ * @return string Dequoted string
*/
-function rc_image_content_type($data)
+function strip_quotes($str)
{
- $type = 'jpeg';
- if (preg_match('/^\x89\x50\x4E\x47/', $data)) $type = 'png';
- else if (preg_match('/^\x47\x49\x46\x38/', $data)) $type = 'gif';
- else if (preg_match('/^\x00\x00\x01\x00/', $data)) $type = 'ico';
-// else if (preg_match('/^\xFF\xD8\xFF\xE0/', $data)) $type = 'jpeg';
+ return str_replace(array("'", '"'), '', $str);
+}
- return 'image/' . $type;
+
+/**
+ * Remove new lines characters from given string
+ *
+ * @param string $str Input value
+ *
+ * @return string Stripped string
+ */
+function strip_newlines($str)
+{
+ return preg_replace('/[\r\n]/', '', $str);
}
/**
- * Explode quoted string
- *
- * @param string Delimiter expression string for preg_match()
- * @param string Input string
+ * Improved equivalent to strtotime()
+ *
+ * @param string $date Date string
+ *
+ * @return int Unix timestamp
*/
-function rcube_explode_quoted_string($delimiter, $string)
+function rcube_strtotime($date)
{
- $result = array();
- $strlen = strlen($string);
-
- for ($q=$p=$i=0; $i < $strlen; $i++) {
- if ($string[$i] == "\"" && $string[$i-1] != "\\") {
- $q = $q ? false : true;
- }
- else if (!$q && preg_match("/$delimiter/", $string[$i])) {
- $result[] = substr($string, $p, $i - $p);
- $p = $i + 1;
+ // check for MS Outlook vCard date format YYYYMMDD
+ if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) {
+ return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1]));
+ }
+ else if (is_numeric($date)) {
+ return $date;
+ }
+
+ // support non-standard "GMTXXXX" literal
+ $date = preg_replace('/GMT\s*([+-][0-9]+)/', '\\1', $date);
+
+ // if date parsing fails, we have a date in non-rfc format.
+ // remove token from the end and try again
+ while ((($ts = @strtotime($date)) === false) || ($ts < 0)) {
+ $d = explode(' ', $date);
+ array_pop($d);
+ if (!$d) {
+ break;
+ }
+ $date = implode(' ', $d);
}
- }
- $result[] = substr($string, $p);
- return $result;
+ return $ts;
}
/**
- * Get all keys from array (recursive)
- *
- * @param array Input array
- * @return array
+ * Compose a valid representation of name and e-mail address
+ *
+ * @param string $email E-mail address
+ * @param string $name Person name
+ *
+ * @return string Formatted string
*/
-function array_keys_recursive($array)
+function format_email_recipient($email, $name = '')
{
- $keys = array();
+ $email = trim($email);
+
+ if ($name && $name != $email) {
+ // Special chars as defined by RFC 822 need to in quoted string (or escaped).
+ if (preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) {
+ $name = '"'.addcslashes($name, '"').'"';
+ }
- if (!empty($array))
- foreach ($array as $key => $child) {
- $keys[] = $key;
- foreach (array_keys_recursive($child) as $val)
- $keys[] = $val;
+ return "$name <$email>";
}
- return $keys;
+
+ return $email;
}
/**
* mbstring replacement functions
*/
-
if (!extension_loaded('mbstring'))
{
function mb_strlen($str)
{
- return strlen($str);
+ return strlen($str);
}
function mb_strtolower($str)
@@ -552,3 +466,89 @@ if (!function_exists('idn_to_ascii'))
}
}
+
+/*
+ * Idn_to_ascii wrapper.
+ * Intl/Idn modules version of this function doesn't work with e-mail address
+ */
+function rcube_idn_to_ascii($str)
+{
+ return rcube_idn_convert($str, true);
+}
+
+/*
+ * Idn_to_ascii wrapper.
+ * Intl/Idn modules version of this function doesn't work with e-mail address
+ */
+function rcube_idn_to_utf8($str)
+{
+ return rcube_idn_convert($str, false);
+}
+
+function rcube_idn_convert($input, $is_utf=false)
+{
+ if ($at = strpos($input, '@')) {
+ $user = substr($input, 0, $at);
+ $domain = substr($input, $at+1);
+ }
+ else {
+ $domain = $input;
+ }
+
+ $domain = $is_utf ? idn_to_ascii($domain) : idn_to_utf8($domain);
+
+ if ($domain === false) {
+ return '';
+ }
+
+ return $at ? $user . '@' . $domain : $domain;
+}
+
+
+/**
+ * Use PHP5 autoload for dynamic class loading
+ *
+ * @todo Make Zend, PEAR etc play with this
+ * @todo Make our classes conform to a more straight forward CS.
+ */
+function rcube_autoload($classname)
+{
+ $filename = preg_replace(
+ array(
+ '/MDB2_(.+)/',
+ '/Mail_(.+)/',
+ '/Net_(.+)/',
+ '/Auth_(.+)/',
+ '/^html_.+/',
+ '/^utf8$/',
+ ),
+ array(
+ 'MDB2/\\1',
+ 'Mail/\\1',
+ 'Net/\\1',
+ 'Auth/\\1',
+ 'html',
+ 'utf8.class',
+ ),
+ $classname
+ );
+
+ if ($fp = @fopen("$filename.php", 'r', true)) {
+ fclose($fp);
+ include_once("$filename.php");
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Local callback function for PEAR errors
+ */
+function rcube_pear_error($err)
+{
+ error_log(sprintf("%s (%s): %s",
+ $err->getMessage(),
+ $err->getCode(),
+ $err->getUserinfo()), 0);
+}
diff --git a/program/include/rcube_smtp.php b/program/include/rcube_smtp.php
index 854505d79..0923e3be0 100644
--- a/program/include/rcube_smtp.php
+++ b/program/include/rcube_smtp.php
@@ -52,7 +52,7 @@ class rcube_smtp
*/
public function connect($host=null, $port=null, $user=null, $pass=null)
{
- $RCMAIL = rcmail::get_instance();
+ $RCMAIL = rcube::get_instance();
// disconnect/destroy $this->conn
$this->disconnect();
@@ -74,7 +74,7 @@ class rcube_smtp
'smtp_auth_callbacks' => array(),
));
- $smtp_host = rcube_parse_host($CONFIG['smtp_server']);
+ $smtp_host = rcmail::parse_host($CONFIG['smtp_server']);
// when called from Installer it's possible to have empty $smtp_host here
if (!$smtp_host) $smtp_host = 'localhost';
$smtp_port = is_numeric($CONFIG['smtp_port']) ? $CONFIG['smtp_port'] : 25;
@@ -338,7 +338,7 @@ class rcube_smtp
*/
public function debug_handler(&$smtp, $message)
{
- write_log('smtp', preg_replace('/\r\n$/', '', $message));
+ rcmail::write_log('smtp', preg_replace('/\r\n$/', '', $message));
}
diff --git a/program/include/rcube_spellchecker.php b/program/include/rcube_spellchecker.php
index a6f391346..8dfc3ead1 100644
--- a/program/include/rcube_spellchecker.php
+++ b/program/include/rcube_spellchecker.php
@@ -61,7 +61,7 @@ class rcube_spellchecker
$this->lang = $lang ? $lang : 'en';
if ($this->engine == 'pspell' && !extension_loaded('pspell')) {
- raise_error(array(
+ rcube::raise_error(array(
'code' => 500, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Pspell extension not available"), true, true);
@@ -535,7 +535,7 @@ class rcube_spellchecker
private function update_dict()
{
if (strcasecmp($this->options['dictionary'], 'shared') != 0) {
- $userid = (int) $this->rc->user->ID;
+ $userid = $this->rc->get_user_id();
}
$plugin = $this->rc->plugins->exec_hook('spell_dictionary_save', array(
@@ -548,24 +548,24 @@ class rcube_spellchecker
if ($this->have_dict) {
if (!empty($this->dict)) {
$this->rc->db->query(
- "UPDATE ".get_table_name('dictionary')
+ "UPDATE ".$this->rc->db->table_name('dictionary')
." SET data = ?"
- ." WHERE user_id " . ($plugin['userid'] ? "= ".$plugin['userid'] : "IS NULL")
+ ." WHERE user_id " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quoteIdentifier('language') . " = ?",
implode(' ', $plugin['dictionary']), $plugin['language']);
}
// don't store empty dict
else {
$this->rc->db->query(
- "DELETE FROM " . get_table_name('dictionary')
- ." WHERE user_id " . ($plugin['userid'] ? "= ".$plugin['userid'] : "IS NULL")
+ "DELETE FROM " . $this->rc->db->table_name('dictionary')
+ ." WHERE user_id " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quoteIdentifier('language') . " = ?",
$plugin['language']);
}
}
else if (!empty($this->dict)) {
$this->rc->db->query(
- "INSERT INTO " .get_table_name('dictionary')
+ "INSERT INTO " .$this->rc->db->table_name('dictionary')
." (user_id, " . $this->rc->db->quoteIdentifier('language') . ", data) VALUES (?, ?, ?)",
$plugin['userid'], $plugin['language'], implode(' ', $plugin['dictionary']));
}
@@ -582,7 +582,7 @@ class rcube_spellchecker
}
if (strcasecmp($this->options['dictionary'], 'shared') != 0) {
- $userid = (int) $this->rc->user->ID;
+ $userid = $this->rc->get_user_id();
}
$plugin = $this->rc->plugins->exec_hook('spell_dictionary_get', array(
@@ -591,8 +591,8 @@ class rcube_spellchecker
if (empty($plugin['abort'])) {
$dict = array();
$this->rc->db->query(
- "SELECT data FROM ".get_table_name('dictionary')
- ." WHERE user_id ". ($plugin['userid'] ? "= ".$plugin['userid'] : "IS NULL")
+ "SELECT data FROM ".$this->rc->db->table_name('dictionary')
+ ." WHERE user_id ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL")
." AND " . $this->rc->db->quoteIdentifier('language') . " = ?",
$plugin['language']);
diff --git a/program/include/rcube_sqlite.inc b/program/include/rcube_sqlite.inc
deleted file mode 100644
index 3b74b2665..000000000
--- a/program/include/rcube_sqlite.inc
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcube_sqlite.inc |
- | |
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2010, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Provide callback functions for sqlite that will emulate |
- | sone MySQL functions |
- | |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube@gmail.com> |
- +-----------------------------------------------------------------------+
-
- $Id$
-
-*/
-
-/**
- * Callback functions for sqlite database interface
- *
- * @package Database
- */
-
-
-function rcube_sqlite_from_unixtime($timestamp)
-{
- $timestamp = trim($timestamp);
- if (!preg_match('/^[0-9]+$/is', $timestamp))
- $ret = strtotime($timestamp);
- else
- $ret = $timestamp;
-
- $ret = date('Y-m-d H:i:s', $ret);
- rcube_sqlite_debug("FROM_UNIXTIME ($timestamp) = $ret");
- return $ret;
-}
-
-
-function rcube_sqlite_unix_timestamp($timestamp='')
-{
- $timestamp = trim($timestamp);
- if (!$timestamp)
- $ret = time();
- else if (!preg_match('/^[0-9]+$/is', $timestamp))
- $ret = strtotime($timestamp);
- else
- $ret = $timestamp;
-
- rcube_sqlite_debug("UNIX_TIMESTAMP ($timestamp) = $ret");
- return $ret;
-}
-
-
-function rcube_sqlite_now()
-{
- rcube_sqlite_debug("NOW() = ".date("Y-m-d H:i:s"));
- return date("Y-m-d H:i:s");
-}
-
-
-function rcube_sqlite_md5($str)
-{
- return md5($str);
-}
-
-
-function rcube_sqlite_debug($str)
-{
- //console($str);
-}
-
diff --git a/program/include/rcube_storage.php b/program/include/rcube_storage.php
index 8123e9cee..e80ee6abc 100644
--- a/program/include/rcube_storage.php
+++ b/program/include/rcube_storage.php
@@ -434,7 +434,7 @@ abstract class rcube_storage
* @param int $uid Message UID to fetch
* @param string $folder Folder to read from
*
- * @return object rcube_mail_header Message data
+ * @return object rcube_message_header Message data
*/
abstract function get_message($uid, $folder = null);
@@ -446,7 +446,7 @@ abstract class rcube_storage
* @param string $folder Folder to read from
* @param bool $force True to skip cache
*
- * @return rcube_mail_header Message headers
+ * @return rcube_message_header Message headers
*/
abstract function get_message_headers($uid, $folder = null, $force = false);
@@ -477,7 +477,7 @@ abstract class rcube_storage
public function get_body($uid, $part = 1)
{
$headers = $this->get_message_headers($uid);
- return rcube_charset_convert($this->get_message_part($uid, $part, null),
+ return rcube_charset::convert($this->get_message_part($uid, $part, null),
$headers->charset ? $headers->charset : $this->default_charset);
}
@@ -970,6 +970,7 @@ abstract class rcube_storage
*/
abstract function clear_cache($key = null, $prefix_mode = false);
+
/**
* Returns cached value
*
@@ -979,93 +980,10 @@ abstract class rcube_storage
*/
abstract function get_cache($key);
+
/**
* Delete outdated cache entries
*/
abstract function expunge_cache();
} // end class rcube_storage
-
-
-/**
- * Class representing a message part
- *
- * @package Mail
- */
-class rcube_message_part
-{
- var $mime_id = '';
- var $ctype_primary = 'text';
- var $ctype_secondary = 'plain';
- var $mimetype = 'text/plain';
- var $disposition = '';
- var $filename = '';
- var $encoding = '8bit';
- var $charset = '';
- var $size = 0;
- var $headers = array();
- var $d_parameters = array();
- var $ctype_parameters = array();
-
- function __clone()
- {
- if (isset($this->parts)) {
- foreach ($this->parts as $idx => $part) {
- if (is_object($part)) {
- $this->parts[$idx] = clone $part;
- }
- }
- }
- }
-}
-
-
-/**
- * Class for sorting an array of rcube_mail_header objects in a predetermined order.
- *
- * @package Mail
- * @author Eric Stadtherr
- */
-class rcube_header_sorter
-{
- private $uids = array();
-
-
- /**
- * Set the predetermined sort order.
- *
- * @param array $index Numerically indexed array of IMAP UIDs
- */
- function set_index($index)
- {
- $index = array_flip($index);
-
- $this->uids = $index;
- }
-
- /**
- * Sort the array of header objects
- *
- * @param array $headers Array of rcube_mail_header objects indexed by UID
- */
- function sort_headers(&$headers)
- {
- uksort($headers, array($this, "compare_uids"));
- }
-
- /**
- * Sort method called by uksort()
- *
- * @param int $a Array key (UID)
- * @param int $b Array key (UID)
- */
- function compare_uids($a, $b)
- {
- // then find each sequence number in my ordered list
- $posa = isset($this->uids[$a]) ? intval($this->uids[$a]) : -1;
- $posb = isset($this->uids[$b]) ? intval($this->uids[$b]) : -1;
-
- // return the relative position as the comparison value
- return $posa - $posb;
- }
-}
diff --git a/program/include/rcube_string_replacer.php b/program/include/rcube_string_replacer.php
index b3d29eb97..320f89af7 100644
--- a/program/include/rcube_string_replacer.php
+++ b/program/include/rcube_string_replacer.php
@@ -98,7 +98,7 @@ class rcube_string_replacer
$i = $this->add($prefix . html::a(array(
'href' => $url_prefix . $url,
'target' => '_blank'
- ), Q($url)) . $suffix);
+ ), rcube_ui::Q($url)) . $suffix);
}
// Return valid link for recognized schemes, otherwise, return the unmodified string for unrecognized schemes.
@@ -118,8 +118,8 @@ class rcube_string_replacer
$i = $this->add(html::a(array(
'href' => 'mailto:' . $href,
- 'onclick' => "return ".JS_OBJECT_NAME.".command('compose','".JQ($href)."',this)",
- ), Q($href)) . $suffix);
+ 'onclick' => "return ".JS_OBJECT_NAME.".command('compose','".rcube_ui::JQ($href)."',this)",
+ ), rcube_ui::Q($href)) . $suffix);
return $i >= 0 ? $this->get_replacement($i) : '';
}
diff --git a/program/include/rcube_ui.php b/program/include/rcube_ui.php
new file mode 100644
index 000000000..262571047
--- /dev/null
+++ b/program/include/rcube_ui.php
@@ -0,0 +1,1468 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_ui.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
+ | Copyright (C) 2011-2012, Kolab Systems AG |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | Provide basic functions for the webmail user interface |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube@gmail.com> |
+ | Author: Aleksander Machniak <alec@alec.pl> |
+ +-----------------------------------------------------------------------+
+
+ $Id$
+
+*/
+
+/**
+ * Roundcube Webmail functions for user interface
+ *
+ * @package Core
+ * @author Thomas Bruederli <roundcube@gmail.com>
+ * @author Aleksander Machniak <alec@alec.pl>
+ */
+class rcube_ui
+{
+ // define constants for input reading
+ const INPUT_GET = 0x0101;
+ const INPUT_POST = 0x0102;
+ const INPUT_GPC = 0x0103;
+
+
+ /**
+ * Get localized text in the desired language
+ * It's a global wrapper for rcube::gettext()
+ *
+ * @param mixed $p Named parameters array or label name
+ * @param string $domain Domain to search in (e.g. plugin name)
+ *
+ * @return string Localized text
+ * @see rcube::gettext()
+ */
+ public static function label($p, $domain = null)
+ {
+ return rcube::get_instance()->gettext($p, $domain);
+ }
+
+
+ /**
+ * Global wrapper of rcube::text_exists()
+ * to check whether a text label is defined
+ *
+ * @see rcube::text_exists()
+ */
+ public static function label_exists($name, $domain = null, &$ref_domain = null)
+ {
+ return rcube::get_instance()->text_exists($name, $domain, $ref_domain);
+ }
+
+
+ /**
+ * 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
+ */
+ public static function url($action, $p = array(), $task = null)
+ {
+ return rcube::get_instance()->url((array)$p + array('_action' => $action, 'task' => $task));
+ }
+
+
+ /**
+ * 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 string The quoted string
+ */
+ public static function rep_specialchars_output($str, $enctype = '', $mode = '', $newlines = true)
+ {
+ static $html_encode_arr = false;
+ static $js_rep_table = false;
+ static $xml_rep_table = false;
+
+ // encode for HTML output
+ if ($enctype == 'html') {
+ if (!$html_encode_arr) {
+ $html_encode_arr = get_html_translation_table(HTML_SPECIALCHARS);
+ unset($html_encode_arr['?']);
+ }
+
+ $encode_arr = $html_encode_arr;
+
+ // don't replace quotes and html tags
+ if ($mode == 'show' || $mode == '') {
+ $ltpos = strpos($str, '<');
+ if ($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);
+ }
+
+ $out = strtr($str, $encode_arr);
+
+ // avoid douple quotation of &
+ $out = preg_replace('/&amp;([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $out);
+
+ return $newlines ? nl2br($out) : $out;
+ }
+
+ // if the replace tables for XML and JS are not yet defined
+ if ($js_rep_table === false) {
+ $js_rep_table = $xml_rep_table = array();
+ $xml_rep_table['&'] = '&amp;';
+
+ // can be increased to support more charsets
+ for ($c=160; $c<256; $c++) {
+ $xml_rep_table[chr($c)] = "&#$c;";
+ }
+
+ $xml_rep_table['"'] = '&quot;';
+ $js_rep_table['"'] = '\\"';
+ $js_rep_table["'"] = "\\'";
+ $js_rep_table["\\"] = "\\\\";
+ // Unicode line and paragraph separators (#1486310)
+ $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A8))] = '&#8232;';
+ $js_rep_table[chr(hexdec(E2)).chr(hexdec(80)).chr(hexdec(A9))] = '&#8233;';
+ }
+
+ // encode for javascript use
+ if ($enctype == 'js') {
+ return preg_replace(array("/\r?\n/", "/\r/", '/<\\//'), array('\n', '\n', '<\\/'), strtr($str, $js_rep_table));
+ }
+
+ // encode for plaintext
+ if ($enctype == 'text') {
+ return str_replace("\r\n", "\n", $mode=='remove' ? strip_tags($str) : $str);
+ }
+
+ if ($enctype == 'url') {
+ return rawurlencode($str);
+ }
+
+ // encode for XML
+ if ($enctype == 'xml') {
+ return strtr($str, $xml_rep_table);
+ }
+
+ // no encoding given -> return original string
+ return $str;
+ }
+
+
+ /**
+ * Quote a given string.
+ * Shortcut function for self::rep_specialchars_output()
+ *
+ * @return string HTML-quoted string
+ * @see self::rep_specialchars_output()
+ */
+ public static function Q($str, $mode = 'strict', $newlines = true)
+ {
+ return self::rep_specialchars_output($str, 'html', $mode, $newlines);
+ }
+
+
+ /**
+ * Quote a given string for javascript output.
+ * Shortcut function for self::rep_specialchars_output()
+ *
+ * @return string JS-quoted string
+ * @see self::rep_specialchars_output()
+ */
+ public static function JQ($str)
+ {
+ return self::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
+ */
+ public static function get_input_value($fname, $source, $allow_html=FALSE, $charset=NULL)
+ {
+ $value = NULL;
+
+ if ($source == self::INPUT_GET) {
+ if (isset($_GET[$fname])) {
+ $value = $_GET[$fname];
+ }
+ }
+ else if ($source == self::INPUT_POST) {
+ if (isset($_POST[$fname])) {
+ $value = $_POST[$fname];
+ }
+ }
+ else if ($source == self::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];
+ }
+ }
+
+ return self::parse_input_value($value, $allow_html, $charset);
+ }
+
+ /**
+ * Parse/validate input value. See self::get_input_value()
+ * Performs stripslashes() and charset conversion if necessary
+ *
+ * @param string Input value
+ * @param boolean Allow HTML tags in field value
+ * @param string Charset to convert into
+ *
+ * @return string Parsed value
+ */
+ public static function parse_input_value($value, $allow_html=FALSE, $charset=NULL)
+ {
+ global $OUTPUT;
+
+ if (empty($value)) {
+ return $value;
+ }
+
+ if (is_array($value)) {
+ foreach ($value as $idx => $val) {
+ $value[$idx] = self::parse_input_value($val, $allow_html, $charset);
+ }
+ return $value;
+ }
+
+ // strip single quotes if magic_quotes_sybase is enabled
+ if (ini_get('magic_quotes_sybase')) {
+ $value = str_replace("''", "'", $value);
+ }
+ // strip slashes if magic_quotes enabled
+ else if (get_magic_quotes_gpc() || get_magic_quotes_runtime()) {
+ $value = stripslashes($value);
+ }
+
+ // remove HTML tags if not allowed
+ if (!$allow_html) {
+ $value = strip_tags($value);
+ }
+
+ $output_charset = is_object($OUTPUT) ? $OUTPUT->get_charset() : null;
+
+ // remove invalid characters (#1488124)
+ if ($output_charset == 'UTF-8') {
+ $value = rcube_charset::clean($value);
+ }
+
+ // convert to internal charset
+ if ($charset && $output_charset) {
+ $value = rcube_charset::convert($value, $output_charset, $charset);
+ }
+
+ return $value;
+ }
+
+
+ /**
+ * Convert array of request parameters (prefixed with _)
+ * to a regular array with non-prefixed keys.
+ *
+ * @param int $mode Source to get value from (GPC)
+ * @param string $ignore PCRE expression to skip parameters by name
+ *
+ * @return array Hash array with all request parameters
+ */
+ public static function request2param($mode = null, $ignore = 'task|action')
+ {
+ $out = array();
+ $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST);
+
+ foreach ($src as $key => $value) {
+ $fname = $key[0] == '_' ? substr($key, 1) : $key;
+ if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) {
+ $out[$fname] = self::get_input_value($key, $mode);
+ }
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Convert the given string into a valid HTML identifier
+ * Same functionality as done in app.js with rcube_webmail.html_identifier()
+ */
+ public static function html_identifier($str, $encode=false)
+ {
+ if ($encode) {
+ return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
+ }
+ else {
+ return asciiwords($str, true, '_');
+ }
+ }
+
+
+ /**
+ * Create a HTML table based on the given data
+ *
+ * @param array Named table attributes
+ * @param mixed Table row data. Either a two-dimensional array or a valid SQL result set
+ * @param array List of cols to show
+ * @param string Name of the identifier col
+ *
+ * @return string HTML table code
+ */
+ public static function table_output($attrib, $table_data, $a_show_cols, $id_col)
+ {
+ global $RCMAIL;
+
+ $table = new html_table(/*array('cols' => count($a_show_cols))*/);
+
+ // add table header
+ if (!$attrib['noheader']) {
+ foreach ($a_show_cols as $col) {
+ $table->add_header($col, self::Q(self::label($col)));
+ }
+ }
+
+ if (!is_array($table_data)) {
+ $db = $RCMAIL->get_dbh();
+ while ($table_data && ($sql_arr = $db->fetch_assoc($table_data))) {
+ $table->add_row(array('id' => 'rcmrow' . self::html_identifier($sql_arr[$id_col])));
+
+ // format each col
+ foreach ($a_show_cols as $col) {
+ $table->add($col, self::Q($sql_arr[$col]));
+ }
+ }
+ }
+ else {
+ foreach ($table_data as $row_data) {
+ $class = !empty($row_data['class']) ? $row_data['class'] : '';
+ $rowid = 'rcmrow' . self::html_identifier($row_data[$id_col]);
+
+ $table->add_row(array('id' => $rowid, 'class' => $class));
+
+ // format each col
+ foreach ($a_show_cols as $col) {
+ $table->add($col, self::Q(is_array($row_data[$col]) ? $row_data[$col][0] : $row_data[$col]));
+ }
+ }
+ }
+
+ return $table->show($attrib);
+ }
+
+
+ /**
+ * 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
+ */
+ public static function get_edit_field($col, $value, $attrib, $type = 'text')
+ {
+ static $colcounts = array();
+
+ $fname = '_'.$col;
+ $attrib['name'] = $fname . ($attrib['array'] ? '[]' : '');
+ $attrib['class'] = trim($attrib['class'] . ' ff_' . $col);
+
+ if ($type == 'checkbox') {
+ $attrib['value'] = '1';
+ $input = new html_checkbox($attrib);
+ }
+ else if ($type == 'textarea') {
+ $attrib['cols'] = $attrib['size'];
+ $input = new html_textarea($attrib);
+ }
+ else if ($type == 'select') {
+ $input = new html_select($attrib);
+ $input->add('---', '');
+ $input->add(array_values($attrib['options']), array_keys($attrib['options']));
+ }
+ else if ($attrib['type'] == 'password') {
+ $input = new html_passwordfield($attrib);
+ }
+ else {
+ if ($attrib['type'] != 'text' && $attrib['type'] != 'hidden') {
+ $attrib['type'] = 'text';
+ }
+ $input = new html_inputfield($attrib);
+ }
+
+ // use value from post
+ if (isset($_POST[$fname])) {
+ $postvalue = self::get_input_value($fname, self::INPUT_POST, true);
+ $value = $attrib['array'] ? $postvalue[intval($colcounts[$col]++)] : $postvalue;
+ }
+
+ $out = $input->show($value);
+
+ return $out;
+ }
+
+
+ /**
+ * Replace all css definitions with #container [def]
+ * and remove css-inlined scripting
+ *
+ * @param string CSS source code
+ * @param string Container ID to use as prefix
+ *
+ * @return string Modified CSS source
+ * @todo I'm not sure this should belong to rcube_ui class
+ */
+ public static function mod_css_styles($source, $container_id, $allow_remote=false)
+ {
+ $last_pos = 0;
+ $replacements = new rcube_string_replacer;
+
+ // ignore the whole block if evil styles are detected
+ $source = self::xss_entity_decode($source);
+ $stripped = preg_replace('/[^a-z\(:;]/i', '', $source);
+ $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : '');
+ if (preg_match("/$evilexpr/i", $stripped)) {
+ return '/* evil! */';
+ }
+
+ // cut out all contents between { and }
+ while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) {
+ $styles = substr($source, $pos+1, $pos2-($pos+1));
+
+ // check every line of a style block...
+ if ($allow_remote) {
+ $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY);
+ foreach ($a_styles as $line) {
+ $stripped = preg_replace('/[^a-z\(:;]/i', '', $line);
+ // ... and only allow strict url() values
+ $regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims';
+ if (stripos($stripped, 'url(') && !preg_match($regexp, $line)) {
+ $a_styles = array('/* evil! */');
+ break;
+ }
+ }
+ $styles = join(";\n", $a_styles);
+ }
+
+ $key = $replacements->add($styles);
+ $source = substr($source, 0, $pos+1)
+ . $replacements->get_replacement($key)
+ . substr($source, $pos2, strlen($source)-$pos2);
+ $last_pos = $pos+2;
+ }
+
+ // remove html comments 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',
+ '/'.preg_quote($container_id, '/').'\s+body/i',
+ ),
+ array(
+ '',
+ "\\1#$container_id \\2",
+ $container_id,
+ ),
+ $source);
+
+ // put block contents back in
+ $styles = $replacements->resolve($styles);
+
+ return $styles;
+ }
+
+
+ /**
+ * Convert the given date to a human readable form
+ * This uses the date formatting properties from config
+ *
+ * @param mixed Date representation (string, timestamp or DateTime object)
+ * @param string Date format to use
+ * @param bool Enables date convertion according to user timezone
+ *
+ * @return string Formatted date string
+ */
+ public static function format_date($date, $format = null, $convert = true)
+ {
+ global $RCMAIL, $CONFIG;
+
+ if (is_object($date) && is_a($date, 'DateTime')) {
+ $timestamp = $date->format('U');
+ }
+ else {
+ if (!empty($date)) {
+ $timestamp = rcube_strtotime($date);
+ }
+
+ if (empty($timestamp)) {
+ return '';
+ }
+
+ try {
+ $date = new DateTime("@".$timestamp);
+ }
+ catch (Exception $e) {
+ return '';
+ }
+ }
+
+ if ($convert) {
+ try {
+ // convert to the right timezone
+ $stz = date_default_timezone_get();
+ $tz = new DateTimeZone($RCMAIL->config->get('timezone'));
+ $date->setTimezone($tz);
+ date_default_timezone_set($tz->getName());
+
+ $timestamp = $date->format('U');
+ }
+ catch (Exception $e) {
+ }
+ }
+
+ // define date format depending on current time
+ if (!$format) {
+ $now = 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']);
+
+ if ($CONFIG['prettydate'] && $timestamp > $today_limit && $timestamp < $now) {
+ $format = $RCMAIL->config->get('date_today', $RCMAIL->config->get('time_format', 'H:i'));
+ $today = true;
+ }
+ else if ($CONFIG['prettydate'] && $timestamp > $week_limit && $timestamp < $now) {
+ $format = $RCMAIL->config->get('date_short', 'D H:i');
+ }
+ else {
+ $format = $RCMAIL->config->get('date_long', 'Y-m-d H:i');
+ }
+ }
+
+ // strftime() format
+ if (preg_match('/%[a-z]+/i', $format)) {
+ $format = strftime($format, $timestamp);
+ if ($stz) {
+ date_default_timezone_set($stz);
+ }
+ return $today ? (self::label('today') . ' ' . $format) : $format;
+ }
+
+ // 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 .= self::label(strtolower(date('D', $timestamp)));
+ }
+ // weekday long
+ else if ($format[$i] == 'l') {
+ $out .= self::label(strtolower(date('l', $timestamp)));
+ }
+ // month name (short)
+ else if ($format[$i] == 'M') {
+ $out .= self::label(strtolower(date('M', $timestamp)));
+ }
+ // month name (long)
+ else if ($format[$i] == 'F') {
+ $out .= self::label('long'.strtolower(date('M', $timestamp)));
+ }
+ else if ($format[$i] == 'x') {
+ $out .= strftime('%x %X', $timestamp);
+ }
+ else {
+ $out .= date($format[$i], $timestamp);
+ }
+ }
+
+ if ($today) {
+ $label = self::label('today');
+ // replcae $ character with "Today" label (#1486120)
+ if (strpos($out, '$') !== false) {
+ $out = preg_replace('/\$/', $label, $out, 1);
+ }
+ else {
+ $out = $label . ' ' . $out;
+ }
+ }
+
+ if ($stz) {
+ date_default_timezone_set($stz);
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Return folders list in HTML
+ *
+ * @param array $attrib Named parameters
+ *
+ * @return string HTML code for the gui object
+ */
+ public static function folder_list($attrib)
+ {
+ global $RCMAIL;
+ static $a_mailboxes;
+
+ $attrib += array('maxlength' => 100, 'realnames' => false, 'unreadwrap' => ' (%s)');
+
+ // add some labels to client
+ $RCMAIL->output->add_label('purgefolderconfirm', 'deletemessagesconfirm');
+
+ $type = $attrib['type'] ? $attrib['type'] : 'ul';
+ unset($attrib['type']);
+
+ if ($type == 'ul' && !$attrib['id']) {
+ $attrib['id'] = 'rcmboxlist';
+ }
+
+ if (empty($attrib['folder_name'])) {
+ $attrib['folder_name'] = '*';
+ }
+
+ // get current folder
+ $mbox_name = $RCMAIL->storage->get_folder();
+
+ // build the folders tree
+ if (empty($a_mailboxes)) {
+ // get mailbox list
+ $a_folders = $RCMAIL->storage->list_folders_subscribed(
+ '', $attrib['folder_name'], $attrib['folder_filter']);
+ $delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
+ $a_mailboxes = array();
+
+ foreach ($a_folders as $folder) {
+ self::build_folder_tree($a_mailboxes, $folder, $delimiter);
+ }
+ }
+
+ // allow plugins to alter the folder tree or to localize folder names
+ $hook = $RCMAIL->plugins->exec_hook('render_mailboxlist', array(
+ 'list' => $a_mailboxes,
+ 'delimiter' => $delimiter,
+ 'type' => $type,
+ 'attribs' => $attrib,
+ ));
+
+ $a_mailboxes = $hook['list'];
+ $attrib = $hook['attribs'];
+
+ if ($type == 'select') {
+ $select = new html_select($attrib);
+
+ // add no-selection option
+ if ($attrib['noselection']) {
+ $select->add(self::label($attrib['noselection']), '');
+ }
+
+ self::render_folder_tree_select($a_mailboxes, $mbox_name, $attrib['maxlength'], $select, $attrib['realnames']);
+ $out = $select->show($attrib['default']);
+ }
+ else {
+ $js_mailboxlist = array();
+ $out = html::tag('ul', $attrib, self::render_folder_tree_html($a_mailboxes, $mbox_name, $js_mailboxlist, $attrib), html::$common_attrib);
+
+ $RCMAIL->output->add_gui_object('mailboxlist', $attrib['id']);
+ $RCMAIL->output->set_env('mailboxes', $js_mailboxlist);
+ $RCMAIL->output->set_env('unreadwrap', $attrib['unreadwrap']);
+ $RCMAIL->output->set_env('collapsed_folders', (string)$RCMAIL->config->get('collapsed_folders'));
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Return folders list as html_select object
+ *
+ * @param array $p Named parameters
+ *
+ * @return html_select HTML drop-down object
+ */
+ public static function folder_selector($p = array())
+ {
+ global $RCMAIL;
+
+ $p += array('maxlength' => 100, 'realnames' => false);
+ $a_mailboxes = array();
+ $storage = $RCMAIL->get_storage();
+
+ if (empty($p['folder_name'])) {
+ $p['folder_name'] = '*';
+ }
+
+ if ($p['unsubscribed']) {
+ $list = $storage->list_folders('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']);
+ }
+ else {
+ $list = $storage->list_folders_subscribed('', $p['folder_name'], $p['folder_filter'], $p['folder_rights']);
+ }
+
+ $delimiter = $storage->get_hierarchy_delimiter();
+
+ foreach ($list as $folder) {
+ if (empty($p['exceptions']) || !in_array($folder, $p['exceptions'])) {
+ self::build_folder_tree($a_mailboxes, $folder, $delimiter);
+ }
+ }
+
+ $select = new html_select($p);
+
+ if ($p['noselection']) {
+ $select->add($p['noselection'], '');
+ }
+
+ self::render_folder_tree_select($a_mailboxes, $mbox, $p['maxlength'], $select, $p['realnames'], 0, $p);
+
+ return $select;
+ }
+
+
+ /**
+ * Create a hierarchical array of the mailbox list
+ */
+ private static function build_folder_tree(&$arrFolders, $folder, $delm = '/', $path = '')
+ {
+ global $RCMAIL;
+
+ // Handle namespace prefix
+ $prefix = '';
+ if (!$path) {
+ $n_folder = $folder;
+ $folder = $RCMAIL->storage->mod_folder($folder);
+
+ if ($n_folder != $folder) {
+ $prefix = substr($n_folder, 0, -strlen($folder));
+ }
+ }
+
+ $pos = strpos($folder, $delm);
+
+ if ($pos !== false) {
+ $subFolders = substr($folder, $pos+1);
+ $currentFolder = substr($folder, 0, $pos);
+
+ // sometimes folder has a delimiter as the last character
+ if (!strlen($subFolders)) {
+ $virtual = false;
+ }
+ else if (!isset($arrFolders[$currentFolder])) {
+ $virtual = true;
+ }
+ else {
+ $virtual = $arrFolders[$currentFolder]['virtual'];
+ }
+ }
+ else {
+ $subFolders = false;
+ $currentFolder = $folder;
+ $virtual = false;
+ }
+
+ $path .= $prefix . $currentFolder;
+
+ if (!isset($arrFolders[$currentFolder])) {
+ $arrFolders[$currentFolder] = array(
+ 'id' => $path,
+ 'name' => rcube_charset::convert($currentFolder, 'UTF7-IMAP'),
+ 'virtual' => $virtual,
+ 'folders' => array());
+ }
+ else {
+ $arrFolders[$currentFolder]['virtual'] = $virtual;
+ }
+
+ if (strlen($subFolders)) {
+ self::build_folder_tree($arrFolders[$currentFolder]['folders'], $subFolders, $delm, $path.$delm);
+ }
+ }
+
+
+ /**
+ * Return html for a structured list &lt;ul&gt; for the mailbox tree
+ */
+ private static function render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $attrib, $nestLevel = 0)
+ {
+ global $RCMAIL;
+
+ $maxlength = intval($attrib['maxlength']);
+ $realnames = (bool)$attrib['realnames'];
+ $msgcounts = $RCMAIL->storage->get_cache('messagecount');
+ $collapsed = $RCMAIL->config->get('collapsed_folders');
+
+ $out = '';
+ foreach ($arrFolders as $key => $folder) {
+ $title = null;
+ $folder_class = self::folder_classname($folder['id']);
+ $collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false;
+ $unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0;
+
+ if ($folder_class && !$realnames) {
+ $foldername = $RCMAIL->gettext($folder_class);
+ }
+ else {
+ $foldername = $folder['name'];
+
+ // shorten the folder name to a given length
+ if ($maxlength && $maxlength > 1) {
+ $fname = abbreviate_string($foldername, $maxlength);
+ if ($fname != $foldername) {
+ $title = $foldername;
+ }
+ $foldername = $fname;
+ }
+ }
+
+ // make folder name safe for ids and class names
+ $folder_id = self::html_identifier($folder['id'], true);
+ $classes = array('mailbox');
+
+ // set special class for Sent, Drafts, Trash and Junk
+ if ($folder_class) {
+ $classes[] = $folder_class;
+ }
+
+ if ($folder['id'] == $mbox_name) {
+ $classes[] = 'selected';
+ }
+
+ if ($folder['virtual']) {
+ $classes[] = 'virtual';
+ }
+ else if ($unread) {
+ $classes[] = 'unread';
+ }
+
+ $js_name = self::JQ($folder['id']);
+ $html_name = self::Q($foldername) . ($unread ? html::span('unreadcount', sprintf($attrib['unreadwrap'], $unread)) : '');
+ $link_attrib = $folder['virtual'] ? array() : array(
+ 'href' => self::url('', array('_mbox' => $folder['id'])),
+ 'onclick' => sprintf("return %s.command('list','%s',this)", JS_OBJECT_NAME, $js_name),
+ 'rel' => $folder['id'],
+ 'title' => $title,
+ );
+
+ $out .= html::tag('li', array(
+ 'id' => "rcmli".$folder_id,
+ 'class' => join(' ', $classes),
+ 'noclose' => true),
+ html::a($link_attrib, $html_name) .
+ (!empty($folder['folders']) ? html::div(array(
+ 'class' => ($collapsed ? 'collapsed' : 'expanded'),
+ 'style' => "position:absolute",
+ 'onclick' => sprintf("%s.command('collapse-folder', '%s')", JS_OBJECT_NAME, $js_name)
+ ), '&nbsp;') : ''));
+
+ $jslist[$folder_id] = array(
+ 'id' => $folder['id'],
+ 'name' => $foldername,
+ 'virtual' => $folder['virtual']
+ );
+
+ if (!empty($folder['folders'])) {
+ $out .= html::tag('ul', array('style' => ($collapsed ? "display:none;" : null)),
+ self::render_folder_tree_html($folder['folders'], $mbox_name, $jslist, $attrib, $nestLevel+1));
+ }
+
+ $out .= "</li>\n";
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Return html for a flat list <select> for the mailbox tree
+ */
+ private static function render_folder_tree_select(&$arrFolders, &$mbox_name, $maxlength, &$select, $realnames = false, $nestLevel = 0, $opts = array())
+ {
+ global $RCMAIL;
+
+ $out = '';
+
+ foreach ($arrFolders as $key => $folder) {
+ // skip exceptions (and its subfolders)
+ if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) {
+ continue;
+ }
+
+ // skip folders in which it isn't possible to create subfolders
+ if (!empty($opts['skip_noinferiors'])) {
+ $attrs = $RCMAIL->storage->folder_attributes($folder['id']);
+ if ($attrs && in_array('\\Noinferiors', $attrs)) {
+ continue;
+ }
+ }
+
+ if (!$realnames && ($folder_class = self::folder_classname($folder['id']))) {
+ $foldername = self::label($folder_class);
+ }
+ else {
+ $foldername = $folder['name'];
+
+ // shorten the folder name to a given length
+ if ($maxlength && $maxlength > 1) {
+ $foldername = abbreviate_string($foldername, $maxlength);
+ }
+
+ $select->add(str_repeat('&nbsp;', $nestLevel*4) . $foldername, $folder['id']);
+
+ if (!empty($folder['folders'])) {
+ $out .= self::render_folder_tree_select($folder['folders'], $mbox_name, $maxlength,
+ $select, $realnames, $nestLevel+1, $opts);
+ }
+ }
+ }
+
+ return $out;
+ }
+
+
+ /**
+ * Return internal name for the given folder if it matches the configured special folders
+ */
+ private static function folder_classname($folder_id)
+ {
+ global $CONFIG;
+
+ if ($folder_id == 'INBOX') {
+ return 'inbox';
+ }
+
+ // for these mailboxes we have localized labels and css classes
+ foreach (array('sent', 'drafts', 'trash', 'junk') as $smbx)
+ {
+ if ($folder_id == $CONFIG[$smbx.'_mbox']) {
+ return $smbx;
+ }
+ }
+ }
+
+
+ /**
+ * Try to localize the given IMAP folder name.
+ * UTF-7 decode it in case no localized text was found
+ *
+ * @param string $name Folder name
+ *
+ * @return string Localized folder name in UTF-8 encoding
+ */
+ public static function localize_foldername($name)
+ {
+ if ($folder_class = self::folder_classname($name)) {
+ return self::label($folder_class);
+ }
+ else {
+ return rcube_charset::convert($name, 'UTF7-IMAP');
+ }
+ }
+
+
+ public static function localize_folderpath($path)
+ {
+ global $RCMAIL;
+
+ $protect_folders = $RCMAIL->config->get('protect_default_folders');
+ $default_folders = (array) $RCMAIL->config->get('default_folders');
+ $delimiter = $RCMAIL->storage->get_hierarchy_delimiter();
+ $path = explode($delimiter, $path);
+ $result = array();
+
+ foreach ($path as $idx => $dir) {
+ $directory = implode($delimiter, array_slice($path, 0, $idx+1));
+ if ($protect_folders && in_array($directory, $default_folders)) {
+ unset($result);
+ $result[] = self::localize_foldername($directory);
+ }
+ else {
+ $result[] = rcube_charset::convert($dir, 'UTF7-IMAP');
+ }
+ }
+
+ return implode($delimiter, $result);
+ }
+
+
+ public static function quota_display($attrib)
+ {
+ global $OUTPUT;
+
+ if (!$attrib['id']) {
+ $attrib['id'] = 'rcmquotadisplay';
+ }
+
+ $_SESSION['quota_display'] = !empty($attrib['display']) ? $attrib['display'] : 'text';
+
+ $OUTPUT->add_gui_object('quotadisplay', $attrib['id']);
+
+ $quota = self::quota_content($attrib);
+
+ $OUTPUT->add_script('rcmail.set_quota('.rcube_output::json_serialize($quota).');', 'docready');
+
+ return html::span($attrib, '');
+ }
+
+
+ public static function quota_content($attrib = null)
+ {
+ global $RCMAIL;
+
+ $quota = $RCMAIL->storage->get_quota();
+ $quota = $RCMAIL->plugins->exec_hook('quota', $quota);
+
+ $quota_result = (array) $quota;
+ $quota_result['type'] = isset($_SESSION['quota_display']) ? $_SESSION['quota_display'] : '';
+
+ if (!$quota['total'] && $RCMAIL->config->get('quota_zero_as_unlimited')) {
+ $quota_result['title'] = self::label('unlimited');
+ $quota_result['percent'] = 0;
+ }
+ else if ($quota['total']) {
+ if (!isset($quota['percent'])) {
+ $quota_result['percent'] = min(100, round(($quota['used']/max(1,$quota['total']))*100));
+ }
+
+ $title = sprintf('%s / %s (%.0f%%)',
+ self::show_bytes($quota['used'] * 1024), self::show_bytes($quota['total'] * 1024),
+ $quota_result['percent']);
+
+ $quota_result['title'] = $title;
+
+ if ($attrib['width']) {
+ $quota_result['width'] = $attrib['width'];
+ }
+ if ($attrib['height']) {
+ $quota_result['height'] = $attrib['height'];
+ }
+ }
+ else {
+ $quota_result['title'] = self::label('unknown');
+ $quota_result['percent'] = 0;
+ }
+
+ return $quota_result;
+ }
+
+
+ /**
+ * Outputs error message according to server error/response codes
+ *
+ * @param string $fallback Fallback message label
+ * @param array $fallback_args Fallback message label arguments
+ */
+ public static function display_server_error($fallback = null, $fallback_args = null)
+ {
+ global $RCMAIL;
+
+ $err_code = $RCMAIL->storage->get_error_code();
+ $res_code = $RCMAIL->storage->get_response_code();
+
+ if ($err_code < 0) {
+ $RCMAIL->output->show_message('storageerror', 'error');
+ }
+ else if ($res_code == rcube_storage::NOPERM) {
+ $RCMAIL->output->show_message('errornoperm', 'error');
+ }
+ else if ($res_code == rcube_storage::READONLY) {
+ $RCMAIL->output->show_message('errorreadonly', 'error');
+ }
+ else if ($err_code && ($err_str = $RCMAIL->storage->get_error_str())) {
+ // try to detect access rights problem and display appropriate message
+ if (stripos($err_str, 'Permission denied') !== false) {
+ $RCMAIL->output->show_message('errornoperm', 'error');
+ }
+ else {
+ $RCMAIL->output->show_message('servererrormsg', 'error', array('msg' => $err_str));
+ }
+ }
+ else if ($fallback) {
+ $RCMAIL->output->show_message($fallback, 'error', $fallback_args);
+ }
+ }
+
+
+ /**
+ * Generate CSS classes from mimetype and filename extension
+ *
+ * @param string $mimetype Mimetype
+ * @param string $filename Filename
+ *
+ * @return string CSS classes separated by space
+ */
+ public static function file2class($mimetype, $filename)
+ {
+ list($primary, $secondary) = explode('/', $mimetype);
+
+ $classes = array($primary ? $primary : 'unknown');
+ if ($secondary) {
+ $classes[] = $secondary;
+ }
+ if (preg_match('/\.([a-z0-9]+)$/i', $filename, $m)) {
+ $classes[] = $m[1];
+ }
+
+ return strtolower(join(" ", $classes));
+ }
+
+
+ /**
+ * Output HTML editor scripts
+ *
+ * @param string $mode Editor mode
+ */
+ public static function html_editor($mode = '')
+ {
+ global $RCMAIL;
+
+ $hook = $RCMAIL->plugins->exec_hook('html_editor', array('mode' => $mode));
+
+ if ($hook['abort']) {
+ return;
+ }
+
+ $lang = strtolower($_SESSION['language']);
+
+ // TinyMCE uses two-letter lang codes, with exception of Chinese
+ if (strpos($lang, 'zh_') === 0) {
+ $lang = str_replace('_', '-', $lang);
+ }
+ else {
+ $lang = substr($lang, 0, 2);
+ }
+
+ if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js')) {
+ $lang = 'en';
+ }
+
+ $script = json_encode(array(
+ 'mode' => $mode,
+ 'lang' => $lang,
+ 'skin_path' => $RCMAIL->output->get_skin_path(),
+ 'spellcheck' => intval($RCMAIL->config->get('enable_spellcheck')),
+ 'spelldict' => intval($RCMAIL->config->get('spellcheck_dictionary'))
+ ));
+
+ $RCMAIL->output->include_script('tiny_mce/tiny_mce.js');
+ $RCMAIL->output->include_script('editor.js');
+ $RCMAIL->output->add_script("rcmail_editor_init($script)", 'docready');
+ }
+
+
+ /**
+ * Replaces TinyMCE's emoticon images with plain-text representation
+ *
+ * @param string $html HTML content
+ *
+ * @return string HTML content
+ */
+ public static function replace_emoticons($html)
+ {
+ $emoticons = array(
+ '8-)' => 'smiley-cool',
+ ':-#' => 'smiley-foot-in-mouth',
+ ':-*' => 'smiley-kiss',
+ ':-X' => 'smiley-sealed',
+ ':-P' => 'smiley-tongue-out',
+ ':-@' => 'smiley-yell',
+ ":'(" => 'smiley-cry',
+ ':-(' => 'smiley-frown',
+ ':-D' => 'smiley-laughing',
+ ':-)' => 'smiley-smile',
+ ':-S' => 'smiley-undecided',
+ ':-$' => 'smiley-embarassed',
+ 'O:-)' => 'smiley-innocent',
+ ':-|' => 'smiley-money-mouth',
+ ':-O' => 'smiley-surprised',
+ ';-)' => 'smiley-wink',
+ );
+
+ foreach ($emoticons as $idx => $file) {
+ // <img title="Cry" src="http://.../program/js/tiny_mce/plugins/emotions/img/smiley-cry.gif" border="0" alt="Cry" />
+ $search[] = '/<img title="[a-z ]+" src="https?:\/\/[a-z0-9_.\/-]+\/tiny_mce\/plugins\/emotions\/img\/'.$file.'.gif"[^>]+\/>/i';
+ $replace[] = $idx;
+ }
+
+ return preg_replace($search, $replace, $html);
+ }
+
+
+ /**
+ * File upload progress handler.
+ */
+ public static function upload_progress()
+ {
+ global $RCMAIL;
+
+ $prefix = ini_get('apc.rfc1867_prefix');
+ $params = array(
+ 'action' => $RCMAIL->action,
+ 'name' => self::get_input_value('_progress', self::INPUT_GET),
+ );
+
+ if (function_exists('apc_fetch')) {
+ $status = apc_fetch($prefix . $params['name']);
+
+ if (!empty($status)) {
+ $status['percent'] = round($status['current']/$status['total']*100);
+ $params = array_merge($status, $params);
+ }
+ }
+
+ if (isset($params['percent']))
+ $params['text'] = self::label(array('name' => 'uploadprogress', 'vars' => array(
+ 'percent' => $params['percent'] . '%',
+ 'current' => self::show_bytes($params['current']),
+ 'total' => self::show_bytes($params['total'])
+ )));
+
+ $RCMAIL->output->command('upload_progress_update', $params);
+ $RCMAIL->output->send();
+ }
+
+
+ /**
+ * Initializes file uploading interface.
+ */
+ public static function upload_init()
+ {
+ global $RCMAIL;
+
+ // Enable upload progress bar
+ if (($seconds = $RCMAIL->config->get('upload_progress')) && ini_get('apc.rfc1867')) {
+ if ($field_name = ini_get('apc.rfc1867_name')) {
+ $RCMAIL->output->set_env('upload_progress_name', $field_name);
+ $RCMAIL->output->set_env('upload_progress_time', (int) $seconds);
+ }
+ }
+
+ // find max filesize value
+ $max_filesize = parse_bytes(ini_get('upload_max_filesize'));
+ $max_postsize = parse_bytes(ini_get('post_max_size'));
+ if ($max_postsize && $max_postsize < $max_filesize) {
+ $max_filesize = $max_postsize;
+ }
+
+ $RCMAIL->output->set_env('max_filesize', $max_filesize);
+ $max_filesize = self::show_bytes($max_filesize);
+ $RCMAIL->output->set_env('filesizeerror', self::label(array(
+ 'name' => 'filesizeerror', 'vars' => array('size' => $max_filesize))));
+
+ return $max_filesize;
+ }
+
+
+ /**
+ * Initializes client-side autocompletion.
+ */
+ public static function autocomplete_init()
+ {
+ global $RCMAIL;
+ static $init;
+
+ if ($init) {
+ return;
+ }
+
+ $init = 1;
+
+ if (($threads = (int)$RCMAIL->config->get('autocomplete_threads')) > 0) {
+ $book_types = (array) $RCMAIL->config->get('autocomplete_addressbooks', 'sql');
+ if (count($book_types) > 1) {
+ $RCMAIL->output->set_env('autocomplete_threads', $threads);
+ $RCMAIL->output->set_env('autocomplete_sources', $book_types);
+ }
+ }
+
+ $RCMAIL->output->set_env('autocomplete_max', (int)$RCMAIL->config->get('autocomplete_max', 15));
+ $RCMAIL->output->set_env('autocomplete_min_length', $RCMAIL->config->get('autocomplete_min_length'));
+ $RCMAIL->output->add_label('autocompletechars', 'autocompletemore');
+ }
+
+
+ /**
+ * Returns supported font-family specifications
+ *
+ * @param string $font Font name
+ *
+ * @param string|array Font-family specification array or string (if $font is used)
+ */
+ public static function font_defs($font = null)
+ {
+ $fonts = array(
+ 'Andale Mono' => '"Andale Mono",Times,monospace',
+ 'Arial' => 'Arial,Helvetica,sans-serif',
+ 'Arial Black' => '"Arial Black","Avant Garde",sans-serif',
+ 'Book Antiqua' => '"Book Antiqua",Palatino,serif',
+ 'Courier New' => '"Courier New",Courier,monospace',
+ 'Georgia' => 'Georgia,Palatino,serif',
+ 'Helvetica' => 'Helvetica,Arial,sans-serif',
+ 'Impact' => 'Impact,Chicago,sans-serif',
+ 'Tahoma' => 'Tahoma,Arial,Helvetica,sans-serif',
+ 'Terminal' => 'Terminal,Monaco,monospace',
+ 'Times New Roman' => '"Times New Roman",Times,serif',
+ 'Trebuchet MS' => '"Trebuchet MS",Geneva,sans-serif',
+ 'Verdana' => 'Verdana,Geneva,sans-serif',
+ );
+
+ if ($font) {
+ return $fonts[$font];
+ }
+
+ return $fonts;
+ }
+
+
+ /**
+ * Create a human readable string for a number of bytes
+ *
+ * @param int Number of bytes
+ *
+ * @return string Byte string
+ */
+ public static function show_bytes($bytes)
+ {
+ if ($bytes >= 1073741824) {
+ $gb = $bytes/1073741824;
+ $str = sprintf($gb>=10 ? "%d " : "%.1f ", $gb) . self::label('GB');
+ }
+ else if ($bytes >= 1048576) {
+ $mb = $bytes/1048576;
+ $str = sprintf($mb>=10 ? "%d " : "%.1f ", $mb) . self::label('MB');
+ }
+ else if ($bytes >= 1024) {
+ $str = sprintf("%d ", round($bytes/1024)) . self::label('KB');
+ }
+ else {
+ $str = sprintf('%d ', $bytes) . self::label('B');
+ }
+
+ return $str;
+ }
+
+
+ /**
+ * Decode escaped entities used by known XSS exploits.
+ * See http://downloads.securityfocus.com/vulnerabilities/exploits/26800.eml for examples
+ *
+ * @param string CSS content to decode
+ *
+ * @return string Decoded string
+ * @todo I'm not sure this should belong to rcube_ui class
+ */
+ public static function xss_entity_decode($content)
+ {
+ $out = html_entity_decode(html_entity_decode($content));
+ $out = preg_replace_callback('/\\\([0-9a-f]{4})/i',
+ array(self, 'xss_entity_decode_callback'), $out);
+ $out = preg_replace('#/\*.*\*/#Ums', '', $out);
+
+ return $out;
+ }
+
+
+ /**
+ * preg_replace_callback callback for xss_entity_decode
+ *
+ * @param array $matches Result from preg_replace_callback
+ *
+ * @return string Decoded entity
+ */
+ public static function xss_entity_decode_callback($matches)
+ {
+ return chr(hexdec($matches[1]));
+ }
+
+
+ /**
+ * Check if we can process not exceeding memory_limit
+ *
+ * @param integer Required amount of memory
+ *
+ * @return boolean True if memory won't be exceeded, False otherwise
+ */
+ public static function mem_check($need)
+ {
+ $mem_limit = parse_bytes(ini_get('memory_limit'));
+ $memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
+
+ return $mem_limit > 0 && $memory + $need > $mem_limit ? false : true;
+ }
+
+
+ /**
+ * Check if working in SSL mode
+ *
+ * @param integer $port HTTPS port number
+ * @param boolean $use_https Enables 'use_https' option checking
+ *
+ * @return boolean
+ */
+ public static function https_check($port=null, $use_https=true)
+ {
+ global $RCMAIL;
+
+ if (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
+ return true;
+ }
+ if (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') {
+ return true;
+ }
+ if ($port && $_SERVER['SERVER_PORT'] == $port) {
+ return true;
+ }
+ if ($use_https && isset($RCMAIL) && $RCMAIL->config->get('use_https')) {
+ return true;
+ }
+
+ return false;
+ }
+
+}
diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php
index d1df64391..804267459 100644
--- a/program/include/rcube_user.php
+++ b/program/include/rcube_user.php
@@ -66,7 +66,7 @@ class rcube_user
if ($id && !$sql_arr) {
$sql_result = $this->db->query(
- "SELECT * FROM ".get_table_name('users')." WHERE user_id = ?", $id);
+ "SELECT * FROM ".$this->db->table_name('users')." WHERE user_id = ?", $id);
$sql_arr = $this->db->fetch_assoc($sql_result);
}
@@ -127,9 +127,9 @@ class rcube_user
if (!empty($_SESSION['preferences'])) {
// Check last write attempt time, try to write again (every 5 minutes)
if ($_SESSION['preferences_time'] < time() - 5 * 60) {
- $saved_prefs = unserialize($_SESSION['preferences']);
+ $saved_prefs = unserialize($_SESSION['preferences']);
$this->rc->session->remove('preferences');
- $this->rc->session->remove('preferences_time');
+ $this->rc->session->remove('preferences_time');
$this->save_prefs($saved_prefs);
}
else {
@@ -173,7 +173,7 @@ class rcube_user
$save_prefs = serialize($save_prefs);
$this->db->query(
- "UPDATE ".get_table_name('users').
+ "UPDATE ".$this->db->table_name('users').
" SET preferences = ?".
", language = ?".
" WHERE user_id = ?",
@@ -232,7 +232,7 @@ class rcube_user
$result = array();
$sql_result = $this->db->query(
- "SELECT * FROM ".get_table_name('identities').
+ "SELECT * FROM ".$this->db->table_name('identities').
" WHERE del <> 1 AND user_id = ?".
($sql_add ? " ".$sql_add : "").
" ORDER BY ".$this->db->quoteIdentifier('standard')." DESC, name ASC, identity_id ASC",
@@ -267,7 +267,7 @@ class rcube_user
$query_params[] = $iid;
$query_params[] = $this->ID;
- $sql = "UPDATE ".get_table_name('identities').
+ $sql = "UPDATE ".$this->db->table_name('identities').
" SET changed = ".$this->db->now().", ".join(', ', $query_cols).
" WHERE identity_id = ?".
" AND user_id = ?".
@@ -301,7 +301,7 @@ class rcube_user
$insert_cols[] = 'user_id';
$insert_values[] = $this->ID;
- $sql = "INSERT INTO ".get_table_name('identities').
+ $sql = "INSERT INTO ".$this->db->table_name('identities').
" (changed, ".join(', ', $insert_cols).")".
" VALUES (".$this->db->now().", ".join(', ', array_pad(array(), sizeof($insert_values), '?')).")";
@@ -324,7 +324,7 @@ class rcube_user
return false;
$sql_result = $this->db->query(
- "SELECT count(*) AS ident_count FROM ".get_table_name('identities').
+ "SELECT count(*) AS ident_count FROM ".$this->db->table_name('identities').
" WHERE user_id = ? AND del <> 1",
$this->ID);
@@ -335,7 +335,7 @@ class rcube_user
return -1;
$this->db->query(
- "UPDATE ".get_table_name('identities').
+ "UPDATE ".$this->db->table_name('identities').
" SET del = 1, changed = ".$this->db->now().
" WHERE user_id = ?".
" AND identity_id = ?",
@@ -355,7 +355,7 @@ class rcube_user
{
if ($this->ID && $iid) {
$this->db->query(
- "UPDATE ".get_table_name('identities').
+ "UPDATE ".$this->db->table_name('identities').
" SET ".$this->db->quoteIdentifier('standard')." = '0'".
" WHERE user_id = ?".
" AND identity_id <> ?".
@@ -373,7 +373,7 @@ class rcube_user
{
if ($this->ID) {
$this->db->query(
- "UPDATE ".get_table_name('users').
+ "UPDATE ".$this->db->table_name('users').
" SET last_login = ".$this->db->now().
" WHERE user_id = ?",
$this->ID);
@@ -403,7 +403,7 @@ class rcube_user
$dbh = rcmail::get_instance()->get_dbh();
// query for matching user name
- $query = "SELECT * FROM ".get_table_name('users')." WHERE mail_host = ? AND %s = ?";
+ $query = "SELECT * FROM ".$dbh->table_name('users')." WHERE mail_host = ? AND %s = ?";
$sql_result = $dbh->query(sprintf($query, 'username'), $host, $user);
// query for matching alias
@@ -451,7 +451,7 @@ class rcube_user
$dbh = $rcmail->get_dbh();
$dbh->query(
- "INSERT INTO ".get_table_name('users').
+ "INSERT INTO ".$dbh->table_name('users').
" (created, last_login, username, mail_host, alias, language)".
" VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?, ?)",
strip_newlines($user),
@@ -507,7 +507,7 @@ class rcube_user
}
}
else {
- raise_error(array(
+ rcube::raise_error(array(
'code' => 500,
'type' => 'php',
'line' => __LINE__,
@@ -573,7 +573,7 @@ class rcube_user
$sql_result = $this->db->query(
"SELECT search_id AS id, ".$this->db->quoteIdentifier('name')
- ." FROM ".get_table_name('searches')
+ ." FROM ".$this->db->table_name('searches')
." WHERE user_id = ?"
." AND ".$this->db->quoteIdentifier('type')." = ?"
." ORDER BY ".$this->db->quoteIdentifier('name'),
@@ -607,7 +607,7 @@ class rcube_user
"SELECT ".$this->db->quoteIdentifier('name')
.", ".$this->db->quoteIdentifier('data')
.", ".$this->db->quoteIdentifier('type')
- ." FROM ".get_table_name('searches')
+ ." FROM ".$this->db->table_name('searches')
." WHERE user_id = ?"
." AND search_id = ?",
(int) $this->ID, (int) $id);
@@ -638,7 +638,7 @@ class rcube_user
return false;
$this->db->query(
- "DELETE FROM ".get_table_name('searches')
+ "DELETE FROM ".$this->db->table_name('searches')
." WHERE user_id = ?"
." AND search_id = ?",
(int) $this->ID, $sid);
@@ -668,7 +668,7 @@ class rcube_user
$insert_cols[] = $this->db->quoteIdentifier('data');
$insert_values[] = serialize($data['data']);
- $sql = "INSERT INTO ".get_table_name('searches')
+ $sql = "INSERT INTO ".$this->db->table_name('searches')
." (".join(', ', $insert_cols).")"
." VALUES (".join(', ', array_pad(array(), sizeof($insert_values), '?')).")";
diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php
index ad8e35e43..7163ef75c 100644
--- a/program/include/rcube_vcard.php
+++ b/program/include/rcube_vcard.php
@@ -389,7 +389,7 @@ class rcube_vcard
if (is_array($subnode) && (($charset = $force_charset) || ($subnode['charset'] && ($charset = $subnode['charset'][0])))) {
foreach ($subnode as $j => $value) {
if (is_numeric($j) && is_string($value))
- $card[$key][$i][$j] = rcube_charset_convert($value, $charset);
+ $card[$key][$i][$j] = rcube_charset::convert($value, $charset);
}
unset($card[$key][$i]['charset']);
}
@@ -425,7 +425,7 @@ class rcube_vcard
$charset = null;
// detect charset and convert to utf-8
else if (($charset = self::detect_encoding($data)) && $charset != RCMAIL_CHARSET) {
- $data = rcube_charset_convert($data, $charset);
+ $data = rcube_charset::convert($data, $charset);
$data = preg_replace(array('/^[\xFE\xFF]{2}/', '/^\xEF\xBB\xBF/', '/^\x00+/'), '', $data); // also remove BOM
$charset = RCMAIL_CHARSET;
}
@@ -780,7 +780,7 @@ class rcube_vcard
)*\z/xs', substr($string, 0, 2048)))
return 'UTF-8';
- return rcmail::get_instance()->config->get('default_charset', 'ISO-8859-1'); # fallback to Latin-1
+ return rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); # fallback to Latin-1
}
}
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index a31370b16..e52da3936 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -203,7 +203,7 @@ function rcmail_directory_list($attrib)
'rel' => '%s',
'onclick' => "return ".JS_OBJECT_NAME.".command('list','%s',this)"), '%s'));
- $sources = (array) $OUTPUT->env['address_sources'];
+ $sources = (array) $OUTPUT->get_env('address_sources');
reset($sources);
// currently selected source
diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc
index ebf79be4e..c0a5bf7bc 100644
--- a/program/steps/mail/compose.inc
+++ b/program/steps/mail/compose.inc
@@ -1162,10 +1162,22 @@ function rcmail_save_attachment(&$message, $pid)
$data = $message->get_part_content($pid);
}
+ $mimetype = $part->ctype_primary . '/' . $part->ctype_secondary;
+ $filename = $part->filename;
+ if (!strlen($filename)) {
+ if ($mimetype == 'text/html') {
+ $filename = rcube_label('htmlmessage');
+ }
+ else {
+ $filename = 'Part_'.$pid;
+ }
+ $filename .= '.' . $part->ctype_secondary;
+ }
+
$attachment = array(
'group' => $COMPOSE['id'],
- 'name' => $part->filename ? $part->filename : 'Part_'.$pid.'.'.$part->ctype_secondary,
- 'mimetype' => $part->ctype_primary . '/' . $part->ctype_secondary,
+ 'name' => $filename,
+ 'mimetype' => $mimetype,
'content_id' => $part->content_id,
'data' => $data,
'path' => $path,
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index 8dcd37b20..319166c2d 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -230,7 +230,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null
// Make sure there are no duplicated columns (#1486999)
$a_show_cols = array_unique($a_show_cols);
- // Plugins may set header's list_cols/list_flags and other rcube_mail_header variables
+ // Plugins may set header's list_cols/list_flags and other rcube_message_header variables
// and list columns
$plugin = $RCMAIL->plugins->exec_hook('messages_list',
array('messages' => $a_headers, 'cols' => $a_show_cols));
@@ -1024,10 +1024,20 @@ function rcmail_message_body($attrib)
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' && $part->size) {
+ else if ($part->type == 'content') {
+ // unsapported
+ if ($part->realtype) {
+ if ($part->realtype == 'multipart/encrypted') {
+ $out .= html::span('part-notice', rcube_label('encryptedmessage'));
+ }
+ continue;
+ }
+ else if (!$part->size) {
+ continue;
+ }
// Check if we have enough memory to handle the message in it
// #1487424: we need up to 10x more memory than the body
- if (!rcmail_mem_check($part->size * 10)) {
+ else if (!rcmail_mem_check($part->size * 10)) {
$out .= html::span('part-notice', rcube_label('messagetoobig'). ' '
. html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id
.'&_mbox='. urlencode($RCMAIL->storage->get_folder()), rcube_label('download')));
@@ -1438,9 +1448,14 @@ function rcmail_message_part_controls($attrib)
$part = $MESSAGE->mime_parts[$part];
$table = new html_table(array('cols' => 3));
- if (!empty($part->filename)) {
+ $filename = $part->filename;
+ if (empty($filename) && $attach_prop->mimetype == 'text/html') {
+ $filename = rcube_label('htmlmessage');
+ }
+
+ if (!empty($filename)) {
$table->add('title', Q(rcube_label('filename')));
- $table->add('header', Q($part->filename));
+ $table->add('header', Q($filename));
$table->add('download-link', html::a(array('href' => './?'.str_replace('_frame=', '_download=', $_SERVER['QUERY_STRING'])), Q(rcube_label('download'))));
}
diff --git a/program/steps/mail/get.inc b/program/steps/mail/get.inc
index 924433df3..19be4bd07 100644
--- a/program/steps/mail/get.inc
+++ b/program/steps/mail/get.inc
@@ -69,8 +69,15 @@ if (!empty($_GET['_uid'])) {
// show part page
if (!empty($_GET['_frame'])) {
- if (($part_id = get_input_value('_part', RCUBE_INPUT_GPC)) && ($part = $MESSAGE->mime_parts[$part_id]) && $part->filename)
- $OUTPUT->set_pagetitle($part->filename);
+ if (($part_id = get_input_value('_part', RCUBE_INPUT_GPC)) && ($part = $MESSAGE->mime_parts[$part_id])) {
+ $filename = $part->filename;
+ if (empty($filename) && $part->mimetype == 'text/html') {
+ $filename = rcube_label('htmlmessage');
+ }
+ if (!empty($filename)) {
+ $OUTPUT->set_pagetitle($filename);
+ }
+ }
$OUTPUT->send('messagepart');
exit;
@@ -130,15 +137,25 @@ else if (strlen($pid = get_input_value('_part', RCUBE_INPUT_GET))) {
$out = rcmail_print_body($part, array('safe' => $MESSAGE->is_safe, 'inline_html' => false));
}
- $OUTPUT = new rcube_html_page();
+ $OUTPUT = new rcube_output_html();
$OUTPUT->write($out);
}
else {
// don't kill the connection if download takes more than 30 sec.
@set_time_limit(0);
+ if ($part->filename) {
+ $filename = $part->filename;
+ }
+ else if ($part->mimetype == 'text/html') {
+ $filename = rcube_label('htmlmessage');
+ }
+ else {
+ $filename = ($MESSAGE->subject ? $MESSAGE->subject : 'roundcube');
+ }
+
$ext = '.' . ($mimetype == 'text/plain' ? 'txt' : $ctype_secondary);
- $filename = $part->filename ? $part->filename : ($MESSAGE->subject ? $MESSAGE->subject : 'roundcube') . $ext;
+ $filename .= $ext;
$filename = preg_replace('[\r\n]', '', $filename);
if ($browser->ie && $browser->ver < 7)
diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc
index c6c6d9636..076098a56 100644
--- a/program/steps/mail/show.inc
+++ b/program/steps/mail/show.inc
@@ -126,20 +126,24 @@ function rcmail_message_attachments($attrib)
if (sizeof($MESSAGE->attachments)) {
foreach ($MESSAGE->attachments as $attach_prop) {
- if ($PRINT_MODE) {
- $ol .= html::tag('li', null, sprintf("%s (%s)", Q($attach_prop->filename), Q(show_bytes($attach_prop->size))));
+ $filename = $attach_prop->filename;
+ if (empty($filename) && $attach_prop->mimetype == 'text/html') {
+ $filename = rcube_label('htmlmessage');
}
- else {
- if (mb_strlen($attach_prop->filename) > 50) {
- $filename = abbreviate_string($attach_prop->filename, 50);
- $title = $attach_prop->filename;
+
+ if ($PRINT_MODE) {
+ $ol .= html::tag('li', null, sprintf("%s (%s)", Q($filename), Q(show_bytes($attach_prop->size))));
}
else {
- $filename = $attach_prop->filename;
- $title = '';
- }
-
- $ol .= html::tag('li', rcmail_filetype2classname($attach_prop->mimetype, $attach_prop->filename),
+ if (mb_strlen($filename) > 50) {
+ $filename = abbreviate_string($filename, 50);
+ $title = $filename;
+ }
+ else {
+ $title = '';
+ }
+
+ $ol .= html::tag('li', rcmail_filetype2classname($attach_prop->mimetype, $filename),
html::a(array(
'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false),
'onclick' => sprintf(
diff --git a/program/steps/utils/error.inc b/program/steps/utils/error.inc
index 050c1f7cd..000674417 100644
--- a/program/steps/utils/error.inc
+++ b/program/steps/utils/error.inc
@@ -22,6 +22,7 @@
*/
+$rcmail = rcmail::get_instance();
// browser is not compatible with this application
if ($ERROR_CODE==409) {
@@ -88,7 +89,7 @@ else {
$__error_title = "SERVICE CURRENTLY NOT AVAILABLE!";
$__error_text = "Please contact your server-administrator.";
- if (($CONFIG['debug_level'] & 4) && $ERROR_MESSAGE)
+ if (($rcmail->config->get('debug_level') & 4) && $ERROR_MESSAGE)
$__error_text = $ERROR_MESSAGE;
else
$__error_text = sprintf('Error No. [%s]', $ERROR_CODE);
@@ -97,7 +98,7 @@ else {
$HTTP_ERR_CODE = $ERROR_CODE && $ERROR_CODE < 600 ? $ERROR_CODE : 500;
// Ajax request
-if ($OUTPUT && ($OUTPUT instanceof rcube_json_output)) {
+if ($rcmail->output && $rcmail->output->type == 'js') {
header("HTTP/1.0 $HTTP_ERR_CODE $__error_title");
die;
}
@@ -110,13 +111,13 @@ $__page_content = <<<EOF
</div>
EOF;
-if ($OUTPUT && $OUTPUT->template_exists('error')) {
- $OUTPUT->reset();
- $OUTPUT->send('error');
+if ($rcmail->output && $rcmail->output->template_exists('error')) {
+ $rcmail->output->reset();
+ $rcmail->output->send('error');
}
-$__skin = $CONFIG->skin ? $CONFIG->skin : 'default';
-$__productname = $CONFIG['product_name'] ? $CONFIG['product_name'] : 'Roundcube Webmail';
+$__skin = $rcmail->config->get('skin', 'default');
+$__productname = $rcmail->config->get('product_name', 'Roundcube Webmail');
// print system error page
print <<<EOF