From 5a2d2a6f75b115183459997cc2aa787d9a085fe8 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Mon, 14 Oct 2013 02:53:34 -0400
Subject: [PATCH] Fix HTML part detection when encapsulated inside multipart/signed (#1489372)

---
 program/lib/Roundcube/rcube.php |  129 ++++++++++++++++++++++++++++++++++---------
 1 files changed, 102 insertions(+), 27 deletions(-)

diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index eea2fde..399f84f 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/program/lib/Roundcube/rcube.php
@@ -99,20 +99,20 @@
     protected $texts;
     protected $caches = array();
     protected $shutdown_functions = array();
-    protected $expunge_cache = false;
 
 
     /**
      * This implements the 'singleton' design pattern
      *
      * @param integer Options to initialize with this instance. See rcube::INIT_WITH_* constants
+     * @param string Environment name to run (e.g. live, dev, test)
      *
      * @return rcube The one and only instance
      */
-    static function get_instance($mode = 0)
+    static function get_instance($mode = 0, $env = '')
     {
         if (!self::$instance) {
-            self::$instance = new rcube();
+            self::$instance = new rcube($env);
             self::$instance->init($mode);
         }
 
@@ -123,10 +123,10 @@
     /**
      * Private constructor
      */
-    protected function __construct()
+    protected function __construct($env = '')
     {
         // load configuration
-        $this->config  = new rcube_config;
+        $this->config  = new rcube_config($env);
         $this->plugins = new rcube_dummy_plugin_api;
 
         register_shutdown_function(array($this, 'shutdown'));
@@ -258,6 +258,39 @@
 
 
     /**
+     * Initialize and get shared cache object
+     *
+     * @param string $name   Cache identifier
+     * @param bool   $packed Enables/disables data serialization
+     *
+     * @return rcube_cache_shared Cache object
+     */
+    public function get_cache_shared($name, $packed=true)
+    {
+        $shared_name = "shared_$name";
+
+        if (!array_key_exists($shared_name, $this->caches)) {
+            $opt  = strtolower($name) . '_cache';
+            $type = $this->config->get($opt);
+            $ttl  = $this->config->get($opt . '_ttl');
+
+            if (!$type) {
+                // cache is disabled
+                return $this->caches[$shared_name] = null;
+            }
+
+            if ($ttl === null) {
+                $ttl = $this->config->get('shared_cache_ttl', '10d');
+            }
+
+            $this->caches[$shared_name] = new rcube_cache_shared($type, $name, $ttl, $packed);
+        }
+
+        return $this->caches[$shared_name];
+    }
+
+
+    /**
      * Create SMTP object and connect to server
      *
      * @param boolean True if connection should be established
@@ -345,6 +378,7 @@
             '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,
@@ -424,22 +458,36 @@
         ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid');
         ini_set('session.use_cookies', 1);
         ini_set('session.use_only_cookies', 1);
-        ini_set('session.serialize_handler', 'php');
         ini_set('session.cookie_httponly', 1);
 
         // use database for storing session data
         $this->session = new rcube_session($this->get_dbh(), $this->config);
 
-        $this->session->register_gc_handler(array($this, 'temp_gc'));
-        $this->session->register_gc_handler(array($this, 'cache_gc'));
-
+        $this->session->register_gc_handler(array($this, 'gc'));
         $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME']));
         $this->session->set_ip_check($this->config->get('ip_check'));
 
+        if ($this->config->get('session_auth_name')) {
+            $this->session->set_cookiename($this->config->get('session_auth_name'));
+        }
+
         // start PHP session (if not in CLI mode)
         if ($_SERVER['REMOTE_ADDR']) {
-            session_start();
+            $this->session->start();
         }
+    }
+
+
+    /**
+     * Garbage collector - cache/temp cleaner
+     */
+    public function gc()
+    {
+        rcube_cache::gc();
+        rcube_cache_shared::gc();
+        $this->get_storage()->cache_gc();
+
+        $this->gc_temp();
     }
 
 
@@ -447,18 +495,25 @@
      * Garbage collector function for temp files.
      * Remove temp files older than two days
      */
-    public function temp_gc()
+    public function gc_temp()
     {
         $tmp = unslashify($this->config->get('temp_dir'));
-        $expire = time() - 172800;  // expire in 48 hours
+
+        // expire in 48 hours by default
+        $temp_dir_ttl = $this->config->get('temp_dir_ttl', '48h');
+        $temp_dir_ttl = get_offset_sec($temp_dir_ttl);
+        if ($temp_dir_ttl < 6*3600)
+            $temp_dir_ttl = 6*3600;   // 6 hours sensible lower bound.
+
+        $expire = time() - $temp_dir_ttl;
 
         if ($tmp && ($dir = opendir($tmp))) {
             while (($fname = readdir($dir)) !== false) {
-                if ($fname{0} == '.') {
+                if ($fname[0] == '.') {
                     continue;
                 }
 
-                if (filemtime($tmp.'/'.$fname) < $expire) {
+                if (@filemtime($tmp.'/'.$fname) < $expire) {
                     @unlink($tmp.'/'.$fname);
                 }
             }
@@ -469,14 +524,21 @@
 
 
     /**
-     * Garbage collector for cache entries.
-     * Set flag to expunge caches on shutdown
+     * Runs garbage collector with probability based on
+     * session settings. This is intended for environments
+     * without a session.
      */
-    public function cache_gc()
+    public function gc_run()
     {
-        // because this gc function is called before storage is initialized,
-        // we just set a flag to expunge storage cache on shutdown.
-        $this->expunge_cache = true;
+        $probability = (int) ini_get('session.gc_probability');
+        $divisor     = (int) ini_get('session.gc_divisor');
+
+        if ($divisor > 0 && $probability > 0) {
+            $random = mt_rand(1, $divisor);
+            if ($random <= $probability) {
+                $this->gc();
+            }
+        }
     }
 
 
@@ -640,7 +702,11 @@
         // 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]);
+            $lang         = $accept_langs[0];
+
+            if (preg_match('/^([a-z]+)[_-]([a-z]+)$/i', $lang, $m)) {
+                $lang = $m[1] . '_' . strtoupper($m[2]);
+            }
         }
 
         if (empty($rcube_languages)) {
@@ -860,6 +926,14 @@
             call_user_func($function);
         }
 
+        // write session data as soon as possible and before
+        // closing database connection, don't do this before
+        // registered shutdown functions, they may need the session
+        // Note: this will run registered gc handlers (ie. cache gc)
+        if ($_SERVER['REMOTE_ADDR'] && is_object($this->session)) {
+            $this->session->write_close();
+        }
+
         if (is_object($this->smtp)) {
             $this->smtp->disconnect();
         }
@@ -871,9 +945,6 @@
         }
 
         if (is_object($this->storage)) {
-            if ($this->expunge_cache) {
-                $this->storage->expunge_cache();
-            }
             $this->storage->close();
         }
     }
@@ -1065,8 +1136,8 @@
      *      - 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
+     *      - file:    File where error occurred
+     *      - line:    Line where error occurred
      * @param boolean True to log the error
      * @param boolean Terminate script execution
      */
@@ -1337,6 +1408,10 @@
             'options' => $options,
         ));
 
+        if ($plugin['abort']) {
+            return isset($plugin['result']) ? $plugin['result'] : false;
+        }
+
         $from    = $plugin['from'];
         $mailto  = $plugin['mailto'];
         $options = $plugin['options'];
@@ -1433,7 +1508,7 @@
                     $subject    = str_replace("\r\n", $delim, $subject);
                 }
 
-                if (ini_get('safe_mode'))
+                if (filter_var(ini_get('safe_mode'), FILTER_VALIDATE_BOOLEAN))
                     $sent = mail($to, $subject, $msg_body, $header_str);
                 else
                     $sent = mail($to, $subject, $msg_body, $header_str, "-f$from");

--
Gitblit v1.9.1