summaryrefslogtreecommitdiff
path: root/program/lib/Roundcube
diff options
context:
space:
mode:
Diffstat (limited to 'program/lib/Roundcube')
-rw-r--r--program/lib/Roundcube/bootstrap.php12
-rw-r--r--program/lib/Roundcube/rcube.php9
-rw-r--r--program/lib/Roundcube/rcube_addressbook.php24
-rw-r--r--program/lib/Roundcube/rcube_config.php246
-rw-r--r--program/lib/Roundcube/rcube_contacts.php4
-rw-r--r--program/lib/Roundcube/rcube_csv2vcard.php2
-rw-r--r--program/lib/Roundcube/rcube_db.php36
-rw-r--r--program/lib/Roundcube/rcube_db_mysql.php25
-rw-r--r--program/lib/Roundcube/rcube_imap.php26
-rw-r--r--program/lib/Roundcube/rcube_imap_cache.php45
-rw-r--r--program/lib/Roundcube/rcube_imap_generic.php49
-rw-r--r--program/lib/Roundcube/rcube_ldap.php1
-rw-r--r--program/lib/Roundcube/rcube_mime.php18
-rw-r--r--program/lib/Roundcube/rcube_storage.php2
-rw-r--r--program/lib/Roundcube/rcube_utils.php38
-rw-r--r--program/lib/Roundcube/rcube_vcard.php9
16 files changed, 392 insertions, 154 deletions
diff --git a/program/lib/Roundcube/bootstrap.php b/program/lib/Roundcube/bootstrap.php
index 5d5a22387..6e5143382 100644
--- a/program/lib/Roundcube/bootstrap.php
+++ b/program/lib/Roundcube/bootstrap.php
@@ -26,25 +26,25 @@
*/
$config = array(
- 'error_reporting' => E_ALL &~ (E_NOTICE | E_STRICT),
+ 'error_reporting' => E_ALL & ~E_NOTICE & ~E_STRICT,
// Some users are not using Installer, so we'll check some
// critical PHP settings here. Only these, which doesn't provide
// an error/warning in the logs later. See (#1486307).
'mbstring.func_overload' => 0,
- 'magic_quotes_runtime' => 0,
- 'magic_quotes_sybase' => 0, // #1488506
+ 'magic_quotes_runtime' => false,
+ 'magic_quotes_sybase' => false, // #1488506
);
// check these additional ini settings if not called via CLI
if (php_sapi_name() != 'cli') {
$config += array(
- 'suhosin.session.encrypt' => 0,
- 'file_uploads' => 1,
+ 'suhosin.session.encrypt' => false,
+ 'file_uploads' => true,
);
}
foreach ($config as $optname => $optval) {
- $ini_optval = filter_var(ini_get($optname), FILTER_VALIDATE_BOOLEAN);
+ $ini_optval = filter_var(ini_get($optname), is_bool($optval) ? FILTER_VALIDATE_BOOLEAN : FILTER_VALIDATE_INT);
if ($optval != $ini_optval && @ini_set($optname, $optval) === false) {
$error = "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).";
diff --git a/program/lib/Roundcube/rcube.php b/program/lib/Roundcube/rcube.php
index af9c069cf..d9c3dd8b9 100644
--- a/program/lib/Roundcube/rcube.php
+++ b/program/lib/Roundcube/rcube.php
@@ -498,7 +498,14 @@ class rcube
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) {
diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php
index 4ed139c45..9301211ff 100644
--- a/program/lib/Roundcube/rcube_addressbook.php
+++ b/program/lib/Roundcube/rcube_addressbook.php
@@ -3,7 +3,7 @@
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2012, The Roundcube Dev Team |
+ | Copyright (C) 2006-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -35,6 +35,7 @@ abstract class rcube_addressbook
/** public properties (mandatory) */
public $primary_key;
public $groups = false;
+ public $export_groups = true;
public $readonly = true;
public $searchonly = false;
public $undelete = false;
@@ -423,7 +424,7 @@ abstract class rcube_addressbook
* @param boolean True to return one array with all values, False for hash array with values grouped by type
* @return array List of column values
*/
- function get_col_values($col, $data, $flat = false)
+ public static function get_col_values($col, $data, $flat = false)
{
$out = array();
foreach ((array)$data as $c => $values) {
@@ -476,7 +477,8 @@ abstract class rcube_addressbook
$fn = trim(join(' ', array_filter(array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix']))));
// use email address part for name
- $email = is_array($contact['email']) ? $contact['email'][0] : $contact['email'];
+ $email = self::get_col_values('email', $contact, true);
+ $email = $email[0];
if ($email && (empty($fn) || $fn == $email)) {
// return full email
@@ -523,9 +525,9 @@ abstract class rcube_addressbook
$fn = $contact['name'];
// fallback to email address
- $email = is_array($contact['email']) ? $contact['email'][0] : $contact['email'];
- if (empty($fn) && $email)
- return $email;
+ if (empty($fn) && ($email = self::get_col_values('email', $contact, true)) && !empty($email)) {
+ return $email[0];
+ }
return $fn;
}
@@ -538,8 +540,8 @@ abstract class rcube_addressbook
$key = $contact[$sort_col] . ':' . $contact['sourceid'];
// add email to a key to not skip contacts with the same name (#1488375)
- if (!empty($contact['email'])) {
- $key .= ':' . implode(':', (array)$contact['email']);
+ if (($email = self::get_col_values('email', $contact, true)) && !empty($email)) {
+ $key .= ':' . implode(':', (array)$email);
}
return $key;
@@ -561,9 +563,9 @@ abstract class rcube_addressbook
// use only strict comparison (mode = 1)
// @TODO: partial search, e.g. match only day and month
if (in_array($colname, $this->date_cols)) {
- return (($value = rcube_utils::strtotime($value))
- && ($search = rcube_utils::strtotime($search))
- && date('Ymd', $value) == date('Ymd', $search));
+ return (($value = rcube_utils::anytodatetime($value))
+ && ($search = rcube_utils::anytodatetime($search))
+ && $value->format('Ymd') == $search->format('Ymd'));
}
// composite field, e.g. address
diff --git a/program/lib/Roundcube/rcube_config.php b/program/lib/Roundcube/rcube_config.php
index 62567a0e0..a3741758f 100644
--- a/program/lib/Roundcube/rcube_config.php
+++ b/program/lib/Roundcube/rcube_config.php
@@ -3,7 +3,7 @@
/*
+-----------------------------------------------------------------------+
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
+ | Copyright (C) 2008-2013, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -27,7 +27,7 @@ class rcube_config
const DEFAULT_SKIN = 'larry';
private $env = '';
- private $basedir = 'config/';
+ private $paths = array();
private $prop = array();
private $errors = array();
private $userprefs = array();
@@ -58,7 +58,32 @@ class rcube_config
public function __construct($env = '')
{
$this->env = $env;
- $this->basedir = RCUBE_CONFIG_DIR;
+
+ if ($paths = getenv('RCUBE_CONFIG_PATH')) {
+ $this->paths = explode(PATH_SEPARATOR, $paths);
+ // make all paths absolute
+ foreach ($this->paths as $i => $path) {
+ if (!$this->_is_absolute($path)) {
+ if ($realpath = realpath(RCUBE_INSTALL_PATH . $path)) {
+ $this->paths[$i] = unslashify($realpath) . '/';
+ }
+ else {
+ unset($this->paths[$i]);
+ }
+ }
+ else {
+ $this->paths[$i] = unslashify($path) . '/';
+ }
+ }
+ }
+
+ if (defined('RCUBE_CONFIG_DIR') && !in_array(RCUBE_CONFIG_DIR, $this->paths)) {
+ $this->paths[] = RCUBE_CONFIG_DIR;
+ }
+
+ if (empty($this->paths)) {
+ $this->paths[] = RCUBE_INSTALL_PATH . 'config/';
+ }
$this->load();
@@ -138,17 +163,6 @@ class rcube_config
// enable display_errors in 'show' level, but not for ajax requests
ini_set('display_errors', intval(empty($_REQUEST['_remote']) && ($this->prop['debug_level'] & 4)));
- // set timezone auto settings values
- if ($this->prop['timezone'] == 'auto') {
- $this->prop['_timezone_value'] = $this->client_timezone();
- }
- else if (is_numeric($this->prop['timezone']) && ($tz = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0))) {
- $this->prop['timezone'] = $tz;
- }
- else if (empty($this->prop['timezone'])) {
- $this->prop['timezone'] = 'UTC';
- }
-
// remove deprecated properties
unset($this->prop['dst_active']);
@@ -186,47 +200,73 @@ class rcube_config
*/
public function load_from_file($file)
{
- $fpath = $this->resolve_path($file);
- if ($fpath && is_file($fpath) && is_readable($fpath)) {
- // use output buffering, we don't need any output here
- ob_start();
- include($fpath);
- ob_end_clean();
-
- if (is_array($config)) {
- $this->merge($config);
- return true;
- }
- // deprecated name of config variable
- else if (is_array($rcmail_config)) {
- $this->merge($rcmail_config);
- return true;
+ $success = false;
+
+ foreach ($this->resolve_paths($file) as $fpath) {
+ if ($fpath && is_file($fpath) && is_readable($fpath)) {
+ // use output buffering, we don't need any output here
+ ob_start();
+ include($fpath);
+ ob_end_clean();
+
+ if (is_array($config)) {
+ $this->merge($config);
+ $success = true;
+ }
+ // deprecated name of config variable
+ if (is_array($rcmail_config)) {
+ $this->merge($rcmail_config);
+ $success = true;
+ }
}
}
- return false;
+ return $success;
}
/**
- * Helper method to resolve the absolute path to the given config file.
+ * Helper method to resolve absolute paths to the given config file.
* This also takes the 'env' property into account.
+ *
+ * @param string Filename or absolute file path
+ * @param boolean Return -$env file path if exists
+ * @return array List of candidates in config dir path(s)
*/
- public function resolve_path($file, $use_env = true)
+ public function resolve_paths($file, $use_env = true)
{
- if (strpos($file, '/') === false) {
- $file = realpath($this->basedir . '/' . $file);
- }
+ $files = array();
+ $abs_path = $this->_is_absolute($file);
+
+ foreach ($this->paths as $basepath) {
+ $realpath = $abs_path ? $file : realpath($basepath . '/' . $file);
- // check if <file>-env.ini exists
- if ($file && $use_env && !empty($this->env)) {
- $envfile = preg_replace('/\.(inc.php)$/', '-' . $this->env . '.\\1', $file);
- if (is_file($envfile))
- return $envfile;
+ // check if <file>-env.ini exists
+ if ($realpath && $use_env && !empty($this->env)) {
+ $envfile = preg_replace('/\.(inc.php)$/', '-' . $this->env . '.\\1', $realpath);
+ if (is_file($envfile))
+ $realpath = $envfile;
+ }
+
+ if ($realpath) {
+ $files[] = $realpath;
+
+ // no need to continue the loop if an absolute file path is given
+ if ($abs_path) {
+ break;
+ }
+ }
}
- return $file;
+ return $files;
}
+ /**
+ * Determine whether the given file path is absolute or relative
+ */
+ private function _is_absolute($path)
+ {
+ return $path[0] == DIRECTORY_SEPARATOR || preg_match('!^[a-z]:[\\\\/]!i', $path);
+ }
/**
* Getter for a specific config parameter
@@ -246,8 +286,10 @@ class rcube_config
$rcube = rcube::get_instance();
- if ($name == 'timezone' && isset($this->prop['_timezone_value'])) {
- $result = $this->prop['_timezone_value'];
+ if ($name == 'timezone') {
+ if (empty($result) || $result == 'auto') {
+ $result = $this->client_timezone();
+ }
}
else if ($name == 'client_mimetypes') {
if ($result == null && $def == null)
@@ -282,8 +324,8 @@ class rcube_config
*/
public function merge($prefs)
{
+ $prefs = $this->fix_legacy_props($prefs);
$this->prop = array_merge($this->prop, $prefs, $this->userprefs);
- $this->fix_legacy_props();
}
@@ -295,6 +337,8 @@ class rcube_config
*/
public function set_user_prefs($prefs)
{
+ $prefs = $this->fix_legacy_props($prefs);
+
// Honor the dont_override setting for any existing user preferences
$dont_override = $this->get('dont_override');
if (is_array($dont_override) && !empty($dont_override)) {
@@ -303,11 +347,6 @@ class rcube_config
}
}
- // convert user's timezone into the new format
- if (is_numeric($prefs['timezone']) && ($tz = timezone_name_from_abbr('', $prefs['timezone'] * 3600, 0))) {
- $prefs['timezone'] = $tz;
- }
-
// larry is the new default skin :-)
if ($prefs['skin'] == 'default') {
$prefs['skin'] = self::DEFAULT_SKIN;
@@ -315,22 +354,13 @@ class rcube_config
$this->userprefs = $prefs;
$this->prop = array_merge($this->prop, $prefs);
-
- $this->fix_legacy_props();
-
- // override timezone settings with client values
- if ($this->prop['timezone'] == 'auto') {
- $this->prop['_timezone_value'] = isset($_SESSION['timezone']) ? $this->client_timezone() : $this->prop['_timezone_value'];
- }
- else if (isset($this->prop['_timezone_value']))
- unset($this->prop['_timezone_value']);
}
/**
* Getter for all config options
*
- * @return array Hash array containg all config properties
+ * @return array Hash array containing all config properties
*/
public function all()
{
@@ -464,13 +494,12 @@ class rcube_config
*/
private function client_timezone()
{
- if (isset($_SESSION['timezone']) && is_numeric($_SESSION['timezone'])
- && ($ctz = timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0))) {
- return $ctz;
- }
- else if (!empty($_SESSION['timezone'])) {
+ // @TODO: remove this legacy timezone handling in the future
+ $props = $this->fix_legacy_props(array('timezone' => $_SESSION['timezone']));
+
+ if (!empty($props['timezone'])) {
try {
- $tz = timezone_open($_SESSION['timezone']);
+ $tz = new DateTimeZone($props['timezone']);
return $tz->getName();
}
catch (Exception $e) { /* gracefully ignore */ }
@@ -482,16 +511,93 @@ class rcube_config
/**
* Convert legacy options into new ones
+ *
+ * @param array $props Hash array with config props
+ *
+ * @return array Converted config props
*/
- private function fix_legacy_props()
+ private function fix_legacy_props($props)
{
foreach ($this->legacy_props as $new => $old) {
- if (isset($this->prop[$old])) {
- if (!isset($this->prop[$new])) {
- $this->prop[$new] = $this->prop[$old];
+ if (isset($props[$old])) {
+ if (!isset($props[$new])) {
+ $props[$new] = $props[$old];
}
- unset($this->prop[$old]);
+ unset($props[$old]);
}
}
+
+ // convert deprecated numeric timezone value
+ if (isset($props['timezone']) && is_numeric($props['timezone'])) {
+ if ($tz = self::timezone_name_from_abbr($props['timezone'])) {
+ $props['timezone'] = $tz;
+ }
+ else {
+ unset($props['timezone']);
+ }
+ }
+
+ return $props;
+ }
+
+ /**
+ * timezone_name_from_abbr() replacement. Converts timezone offset
+ * into timezone name abbreviation.
+ *
+ * @param float $offset Timezone offset (in hours)
+ *
+ * @return string Timezone abbreviation
+ */
+ static public function timezone_name_from_abbr($offset)
+ {
+ // List of timezones here is not complete - https://bugs.php.net/bug.php?id=44780
+ if ($tz = timezone_name_from_abbr('', $offset * 3600, 0)) {
+ return $tz;
+ }
+
+ // try with more complete list (#1489261)
+ $timezones = array(
+ '-660' => "Pacific/Apia",
+ '-600' => "Pacific/Honolulu",
+ '-570' => "Pacific/Marquesas",
+ '-540' => "America/Anchorage",
+ '-480' => "America/Los_Angeles",
+ '-420' => "America/Denver",
+ '-360' => "America/Chicago",
+ '-300' => "America/New_York",
+ '-270' => "America/Caracas",
+ '-240' => "America/Halifax",
+ '-210' => "Canada/Newfoundland",
+ '-180' => "America/Sao_Paulo",
+ '-60' => "Atlantic/Azores",
+ '0' => "Europe/London",
+ '60' => "Europe/Paris",
+ '120' => "Europe/Helsinki",
+ '180' => "Europe/Moscow",
+ '210' => "Asia/Tehran",
+ '240' => "Asia/Dubai",
+ '300' => "Asia/Karachi",
+ '270' => "Asia/Kabul",
+ '300' => "Asia/Karachi",
+ '330' => "Asia/Kolkata",
+ '345' => "Asia/Katmandu",
+ '360' => "Asia/Yekaterinburg",
+ '390' => "Asia/Rangoon",
+ '420' => "Asia/Krasnoyarsk",
+ '480' => "Asia/Shanghai",
+ '525' => "Australia/Eucla",
+ '540' => "Asia/Tokyo",
+ '570' => "Australia/Adelaide",
+ '600' => "Australia/Melbourne",
+ '630' => "Australia/Lord_Howe",
+ '660' => "Asia/Vladivostok",
+ '690' => "Pacific/Norfolk",
+ '720' => "Pacific/Auckland",
+ '765' => "Pacific/Chatham",
+ '780' => "Pacific/Enderbury",
+ '840' => "Pacific/Kiritimati",
+ );
+
+ return $timezones[(string) intval($offset * 60)];
}
}
diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php
index 3919cdc6e..6d01368a1 100644
--- a/program/lib/Roundcube/rcube_contacts.php
+++ b/program/lib/Roundcube/rcube_contacts.php
@@ -718,6 +718,10 @@ class rcube_contacts extends rcube_addressbook
foreach ($save_data as $key => $values) {
list($field, $section) = explode(':', $key);
$fulltext = in_array($field, $this->fulltext_cols);
+ // avoid casting DateTime objects to array
+ if (is_object($values) && is_a($values, 'DateTime')) {
+ $values = array(0 => $values);
+ }
foreach ((array)$values as $value) {
if (isset($value))
$vcard->set($field, $value, $section);
diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php
index fb8d8f103..00e6d4e20 100644
--- a/program/lib/Roundcube/rcube_csv2vcard.php
+++ b/program/lib/Roundcube/rcube_csv2vcard.php
@@ -145,6 +145,7 @@ class rcube_csv2vcard
'work_mobile' => 'phone:work,cell',
'work_title' => 'jobtitle',
'work_zip' => 'zipcode:work',
+ 'group' => 'groups',
);
/**
@@ -268,6 +269,7 @@ class rcube_csv2vcard
'work_mobile' => "Work Mobile",
'work_title' => "Work Title",
'work_zip' => "Work Zip",
+ 'groups' => "Group",
);
protected $local_label_map = array();
diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php
index 852070073..e66226ff5 100644
--- a/program/lib/Roundcube/rcube_db.php
+++ b/program/lib/Roundcube/rcube_db.php
@@ -386,17 +386,7 @@ class rcube_db
$result = $this->dbh->query($query);
if ($result === false) {
- $error = $this->dbh->errorInfo();
-
- if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') {
- $this->db_error = true;
- $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
-
- rcube::raise_error(array('code' => 500, 'type' => 'db',
- 'line' => __LINE__, 'file' => __FILE__,
- 'message' => $this->db_error_msg . " (SQL Query: $query)"
- ), true, false);
- }
+ $result = $this->handle_error($query);
}
$this->last_result = $result;
@@ -405,6 +395,30 @@ class rcube_db
}
/**
+ * Helper method to handle DB errors.
+ * This by default logs the error but could be overriden by a driver implementation
+ *
+ * @param string Query that triggered the error
+ * @return mixed Result to be stored and returned
+ */
+ protected function handle_error($query)
+ {
+ $error = $this->dbh->errorInfo();
+
+ if (empty($this->options['ignore_key_errors']) || $error[0] != '23000') {
+ $this->db_error = true;
+ $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]);
+
+ rcube::raise_error(array('code' => 500, 'type' => 'db',
+ 'line' => __LINE__, 'file' => __FILE__,
+ 'message' => $this->db_error_msg . " (SQL Query: $query)"
+ ), true, false);
+ }
+
+ return false;
+ }
+
+ /**
* Get number of affected rows for the last query
*
* @param mixed $result Optional query handle
diff --git a/program/lib/Roundcube/rcube_db_mysql.php b/program/lib/Roundcube/rcube_db_mysql.php
index 6fa5ad768..24f9ce1bd 100644
--- a/program/lib/Roundcube/rcube_db_mysql.php
+++ b/program/lib/Roundcube/rcube_db_mysql.php
@@ -179,4 +179,29 @@ class rcube_db_mysql extends rcube_db
return isset($this->variables[$varname]) ? $this->variables[$varname] : $default;
}
+ /**
+ * Handle DB errors, re-issue the query on deadlock errors from InnoDB row-level locking
+ *
+ * @param string Query that triggered the error
+ * @return mixed Result to be stored and returned
+ */
+ protected function handle_error($query)
+ {
+ $error = $this->dbh->errorInfo();
+
+ // retry after "Deadlock found when trying to get lock" errors
+ $retries = 2;
+ while ($error[1] == 1213 && $retries >= 0) {
+ usleep(50000); // wait 50 ms
+ $result = $this->dbh->query($query);
+ if ($result !== false) {
+ return $result;
+ }
+ $error = $this->dbh->errorInfo();
+ $retries--;
+ }
+
+ return parent::handle_error($query);
+ }
+
}
diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php
index c5346c8aa..aa074233f 100644
--- a/program/lib/Roundcube/rcube_imap.php
+++ b/program/lib/Roundcube/rcube_imap.php
@@ -70,7 +70,7 @@ class rcube_imap extends rcube_storage
protected $search_sort_field = '';
protected $search_threads = false;
protected $search_sorted = false;
- protected $options = array('auth_method' => 'check');
+ protected $options = array('auth_type' => 'check');
protected $caching = false;
protected $messages_caching = false;
protected $threading = false;
@@ -391,10 +391,10 @@ class rcube_imap extends rcube_storage
public function check_permflag($flag)
{
$flag = strtoupper($flag);
- $imap_flag = $this->conn->flags[$flag];
$perm_flags = $this->get_permflags($this->folder);
+ $imap_flag = $this->conn->flags[$flag];
- return in_array_nocase($imap_flag, $perm_flags);
+ return $imap_flag && !empty($perm_flags) && in_array_nocase($imap_flag, $perm_flags);
}
@@ -410,17 +410,7 @@ class rcube_imap extends rcube_storage
if (!strlen($folder)) {
return array();
}
-/*
- Checking PERMANENTFLAGS is rather rare, so we disable caching of it
- Re-think when we'll use it for more than only MDNSENT flag
- $cache_key = 'mailboxes.permanentflags.' . $folder;
- $permflags = $this->get_cache($cache_key);
-
- if ($permflags !== null) {
- return explode(' ', $permflags);
- }
-*/
if (!$this->check_connection()) {
return array();
}
@@ -435,10 +425,7 @@ class rcube_imap extends rcube_storage
if (!is_array($permflags)) {
$permflags = array();
}
-/*
- // Store permflags as string to limit cached object size
- $this->update_cache($cache_key, implode(' ', $permflags));
-*/
+
return $permflags;
}
@@ -3798,9 +3785,10 @@ class rcube_imap extends rcube_storage
if ($this->messages_caching && !$this->mcache) {
$rcube = rcube::get_instance();
if (($dbh = $rcube->get_dbh()) && ($userid = $rcube->get_user_id())) {
- $ttl = $rcube->config->get('messages_cache_ttl', '10d');
+ $ttl = $rcube->config->get('messages_cache_ttl', '10d');
+ $threshold = $rcube->config->get('messages_cache_threshold', 50);
$this->mcache = new rcube_imap_cache(
- $dbh, $this, $userid, $this->options['skip_deleted'], $ttl);
+ $dbh, $this, $userid, $this->options['skip_deleted'], $ttl, $threshold);
}
}
diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php
index 061ac546d..d72bfe0ab 100644
--- a/program/lib/Roundcube/rcube_imap_cache.php
+++ b/program/lib/Roundcube/rcube_imap_cache.php
@@ -56,6 +56,13 @@ class rcube_imap_cache
private $ttl;
/**
+ * Maximum cached message size
+ *
+ * @var int
+ */
+ private $threshold;
+
+ /**
* Internal (in-memory) cache
*
* @var array
@@ -96,9 +103,9 @@ class rcube_imap_cache
* @param int $userid User identifier
* @param bool $skip_deleted skip_deleted flag
* @param string $ttl Expiration time of memcache/apc items
- *
+ * @param int $threshold Maximum cached message size
*/
- function __construct($db, $imap, $userid, $skip_deleted, $ttl=0)
+ function __construct($db, $imap, $userid, $skip_deleted, $ttl=0, $threshold=0)
{
// convert ttl string to seconds
$ttl = get_offset_sec($ttl);
@@ -109,6 +116,7 @@ class rcube_imap_cache
$this->userid = $userid;
$this->skip_deleted = $skip_deleted;
$this->ttl = $ttl;
+ $this->threshold = $threshold;
}
@@ -1155,13 +1163,13 @@ class rcube_imap_cache
// Save current message from internal cache
if ($message = $this->icache['__message']) {
// clean up some object's data
- $object = $this->message_object_prepare($message['object']);
+ $this->message_object_prepare($message['object']);
// calculate current md5 sum
- $md5sum = md5(serialize($object));
+ $md5sum = md5(serialize($message['object']));
if ($message['md5sum'] != $md5sum) {
- $this->add_message($message['mailbox'], $object, !$message['exists']);
+ $this->add_message($message['mailbox'], $message['object'], !$message['exists']);
}
$this->icache['__message']['md5sum'] = $md5sum;
@@ -1171,12 +1179,19 @@ class rcube_imap_cache
/**
* Prepares message object to be stored in database.
+ *
+ * @param rcube_message_header|rcube_message_part
*/
- private function message_object_prepare($msg)
+ private function message_object_prepare(&$msg, &$size = 0)
{
- // Remove body too big (>25kB)
- if ($msg->body && strlen($msg->body) > 25 * 1024) {
- unset($msg->body);
+ // Remove body too big
+ if ($msg->body && ($length = strlen($msg->body))) {
+ $size += $length;
+
+ if ($size > $this->threshold * 1024) {
+ $size -= $length;
+ unset($msg->body);
+ }
}
// Fix mimetype which might be broken by some code when message is displayed
@@ -1186,13 +1201,19 @@ class rcube_imap_cache
list($msg->ctype_primary, $msg->ctype_secondary) = explode('/', $msg->mimetype);
}
+ unset($msg->replaces);
+
if (is_array($msg->structure->parts)) {
- foreach ($msg->structure->parts as $idx => $part) {
- $msg->structure->parts[$idx] = $this->message_object_prepare($part);
+ foreach ($msg->structure->parts as $part) {
+ $this->message_object_prepare($part, $size);
}
}
- return $msg;
+ if (is_array($msg->parts)) {
+ foreach ($msg->parts as $part) {
+ $this->message_object_prepare($part, $size);
+ }
+ }
}
diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php
index e1193749b..bce4cd4e2 100644
--- a/program/lib/Roundcube/rcube_imap_generic.php
+++ b/program/lib/Roundcube/rcube_imap_generic.php
@@ -704,22 +704,11 @@ class rcube_imap_generic
*/
function connect($host, $user, $password, $options=null)
{
- // set options
- if (is_array($options)) {
- $this->prefs = $options;
- }
- // set auth method
- if (!empty($this->prefs['auth_type'])) {
- $auth_method = strtoupper($this->prefs['auth_type']);
- } else {
- $auth_method = 'CHECK';
- }
+ // configure
+ $this->set_prefs($options);
- if (!empty($this->prefs['disabled_caps'])) {
- $this->prefs['disabled_caps'] = array_map('strtoupper', (array)$this->prefs['disabled_caps']);
- }
-
- $result = false;
+ $auth_method = $this->prefs['auth_type'];
+ $result = false;
// initialize connection
$this->error = '';
@@ -896,6 +885,36 @@ class rcube_imap_generic
}
/**
+ * Initializes environment
+ */
+ protected function set_prefs($prefs)
+ {
+ // set preferences
+ if (is_array($prefs)) {
+ $this->prefs = $prefs;
+ }
+
+ // set auth method
+ if (!empty($this->prefs['auth_type'])) {
+ $this->prefs['auth_type'] = strtoupper($this->prefs['auth_type']);
+ }
+ else {
+ $this->prefs['auth_type'] = 'CHECK';
+ }
+
+ // disabled capabilities
+ if (!empty($this->prefs['disabled_caps'])) {
+ $this->prefs['disabled_caps'] = array_map('strtoupper', (array)$this->prefs['disabled_caps']);
+ }
+
+ // additional message flags
+ if (!empty($this->prefs['message_flags'])) {
+ $this->flags = array_merge($this->flags, $this->prefs['message_flags']);
+ unset($this->prefs['message_flags']);
+ }
+ }
+
+ /**
* Checks connection status
*
* @return bool True if connection is active and user is logged in, False otherwise.
diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php
index cb7fa8466..78573789b 100644
--- a/program/lib/Roundcube/rcube_ldap.php
+++ b/program/lib/Roundcube/rcube_ldap.php
@@ -34,6 +34,7 @@ class rcube_ldap extends rcube_addressbook
public $ready = false;
public $group_id = 0;
public $coltypes = array();
+ public $export_groups = false;
// private properties
protected $ldap;
diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php
index 572540f47..96a8eac61 100644
--- a/program/lib/Roundcube/rcube_mime.php
+++ b/program/lib/Roundcube/rcube_mime.php
@@ -708,12 +708,20 @@ class rcube_mime
*/
public static function file_content_type($path, $name, $failover = 'application/octet-stream', $is_stream = false, $skip_suffix = false)
{
+ static $mime_ext = array();
+
$mime_type = null;
- $mime_magic = rcube::get_instance()->config->get('mime_magic');
- $mime_ext = $skip_suffix ? null : @include(RCUBE_CONFIG_DIR . '/mimetypes.php');
+ $config = rcube::get_instance()->config;
+ $mime_magic = $config->get('mime_magic');
+
+ if (!$skip_suffix && empty($mime_ext)) {
+ foreach ($config->resolve_paths('mimetypes.php') as $fpath) {
+ $mime_ext = array_merge($mime_ext, (array) @include($fpath));
+ }
+ }
// use file name suffix with hard-coded mime-type map
- if (is_array($mime_ext) && $name) {
+ if (!$skip_suffix && is_array($mime_ext) && $name) {
if ($suffix = substr($name, strrpos($name, '.')+1)) {
$mime_type = $mime_ext[strtolower($suffix)];
}
@@ -818,7 +826,9 @@ class rcube_mime
// fallback to some well-known types most important for daily emails
if (empty($mime_types)) {
- $mime_extensions = (array) @include(RCUBE_CONFIG_DIR . '/mimetypes.php');
+ foreach (rcube::get_instance()->config->resolve_paths('mimetypes.php') as $fpath) {
+ $mime_extensions = array_merge($mime_extensions, (array) @include($fpath));
+ }
foreach ($mime_extensions as $ext => $mime) {
$mime_types[$mime][] = $ext;
diff --git a/program/lib/Roundcube/rcube_storage.php b/program/lib/Roundcube/rcube_storage.php
index de8334551..e697b2c73 100644
--- a/program/lib/Roundcube/rcube_storage.php
+++ b/program/lib/Roundcube/rcube_storage.php
@@ -39,7 +39,7 @@ abstract class rcube_storage
protected $default_charset = 'ISO-8859-1';
protected $default_folders = array('INBOX');
protected $search_set;
- protected $options = array('auth_method' => 'check');
+ protected $options = array('auth_type' => 'check');
protected $page_size = 10;
protected $threading = false;
diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php
index 2540f779d..1d76ae508 100644
--- a/program/lib/Roundcube/rcube_utils.php
+++ b/program/lib/Roundcube/rcube_utils.php
@@ -787,6 +787,44 @@ class rcube_utils
return (int) $ts;
}
+ /**
+ * Date parsing function that turns the given value into a DateTime object
+ *
+ * @param string $date Date string
+ *
+ * @return object DateTime instance or false on failure
+ */
+ public static function anytodatetime($date)
+ {
+ if (is_object($date) && is_a($date, 'DateTime')) {
+ return $date;
+ }
+
+ $dt = false;
+ $date = trim($date);
+
+ // try to parse string with DateTime first
+ if (!empty($date)) {
+ try {
+ $dt = new DateTime($date);
+ }
+ catch (Exception $e) {
+ // ignore
+ }
+ }
+
+ // try our advanced strtotime() method
+ if (!$dt && ($timestamp = self::strtotime($date))) {
+ try {
+ $dt = new DateTime("@".$timestamp);
+ }
+ catch (Exception $e) {
+ // ignore
+ }
+ }
+
+ return $dt;
+ }
/*
* Idn_to_ascii wrapper.
diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php
index a71305c4b..d54dc56ad 100644
--- a/program/lib/Roundcube/rcube_vcard.php
+++ b/program/lib/Roundcube/rcube_vcard.php
@@ -47,6 +47,7 @@ class rcube_vcard
'manager' => 'X-MANAGER',
'spouse' => 'X-SPOUSE',
'edit' => 'X-AB-EDIT',
+ 'groups' => 'CATEGORIES',
);
private $typemap = array(
'IPHONE' => 'mobile',
@@ -357,8 +358,8 @@ class rcube_vcard
case 'birthday':
case 'anniversary':
- if (($val = rcube_utils::strtotime($value)) && ($fn = self::$fieldmap[$field])) {
- $this->raw[$fn][] = array(0 => date('Y-m-d', $val), 'value' => array('date'));
+ if (($val = rcube_utils::anytodatetime($value)) && ($fn = self::$fieldmap[$field])) {
+ $this->raw[$fn][] = array(0 => $val->format('Y-m-d'), 'value' => array('date'));
}
break;
@@ -756,7 +757,7 @@ class rcube_vcard
*
* @return string Joined and quoted string
*/
- private static function vcard_quote($s, $sep = ';')
+ public static function vcard_quote($s, $sep = ';')
{
if (is_array($s)) {
foreach($s as $part) {
@@ -765,7 +766,7 @@ class rcube_vcard
return(implode($sep, (array)$r));
}
- return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', ',' => '\,', ';' => '\;'));
+ return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', $sep => '\\'.$sep));
}
/**