summaryrefslogtreecommitdiff
path: root/program/include
diff options
context:
space:
mode:
Diffstat (limited to 'program/include')
-rw-r--r--program/include/html.php2
-rw-r--r--program/include/iniset.php4
-rw-r--r--program/include/rcmail.php27
-rw-r--r--program/include/rcube_imap.php5
-rw-r--r--program/include/rcube_message.php5
-rw-r--r--program/include/rcube_output.php2
-rw-r--r--program/include/rcube_output_html.php183
-rw-r--r--program/include/rcube_plugin.php2
-rw-r--r--program/include/rcube_plugin_api.php24
-rw-r--r--program/include/rcube_string_replacer.php30
-rw-r--r--program/include/rcube_user.php13
11 files changed, 188 insertions, 109 deletions
diff --git a/program/include/html.php b/program/include/html.php
index 234985241..880873ddc 100644
--- a/program/include/html.php
+++ b/program/include/html.php
@@ -334,7 +334,7 @@ class html
*/
public static function quote($str)
{
- return htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
+ return @htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
}
}
diff --git a/program/include/iniset.php b/program/include/iniset.php
index a2f43b380..82278c9f8 100644
--- a/program/include/iniset.php
+++ b/program/include/iniset.php
@@ -34,7 +34,9 @@ $config = array(
);
foreach ($config as $optname => $optval) {
if ($optval != ini_get($optname) && @ini_set($optname, $optval) === false) {
- die("ERROR: Wrong '$optname' option value. Read REQUIREMENTS section in INSTALL file or use Roundcube Installer, please!");
+ die("ERROR: Wrong '$optname' option value and it wasn't possible to set it to required value ($optval).\n"
+ ."Check your PHP configuration (including php_admin_flag).\n"
+ ."Read REQUIREMENTS section in INSTALL file or use Roundcube Installer!");
}
}
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index ec3d537ec..c2f76b388 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -258,8 +258,8 @@ class rcmail extends rcube
$autocomplete = (array) $this->config->get('autocomplete_addressbooks');
$list = array();
- // We are using the DB address book
- if ($abook_type != 'ldap') {
+ // We are using the DB address book or a plugin address book
+ if ($abook_type != 'ldap' && $abook_type != '') {
if (!isset($this->address_books['0']))
$this->address_books['0'] = new rcube_contacts($this->db, $this->get_user_id());
$list['0'] = array(
@@ -452,6 +452,10 @@ class rcmail extends rcube
$username .= '@'.rcube_utils::parse_host($config['username_domain'], $host);
}
+ if (!isset($config['login_lc'])) {
+ $config['login_lc'] = 2; // default
+ }
+
// Convert username to lowercase. If storage backend
// is case-insensitive we need to store always the same username (#1487113)
if ($config['login_lc']) {
@@ -483,21 +487,7 @@ class rcmail extends rcube
$storage = $this->get_storage();
// try to log in
- if (!($login = $storage->connect($host, $username, $pass, $port, $ssl))) {
- // try with lowercase
- $username_lc = mb_strtolower($username);
- if ($username_lc != $username) {
- // try to find user record again -> overwrite username
- if (!$user && ($user = rcube_user::query($username_lc, $host)))
- $username_lc = $user->data['username'];
-
- if ($login = $storage->connect($host, $username_lc, $pass, $port, $ssl))
- $username = $username_lc;
- }
- }
-
- // exit if login failed
- if (!$login) {
+ if (!$storage->connect($host, $username, $pass, $port, $ssl)) {
return false;
}
@@ -2112,8 +2102,7 @@ class rcmail extends rcube
if (!$storage->connect($host, $user, $pass, $port, $ssl)) {
if (is_object($this->output)) {
- $error = $storage->get_error_code() == -1 ? 'storageerror' : 'sessionerror';
- $this->output->show_message($error, 'error');
+ $this->output->show_message('storageerror', 'error');
}
}
else {
diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php
index 1e6cf360b..a89fd164d 100644
--- a/program/include/rcube_imap.php
+++ b/program/include/rcube_imap.php
@@ -4119,6 +4119,11 @@ class rcube_imap extends rcube_storage
return $this->delete_folder($folder);
}
+ function clear_mailbox($folder = null)
+ {
+ return $this->clear_folder($folder);
+ }
+
public function mailbox_exists($folder, $subscription=false)
{
return $this->folder_exists($folder, $subscription);
diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php
index c189df57d..38d18171c 100644
--- a/program/include/rcube_message.php
+++ b/program/include/rcube_message.php
@@ -372,9 +372,10 @@ class rcube_message
foreach ($structure->parts as $p => $sub_part) {
$sub_mimetype = $sub_part->mimetype;
- // skip empty parts
- if (!$sub_part->size)
+ // skip empty text parts
+ if (!$sub_part->size && preg_match('#^text/(plain|html|enriched)$#', $sub_mimetype)) {
continue;
+ }
// check if sub part is
if ($sub_mimetype == 'text/plain')
diff --git a/program/include/rcube_output.php b/program/include/rcube_output.php
index 9aa7c9eba..5c582e67c 100644
--- a/program/include/rcube_output.php
+++ b/program/include/rcube_output.php
@@ -44,7 +44,7 @@ abstract class rcube_output
*/
public function __construct($task = null, $framed = false)
{
- $this->app = rcmail::get_instance();
+ $this->app = rcube::get_instance();
$this->config = $this->app->config;
$this->browser = new rcube_browser();
}
diff --git a/program/include/rcube_output_html.php b/program/include/rcube_output_html.php
index 616ab3883..d42171869 100644
--- a/program/include/rcube_output_html.php
+++ b/program/include/rcube_output_html.php
@@ -33,7 +33,7 @@ class rcube_output_html extends rcube_output
protected $js_env = array();
protected $js_labels = array();
protected $js_commands = array();
- protected $plugin_skin_path;
+ protected $skin_paths = array();
protected $template_name;
protected $scripts_path = '';
protected $script_files = array();
@@ -164,9 +164,27 @@ class rcube_output_html extends rcube_output
$this->config->set('skin_path', $skin_path);
+ // register skin path(s)
+ $this->skin_paths = array();
+ $this->load_skin($skin_path);
+
return $valid;
}
+ /**
+ * Helper method to recursively read skin meta files and register search paths
+ */
+ private function load_skin($skin_path)
+ {
+ $this->skin_paths[] = $skin_path;
+
+ // read meta file and check for dependecies
+ $meta = @json_decode(@file_get_contents($skin_path.'/meta.json'), true);
+ if ($meta['extends'] && is_dir('skins/' . $meta['extends'])) {
+ $this->load_skin('skins/' . $meta['extends']);
+ }
+ }
+
/**
* Check if a specific template exists
@@ -176,8 +194,14 @@ class rcube_output_html extends rcube_output
*/
public function template_exists($name)
{
- $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]));
+ $found = false;
+ foreach ($this->skin_paths as $skin_path) {
+ $filename = $skin_path . '/templates/' . $name . '.html';
+ $found = (is_file($filename) && is_readable($filename)) || ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name]));
+ if ($found)
+ break;
+ }
+ return $found;
}
@@ -364,41 +388,60 @@ class rcube_output_html extends rcube_output
*/
function parse($name = 'main', $exit = true, $write = true)
{
- $skin_path = $this->config->get('skin_path');
$plugin = false;
$realname = $name;
- $temp = explode('.', $name, 2);
-
- $this->plugin_skin_path = null;
- $this->template_name = $realname;
+ $this->template_name = $realname;
+ $temp = explode('.', $name, 2);
if (count($temp) > 1) {
$plugin = $temp[0];
$name = $temp[1];
$skin_dir = $plugin . '/skins/' . $this->config->get('skin');
- $skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
- // fallback to default skin
- if (!is_dir($skin_path)) {
+ // apply skin search escalation list to plugin directory
+ $plugin_skin_paths = array();
+ foreach ($this->skin_paths as $skin_path) {
+ $plugin_skin_paths[] = $this->app->plugins->dir . $plugin . '/' . $skin_path;
+ }
+
+ // add fallback to default skin
+ if (is_dir($this->app->plugins->dir . $plugin . '/skins/default')) {
$skin_dir = $plugin . '/skins/default';
- $skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
+ $plugin_skin_paths[] = $this->app->plugins->dir . $skin_dir;
}
+
+ // add plugin skin paths to search list
+ $this->skin_paths = array_merge($plugin_skin_paths, $this->skin_paths);
}
- $path = "$skin_path/templates/$name.html";
+ // find skin template
+ $path = false;
+ foreach ($this->skin_paths as $skin_path) {
+ $path = "$skin_path/templates/$name.html";
- if (!is_readable($path) && $this->deprecated_templates[$realname]) {
- $path = "$skin_path/templates/".$this->deprecated_templates[$realname].".html";
- if (is_readable($path))
- rcube::raise_error(array('code' => 502, 'type' => 'php',
+ // fallback to deprecated template names
+ if (!is_readable($path) && $this->deprecated_templates[$realname]) {
+ $path = "$skin_path/templates/" . $this->deprecated_templates[$realname] . ".html";
+ rcube::raise_error(array(
+ 'code' => 502, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Using deprecated template '".$this->deprecated_templates[$realname]
- ."' in $skin_path/templates. Please rename to '".$realname."'"),
- true, false);
+ 'message' => "Using deprecated template '" . $this->deprecated_templates[$realname]
+ . "' in $skin_path/templates. Please rename to '$realname'"),
+ true, false);
+ }
+
+ if (is_readable($path)) {
+ $this->config->set('skin_path', $skin_path);
+ $this->base_path = $skin_path;
+ break;
+ }
+ else {
+ $path = false;
+ }
}
// read template file
- if (($templ = @file_get_contents($path)) === false) {
+ if (!$path || ($templ = @file_get_contents($path)) === false) {
rcube::raise_error(array(
'code' => 501,
'type' => 'php',
@@ -426,7 +469,7 @@ class rcube_output_html extends rcube_output
$output = $hook['content'];
unset($hook['content']);
- $output = $this->parse_with_globals($output);
+ $output = $this->parse_with_globals($this->fix_paths($output));
// make sure all <form> tags have a valid request token
$output = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $output);
@@ -498,7 +541,7 @@ class rcube_output_html extends rcube_output
public function abs_url($str)
{
if ($str[0] == '/')
- return $this->config->get('skin_path') . $str;
+ return $this->base_path . $str;
else
return $str;
}
@@ -532,7 +575,7 @@ class rcube_output_html extends rcube_output
{
$GLOBALS['__version'] = html::quote(RCMAIL_VERSION);
$GLOBALS['__comm_path'] = html::quote($this->app->comm_path);
- $GLOBALS['__skin_path'] = html::quote($this->config->get('skin_path'));
+ $GLOBALS['__skin_path'] = html::quote($this->base_path);
return preg_replace_callback('/\$(__[a-z0-9_\-]+)/',
array($this, 'globals_callback'), $input);
@@ -549,6 +592,43 @@ class rcube_output_html extends rcube_output
/**
+ * Correct absolute paths in images and other tags
+ * add timestamp to .js and .css filename
+ */
+ protected function fix_paths($output)
+ {
+ return preg_replace_callback(
+ '!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
+ array($this, 'file_callback'), $output);
+ }
+
+
+ /**
+ * 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];
+ }
+
+
+ /**
* Public wrapper to dipp into template parsing.
*
* @param string $input
@@ -710,6 +790,9 @@ class rcube_output_html extends rcube_output
// show a label
case 'label':
+ if ($attrib['expression'])
+ $attrib['name'] = eval("return " . $this->parse_expression($attrib['expression']) .";");
+
if ($attrib['name'] || $attrib['command']) {
// @FIXME: 'noshow' is useless, remove?
if ($attrib['noshow']) {
@@ -741,8 +824,17 @@ class rcube_output_html extends rcube_output
// 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->get('skin_path')).$attrib['file']);
+ $old_base_path = $this->base_path;
+ $skin_paths = $this->skin_paths;
+ if ($attrib['skin_path'])
+ array_unshift($skin_paths, $attrib['skin_path']);
+ foreach ($skin_paths as $skin_path) {
+ $path = realpath($skin_path . $attrib['file']);
+ if (is_file($path)) {
+ $this->base_path = $skin_path;
+ break;
+ }
+ }
if (is_readable($path)) {
if ($this->config->get('skin_include_php')) {
@@ -752,14 +844,16 @@ class rcube_output_html extends rcube_output
$incl = file_get_contents($path);
}
$incl = $this->parse_conditions($incl);
- return $this->parse_xml($incl);
+ $incl = $this->parse_xml($incl);
+ $incl = $this->fix_paths($incl);
+ $this->base_path = $old_base_path;
+ return $incl;
}
break;
case 'plugin.include':
$hook = $this->app->plugins->exec_hook("template_plugin_include", $attrib);
return $hook['content'];
- break;
// define a container block
case 'container':
@@ -1239,14 +1333,6 @@ class rcube_output_html extends rcube_output
$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 = $this->app->plugins->exec_hook("send_page", array('content' => $output));
if (!$hook['abort']) {
@@ -1261,31 +1347,6 @@ class rcube_output_html extends rcube_output
/**
- * 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];
- }
-
-
- /**
* Returns iframe object, registers some related env variables
*
* @param array $attrib HTML attributes
diff --git a/program/include/rcube_plugin.php b/program/include/rcube_plugin.php
index c1035733b..45088850a 100644
--- a/program/include/rcube_plugin.php
+++ b/program/include/rcube_plugin.php
@@ -202,7 +202,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
diff --git a/program/include/rcube_plugin_api.php b/program/include/rcube_plugin_api.php
index 9ef68cab9..107c81026 100644
--- a/program/include/rcube_plugin_api.php
+++ b/program/include/rcube_plugin_api.php
@@ -31,7 +31,7 @@ if (!defined('RCMAIL_PLUGINS_DIR'))
*/
class rcube_plugin_api
{
- static private $instance;
+ static protected $instance;
public $dir;
public $url = 'plugins/';
@@ -39,16 +39,16 @@ class rcube_plugin_api
public $output;
public $handlers = array();
- private $plugins = array();
- private $tasks = array();
- private $actions = array();
- private $actionmap = array();
- private $objectsmap = array();
- private $template_contents = array();
- private $active_hook = false;
+ protected $plugins = array();
+ protected $tasks = array();
+ protected $actions = array();
+ protected $actionmap = array();
+ protected $objectsmap = array();
+ protected $template_contents = array();
+ protected $active_hook = false;
// Deprecated names of hooks, will be removed after 0.5-stable release
- private $deprecated_hooks = array(
+ protected $deprecated_hooks = array(
'create_user' => 'user_create',
'kill_session' => 'session_destroy',
'upload_attachment' => 'attachment_upload',
@@ -98,7 +98,7 @@ class rcube_plugin_api
/**
* Private constructor
*/
- private function __construct()
+ protected function __construct()
{
$this->dir = slashify(RCMAIL_PLUGINS_DIR);
}
@@ -470,7 +470,7 @@ class rcube_plugin_api
* @param array $attrib
* @return array
*/
- private function template_container_hook($attrib)
+ protected function template_container_hook($attrib)
{
$container = $attrib['name'];
return array('content' => $attrib['content'] . $this->template_contents[$container]);
@@ -483,7 +483,7 @@ class rcube_plugin_api
* @param string $fn Filename
* @return string
*/
- private function resource_url($fn)
+ protected function resource_url($fn)
{
if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn))
return $this->url . $fn;
diff --git a/program/include/rcube_string_replacer.php b/program/include/rcube_string_replacer.php
index c29f0e476..edb2ac34f 100644
--- a/program/include/rcube_string_replacer.php
+++ b/program/include/rcube_string_replacer.php
@@ -37,16 +37,16 @@ class rcube_string_replacer
{
// Simplified domain expression for UTF8 characters handling
// Support unicode/punycode in top-level domain part
- $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})';
+ $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.?([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-zA-Z0-9]{2,})';
$url1 = '.:;,';
- $url2 = 'a-z0-9%=#@+?!&\\/_~\\[\\]{}-';
+ $url2 = 'a-zA-Z0-9%=#$@+?!&\\/_~\\[\\]{}\*-';
- $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i";
+ $this->link_pattern = "/([\w]+:\/\/|\W[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)($utf_domain([$url1]?[$url2]+)*)/";
$this->mailto_pattern = "/("
."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*" // local-part
."@$utf_domain" // domain-part
."(\?[$url1$url2]+)?" // e.g. ?subject=test...
- .")/i";
+ .")/";
}
/**
@@ -81,11 +81,11 @@ class rcube_string_replacer
$i = -1;
$scheme = strtolower($matches[1]);
- if (preg_match('!^(http|ftp|file)s?://!', $scheme)) {
+ if (preg_match('!^(http|ftp|file)s?://!i', $scheme)) {
$url = $matches[1] . $matches[2];
}
- else if (preg_match('/^(\W)www\.$/', $matches[1], $m)) {
- $url = 'www.' . $matches[2];
+ else if (preg_match('/^(\W*)(www\.)$/i', $matches[1], $m)) {
+ $url = $m[2] . $matches[2];
$url_prefix = 'http://';
$prefix = $m[1];
}
@@ -134,6 +134,22 @@ class rcube_string_replacer
}
/**
+ * Replace all defined (link|mailto) patterns with replacement string
+ *
+ * @param string $str Text
+ *
+ * @return string Text
+ */
+ public function replace($str)
+ {
+ // search for patterns like links and e-mail addresses
+ $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str);
+ $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str);
+
+ return $str;
+ }
+
+ /**
* Replace substituted strings with original values
*/
public function resolve($str)
diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php
index 5a65a519d..b92187ad4 100644
--- a/program/include/rcube_user.php
+++ b/program/include/rcube_user.php
@@ -449,6 +449,7 @@ class rcube_user
'user_name' => $user_name,
'user_email' => $user_email,
'email_list' => $email_list,
+ 'language' => $_SESSION['language'],
));
// plugin aborted this operation
@@ -462,13 +463,17 @@ class rcube_user
" VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)",
strip_newlines($data['user']),
strip_newlines($data['host']),
- strip_newlines($data['language'] ? $data['language'] : $_SESSION['language']));
+ strip_newlines($data['language']));
if ($user_id = $dbh->insert_id('users')) {
// create rcube_user instance to make plugin hooks work
- $user_instance = new rcube_user($user_id);
- $rcube->user = $user_instance;
-
+ $user_instance = new rcube_user($user_id, array(
+ 'user_id' => $user_id,
+ 'username' => $data['user'],
+ 'mail_host' => $data['host'],
+ 'language' => $data['language'],
+ ));
+ $rcube->user = $user_instance;
$mail_domain = $rcube->config->mail_domain($data['host']);
$user_name = $data['user_name'];
$user_email = $data['user_email'];