diff options
Diffstat (limited to 'program/include')
-rw-r--r-- | program/include/html.php | 2 | ||||
-rw-r--r-- | program/include/iniset.php | 4 | ||||
-rw-r--r-- | program/include/rcmail.php | 27 | ||||
-rw-r--r-- | program/include/rcube_imap.php | 5 | ||||
-rw-r--r-- | program/include/rcube_message.php | 5 | ||||
-rw-r--r-- | program/include/rcube_output.php | 2 | ||||
-rw-r--r-- | program/include/rcube_output_html.php | 183 | ||||
-rw-r--r-- | program/include/rcube_plugin.php | 2 | ||||
-rw-r--r-- | program/include/rcube_plugin_api.php | 24 | ||||
-rw-r--r-- | program/include/rcube_string_replacer.php | 30 | ||||
-rw-r--r-- | program/include/rcube_user.php | 13 |
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']; |