From ced34cb15e095836767971aa4d27b141fb1d7ec9 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sat, 18 Oct 2014 08:47:54 -0400
Subject: [PATCH] Merge pull request #230 from bytesatwork-xx/master

---
 program/lib/Roundcube/rcube.php |  270 ++++++++++++++++++++++++++++++++++++++++--------------
 1 files changed, 200 insertions(+), 70 deletions(-)

diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index e0fa22c..03f4963 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/program/lib/Roundcube/rcube.php
@@ -3,8 +3,8 @@
 /*
  +-----------------------------------------------------------------------+
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2008-2012, The Roundcube Dev Team                       |
- | Copyright (C) 2011-2012, Kolab Systems AG                             |
+ | Copyright (C) 2008-2014, The Roundcube Dev Team                       |
+ | Copyright (C) 2011-2014, Kolab Systems AG                             |
  |                                                                       |
  | Licensed under the GNU General Public License version 3 or            |
  | any later version with exceptions for skins & plugins.                |
@@ -94,6 +94,13 @@
      */
     public $plugins;
 
+    /**
+     * Instance of rcube_user class.
+     *
+     * @var rcube_user
+     */
+    public $user;
+
 
     /* private/protected vars */
     protected $texts;
@@ -165,9 +172,13 @@
     public function get_dbh()
     {
         if (!$this->db) {
-            $config_all = $this->config->all();
-            $this->db = rcube_db::factory($config_all['db_dsnw'], $config_all['db_dsnr'], $config_all['db_persistent']);
-            $this->db->set_debug((bool)$config_all['sql_debug']);
+            $this->db = rcube_db::factory(
+                $this->config->get('db_dsnw'),
+                $this->config->get('db_dsnr'),
+                $this->config->get('db_persistent')
+            );
+
+            $this->db->set_debug((bool)$this->config->get('sql_debug'));
         }
 
         return $this->db;
@@ -348,40 +359,18 @@
         // 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"),
-            'disabled_caps' => $this->config->get("{$driver}_disabled_caps"),
-            'timeout'     => (int) $this->config->get("{$driver}_timeout"),
-            'skip_deleted' => (bool) $this->config->get('skip_deleted'),
-            'driver'      => $driver,
+            '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"),
+            'disabled_caps'  => $this->config->get("{$driver}_disabled_caps"),
+            'socket_options' => $this->config->get("{$driver}_conn_options"),
+            'timeout'        => (int) $this->config->get("{$driver}_timeout"),
+            'skip_deleted'   => (bool) $this->config->get('skip_deleted'),
+            'driver'         => $driver,
         );
 
         if (!empty($_SESSION['storage_host'])) {
@@ -400,30 +389,87 @@
 
         $this->storage->set_options($options);
         $this->set_storage_prop();
-    }
 
+        // subscribe to 'storage_connected' hook for session logging
+        if ($this->config->get('imap_log_session', false)) {
+            $this->plugins->register_hook('storage_connected', array($this, 'storage_log_session'));
+        }
+    }
 
     /**
      * Set storage parameters.
-     * This must be done AFTER connecting to the server!
      */
     protected function set_storage_prop()
     {
         $storage = $this->get_storage();
 
+        // set pagesize from config
+        $pagesize = $this->config->get('mail_pagesize');
+        if (!$pagesize) {
+            $pagesize = $this->config->get('pagesize', 50);
+        }
+
+        $storage->set_pagesize($pagesize);
         $storage->set_charset($this->config->get('default_charset', RCUBE_CHARSET));
 
-        if ($default_folders = $this->config->get('default_folders')) {
-            $storage->set_default_folders($default_folders);
+        // enable caching of mail data
+        $driver         = $this->config->get('storage_driver', 'imap');
+        $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 (isset($_SESSION['mbox'])) {
-            $storage->set_folder($_SESSION['mbox']);
+
+        if ($storage_cache) {
+            $storage->set_caching($storage_cache);
         }
-        if (isset($_SESSION['page'])) {
-            $storage->set_page($_SESSION['page']);
+        if ($messages_cache) {
+            $storage->set_messages_caching(true);
         }
     }
 
+
+    /**
+     * Set special folders type association.
+     * This must be done AFTER connecting to the server!
+     */
+    protected function set_special_folders()
+    {
+        $storage = $this->get_storage();
+        $folders = $storage->get_special_folders(true);
+        $prefs   = array();
+
+        // check SPECIAL-USE flags on IMAP folders
+        foreach ($folders as $type => $folder) {
+            $idx = $type . '_mbox';
+            if ($folder !== $this->config->get($idx)) {
+                $prefs[$idx] = $folder;
+            }
+        }
+
+        // Some special folders differ, update user preferences
+        if (!empty($prefs) && $this->user) {
+            $this->user->save_prefs($prefs);
+        }
+
+        // create default folders (on login)
+        if ($this->config->get('create_default_folders')) {
+            $storage->create_default_folders();
+        }
+    }
+
+
+    /**
+     * Callback for IMAP connection events to log session identifiers
+     */
+    public function storage_log_session($args)
+    {
+        if (!empty($args['session']) && session_id()) {
+            $this->write_log('imap_session', $args['session']);
+        }
+    }
 
     /**
      * Create session object and start the session.
@@ -642,10 +688,11 @@
     /**
      * Load a localization package
      *
-     * @param string Language ID
-     * @param array  Additional text labels/messages
+     * @param string $lang  Language ID
+     * @param array  $add   Additional text labels/messages
+     * @param array  $merge Additional text labels/messages to merge
      */
-    public function load_language($lang = null, $add = array())
+    public function load_language($lang = null, $add = array(), $merge = array())
     {
         $lang = $this->language_prop(($lang ? $lang : $_SESSION['language']));
 
@@ -684,6 +731,11 @@
         // append additional texts (from plugin)
         if (is_array($add) && !empty($add)) {
             $this->texts += $add;
+        }
+
+        // merge additional texts (from plugin)
+        if (is_array($merge) && !empty($merge)) {
+            $this->texts = array_merge($this->texts, $merge);
         }
     }
 
@@ -790,12 +842,19 @@
          * upon decryption; see http://php.net/mcrypt_generic#68082
          */
         $clear = pack("a*H2", $clear, "80");
+        $ckey  = $this->config->get_crypto_key($key);
 
-        if (function_exists('mcrypt_module_open') &&
+        if (function_exists('openssl_encrypt')) {
+            $method = 'DES-EDE3-CBC';
+            $opts   = defined('OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : true;
+            $iv     = $this->create_iv(openssl_cipher_iv_length($method));
+            $cipher = $iv . openssl_encrypt($clear, $method, $ckey, $opts, $iv);
+        }
+        else 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);
+            mcrypt_generic_init($td, $ckey, $iv);
             $cipher = $iv . mcrypt_generic($td, $clear);
             mcrypt_generic_deinit($td);
             mcrypt_module_close($td);
@@ -806,13 +865,13 @@
             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);
+                $cipher = $iv . des($ckey, $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"
+                    'message' => "Could not perform encryption; make sure OpenSSL or Mcrypt or lib/des.inc is available"
                     ), true, true);
             }
         }
@@ -837,12 +896,13 @@
         }
 
         $cipher = $base64 ? base64_decode($cipher) : $cipher;
+        $ckey   = $this->config->get_crypto_key($key);
 
-        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);
+        if (function_exists('openssl_decrypt')) {
+            $method  = 'DES-EDE3-CBC';
+            $opts    = defined('OPENSSL_RAW_DATA') ? OPENSSL_RAW_DATA : true;
+            $iv_size = openssl_cipher_iv_length($method);
+            $iv      = substr($cipher, 0, $iv_size);
 
             // session corruption? (#1485970)
             if (strlen($iv) < $iv_size) {
@@ -850,7 +910,21 @@
             }
 
             $cipher = substr($cipher, $iv_size);
-            mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
+            $clear  = openssl_decrypt($cipher, $method, $ckey, $opts, $iv);
+        }
+        else 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, $ckey, $iv);
             $clear = mdecrypt_generic($td, $cipher);
             mcrypt_generic_deinit($td);
             mcrypt_module_close($td);
@@ -860,15 +934,15 @@
 
             if (function_exists('des')) {
                 $des_iv_size = 8;
-                $iv = substr($cipher, 0, $des_iv_size);
+                $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);
+                $clear  = des($ckey, $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"
+                    'message' => "Could not perform decryption; make sure OpenSSL or Mcrypt or lib/des.inc is available"
                     ), true, true);
             }
         }
@@ -1080,8 +1154,12 @@
             $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;
+        $date_format = $log_driver = $session_key = null;
+        if (self::$instance) {
+            $date_format = self::$instance->config->get('log_date_format');
+            $log_driver  = self::$instance->config->get('log_driver');
+            $session_key = intval(self::$instance->config->get('log_session_id', 8));
+        }
 
         if (empty($date_format)) {
             $date_format = 'd-M-Y H:i:s O';
@@ -1099,6 +1177,11 @@
                 return true;
         }
 
+        // add session ID to the log
+        if ($session_key > 0 && ($sess = session_id())) {
+            $line = '<' . substr($sess, 0, $session_key) . '> ' . $line;
+        }
+
         if ($log_driver == 'syslog') {
             $prio = $name == 'errors' ? LOG_ERR : LOG_INFO;
             syslog($prio, $line);
@@ -1108,7 +1191,20 @@
         // log_driver == 'file' is assumed here
 
         $line = sprintf("[%s]: %s\n", $date, $line);
-        $log_dir  = self::$instance ? self::$instance->config->get('log_dir') : null;
+        $log_dir = null;
+
+        // per-user logging is activated
+        if (self::$instance && self::$instance->config->get('per_user_logging', false) && self::$instance->get_user_id()) {
+            $log_dir = self::$instance->get_user_log_dir();
+            if (empty($log_dir))
+                return false;
+        }
+        else if (!empty($log['dir'])) {
+            $log_dir = $log['dir'];
+        }
+        else if (self::$instance) {
+            $log_dir = self::$instance->config->get('log_dir');
+        }
 
         if (empty($log_dir)) {
             $log_dir = RCUBE_INSTALL_PATH . 'logs';
@@ -1146,7 +1242,6 @@
         // handle PHP exceptions
         if (is_object($arg) && is_a($arg, 'Exception')) {
             $arg = array(
-                'type' => 'php',
                 'code' => $arg->getCode(),
                 'line' => $arg->getLine(),
                 'file' => $arg->getFile(),
@@ -1154,7 +1249,7 @@
             );
         }
         else if (is_string($arg)) {
-            $arg = array('message' => $arg, 'type' => 'php');
+            $arg = array('message' => $arg);
         }
 
         if (empty($arg['code'])) {
@@ -1162,15 +1257,15 @@
         }
 
         // installer
-        if (class_exists('rcube_install', false)) {
-            $rci = rcube_install::get_instance();
+        if (class_exists('rcmail_install', false)) {
+            $rci = rcmail_install::get_instance();
             $rci->raise_error($arg);
             return;
         }
 
         $cli = php_sapi_name() == 'cli';
 
-        if (($log || $terminate) && !$cli && $arg['type'] && $arg['message']) {
+        if (($log || $terminate) && !$cli && $arg['message']) {
             $arg['fatal'] = $terminate;
             self::log_bug($arg);
         }
@@ -1187,6 +1282,9 @@
 
             exit(1);
         }
+        else if ($cli) {
+            fwrite(STDERR, 'ERROR: ' . $arg['message']);
+        }
     }
 
 
@@ -1198,7 +1296,7 @@
      */
     public static function log_bug($arg_arr)
     {
-        $program = strtoupper($arg_arr['type']);
+        $program = strtoupper(!empty($arg_arr['type']) ? $arg_arr['type'] : 'php');
         $level   = self::get_instance()->config->get('debug_level');
 
         // disable errors for ajax requests, write to log instead (#1487831)
@@ -1284,6 +1382,20 @@
         self::write_log($dest, sprintf("%s: %0.4f sec", $label, $diff));
     }
 
+    /**
+     * Setter for system user object
+     *
+     * @param rcube_user Current user instance
+     */
+    public function set_user($user)
+    {
+        if (is_object($user)) {
+            $this->user = $user;
+
+            // overwrite config with user preferences
+            $this->config->set_user_prefs((array)$this->user->get_prefs());
+        }
+    }
 
     /**
      * Getter for logged user ID.
@@ -1347,6 +1459,17 @@
         }
     }
 
+    /**
+     * Get the per-user log directory
+     */
+    protected function get_user_log_dir()
+    {
+        $log_dir = $this->config->get('log_dir', RCUBE_INSTALL_PATH . 'logs');
+        $user_name = $this->get_user_name();
+        $user_log_dir = $log_dir . '/' . $user_name;
+
+        return !empty($user_name) && is_writable($user_log_dir) ? $user_log_dir : false;
+    }
 
     /**
      * Getter for logged user language code.
@@ -1409,6 +1532,13 @@
         ));
 
         if ($plugin['abort']) {
+            if (!empty($plugin['error'])) {
+                $error = $plugin['error'];
+            }
+            if (!empty($plugin['body_file'])) {
+                $body_file = $plugin['body_file'];
+            }
+
             return isset($plugin['result']) ? $plugin['result'] : false;
         }
 

--
Gitblit v1.9.1