Projects
Kolab:3.4
kolab-syncroton
Log In
Username
Password
We truncated the diff of some files because they were too big. If you want to see the full diff for every file,
click here
.
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 17
View file
kolab-syncroton.spec
Changed
@@ -13,7 +13,7 @@ %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} Name: kolab-syncroton -Version: 2.2.1 +Version: 2.2.2 Release: 1%{?dist} Summary: ActiveSync for Kolab Groupware @@ -150,6 +150,9 @@ %attr(0770,%{httpd_user},%{httpd_group}) %{_var}/log/%{name} %changelog +* Fri Oct 18 2013 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 2.2.2-1 +- New upstream version in sync with cache refactoring + * Mon Oct 14 2013 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 2.2.1-1 - New upstream version 2.2.1
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +kolab-syncroton (2.2.2-0~kolab1) unstable; urgency=low + + * Check in version 2.2.2 + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Fri, 18 Oct 2013 15:13:40 +0200 + kolab-syncroton (2.2.1-0~kolab1) unstable; urgency=low * Check in version 2.2.1
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/bootstrap.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/bootstrap.php
Changed
@@ -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)."; @@ -58,7 +58,7 @@ define('RCUBE_CHARSET', 'UTF-8'); if (!defined('RCUBE_LIB_DIR')) { - define('RCUBE_LIB_DIR', dirname(__FILE__).'/'); + define('RCUBE_LIB_DIR', dirname(__FILE__).DIRECTORY_SEPARATOR); } if (!defined('RCUBE_INSTALL_PATH')) { @@ -83,6 +83,16 @@ @mb_regex_encoding(RCUBE_CHARSET); } +// make sure the Roundcube lib directory is in the include_path +$rcube_path = realpath(RCUBE_LIB_DIR . '..'); +$sep = PATH_SEPARATOR; +$regexp = "!(^|$sep)" . preg_quote($rcube_path, '!') . "($sep|\$)!"; +$path = ini_get('include_path'); + +if (!preg_match($regexp, $path)) { + set_include_path($path . PATH_SEPARATOR . $rcube_path); +} + // Register autoloader spl_autoload_register('rcube_autoload');
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/html.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/html.php
Changed
@@ -604,16 +604,17 @@ * * @param mixed $names Option name or array with option names * @param mixed $values Option value or array with option values + * @param array $attrib Additional attributes for the option entry */ - public function add($names, $values = null) + public function add($names, $values = null, $attrib = array()) { if (is_array($names)) { foreach ($names as $i => $text) { - $this->options[] = array('text' => $text, 'value' => $values[$i]); + $this->options[] = array('text' => $text, 'value' => $values[$i]) + $attrib; } } else { - $this->options[] = array('text' => $names, 'value' => $values); + $this->options[] = array('text' => $names, 'value' => $values) + $attrib; } } @@ -644,7 +645,7 @@ $option_content = self::quote($option_content); } - $this->content .= self::tag('option', $attr, $option_content); + $this->content .= self::tag('option', $attr + $option, $option_content, array('value','label','class','style','title','disabled','selected')); } return parent::show();
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube.php
Changed
@@ -467,6 +467,10 @@ $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']) { $this->session->start(); @@ -494,7 +498,14 @@ 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) { @@ -691,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)) { @@ -1121,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 */ @@ -1393,6 +1408,10 @@ 'options' => $options, )); + if ($plugin['abort']) { + return isset($plugin['result']) ? $plugin['result'] : false; + } + $from = $plugin['from']; $mailto = $plugin['mailto']; $options = $plugin['options'];
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_addressbook.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_addressbook.php
Changed
@@ -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 @@ /** public properties (mandatory) */ public $primary_key; public $groups = false; + public $export_groups = true; public $readonly = true; public $searchonly = false; public $undelete = false; @@ -133,7 +134,7 @@ abstract function get_record($id, $assoc=false); /** - * Returns the last error occured (e.g. when updating/inserting failed) + * Returns the last error occurred (e.g. when updating/inserting failed) * * @return array Hash array with the following fields: type, message */ @@ -423,7 +424,7 @@ * @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 @@ $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 @@ $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 @@ $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 @@ // 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
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_base_replacer.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_base_replacer.php
Changed
@@ -90,8 +90,8 @@ if (preg_match_all('/\.\.\//', $path, $matches, PREG_SET_ORDER)) { foreach ($matches as $a_match) { - if (strrpos($base_url, '/')) { - $base_url = substr($base_url, 0, strrpos($base_url, '/')); + if ($pos = strrpos($base_url, '/')) { + $base_url = substr($base_url, 0, $pos); } $path = substr($path, 3); }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_config.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_config.php
Changed
@@ -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 @@ 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 @@ 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(); @@ -94,8 +119,7 @@ } // load host-specific configuration - if (!empty($_SERVER['HTTP_HOST'])) - $this->load_host_config(); + $this->load_host_config(); // set skin (with fallback to old 'skin_path' property) if (empty($this->prop['skin'])) { @@ -138,17 +162,6 @@ // 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']); @@ -162,21 +175,31 @@ */ private function load_host_config() { - $fname = null; - - if (is_array($this->prop['include_host_config'])) { - $fname = $this->prop['include_host_config'][$_SERVER['HTTP_HOST']]; - } - else if (!empty($this->prop['include_host_config'])) { - $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $_SERVER['HTTP_HOST']) . '.inc.php'; + if (empty($this->prop['include_host_config'])) { + return; } - if ($fname) { - $this->load_from_file($fname); + foreach (array('HTTP_HOST', 'SERVER_NAME', 'SERVER_ADDR') as $key) { + $fname = null; + $name = $_SERVER[$key]; + + if (!$name) { + continue; + } + + if (is_array($this->prop['include_host_config'])) { + $fname = $this->prop['include_host_config'][$name]; + } + else { + $fname = preg_replace('/[^a-z0-9\.\-_]/i', '', $name) . '.inc.php'; + } + + if ($fname && $this->load_from_file($fname)) { + return; + } } } - /** * Read configuration from a file * and merge with the already stored config values @@ -186,51 +209,73 @@ */ public function load_from_file($file) { - $fpath = $this->resolve_path($file); - if ($fpath && (is_file($fpath) || file_exists($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 = rtrim($this->basedir, '/') . '/' . $file; + $files = array(); + $abs_path = $this->_is_absolute($file); - if (!realpath($file) === false) { - $file = realpath($file); + foreach ($this->paths as $basepath) { + $realpath = $abs_path ? $file : realpath($basepath . '/' . $file); + + // 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; } - } - // 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))
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_contacts.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_contacts.php
Changed
@@ -718,6 +718,10 @@ 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);
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_csv2vcard.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_csv2vcard.php
Changed
@@ -145,6 +145,7 @@ 'work_mobile' => 'phone:work,cell', 'work_title' => 'jobtitle', 'work_zip' => 'zipcode:work', + 'group' => 'groups', ); /** @@ -268,6 +269,7 @@ 'work_mobile' => "Work Mobile", 'work_title' => "Work Title", 'work_zip' => "Work Zip", + 'groups' => "Group", ); protected $local_label_map = array();
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_db.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_db.php
Changed
@@ -31,7 +31,10 @@ protected $db_dsnr; // DSN for read operations protected $db_connected = false; // Already connected ? protected $db_mode; // Connection mode + protected $db_table_dsn_map = array(); protected $dbh; // Connection handle + protected $dbhs = array(); + protected $table_connections = array(); protected $db_error = false; protected $db_error_msg = ''; @@ -97,9 +100,12 @@ $this->db_dsnw = $db_dsnw; $this->db_dsnr = $db_dsnr; $this->db_pconn = $pconn; + $this->db_dsnw_noread = rcube::get_instance()->config->get('db_dsnw_noread', false); $this->db_dsnw_array = self::parse_dsn($db_dsnw); $this->db_dsnr_array = self::parse_dsn($db_dsnr); + + $this->db_table_dsn_map = array_map(array($this, 'table_name'), rcube::get_instance()->config->get('db_table_dsn', array())); } /** @@ -113,6 +119,13 @@ $this->db_error = false; $this->db_error_msg = null; + // return existing handle + if ($this->dbhs[$mode]) { + $this->dbh = $this->dbhs[$mode]; + $this->db_mode = $mode; + return $this->dbh; + } + // Get database specific connection options $dsn_string = $this->dsn_string($dsn); $dsn_options = $this->dsn_options($dsn); @@ -147,6 +160,7 @@ } $this->dbh = $dbh; + $this->dbhs[$mode] = $dbh; $this->db_mode = $mode; $this->db_connected = true; $this->conn_configure($dsn, $dbh); @@ -175,8 +189,9 @@ * Connect to appropriate database depending on the operation * * @param string $mode Connection mode (r|w) + * @param boolean $force Enforce using the given mode */ - public function db_connect($mode) + public function db_connect($mode, $force = false) { // previous connection failed, don't attempt to connect again if ($this->conn_failure) { @@ -190,14 +205,13 @@ // Already connected if ($this->db_connected) { - // connected to db with the same or "higher" mode - if ($this->db_mode == 'w' || $this->db_mode == $mode) { + // connected to db with the same or "higher" mode (if allowed) + if ($this->db_mode == $mode || $this->db_mode == 'w' && !$force && !$this->db_dsnw_noread) { return; } } $dsn = ($mode == 'r') ? $this->db_dsnr_array : $this->db_dsnw_array; - $this->dsn_connect($dsn, $mode); // use write-master when read-only fails @@ -209,6 +223,46 @@ } /** + * Analyze the given SQL statement and select the appropriate connection to use + */ + protected function dsn_select($query) + { + // no replication + if ($this->db_dsnw == $this->db_dsnr) { + return 'w'; + } + + // Read or write ? + $mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w'; + + // find tables involved in this query + if (preg_match_all('/(?:^|\s)(from|update|into|join)\s+'.$this->options['identifier_start'].'?([a-z0-9._]+)'.$this->options['identifier_end'].'?\s+/i', $query, $matches, PREG_SET_ORDER)) { + foreach ($matches as $m) { + $table = $m[2]; + + // always use direct mapping + if ($this->db_table_dsn_map[$table]) { + $mode = $this->db_table_dsn_map[$table]; + break; // primary table rules + } + else if ($mode == 'r') { + // connected to db with the same or "higher" mode for this table + $db_mode = $this->table_connections[$table]; + if ($db_mode == 'w' && !$this->db_dsnw_noread) { + $mode = $db_mode; + } + } + } + + // remember mode chosen (for primary table) + $table = $matches[0][2]; + $this->table_connections[$table] = $mode; + } + + return $mode; + } + + /** * Activate/deactivate debug mode * * @param boolean $dbg True if SQL queries should be logged @@ -340,10 +394,7 @@ { $query = trim($query); - // Read or write ? - $mode = preg_match('/^(select|show|set)/i', $query) ? 'r' : 'w'; - - $this->db_connect($mode); + $this->db_connect($this->dsn_select($query), true); // check connection before proceeding if (!$this->is_connected()) { @@ -386,17 +437,7 @@ $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 +446,30 @@ } /** + * 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']) || !in_array($error[0], array('23000', '23505'))) { + $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 @@ -854,10 +919,14 @@ */ public function table_name($table) { - $rcube = rcube::get_instance(); + static $rcube; + + if (!$rcube) { + $rcube = rcube::get_instance(); + } // add prefix to the table name if configured - if ($prefix = $rcube->config->get('db_prefix')) { + if (($prefix = $rcube->config->get('db_prefix')) && strpos($table, $prefix) !== 0) { return $prefix . $table; }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_db_mssql.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_db_mssql.php
Changed
@@ -52,7 +52,7 @@ protected function conn_configure($dsn, $dbh) { // Set date format in case of non-default language (#1488918) - $this->query("SET DATEFORMAT ymd"); + $dbh->query("SET DATEFORMAT ymd"); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_db_mysql.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_db_mysql.php
Changed
@@ -60,7 +60,7 @@ */ protected function conn_configure($dsn, $dbh) { - $this->query("SET NAMES 'utf8'"); + $dbh->query("SET NAMES 'utf8'"); } /** @@ -179,4 +179,29 @@ 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); + } + }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_db_pgsql.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_db_pgsql.php
Changed
@@ -36,7 +36,7 @@ */ protected function conn_configure($dsn, $dbh) { - $this->query("SET NAMES 'utf8'"); + $dbh->query("SET NAMES 'utf8'"); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_db_sqlsrv.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_db_sqlsrv.php
Changed
@@ -52,7 +52,7 @@ protected function conn_configure($dsn, $dbh) { // Set date format in case of non-default language (#1488918) - $this->query("SET DATEFORMAT ymd"); + $dbh->query("SET DATEFORMAT ymd"); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_html2text.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_html2text.php
Changed
@@ -611,11 +611,13 @@ $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_ballback'), trim($body)); $body = '<pre>' . htmlspecialchars($body) . '</pre>'; - $text = substr($text, 0, $start) . $body . "\n" . substr($text, $end + 13); + $text = substr_replace($text, $body . "\n", $start, $end + 13 - $start); $offset = 0; + break; } - } while ($end || $next); + } + while ($end || $next); } } @@ -624,8 +626,9 @@ */ public function blockquote_citation_ballback($m) { - $line = ltrim($m[2]); + $line = ltrim($m[2]); $space = $line[0] == '>' ? '' : ' '; + return $m[1] . '>' . $space . $line; }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_imap.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_imap.php
Changed
@@ -70,7 +70,7 @@ 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 @@ 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 @@ 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 @@ if (!is_array($permflags)) { $permflags = array(); } -/* - // Store permflags as string to limit cached object size - $this->update_cache($cache_key, implode(' ', $permflags)); -*/ + return $permflags; } @@ -3773,12 +3760,17 @@ /** * Enable or disable messages caching * - * @param boolean $set Flag + * @param boolean $set Flag + * @param int $mode Cache mode */ - public function set_messages_caching($set) + public function set_messages_caching($set, $mode = null) { if ($set) { $this->messages_caching = true; + + if ($mode && ($cache = $this->get_mcache_engine())) { + $cache->set_mode($mode); + } } else { if ($this->mcache) { @@ -3798,9 +3790,10 @@ 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); } } @@ -3812,7 +3805,7 @@ * Clears the messages cache. * * @param string $folder Folder name - * @param array $uids Optional message UIDs to remove from cache + * @param array $uids Optional message UIDs to remove from cache */ protected function clear_message_cache($folder = null, $uids = null) {
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_imap_cache.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_imap_cache.php
Changed
@@ -27,6 +27,9 @@ */ class rcube_imap_cache { + const MODE_INDEX = 1; + const MODE_MESSAGE = 2; + /** * Instance of rcube_imap * @@ -56,6 +59,13 @@ private $ttl; /** + * Maximum cached message size + * + * @var int + */ + private $threshold; + + /** * Internal (in-memory) cache * * @var array @@ -63,6 +73,7 @@ private $icache = array(); private $skip_deleted = false; + private $mode; /** * List of known flags. Thanks to this we can handle flag changes @@ -88,6 +99,7 @@ ); + /** * Object constructor. * @@ -96,9 +108,9 @@ * @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 +121,10 @@ $this->userid = $userid; $this->skip_deleted = $skip_deleted; $this->ttl = $ttl; + $this->threshold = $threshold; + + // cache all possible information by default + $this->mode = self::MODE_INDEX | self::MODE_MESSAGE; } @@ -123,6 +139,17 @@ /** + * Set cache mode + * + * @param int $mode Cache mode + */ + public function set_mode($mode) + { + $this->mode = $mode; + } + + + /** * Return (sorted) messages index (UIDs). * If index doesn't exist or is invalid, will be updated. * @@ -300,38 +327,46 @@ return array(); } - // Fetch messages from cache - $sql_result = $this->db->query( - "SELECT uid, data, flags" - ." FROM ".$this->db->table_name('cache_messages') - ." WHERE user_id = ?" - ." AND mailbox = ?" - ." AND uid IN (".$this->db->array2list($msgs, 'integer').")", - $this->userid, $mailbox); - - $msgs = array_flip($msgs); $result = array(); - while ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $uid = intval($sql_arr['uid']); - $result[$uid] = $this->build_message($sql_arr); + if ($this->mode & self::MODE_MESSAGE) { + // Fetch messages from cache + $sql_result = $this->db->query( + "SELECT uid, data, flags" + ." FROM ".$this->db->table_name('cache_messages') + ." WHERE user_id = ?" + ." AND mailbox = ?" + ." AND uid IN (".$this->db->array2list($msgs, 'integer').")", + $this->userid, $mailbox); + + $msgs = array_flip($msgs); + + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $uid = intval($sql_arr['uid']); + $result[$uid] = $this->build_message($sql_arr); - if (!empty($result[$uid])) { - // save memory, we don't need message body here (?) - $result[$uid]->body = null; + if (!empty($result[$uid])) { + // save memory, we don't need message body here (?) + $result[$uid]->body = null; - unset($msgs[$uid]); + unset($msgs[$uid]); + } } + + $msgs = array_flip($msgs); } // Fetch not found messages from IMAP server if (!empty($msgs)) { - $messages = $this->imap->fetch_headers($mailbox, array_keys($msgs), false, true); + $messages = $this->imap->fetch_headers($mailbox, $msgs, false, true); // Insert to DB and add to result list if (!empty($messages)) { foreach ($messages as $msg) { - $this->add_message($mailbox, $msg, !array_key_exists($msg->uid, $result)); + if ($this->mode & self::MODE_MESSAGE) { + $this->add_message($mailbox, $msg, !array_key_exists($msg->uid, $result)); + } + $result[$msg->uid] = $msg; } } @@ -362,17 +397,19 @@ return $this->icache['__message']['object']; } - $sql_result = $this->db->query( - "SELECT flags, data" - ." FROM ".$this->db->table_name('cache_messages') - ." WHERE user_id = ?" - ." AND mailbox = ?" - ." AND uid = ?", - $this->userid, $mailbox, (int)$uid); + if ($this->mode & self::MODE_MESSAGE) { + $sql_result = $this->db->query( + "SELECT flags, data" + ." FROM ".$this->db->table_name('cache_messages') + ." WHERE user_id = ?" + ." AND mailbox = ?" + ." AND uid = ?", + $this->userid, $mailbox, (int)$uid); - if ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $message = $this->build_message($sql_arr); - $found = true; + if ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $message = $this->build_message($sql_arr); + $found = true; + } } // Get the message from IMAP server @@ -381,6 +418,10 @@ // cache will be updated in close(), see below } + if (!($this->mode & self::MODE_MESSAGE)) { + return $message; + } + // Save the message in internal cache, will be written to DB in close() // Common scenario: user opens unseen message // - get message (SELECT) @@ -416,6 +457,10 @@ return; } + if (!($this->mode & self::MODE_MESSAGE)) { + return; + } + $flags = 0; $msg = clone $message; @@ -487,6 +532,10 @@
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_imap_generic.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_imap_generic.php
Changed
@@ -706,22 +706,11 @@ */ 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 = ''; @@ -898,6 +887,36 @@ } /** + * 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. @@ -3139,8 +3158,7 @@ } foreach ($data as $entry) { - // If we are running in a murder topology, the entry[2] string needs - // to be escaped. + // Workaround cyrus-murder bug, the entry[2] string needs to be escaped if (self::$mupdate) { $entry[2] = addcslashes($entry[2], '\\"'); }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_ldap.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_ldap.php
Changed
@@ -34,6 +34,7 @@ public $ready = false; public $group_id = 0; public $coltypes = array(); + public $export_groups = false; // private properties protected $ldap; @@ -288,7 +289,9 @@ $replaces = array('%dn' => '', '%dc' => $dc, '%d' => $d, '%fu' => $fu, '%u' => $u); // Search for the dn to use to authenticate - if ($this->prop['search_base_dn'] && $this->prop['search_filter']) { + if ($this->prop['search_base_dn'] && $this->prop['search_filter'] + && (strstr($bind_dn, '%dn') || strstr($this->base_dn, '%dn') || strstr($this->groups_base_dn, '%dn')) + ) { $search_bind_dn = strtr($this->prop['search_bind_dn'], $replaces); $search_base_dn = strtr($this->prop['search_base_dn'], $replaces); $search_filter = strtr($this->prop['search_filter'], $replaces);
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_ldap_generic.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_ldap_generic.php
Changed
@@ -696,11 +696,17 @@ * Turn an LDAP entry into a regular PHP array with attributes as keys. * * @param array $entry Attributes array as retrieved from ldap_get_attributes() or ldap_get_entries() + * * @return array Hash array with attributes as keys */ public static function normalize_entry($entry) { + if (!isset($entry['count'])) { + return $entry; + } + $rec = array(); + for ($i=0; $i < $entry['count']; $i++) { $attr = $entry[$i]; if ($entry[$attr]['count'] == 1) {
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_message.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_message.php
Changed
@@ -195,8 +195,6 @@ /** * Determine if the message contains a HTML part. This must to be * a real part not an attachment (or its part) - * This must to be - * a real part not an attachment (or its part) * * @param bool $enriched Enables checking for text/enriched parts too * @@ -214,14 +212,15 @@ $level = explode('.', $part->mime_id); - // Check if the part belongs to higher-level's alternative/related + // Check if the part belongs to higher-level's multipart part + // this can be alternative/related/signed/encrypted, but not mixed while (array_pop($level) !== null) { if (!count($level)) { return true; } $parent = $this->mime_parts[join('.', $level)]; - if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') { + if (!preg_match('/^multipart\/(alternative|related|signed|encrypted)$/', $parent->mimetype)) { continue 2; } } @@ -435,17 +434,24 @@ continue; } + // We've encountered (malformed) messages with more than + // one text/plain or text/html part here. There's no way to choose + // which one is better, so we'll display first of them and add + // others as attachments (#1489358) + // check if sub part is if ($is_multipart) $related_part = $p; - else if ($sub_mimetype == 'text/plain') + else if ($sub_mimetype == 'text/plain' && !$plain_part) $plain_part = $p; - else if ($sub_mimetype == 'text/html') + else if ($sub_mimetype == 'text/html' && !$html_part) $html_part = $p; - else if ($sub_mimetype == 'text/enriched') + else if ($sub_mimetype == 'text/enriched' && !$enriched_part) $enriched_part = $p; - else - $attach_part = $p; + else { + // add unsupported/unrecognized parts to attachments list + $this->attachments[] = $sub_part; + } } // parse related part (alternative part could be in here) @@ -486,11 +492,6 @@ $this->parts[] = $c; } - - // add unsupported/unrecognized parts to attachments list - if ($attach_part) { - $this->attachments[] = $structure->parts[$attach_part]; - } } // this is an ecrypted message -> create a plaintext body with the according message else if ($mimetype == 'multipart/encrypted') {
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_mime.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_mime.php
Changed
@@ -637,7 +637,8 @@ if ($nextChar === ' ' || $nextChar === $separator) { $afterNextChar = mb_substr($string, $width + 1, 1); - if ($afterNextChar === false) { + // Note: mb_substr() does never return False + if ($afterNextChar === false || $afterNextChar === '') { $subString .= $nextChar; } @@ -650,24 +651,23 @@ $subString = mb_substr($subString, 0, $spacePos); $cutLength = $spacePos + 1; } - else if ($cut === false && $breakPos === false) { - $subString = $string; - $cutLength = null; - } else if ($cut === false) { $spacePos = mb_strpos($string, ' ', 0); - if ($spacePos !== false && $spacePos < $breakPos) { + if ($spacePos !== false && ($breakPos === false || $spacePos < $breakPos)) { $subString = mb_substr($string, 0, $spacePos); $cutLength = $spacePos + 1; } + else if ($breakPos === false) { + $subString = $string; + $cutLength = null; + } else { $subString = mb_substr($string, 0, $breakPos); $cutLength = $breakPos + 1; } } else { - $subString = mb_substr($subString, 0, $width); $cutLength = $width; } } @@ -708,12 +708,20 @@ */ 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 @@ // 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;
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_plugin_api.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_plugin_api.php
Changed
@@ -403,7 +403,7 @@ $args = $ret + $args; } - if ($args['abort']) { + if ($args['break']) { break; } }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_spellchecker.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_spellchecker.php
Changed
@@ -3,8 +3,8 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2011, Kolab Systems AG | - | Copyright (C) 2008-2011, The Roundcube Dev Team | + | Copyright (C) 2011-2013, Kolab Systems AG | + | 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. | @@ -28,21 +28,15 @@ { private $matches = array(); private $engine; + private $backend; private $lang; private $rc; private $error; - private $separator = '/[\s\r\n\t\(\)\/\[\]{}<>\\"]+|[:;?!,\.](?=\W|$)/'; private $options = array(); private $dict; private $have_dict; - // default settings - const GOOGLE_HOST = 'ssl://www.google.com'; - const GOOGLE_PORT = 443; - const MAX_SUGGESTIONS = 10; - - /** * Constructor * @@ -60,6 +54,15 @@ 'ignore_caps' => $this->rc->config->get('spellcheck_ignore_caps'), 'dictionary' => $this->rc->config->get('spellcheck_dictionary'), ); + + $cls = 'rcube_spellcheck_' . $this->engine; + if (class_exists($cls)) { + $this->backend = new $cls($this, $this->lang); + $this->backend->options = $this->options; + } + else { + $this->error = "Unknown spellcheck engine '$this->engine'"; + } } @@ -81,14 +84,8 @@ $this->content = $text; } - if ($this->engine == 'pspell') { - $this->matches = $this->_pspell_check($this->content); - } - else if ($this->engine == 'enchant') { - $this->matches = $this->_enchant_check($this->content); - } - else { - $this->matches = $this->_googie_check($this->content); + if ($this->backend) { + $this->matches = $this->backend->check($this->content); } return $this->found() == 0; @@ -115,14 +112,11 @@ */ function get_suggestions($word) { - if ($this->engine == 'pspell') { - return $this->_pspell_suggestions($word); - } - else if ($this->engine == 'enchant') { - return $this->_enchant_suggestions($word); + if ($this->backend) { + return $this->backend->get_suggestions($word); } - return $this->_googie_suggestions($word); + return array(); } @@ -136,14 +130,15 @@ */ function get_words($text = null, $is_html=false) { - if ($this->engine == 'pspell') { - return $this->_pspell_words($text, $is_html); + if ($is_html) { + $text = $this->html2text($text); } - else if ($this->engine == 'enchant') { - return $this->_enchant_words($text, $is_html); + + if ($this->backend) { + return $this->backend->get_words($text); } - return $this->_googie_words($text, $is_html); + return array(); } @@ -199,394 +194,7 @@ */ function error() { - return $this->error; - } - - - /** - * Checks the text using pspell - * - * @param string $text Text content for spellchecking - */ - private function _pspell_check($text) - { - // init spellchecker - $this->_pspell_init(); - - if (!$this->plink) { - return array(); - } - - // tokenize - $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); - - $diff = 0; - $matches = array(); - - foreach ($text as $w) { - $word = trim($w[0]); - $pos = $w[1] - $diff; - $len = mb_strlen($word); - - // skip exceptions - if ($this->is_exception($word)) { - } - else if (!pspell_check($this->plink, $word)) { - $suggestions = pspell_suggest($this->plink, $word); - - if (sizeof($suggestions) > self::MAX_SUGGESTIONS) { - $suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS); - } - - $matches[] = array($word, $pos, $len, null, $suggestions); - } - - $diff += (strlen($word) - $len); - } - - return $matches; - } - - - /** - * Returns the misspelled words - */ - private function _pspell_words($text = null, $is_html=false) - { - $result = array(); - - if ($text) { - // init spellchecker - $this->_pspell_init(); - - if (!$this->plink) { - return array(); - } - - // With PSpell we don't need to get suggestions to return misspelled words - if ($is_html) { - $text = $this->html2text($text); - } - - $text = preg_split($this->separator, $text, NULL, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE); - - foreach ($text as $w) { - $word = trim($w[0]); - - // skip exceptions - if ($this->is_exception($word)) { - continue; - } - - if (!pspell_check($this->plink, $word)) { - $result[] = $word; - } - } - - return $result; - } - - foreach ($this->matches as $m) { - $result[] = $m[0]; - }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_storage.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_storage.php
Changed
@@ -39,7 +39,7 @@ 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;
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_string_replacer.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_string_replacer.php
Changed
@@ -24,11 +24,16 @@ */ class rcube_string_replacer { - public static $pattern = '/##str_replacement\[([0-9]+)\]##/'; + public static $pattern = '/##str_replacement_(\d+)##/'; public $mailto_pattern; public $link_pattern; + public $linkref_index; + public $linkref_pattern; + private $values = array(); private $options = array(); + private $linkrefs = array(); + private $urls = array(); function __construct($options = array()) @@ -45,6 +50,8 @@ ."@$utf_domain" // domain-part ."(\?[$url1$url2]+)?" // e.g. ?subject=test... .")/"; + $this->linkref_index = '/\[([^\]#]+)\](:?\s*##str_replacement_(\d+)##)/'; + $this->linkref_pattern = '/\[([^\]#]+)\]/'; $this->options = $options; } @@ -67,7 +74,7 @@ */ public function get_replacement($i) { - return '##str_replacement['.$i.']##'; + return '##str_replacement_' . $i . '##'; } /** @@ -96,6 +103,7 @@ $attrib['href'] = $url_prefix . $url; $i = $this->add(html::a($attrib, rcube::Q($url)) . $suffix); + $this->urls[$i] = $attrib['href']; } // Return valid link for recognized schemes, otherwise @@ -104,6 +112,32 @@ } /** + * Callback to add an entry to the link index + */ + public function linkref_addindex($matches) + { + $key = $matches[1]; + $this->linkrefs[$key] = $this->urls[$matches[3]]; + + return $this->get_replacement($this->add('['.$key.']')) . $matches[2]; + } + + /** + * Callback to replace link references with real links + */ + public function linkref_callback($matches) + { + $i = 0; + if ($url = $this->linkrefs[$matches[1]]) { + $attrib = (array)$this->options['link_attribs']; + $attrib['href'] = $url; + $i = $this->add(html::a($attrib, rcube::Q($matches[1]))); + } + + return $i > 0 ? '['.$this->get_replacement($i).']' : $matches[0]; + } + + /** * Callback function used to build mailto: links around e-mail strings * * @param array Matches result from preg_replace_callback @@ -142,6 +176,9 @@ // 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); + // resolve link references + $str = preg_replace_callback($this->linkref_index, array($this, 'linkref_addindex'), $str); + $str = preg_replace_callback($this->linkref_pattern, array($this, 'linkref_callback'), $str); return $str; }
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_utils.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_utils.php
Changed
@@ -390,12 +390,13 @@ * Convert array of request parameters (prefixed with _) * to a regular array with non-prefixed keys. * - * @param int $mode Source to get value from (GPC) - * @param string $ignore PCRE expression to skip parameters by name + * @param int $mode Source to get value from (GPC) + * @param string $ignore PCRE expression to skip parameters by name + * @param boolean $allow_html Allow HTML tags in field value * * @return array Hash array with all request parameters */ - public static function request2param($mode = null, $ignore = 'task|action') + public static function request2param($mode = null, $ignore = 'task|action', $allow_html = false) { $out = array(); $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST); @@ -403,7 +404,7 @@ foreach (array_keys($src) as $key) { $fname = $key[0] == '_' ? substr($key, 1) : $key; if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) { - $out[$fname] = self::get_input_value($key, $mode); + $out[$fname] = self::get_input_value($key, $mode, $allow_html); } } @@ -444,41 +445,45 @@ $source = self::xss_entity_decode($source); $stripped = preg_replace('/[^a-z\(:;]/i', '', $source); $evilexpr = 'expression|behavior|javascript:|import[^a]' . (!$allow_remote ? '|url\(' : ''); + if (preg_match("/$evilexpr/i", $stripped)) { return '/* evil! */'; } + $strict_url_regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims'; + // cut out all contents between { and } while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { - $styles = substr($source, $pos+1, $pos2-($pos+1)); + $length = $pos2 - $pos - 1; + $styles = substr($source, $pos+1, $length); // check every line of a style block... if ($allow_remote) { $a_styles = preg_split('/;[\r\n]*/', $styles, -1, PREG_SPLIT_NO_EMPTY); + foreach ($a_styles as $line) { $stripped = preg_replace('/[^a-z\(:;]/i', '', $line); // ... and only allow strict url() values - $regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims'; - if (stripos($stripped, 'url(') && !preg_match($regexp, $line)) { + if (stripos($stripped, 'url(') && !preg_match($strict_url_regexp, $line)) { $a_styles = array('/* evil! */'); break; } } + $styles = join(";\n", $a_styles); } - $key = $replacements->add($styles); - $source = substr($source, 0, $pos+1) - . $replacements->get_replacement($key) - . substr($source, $pos2, strlen($source)-$pos2); - $last_pos = $pos+2; + $key = $replacements->add($styles); + $repl = $replacements->get_replacement($key); + $source = substr_replace($source, $repl, $pos+1, $length); + $last_pos = $pos2 - ($length - strlen($repl)); } // remove html comments and add #container to each tag selector. // also replace body definition because we also stripped off the <body> tag - $styles = preg_replace( + $source = preg_replace( array( - '/(^\s*<!--)|(-->\s*$)/', + '/(^\s*<\!--)|(-->\s*$)/m', '/(^\s*|,\s*|\}\s*)([a-z0-9\._#\*][a-z0-9\.\-_]*)/im', '/'.preg_quote($container_id, '/').'\s+body/i', ), @@ -490,9 +495,9 @@ $source); // put block contents back in - $styles = $replacements->resolve($styles); + $source = $replacements->resolve($source); - return $styles; + return $source; } @@ -739,11 +744,22 @@ */ public static function strtotime($date) { + $date = trim($date); + // check for MS Outlook vCard date format YYYYMMDD - if (preg_match('/^([12][90]\d\d)([01]\d)(\d\d)$/', trim($date), $matches)) { - return mktime(0,0,0, intval($matches[2]), intval($matches[3]), intval($matches[1])); + if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) { + return mktime(0,0,0, intval($m[2]), intval($m[3]), intval($m[1])); + } + + // common little-endian formats, e.g. dd/mm/yyyy (not all are supported by strtotime) + if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m) + && $m[1] > 0 && $m[1] <= 31 && $m[2] > 0 && $m[2] <= 12 && $m[3] >= 1970 + ) { + return mktime(0,0,0, intval($m[2]), intval($m[1]), intval($m[3])); } - else if (is_numeric($date)) { + + // unix timestamp + if (is_numeric($date)) { return (int) $date; } @@ -776,6 +792,44 @@ 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.
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_vcard.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_vcard.php
Changed
@@ -47,6 +47,7 @@ 'manager' => 'X-MANAGER', 'spouse' => 'X-SPOUSE', 'edit' => 'X-AB-EDIT', + 'groups' => 'CATEGORIES', ); private $typemap = array( 'IPHONE' => 'mobile', @@ -357,8 +358,8 @@ 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 @@ * * @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 @@ return(implode($sep, (array)$r)); } - return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', ',' => '\,', ';' => '\;')); + return strtr($s, array('\\' => '\\\\', "\r" => '', "\n" => '\n', $sep => '\\'.$sep)); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/ext/Roundcube/rcube_washtml.php -> kolab-syncroton-2.2.2.tar.gz/lib/ext/Roundcube/rcube_washtml.php
Changed
@@ -377,7 +377,14 @@ // Detect max nesting level (for dumpHTML) (#1489110) $this->max_nesting_level = (int) @ini_get('xdebug.max_nesting_level'); - @$node->loadHTML($html); + // Use optimizations if supported + if (version_compare(PHP_VERSION, '5.4.0', '>=')) { + @$node->loadHTML($html, LIBXML_PARSEHUGE | LIBXML_COMPACT); + } + else { + @$node->loadHTML($html); + } + return $this->dumpHtml($node); } @@ -448,7 +455,7 @@ } // fix (unknown/malformed) HTML tags before "wash" - $html = preg_replace_callback('/(<[\/]*)([^\s>]+)/', array($this, 'html_tag_callback'), $html); + $html = preg_replace_callback('/(<(?!\!)[\/]*)([^\s>]+)/', array($this, 'html_tag_callback'), $html); // Remove invalid HTML comments (#1487759) // Don't remove valid conditional comments
View file
kolab-syncroton-2.2.1.tar.gz/lib/kolab_sync.php -> kolab-syncroton-2.2.2.tar.gz/lib/kolab_sync.php
Changed
@@ -43,7 +43,7 @@ public $user; const CHARSET = 'UTF-8'; - const VERSION = "2.2.1"; + const VERSION = "2.2.2"; /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/SQL/mysql.initial.sql -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/SQL/mysql.initial.sql
Changed
@@ -1,29 +1,175 @@ /** * libkolab database schema * - * @version @package_version@ + * @version 1.0 * @author Thomas Bruederli * @licence GNU AGPL **/ + +DROP TABLE IF EXISTS `kolab_folders`; + +CREATE TABLE `kolab_folders` ( + `folder_id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, + `resource` VARCHAR(255) NOT NULL, + `type` VARCHAR(32) NOT NULL, + `synclock` INT(10) NOT NULL DEFAULT '0', + `ctag` VARCHAR(40) DEFAULT NULL, + PRIMARY KEY(`folder_id`), + INDEX `resource_type` (`resource`, `type`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + DROP TABLE IF EXISTS `kolab_cache`; -CREATE TABLE `kolab_cache` ( - `resource` VARCHAR(255) CHARACTER SET ascii NOT NULL, +DROP TABLE IF EXISTS `kolab_cache_contact`; + +CREATE TABLE `kolab_cache_contact` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, `type` VARCHAR(32) CHARACTER SET ascii NOT NULL, + CONSTRAINT `fk_kolab_cache_contact_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`), + INDEX `contact_type` (`folder_id`,`type`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE IF EXISTS `kolab_cache_event`; + +CREATE TABLE `kolab_cache_event` ( + `folder_id` BIGINT UNSIGNED NOT NULL, `msguid` BIGINT UNSIGNED NOT NULL, `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, `created` DATETIME DEFAULT NULL, `changed` DATETIME DEFAULT NULL, `data` TEXT NOT NULL, `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, `dtstart` DATETIME, `dtend` DATETIME, + CONSTRAINT `fk_kolab_cache_event_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE IF EXISTS `kolab_cache_task`; + +CREATE TABLE `kolab_cache_task` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, + `dtstart` DATETIME, + `dtend` DATETIME, + CONSTRAINT `fk_kolab_cache_task_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE IF EXISTS `kolab_cache_journal`; + +CREATE TABLE `kolab_cache_journal` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, + `dtstart` DATETIME, + `dtend` DATETIME, + CONSTRAINT `fk_kolab_cache_journal_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE IF EXISTS `kolab_cache_note`; + +CREATE TABLE `kolab_cache_note` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, + CONSTRAINT `fk_kolab_cache_note_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE IF EXISTS `kolab_cache_file`; + +CREATE TABLE `kolab_cache_file` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, `tags` VARCHAR(255) NOT NULL, `words` TEXT NOT NULL, `filename` varchar(255) DEFAULT NULL, - PRIMARY KEY(`resource`,`type`,`msguid`), - INDEX `resource_filename` (`resource`, `filename`) + CONSTRAINT `fk_kolab_cache_file_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`), + INDEX `folder_filename` (`folder_id`, `filename`) ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; -INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2013041900'); +DROP TABLE IF EXISTS `kolab_cache_configuration`; + +CREATE TABLE `kolab_cache_configuration` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, + `type` VARCHAR(32) CHARACTER SET ascii NOT NULL, + CONSTRAINT `fk_kolab_cache_configuration_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`), + INDEX `configuration_type` (`folder_id`,`type`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + +DROP TABLE IF EXISTS `kolab_cache_freebusy`; + +CREATE TABLE `kolab_cache_freebusy` ( + `folder_id` BIGINT UNSIGNED NOT NULL, + `msguid` BIGINT UNSIGNED NOT NULL, + `uid` VARCHAR(128) CHARACTER SET ascii NOT NULL, + `created` DATETIME DEFAULT NULL, + `changed` DATETIME DEFAULT NULL, + `data` TEXT NOT NULL, + `xml` TEXT NOT NULL, + `tags` VARCHAR(255) NOT NULL, + `words` TEXT NOT NULL, + `dtstart` DATETIME, + `dtend` DATETIME, + CONSTRAINT `fk_kolab_cache_freebusy_folder` FOREIGN KEY (`folder_id`) + REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE, + PRIMARY KEY(`folder_id`,`msguid`) +) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; + + +INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2013100400');
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/bin/modcache.sh -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/bin/modcache.sh
Changed
@@ -4,7 +4,7 @@ /** * Kolab storage cache modification script * - * @version 3.0 + * @version 3.1 * @author Thomas Bruederli <bruederli@kolabsys.com> * * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com> @@ -56,7 +56,14 @@ $opts['username'] = !empty($opts[1]) ? $opts[1] : $opts['user']; $action = $opts[0]; -$rcmail = rcube::get_instance(); +$rcmail = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS); + + +// connect to database +$db = $rcmail->get_dbh(); +$db->db_connect('w'); +if (!$db->is_connected() || $db->is_error()) + die("No DB connection\n"); /* @@ -68,32 +75,42 @@ * Clear/expunge all cache records */ case 'expunge': + $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','journal','note','task'); + $folder_types_db = array_map(array($db, 'quote'), $folder_types); $expire = strtotime(!empty($opts[2]) ? $opts[2] : 'now - 10 days'); - $sql_add = " AND created <= '" . date('Y-m-d 00:00:00', $expire) . "'"; + $sql_where = "type IN (" . join(',', $folder_types_db) . ")"; + + if ($opts['username']) { + $sql_where .= ' AND resource LIKE ?'; + } + + $sql_query = "DELETE FROM %s WHERE folder_id IN (SELECT folder_id FROM kolab_folders WHERE $sql_where) AND created <= " . $db->quote(date('Y-m-d 00:00:00', $expire)); if ($opts['limit']) { - $sql_add .= ' LIMIT ' . intval($opts['limit']); + $sql_query = ' LIMIT ' . intval($opts['limit']); + } + foreach ($folder_types as $type) { + $table_name = 'kolab_cache_' . $type; + $db->query(sprintf($sql_query, $table_name), resource_prefix($opts).'%'); + echo $db->affected_rows() . " records deleted from '$table_name'\n"; } -case 'clear': - // connect to database - $db = $rcmail->get_dbh(); - $db->db_connect('w'); - if (!$db->is_connected() || $db->is_error()) - die("No DB connection\n"); + $db->query("UPDATE kolab_folders SET ctag='' WHERE $sql_where", resource_prefix($opts).'%'); + break; - $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','distribution-list','event','task','configuration','file'); +case 'clear': + $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','journal','note','task'); $folder_types_db = array_map(array($db, 'quote'), $folder_types); if ($opts['all']) { - $sql_query = "DELETE FROM kolab_cache WHERE type IN (" . join(',', $folder_types_db) . ")"; + $sql_query = "DELETE FROM kolab_folders WHERE 1"; } else if ($opts['username']) { - $sql_query = "DELETE FROM kolab_cache WHERE type IN (" . join(',', $folder_types_db) . ") AND resource LIKE ?"; + $sql_query = "DELETE FROM kolab_folders WHERE type IN (" . join(',', $folder_types_db) . ") AND resource LIKE ?"; } if ($sql_query) { $db->query($sql_query . $sql_add, resource_prefix($opts).'%'); - echo $db->affected_rows() . " records deleted from 'kolab_cache'\n"; + echo $db->affected_rows() . " records deleted from 'kolab_folders'\n"; } break; @@ -106,7 +123,7 @@ $rcmail->plugins->load_plugin('libkolab'); if (authenticate($opts)) { - $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','event','task','configuration','file'); + $folder_types = $opts['type'] ? explode(',', $opts['type']) : array('contact','configuration','event','file','task'); foreach ($folder_types as $type) { // sync every folder of the given type foreach (kolab_storage::get_folders($type) as $folder) { @@ -140,7 +157,7 @@ */ function resource_prefix($opts) { - return 'imap://' . urlencode($opts['username']) . '@' . $opts['host'] . '/'; + return 'imap://' . str_replace('%', '\\%', urlencode($opts['username'])) . '@' . $opts['host'] . '/'; }
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/config.inc.php.dist -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/config.inc.php.dist
Changed
@@ -12,9 +12,6 @@ // Defaults to https://<imap-server->/freebusy $rcmail_config['kolab_freebusy_server'] = 'https://<some-host>/<freebusy-path>'; -// Set this option to disable SSL certificate checks when triggering Free/Busy (enabled by default) -$rcmail_config['kolab_ssl_verify_peer'] = false; - // Enables listing of only subscribed folders. This e.g. will limit // folders in calendar view or available addressbooks $rcmail_config['kolab_use_subscriptions'] = false; @@ -23,4 +20,13 @@ // for displaying resource folder names (experimental!) $rcmail_config['kolab_custom_display_names'] = false; -?> +// Configuration of HTTP requests. +// See http://pear.php.net/manual/en/package.http.http-request2.config.php +// for list of supported configuration options (array keys) +$rcmail_config['kolab_http_request'] = array(); + +// When kolab_cache is enabled Roundcube's messages cache will be redundant +// when working on kolab folders. Here we can: +// 2 - bypass messages/indexes cache completely +// 1 - bypass only messages, but use index cache +$rcmail_config['kolab_messages_cache_bypass'] = 0;
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format.php
Changed
@@ -40,6 +40,7 @@ protected $data; protected $xmldata; protected $xmlobject; + protected $formaterror; protected $loaded = false; protected $version = '3.0'; @@ -104,13 +105,17 @@ } $result = new cDateTime(); - // got a unix timestamp (in UTC) - if (is_numeric($datetime)) { - $datetime = new DateTime('@'.$datetime, new DateTimeZone('UTC')); - if ($tz) $datetime->setTimezone($tz); + try { + // got a unix timestamp (in UTC) + if (is_numeric($datetime)) { + $datetime = new DateTime('@'.$datetime, new DateTimeZone('UTC')); + if ($tz) $datetime->setTimezone($tz); + } + else if (is_string($datetime) && strlen($datetime)) { + $datetime = new DateTime($datetime, $tz ?: null); + } } - else if (is_string($datetime) && strlen($datetime)) - $datetime = new DateTime($datetime, $tz ?: null); + catch (Exception $e) {} if ($datetime instanceof DateTime) { $result->setDate($datetime->format('Y'), $datetime->format('n'), $datetime->format('j')); @@ -244,7 +249,7 @@ $log = "Error"; } - if ($log) { + if ($log && !isset($this->formaterror)) { rcube::raise_error(array( 'code' => 660, 'type' => 'php', @@ -252,6 +257,8 @@ 'line' => __LINE__, 'message' => "kolabformat $log: " . kolabformat::errorMessage(), ), true); + + $this->formaterror = $ret; } return $ret; @@ -338,6 +345,7 @@ */ public function load($xml) { + $this->formaterror = null; $read_func = $this->libfunc($this->read_func); if (is_array($read_func)) @@ -361,6 +369,8 @@ */ public function write($version = null) { + $this->formaterror = null; + $this->init(); $write_func = $this->libfunc($this->write_func); if (is_array($write_func)) @@ -389,24 +399,33 @@ $this->obj->setUid($object['uid']); // set some automatic values if missing - if (method_exists($this->obj, 'setCreated') && !$this->obj->created()) { - if (empty($object['created'])) - $object['created'] = new DateTime('now', self::$timezone); - $this->obj->setCreated(self::get_datetime($object['created'])); + if (empty($object['created']) && method_exists($this->obj, 'setCreated')) { + $cdt = $this->obj->created(); + $object['created'] = $cdt && $cdt->isValid() ? self::php_datetime($cdt) : new DateTime('now', self::$timezone); + if (!$cdt || !$cdt->isValid()) + $this->obj->setCreated(self::get_datetime($object['created'])); } $object['changed'] = new DateTime('now', self::$timezone); $this->obj->setLastModified(self::get_datetime($object['changed'], new DateTimeZone('UTC'))); // Save custom properties of the given object - if (!empty($object['x-custom'])) { + if (isset($object['x-custom'])) { $vcustom = new vectorcs; - foreach ($object['x-custom'] as $cp) { + foreach ((array)$object['x-custom'] as $cp) { if (is_array($cp)) $vcustom->push(new CustomProperty($cp[0], $cp[1])); } $this->obj->setCustomProperties($vcustom); } + else { // load custom properties from XML for caching (#2238) + $object['x-custom'] = array(); + $vcustom = $this->obj->customProperties(); + for ($i=0; $i < $vcustom->size(); $i++) { + $cp = $vcustom->get($i); + $object['x-custom'][] = array($cp->identifier, $cp->value); + } + } } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_contact.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_contact.php
Changed
@@ -268,7 +268,7 @@ */ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->uid() /*$this->obj->isValid()*/); + return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->uid() /*$this->obj->isValid()*/)); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_distributionlist.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_distributionlist.php
Changed
@@ -69,7 +69,7 @@ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->isValid()); + return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid())); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_event.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_event.php
Changed
@@ -111,7 +111,8 @@ */ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->isValid() && $this->obj->uid()); + return !$this->formaterror && (($this->data && !empty($this->data['start']) && !empty($this->data['end'])) || + (is_object($this->obj) && $this->obj->isValid() && $this->obj->uid())); } /** @@ -138,6 +139,17 @@ 'attendees' => array(), ); + // derive event end from duration (#1916) + if (!$object['end'] && $object['start'] && ($duration = $this->obj->duration()) && $duration->isValid()) { + $interval = new DateInterval('PT0S'); + $interval->d = $duration->weeks() * 7 + $duration->days(); + $interval->h = $duration->hours(); + $interval->i = $duration->minutes(); + $interval->s = $duration->seconds(); + $object['end'] = clone $object['start']; + $object['end']->add($interval); + } + // organizer is part of the attendees list in Roundcube if ($object['organizer']) { $object['organizer']['role'] = 'ORGANIZER';
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_file.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_file.php
Changed
@@ -95,7 +95,7 @@ */ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->isValid()); + return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid())); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_journal.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_journal.php
Changed
@@ -54,7 +54,7 @@ */ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->isValid()); + return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid())); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_note.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_note.php
Changed
@@ -54,7 +54,7 @@ */ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->isValid()); + return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid())); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_task.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_task.php
Changed
@@ -63,7 +63,7 @@ */ public function is_valid() { - return $this->data || (is_object($this->obj) && $this->obj->isValid()); + return !$this->formaterror && ($this->data || (is_object($this->obj) && $this->obj->isValid())); } /**
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_format_xcal.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_format_xcal.php
Changed
@@ -385,7 +385,7 @@ if (preg_match('/^@(\d+)/', $offset, $d)) { $alarm->setStart(self::get_datetime($d[1], new DateTimeZone('UTC'))); } - else if (preg_match('/^([-+]?)(\d+)([SMHDW])/', $offset, $d)) { + else if (preg_match('/^([-+]?)P?T?(\d+)([SMHDW])/', $offset, $d)) { $days = $hours = $minutes = $seconds = 0; switch ($d[3]) { case 'W': $days = 7*intval($d[2]); break;
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_storage.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_storage.php
Changed
@@ -31,6 +31,9 @@ const COLOR_KEY_PRIVATE = '/private/vendor/kolab/color'; const NAME_KEY_SHARED = '/shared/vendor/kolab/displayname'; const NAME_KEY_PRIVATE = '/private/vendor/kolab/displayname'; + const UID_KEY_SHARED = '/shared/vendor/kolab/uniqueid'; + const UID_KEY_PRIVATE = '/private/vendor/kolab/uniqueid'; + const UID_KEY_CYRUS = '/shared/vendor/cmu/cyrus-imapd/uniqueid'; public static $version = '3.0'; public static $last_error; @@ -103,15 +106,16 @@ * Get a list of storage folders for the given data type * * @param string Data type to list folders for (contact,distribution-list,event,task,note) + * @param boolean Enable to return subscribed folders only (null to use configured subscription mode) * * @return array List of Kolab_Folder objects (folder names in UTF7-IMAP) */ - public static function get_folders($type) + public static function get_folders($type, $subscribed = null) { $folders = $folderdata = array(); if (self::setup()) { - foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) { + foreach ((array)self::list_folders('', '*', $type, $subscribed, $folderdata) as $foldername) { $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]); } } @@ -154,7 +158,7 @@ * This will search all folders storing objects of the given type. * * @param string Object UID - * @param string Object type (contact,distribution-list,event,task,note) + * @param string Object type (contact,event,task,journal,file,note,configuration) * @return array The Kolab object represented as hash array or false if not found */ public static function get_object($uid, $type) @@ -167,7 +171,7 @@ else $folder->set_folder($foldername); - if ($object = $folder->get_object($uid)) + if ($object = $folder->get_object($uid, '*')) return $object; } @@ -276,9 +280,22 @@ { self::setup(); + $oldfolder = self::get_folder($oldname); + $active = self::folder_is_active($oldname); $success = self::$imap->rename_folder($oldname, $newname); self::$last_error = self::$imap->get_error_str(); + // pass active state to new folder name + if ($success && $active) { + self::set_state($oldnam, false); + self::set_state($newname, true); + } + + // assign existing cache entries to new resource uri + if ($success && $oldfolder) { + $oldfolder->cache->rename($newname); + } + return $success; } @@ -388,11 +405,8 @@ self::setup(); // find custom display name in folder METADATA - if (self::$config->get('kolab_custom_display_names', true)) { - $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED)); - if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) { - return $name; - } + if ($name = self::custom_displayname($folder)) { + return $name; } $found = false; @@ -461,6 +475,21 @@ return $folder; } + /** + * Get custom display name (saved in metadata) for the given folder + */ + public static function custom_displayname($folder) + { + // find custom display name in folder METADATA + if (self::$config->get('kolab_custom_display_names', true)) { + $metadata = self::$imap->get_metadata($folder, array(self::NAME_KEY_PRIVATE, self::NAME_KEY_SHARED)); + if (($name = $metadata[$folder][self::NAME_KEY_PRIVATE]) || ($name = $metadata[$folder][self::NAME_KEY_SHARED])) { + return $name; + } + } + + return false; + } /** * Helper method to generate a truncated folder name to display @@ -475,7 +504,7 @@ $length = strlen($names[$i] . ' » '); $prefix = substr($name, 0, $length); $count = count(explode(' » ', $prefix)); - $name = str_repeat(' ', $count-1) . '» ' . substr($name, $length); + $name = str_repeat(' ', $count-1) . '» ' . substr($name, $length); break; } } @@ -497,7 +526,7 @@ public static function folder_selector($type, $attrs, $current = '') { // get all folders of specified type - $folders = self::get_folders($type); + $folders = self::get_folders($type, false); $delim = self::$imap->get_hierarchy_delimiter(); $names = array(); @@ -570,7 +599,7 @@ * * @param string Optional root folder * @param string Optional name pattern - * @param string Data type to list folders for (contact,distribution-list,event,task,note,mail) + * @param string Data type to list folders for (contact,event,task,journal,file,note,mail,configuration) * @param boolean Enable to return subscribed folders only (null to use configured subscription mode) * @param array Will be filled with folder-types data * @@ -654,11 +683,12 @@ */ public static function sort_folders($folders) { + $pad = ' '; $nsnames = array('personal' => array(), 'shared' => array(), 'other' => array()); foreach ($folders as $folder) { $folders[$folder->name] = $folder; $ns = $folder->get_namespace(); - $nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)); // decode » + $nsnames[$ns][$folder->name] = strtolower(html_entity_decode(self::object_name($folder->name, $ns), ENT_COMPAT, RCUBE_CHARSET)) . $pad; // decode » } $names = array(); @@ -963,7 +993,7 @@ } if (!self::$imap->folder_exists($folder)) { - if (!self::$imap->folder_create($folder)) { + if (!self::$imap->create_folder($folder)) { return; } }
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_storage_cache.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_storage_cache.php
Changed
@@ -6,7 +6,7 @@ * @version @package_version@ * @author Thomas Bruederli <bruederli@kolabsys.com> * - * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com> + * Copyright (C) 2012-2013, Kolab Systems AG <contact@kolabsys.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -24,24 +24,44 @@ class kolab_storage_cache { - private $db; - private $imap; - private $folder; - private $uid2msg; - private $objects; - private $index = array(); - private $resource_uri; - private $enabled = true; - private $synched = false; - private $synclock = false; - private $ready = false; - private $max_sql_packet; - private $max_sync_lock_time = 600; - private $binary_items = array( - 'photo' => '|<photo><uri>[^;]+;base64,([^<]+)</uri></photo>|i', - 'pgppublickey' => '|<key><uri>date:application/pgp-keys;base64,([^<]+)</uri></photo>|i', - 'pkcs7publickey' => '|<key><uri>date:application/pkcs7-mime;base64,([^<]+)</uri></photo>|i', - ); + protected $db; + protected $imap; + protected $folder; + protected $uid2msg; + protected $objects; + protected $index = array(); + protected $metadata = array(); + protected $folder_id; + protected $resource_uri; + protected $enabled = true; + protected $synched = false; + protected $synclock = false; + protected $ready = false; + protected $cache_table; + protected $folders_table; + protected $max_sql_packet; + protected $max_sync_lock_time = 600; + protected $binary_items = array(); + protected $extra_cols = array(); + + + /** + * Factory constructor + */ + public static function factory(kolab_storage_folder $storage_folder) + { + $subclass = 'kolab_storage_cache_' . $storage_folder->type; + if (class_exists($subclass)) { + return new $subclass($storage_folder); + } + else { + rcube::raise_error(array( + 'code' => 900, + 'type' => 'php', + 'message' => "No kolab_storage_cache class found for folder of type " . $storage_folder->type + ), true); + } + } /** @@ -55,6 +75,8 @@ $this->enabled = $rcmail->config->get('kolab_cache', false); if ($this->enabled) { + // always read folder cache and lock state from DB master + $this->db->set_table_dsn('kolab_folders', 'w'); // remove sync-lock on script termination $rcmail->add_shutdown_function(array($this, '_sync_unlock')); } @@ -80,9 +102,19 @@ // compose fully qualified ressource uri for this instance $this->resource_uri = $this->folder->get_resource_uri(); + $this->folders_table = $this->db->table_name('kolab_folders'); + $this->cache_table = $this->db->table_name('kolab_cache_' . $this->folder->type); $this->ready = $this->enabled; + $this->folder_id = null; } + /** + * Returns true if this cache supports query by type + */ + public function has_type_col() + { + return in_array('type', $this->extra_cols); + } /** * Synchronize local cache data with remote @@ -96,52 +128,65 @@ // increase time limit @set_time_limit($this->max_sync_lock_time); - // lock synchronization for this folder or wait if locked - $this->_sync_lock(); + // read cached folder metadata + $this->_read_folder_data(); - // synchronize IMAP mailbox cache - $this->imap->folder_sync($this->folder->name); + // check cache status hash first ($this->metadata is set in _read_folder_data()) + if ($this->metadata['ctag'] != $this->folder->get_ctag()) { + // lock synchronization for this folder or wait if locked + $this->_sync_lock(); - // compare IMAP index with object cache index - $imap_index = $this->imap->index($this->folder->name); - $this->index = $imap_index->get(); + // disable messages cache if configured to do so + $this->bypass(true); - // determine objects to fetch or to invalidate - if ($this->ready) { - // read cache index - $sql_result = $this->db->query( - "SELECT msguid, uid FROM kolab_cache WHERE resource=? AND type<>?", - $this->resource_uri, - 'lock' - ); + // synchronize IMAP mailbox cache + $this->imap->folder_sync($this->folder->name); - $old_index = array(); - while ($sql_arr = $this->db->fetch_assoc($sql_result)) { - $old_index[] = $sql_arr['msguid']; - $this->uid2msg[$sql_arr['uid']] = $sql_arr['msguid']; - } + // compare IMAP index with object cache index + $imap_index = $this->imap->index($this->folder->name, null, null, true, true); + $this->index = $imap_index->get(); - // fetch new objects from imap - foreach (array_diff($this->index, $old_index) as $msguid) { - if ($object = $this->folder->read_object($msguid, '*')) { - $this->_extended_insert($msguid, $object); - } - } - $this->_extended_insert(0, null); - - // delete invalid entries from local DB - $del_index = array_diff($old_index, $this->index); - if (!empty($del_index)) { - $quoted_ids = join(',', array_map(array($this->db, 'quote'), $del_index)); - $this->db->query( - "DELETE FROM kolab_cache WHERE resource=? AND msguid IN ($quoted_ids)", - $this->resource_uri + // determine objects to fetch or to invalidate + if ($this->ready) { + // read cache index + $sql_result = $this->db->query( + "SELECT msguid, uid FROM $this->cache_table WHERE folder_id=?", + $this->folder_id ); + + $old_index = array(); + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { + $old_index[] = $sql_arr['msguid']; + $this->uid2msg[$sql_arr['uid']] = $sql_arr['msguid']; + } + + // fetch new objects from imap + foreach (array_diff($this->index, $old_index) as $msguid) { + if ($object = $this->folder->read_object($msguid, '*')) { + $this->_extended_insert($msguid, $object); + } + } + $this->_extended_insert(0, null); + + // delete invalid entries from local DB + $del_index = array_diff($old_index, $this->index); + if (!empty($del_index)) { + $quoted_ids = join(',', array_map(array($this->db, 'quote'), $del_index)); + $this->db->query( + "DELETE FROM $this->cache_table WHERE folder_id=? AND msguid IN ($quoted_ids)", + $this->folder_id + ); + } + + // update ctag value (will be written to database in _sync_unlock()) + $this->metadata['ctag'] = $this->folder->get_ctag(); } - } - // remove lock - $this->_sync_unlock(); + $this->bypass(false); + + // remove lock
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/lib/kolab_storage_folder.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/lib/kolab_storage_folder.php
Changed
@@ -7,7 +7,7 @@ * @author Thomas Bruederli <bruederli@kolabsys.com> * @author Aleksander Machniak <machniak@kolabsys.com> * - * Copyright (C) 2012, Kolab Systems AG <contact@kolabsys.com> + * Copyright (C) 2012-2013, Kolab Systems AG <contact@kolabsys.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -43,8 +43,8 @@ public $default = false; /** - * Is this folder set to be default - * @var boolean + * The kolab_storage_cache instance for caching operations + * @var object */ public $cache; @@ -64,7 +64,6 @@ { $this->imap = rcube::get_instance()->get_storage(); $this->imap->set_options(array('skip_deleted' => true)); - $this->cache = new kolab_storage_cache($this); $this->set_folder($name, $type); } @@ -79,11 +78,16 @@ { $this->type_annotation = $ftype ? $ftype : kolab_storage::folder_type($name); + $oldtype = $this->type; list($this->type, $suffix) = explode('.', $this->type_annotation); $this->default = $suffix == 'default'; $this->name = $name; $this->resource_uri = null; + // get a new cache instance of folder type changed + if (!$this->cache || $type != $oldtype) + $this->cache = kolab_storage_cache::factory($this); + $this->imap->set_folder($this->name); $this->cache->set_folder($this); } @@ -92,7 +96,7 @@ /** * */ - private function get_folder_info() + public function get_folder_info() { if (!isset($this->info)) $this->info = $this->imap->folder_info($this->name); @@ -260,6 +264,52 @@ } /** + * Helper method to extract folder UID metadata + * + * @return string Folder's UID + */ + public function get_uid() + { + // UID is defined in folder METADATA + $metakeys = array(kolab_storage::UID_KEY_SHARED, kolab_storage::UID_KEY_PRIVATE, kolab_storage::UID_KEY_CYRUS); + $metadata = $this->get_metadata($metakeys); + foreach ($metakeys as $key) { + if (($uid = $metadata[$key])) { + return $uid; + } + } + + // generate a folder UID and set it to IMAP + $uid = rtrim(chunk_split(md5($this->name . $this->get_owner()), 12, '-'), '-'); + $this->set_uid($uid); + + return $uid; + } + + /** + * Helper method to set an UID value to the given IMAP folder instance + * + * @param string Folder's UID + * @return boolean True on succes, False on failure + */ + public function set_uid($uid) + { + if (!($success = $this->set_metadata(array(kolab_storage::UID_KEY_SHARED => $uid)))) { + $success = $this->set_metadata(array(kolab_storage::UID_KEY_PRIVATE => $uid)); + } + return $success; + } + + /** + * Compose a folder Etag identifier + */ + public function get_ctag() + { + $fdata = $this->get_imap_data(); + return sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']); + } + + /** * Check activation status of this folder * * @return boolean True if enabled, false if not @@ -303,7 +353,6 @@ return $subscribed ? kolab_storage::folder_subscribe($this->name) : kolab_storage::folder_unsubscribe($this->name); } - /** * Get number of objects stored in this folder * @@ -312,19 +361,12 @@ * @return integer The number of objects of the given type * @see self::select() */ - public function count($type_or_query = null) + public function count($query = null) { - if (!$type_or_query) - $query = array(array('type','=',$this->type)); - else if (is_string($type_or_query)) - $query = array(array('type','=',$type_or_query)); - else - $query = $this->_prepare_query((array)$type_or_query); - // synchronize cache first $this->cache->synchronize(); - return $this->cache->count($query); + return $this->cache->count($this->_prepare_query($query)); } @@ -342,7 +384,7 @@ $this->cache->synchronize(); // fetch objects from cache - return $this->cache->select(array(array('type','=',$type))); + return $this->cache->select($this->_prepare_query($type)); } @@ -388,10 +430,15 @@ */ private function _prepare_query($query) { - $type = null; - foreach ($query as $i => $param) { - if ($param[0] == 'type') { - $type = $param[2]; + // string equals type query + // FIXME: should not be called this way! + if (is_string($query)) { + return $this->cache->has_type_col() && !empty($query) ? array(array('type','=',$query)) : array(); + } + + foreach ((array)$query as $i => $param) { + if ($param[0] == 'type' && !$this->cache->has_type_col()) { + unset($query[$i]); } else if (($param[0] == 'dtstart' || $param[0] == 'dtend' || $param[0] == 'changed')) { if (is_object($param[2]) && is_a($param[2], 'DateTime')) @@ -401,10 +448,6 @@ } } - // add type selector if not in $query - if (!$type) - $query[] = array('type','=',$this->type); - return $query; } @@ -465,6 +508,7 @@ * @param string The IMAP message UID to fetch * @param string The object type expected (use wildcard '*' to accept all types) * @param string The folder name where the message is stored + * * @return mixed Hash array representing the Kolab object, a kolab_format instance or false if not found */ public function read_object($msguid, $type = null, $folder = null) @@ -474,31 +518,31 @@ $this->imap->set_folder($folder); - $headers = $this->imap->get_message_headers($msguid); - $message = null; + $this->cache->bypass(true); + $message = new rcube_message($msguid); + $this->cache->bypass(false); // Message doesn't exist? - if (empty($headers)) { + if (empty($message->headers)) { return false; }
View file
kolab-syncroton-2.2.1.tar.gz/lib/plugins/libkolab/libkolab.php -> kolab-syncroton-2.2.2.tar.gz/lib/plugins/libkolab/libkolab.php
Changed
@@ -27,6 +27,8 @@ class libkolab extends rcube_plugin { + static $http_requests = array(); + /** * Required startup method of a Roundcube plugin */ @@ -59,4 +61,66 @@ $p['fetch_headers'] = trim($p['fetch_headers'] .' X-KOLAB-TYPE X-KOLAB-MIME-VERSION'); return $p; } + + /** + * Wrapper function to load and initalize the HTTP_Request2 Object + * + * @param string|Net_Url2 Request URL + * @param string Request method ('OPTIONS','GET','HEAD','POST','PUT','DELETE','TRACE','CONNECT') + * @param array Configuration for this Request instance, that will be merged + * with default configuration + * + * @return HTTP_Request2 Request object + */ + public static function http_request($url = '', $method = 'GET', $config = array()) + { + $rcube = rcube::get_instance(); + $http_config = (array) $rcube->config->get('kolab_http_request'); + + // deprecated configuration options + if (empty($http_config)) { + foreach (array('ssl_verify_peer', 'ssl_verify_host') as $option) { + $value = $rcube->config->get('kolab_' . $option, true); + if (is_bool($value)) { + $http_config[$option] = $value; + } + } + } + + if (!empty($config)) { + $http_config = array_merge($http_config, $config); + } + + $key = md5(serialize($http_config)); + + if (!($request = self::$http_requests[$key])) { + // load HTTP_Request2 + require_once 'HTTP/Request2.php'; + + try { + $request = new HTTP_Request2(); + $request->setConfig($http_config); + } + catch (Exception $e) { + rcube::raise_error($e, true, true); + } + + // proxy User-Agent string + $request->setHeader('user-agent', $_SERVER['HTTP_USER_AGENT']); + + self::$http_requests[$key] = $request; + } + + // cleanup + try { + $request->setBody(''); + $request->setUrl($url); + $request->setMethod($method); + } + catch (Exception $e) { + rcube::raise_error($e, true, true); + } + + return $request; + } }
View file
kolab-syncroton.dsc
Changed
@@ -2,7 +2,7 @@ Source: kolab-syncroton Binary: kolab-syncroton Architecture: all -Version: 2.2.1-0~kolab1 +Version: 2.2.2-0~kolab1 Maintainer: Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Uploaders: Paul Klos <kolab@klos2day.nl> Homepage: http://www.kolab.org/ @@ -12,5 +12,5 @@ Package-List: kolab-syncroton deb utils extra Files: - 00000000000000000000000000000000 0 kolab-syncroton-2.2.1.tar.gz + 00000000000000000000000000000000 0 kolab-syncroton-2.2.2.tar.gz 00000000000000000000000000000000 0 debian.tar.gz
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.