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']; | 
