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 42
View file
kolab-syncroton.spec
Changed
@@ -25,8 +25,8 @@ %global _ap_sysconfdir %{_sysconfdir}/%{httpd_name} Name: kolab-syncroton -Version: 2.2.3 -Release: 2%{?dist} +Version: 2.2.4 +Release: 1%{?dist} Summary: ActiveSync for Kolab Groupware Group: Applications/Internet @@ -197,6 +197,9 @@ %attr(0770,%{httpd_user},%{httpd_group}) %{_var}/log/%{name} %changelog +* Tue Jan 28 2014 Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> - 2.2.4-1 +- New upstream release + * Tue Nov 12 2013 Jeroen van Meeuwen <vanmeeuwen@kolabsys.com> - 2.2.3-2 - Fix a trailing slash issue - New upstream release
View file
debian.changelog
Changed
@@ -1,3 +1,9 @@ +kolab-syncroton (2.2.4-0~kolab1) unstable; urgency=low + + * New upstream release + + -- Jeroen van Meeuwen (Kolab Systems) <vanmeeuwen@kolabsys.com> Tue, 28 Jan 2014 15:13:40 +0200 + kolab-syncroton (2.2.3-0~kolab13) unstable; urgency=low * added logrotate config for Debian
View file
kolab-syncroton-2.2.3.tar.gz/config/main.inc.php.dist -> kolab-syncroton-2.2.4.tar.gz/config/main.inc.php.dist
Changed
@@ -3,34 +3,37 @@ // This file lists all ActiveSync-related configuration options // Enables ActiveSync protocol debuging -$rcmail_config['activesync_debug'] = true; +$config['activesync_debug'] = true; // Enables logging to a separate directory for every user/device -$rcmail_config['activesync_user_log'] = false; +$config['activesync_user_log'] = false; + +// Enable per-user debugging only if /var/log/syncroton/<username>/ folder exists +$config['activesync_user_debug'] = false; // If specified all ActiveSync-related logs will be saved to this file // Note: This doesn't change Roundcube Framework log locations -$rcmail_config['activesync_log_file'] = null; +$config['activesync_log_file'] = null; // Type of ActiveSync cache. Supported values: 'db', 'apc' and 'memcache'. // Note: This is only for some additional data like timezones mapping. -$rcmail_config['activesync_cache'] = 'db'; +$config['activesync_cache'] = 'db'; // lifetime of ActiveSync cache // possible units: s, m, h, d, w -$rcmail_config['activesync_cache_ttl'] = '1d'; +$config['activesync_cache_ttl'] = '1d'; // Type of ActiveSync Auth cache. Supported values: 'db', 'apc' and 'memcache'. // Note: This is only for username canonification map. -$rcmail_config['activesync_auth_cache'] = 'db'; +$config['activesync_auth_cache'] = 'db'; // lifetime of ActiveSync Auth cache // possible units: s, m, h, d, w -$rcmail_config['activesync_auth_cache_ttl'] = '1d'; +$config['activesync_auth_cache_ttl'] = '1d'; // List of global addressbooks (GAL) // Note: If empty 'autocomplete_addressbooks' setting will be used -$rcmail_config['activesync_addressbooks'] = array(); +$config['activesync_addressbooks'] = array(); // ActiveSync => Roundcube contact fields map for GAL search /* Default: array( @@ -47,16 +50,32 @@ 'title' => 'jobtitle', ); */ -$rcmail_config['activesync_gal_fieldmap'] = null; +$config['activesync_gal_fieldmap'] = null; // List of Roundcube plugins // WARNING: Not all plugins used in Roundcube can be listed here -$rcmail_config['activesync_plugins'] = array(); +$config['activesync_plugins'] = array(); // Defines for how many seconds we'll sleep between every // action for detecting changes in folders. Default: 60 -$rcmail_config['activesync_ping_timeout'] = 60; +$config['activesync_ping_timeout'] = 60; // We start detecting changes n seconds since the last sync of a folder // Default: 180 -$rcmail_config['activesync_quiet_time'] = 180; +$config['activesync_quiet_time'] = 180; + +// When a device is reqistered, by default a set of folders are +// subscribed for syncronization, i.e. INBOX and personal folders with +// defined folder type: +// mail.drafts, mail.wastebasket, mail.sentitems, mail.outbox, +// event, event.default, +// contact, contact.default, +// task, task.default +// This default set can be extended by adding following values: +// 1 - all subscribed folders in personal namespace +// 2 - all folders in personal namespace +// 4 - all subscribed folders in other users namespace +// 8 - all folders in other users namespace +// 16 - all subscribed folders in shared namespace +// 32 - all folders in shared namespace +$config['activesync_init_subscriptions'] = 0;
View file
kolab-syncroton-2.2.3.tar.gz/docs/kolab-syncroton.conf -> kolab-syncroton-2.2.4.tar.gz/docs/kolab-syncroton.conf
Changed
@@ -4,23 +4,44 @@ ScriptAlias /Microsoft-Server-ActiveSync /usr/share/kolab-syncroton/index.php <Directory "/usr/share/kolab-syncroton/"> - Order Allow,Deny - Allow from All AllowOverride All + <ifModule mod_authz_core.c> + Require all granted + </ifModule> + <ifModule !mod_authz_core.c> + Order Allow,Deny + Allow from All + </ifModule> </Directory> <Directory "/usr/share/kolab-syncroton/config/"> - Order Deny,Allow - Deny from All + Options -FollowSymLinks + <ifModule mod_authz_core.c> + Require all denied + </ifModule> + <ifModule !mod_authz_core.c> + Order Deny,Allow + Deny from All + </ifModule> </Directory> <Directory "/usr/share/kolab-syncroton/lib/"> - Order Deny,Allow - Deny from All + <ifModule mod_authz_core.c> + Require all denied + </ifModule> + <ifModule !mod_authz_core.c> + Order Deny,Allow + Deny from All + </ifModule> </Directory> <Directory "/usr/share/kolab-syncroton/logs/"> - Order Deny,Allow - Deny from All + Options -FollowSymLinks + <ifModule mod_authz_core.c> + Require all denied + </ifModule> + <ifModule !mod_authz_core.c> + Order Deny,Allow + Deny from All + </ifModule> </Directory> -
View file
kolab-syncroton-2.2.4.tar.gz/docs/kolab-syncroton.logrotate
Added
@@ -0,0 +1,8 @@ +/var/log/kolab-syncroton/console /var/log/kolab-syncroton/errors /var/log/kolab-syncroton/imap /var/log/kolab-syncroton/ldap /var/log/kolab-syncroton/sendmail /var/log/kolab-syncroton/sieve /var/log/kolab-syncroton/smtp /var/log/kolab-syncroton/sql /var/log/kolab-syncroton/userlogins /var/log/kolab-syncroton/*/console /var/log/kolab-syncroton/*/errors /var/log/kolab-syncroton/*/imap /var/log/kolab-syncroton/*/ldap /var/log/kolab-syncroton/*/sendmail /var/log/kolab-syncroton/*/sieve /var/log/kolab-syncroton/*/smtp /var/log/kolab-syncroton/*/sql /var/log/kolab-syncroton/*/userlogins { + missingok + compress + notifempty + size 30k + create 0660 apache apache +} +
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/html.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/html.php
Changed
@@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | This file is part of the Roundcube Webmail client | - | Copyright (C) 2005-2011, The Roundcube Dev Team | + | Copyright (C) 2005-2013, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -32,8 +32,8 @@ public static $doctype = 'xhtml'; public static $lc_tags = true; - public static $common_attrib = array('id','class','style','title','align'); - public static $containers = array('iframe','div','span','p','h1','h2','h3','form','textarea','table','thead','tbody','tr','th','td','style','script'); + public static $common_attrib = array('id','class','style','title','align','unselectable'); + public static $containers = array('iframe','div','span','p','h1','h2','h3','ul','form','textarea','table','thead','tbody','tr','th','td','style','script'); /**
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube.php
Changed
@@ -642,10 +642,11 @@ /** * Load a localization package * - * @param string Language ID - * @param array Additional text labels/messages + * @param string $lang Language ID + * @param array $add Additional text labels/messages + * @param array $merge Additional text labels/messages to merge */ - public function load_language($lang = null, $add = array()) + public function load_language($lang = null, $add = array(), $merge = array()) { $lang = $this->language_prop(($lang ? $lang : $_SESSION['language'])); @@ -685,6 +686,11 @@ if (is_array($add) && !empty($add)) { $this->texts += $add; } + + // merge additional texts (from plugin) + if (is_array($merge) && !empty($merge)) { + $this->texts = array_merge($this->texts, $merge); + } } @@ -1146,7 +1152,6 @@ // handle PHP exceptions if (is_object($arg) && is_a($arg, 'Exception')) { $arg = array( - 'type' => 'php', 'code' => $arg->getCode(), 'line' => $arg->getLine(), 'file' => $arg->getFile(), @@ -1154,7 +1159,7 @@ ); } else if (is_string($arg)) { - $arg = array('message' => $arg, 'type' => 'php'); + $arg = array('message' => $arg); } if (empty($arg['code'])) { @@ -1170,7 +1175,7 @@ $cli = php_sapi_name() == 'cli'; - if (($log || $terminate) && !$cli && $arg['type'] && $arg['message']) { + if (($log || $terminate) && !$cli && $arg['message']) { $arg['fatal'] = $terminate; self::log_bug($arg); } @@ -1198,7 +1203,7 @@ */ public static function log_bug($arg_arr) { - $program = strtoupper($arg_arr['type']); + $program = strtoupper(!empty($arg_arr['type']) ? $arg_arr['type'] : 'php'); $level = self::get_instance()->config->get('debug_level'); // disable errors for ajax requests, write to log instead (#1487831) @@ -1537,6 +1542,10 @@ !empty($response) ? join('; ', $response) : '')); } } + else { + // allow plugins to catch sending errors with the same parameters as in 'message_before_send' + $this->plugins->exec_hook('message_send_error', $plugin + array('error' => $error)); + } if (is_resource($msg_body)) { fclose($msg_body);
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_addressbook.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_addressbook.php
Changed
@@ -209,6 +209,7 @@ public function validate(&$save_data, $autofix = false) { $rcube = rcube::get_instance(); + $valid = true; // check validity of email addresses foreach ($this->get_col_values('email', $save_data, true) as $email) { @@ -216,12 +217,28 @@ if (!rcube_utils::check_email(rcube_utils::idn_to_ascii($email))) { $error = $rcube->gettext(array('name' => 'emailformaterror', 'vars' => array('email' => $email))); $this->set_error(self::ERROR_VALIDATE, $error); - return false; + $valid = false; + break; } } } - return true; + // allow plugins to do contact validation and auto-fixing + $plugin = $rcube->plugins->exec_hook('contact_validate', array( + 'record' => $save_data, + 'autofix' => $autofix, + 'valid' => $valid, + )); + + if ($valid && !$plugin['valid']) { + $this->set_error(self::ERROR_VALIDATE, $plugin['error']); + } + + if (is_array($plugin['record'])) { + $save_data = $plugin['record']; + } + + return $plugin['valid']; } /** @@ -264,7 +281,8 @@ * @param array Assoziative array with save data * Keys: Field name with optional section in the form FIELD:SECTION * Values: Field value. Can be either a string or an array of strings for multiple values - * @return boolean True on success, False on error + * + * @return mixed On success if ID has been changed returns ID, otherwise True, False on error */ function update($id, $save_cols) { @@ -294,8 +312,10 @@ /** * Mark all records in database as deleted + * + * @param bool $with_groups Remove also groups */ - function delete_all() + function delete_all($with_groups = false) { /* empty for read-only address books */ } @@ -515,8 +535,12 @@ $fn = join(' ', array($contact['surname'], $contact['firstname'], $contact['middlename'])); else if ($compose_mode == 1) $fn = join(' ', array($contact['firstname'], $contact['middlename'], $contact['surname'])); - else + else if ($compose_mode == 0) $fn = !empty($contact['name']) ? $contact['name'] : join(' ', array($contact['prefix'], $contact['firstname'], $contact['middlename'], $contact['surname'], $contact['suffix'])); + else { + $plugin = rcube::get_instance()->plugins->exec_hook('contact_listname', array('contact' => $contact)); + $fn = $plugin['fn']; + } $fn = trim($fn, ', ');
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_browser.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_browser.php
Changed
@@ -28,32 +28,24 @@ { $HTTP_USER_AGENT = strtolower($_SERVER['HTTP_USER_AGENT']); - $this->ver = 0; - $this->win = strpos($HTTP_USER_AGENT, 'win') != false; - $this->mac = strpos($HTTP_USER_AGENT, 'mac') != false; + $this->ver = 0; + $this->win = strpos($HTTP_USER_AGENT, 'win') != false; + $this->mac = strpos($HTTP_USER_AGENT, 'mac') != false; $this->linux = strpos($HTTP_USER_AGENT, 'linux') != false; $this->unix = strpos($HTTP_USER_AGENT, 'unix') != false; - $this->opera = strpos($HTTP_USER_AGENT, 'opera') !== false; - $this->ns4 = strpos($HTTP_USER_AGENT, 'mozilla/4') !== false && strpos($HTTP_USER_AGENT, 'msie') === false; - $this->ns = ($this->ns4 || strpos($HTTP_USER_AGENT, 'netscape') !== false); - $this->ie = !$this->opera && strpos($HTTP_USER_AGENT, 'compatible; msie') !== false; - $this->khtml = strpos($HTTP_USER_AGENT, 'khtml') !== false; - $this->mz = !$this->ie && !$this->khtml && strpos($HTTP_USER_AGENT, 'mozilla/5') !== false; + $this->opera = strpos($HTTP_USER_AGENT, 'opera') !== false; + $this->ns = strpos($HTTP_USER_AGENT, 'netscape') !== false; $this->chrome = strpos($HTTP_USER_AGENT, 'chrome') !== false; - $this->safari = !$this->chrome && ($this->khtml || strpos($HTTP_USER_AGENT, 'safari') !== false); + $this->ie = !$this->opera && (strpos($HTTP_USER_AGENT, 'compatible; msie') !== false || strpos($HTTP_USER_AGENT, 'trident/') !== false); + $this->safari = !$this->chrome && (strpos($HTTP_USER_AGENT, 'safari') !== false || strpos($HTTP_USER_AGENT, 'applewebkit') !== false); + $this->mz = !$this->ie && !$this->safari && !$this->chrome && !$this->ns && strpos($HTTP_USER_AGENT, 'mozilla') !== false; - if ($this->ns || $this->chrome) { - $test = preg_match('/(mozilla|chrome)\/([0-9.]+)/', $HTTP_USER_AGENT, $regs); - $this->ver = $test ? (float)$regs[2] : 0; + if (preg_match('/(chrome|msie|opera|version|khtml)(\s*|\/)([0-9.]+)/', $HTTP_USER_AGENT, $regs)) { + $this->ver = (float) $regs[3]; } - else if ($this->mz) { - $test = preg_match('/rv:([0-9.]+)/', $HTTP_USER_AGENT, $regs); - $this->ver = $test ? (float)$regs[1] : 0; - } - else if ($this->ie || $this->opera) { - $test = preg_match('/(msie|opera) ([0-9.]+)/', $HTTP_USER_AGENT, $regs); - $this->ver = $test ? (float)$regs[2] : 0; + else if (preg_match('/rv:([0-9.]+)/', $HTTP_USER_AGENT, $regs)) { + $this->ver = (float) $regs[1]; } if (preg_match('/ ([a-z]{2})-([a-z]{2})/', $HTTP_USER_AGENT, $regs)) @@ -61,10 +53,10 @@ else $this->lang = 'en'; - $this->dom = ($this->mz || $this->safari || ($this->ie && $this->ver>=5) || ($this->opera && $this->ver>=7)); + $this->dom = $this->mz || $this->safari || ($this->ie && $this->ver>=5) || ($this->opera && $this->ver>=7); $this->pngalpha = $this->mz || $this->safari || ($this->ie && $this->ver>=5.5) || ($this->ie && $this->ver>=5 && $this->mac) || ($this->opera && $this->ver>=7) ? true : false; - $this->imgdata = !$this->ie; + $this->imgdata = !$this->ie; } }
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_charset.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_charset.php
Changed
@@ -199,10 +199,13 @@ $iconv_options = ''; } } + else { + $iconv_options = false; + } } // convert charset using iconv module - if ($iconv_options !== null && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP') { + if ($iconv_options !== false && $from != 'UTF7-IMAP' && $to != 'UTF7-IMAP') { // throw an exception if iconv reports an illegal character in input // it means that input string has been truncated set_error_handler(array('rcube_charset', 'error_handler'), E_NOTICE); @@ -224,10 +227,13 @@ $mbstring_list = mb_list_encodings(); $mbstring_list = array_map('strtoupper', $mbstring_list); } + else { + $mbstring_list = false; + } } // convert charset using mbstring module - if ($mbstring_list !== null) { + if ($mbstring_list !== false) { $aliases['WINDOWS-1257'] = 'ISO-8859-13'; // it happens that mbstring supports ASCII but not US-ASCII if (($from == 'US-ASCII' || $to == 'US-ASCII') && !in_array('US-ASCII', $mbstring_list)) {
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_config.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_config.php
Changed
@@ -373,7 +373,11 @@ */ public function all() { - return $this->prop; + $rcube = rcube::get_instance(); + $plugin = $rcube->plugins->exec_hook('config_get', array( + 'name' => '*', 'result' => $this->prop)); + + return $plugin['result']; } /**
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_contacts.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_contacts.php
Changed
@@ -350,7 +350,7 @@ if (in_array($col, $this->table_cols)) { switch ($mode) { case 1: // strict - $where[] = '(' . $this->db->quoteIdentifier($col) . ' = ' . $this->db->quote($val) + $where[] = '(' . $this->db->quote_identifier($col) . ' = ' . $this->db->quote($val) . ' OR ' . $this->db->ilike($col, $val . $AS . '%') . ' OR ' . $this->db->ilike($col, '%' . $AS . $val . $AS . '%') . ' OR ' . $this->db->ilike($col, '%' . $AS . $val) . ')'; @@ -390,7 +390,7 @@ } foreach (array_intersect($required, $this->table_cols) as $col) { - $and_where[] = $this->db->quoteIdentifier($col).' <> '.$this->db->quote(''); + $and_where[] = $this->db->quote_identifier($col).' <> '.$this->db->quote(''); } if (!empty($where)) { @@ -592,8 +592,8 @@ // validate e-mail addresses $valid = parent::validate($save_data, $autofix); - // require at least one e-mail address (syntax check is already done) - if ($valid && !array_filter($this->get_col_values('email', $save_data, true))) { + // require at least one email address or a name + if ($valid && !strlen($save_data['firstname'].$save_data['surname'].$save_data['name']) && !array_filter($this->get_col_values('email', $save_data, true))) { $this->set_error(self::ERROR_VALIDATE, 'noemailwarning'); $valid = false; } @@ -626,11 +626,11 @@ } } - $save_data = $this->convert_save_data($save_data); + $save_data = $this->convert_save_data($save_data); $a_insert_cols = $a_insert_values = array(); foreach ($save_data as $col => $value) { - $a_insert_cols[] = $this->db->quoteIdentifier($col); + $a_insert_cols[] = $this->db->quote_identifier($col); $a_insert_values[] = $this->db->quote($value); } @@ -655,17 +655,18 @@ * * @param mixed Record identifier * @param array Assoziative array with save data + * * @return boolean True on success, False on error */ function update($id, $save_cols) { - $updated = false; + $updated = false; $write_sql = array(); - $record = $this->get_record($id, true); + $record = $this->get_record($id, true); $save_cols = $this->convert_save_data($save_cols, $record); foreach ($save_cols as $col => $value) { - $write_sql[] = sprintf("%s=%s", $this->db->quoteIdentifier($col), $this->db->quote($value)); + $write_sql[] = sprintf("%s=%s", $this->db->quote_identifier($col), $this->db->quote($value)); } if (!empty($write_sql)) { @@ -683,7 +684,7 @@ $this->result = null; // clear current result (from get_record()) } - return $updated; + return $updated ? true : false; } @@ -812,16 +813,30 @@ /** * Remove all records from the database + * + * @param bool $with_groups Remove also groups + * + * @return int Number of removed records */ - function delete_all() + function delete_all($with_groups = false) { $this->cache = null; - $this->db->query("UPDATE ".$this->db->table_name($this->db_name). - " SET del=1, changed=".$this->db->now(). - " WHERE user_id = ?", $this->user_id); + $this->db->query("UPDATE " . $this->db->table_name($this->db_name) + . " SET del = 1, changed = " . $this->db->now() + . " WHERE user_id = ?", $this->user_id); - return $this->db->affected_rows(); + $count = $this->db->affected_rows(); + + if ($with_groups) { + $this->db->query("UPDATE " . $this->db->table_name($this->db_groups) + . " SET del = 1, changed = " . $this->db->now() + . " WHERE user_id = ?", $this->user_id); + + $count += $this->db->affected_rows(); + } + + return $count; } @@ -860,11 +875,11 @@ function delete_group($gid) { // flag group record as deleted - $sql_result = $this->db->query( - "UPDATE ".$this->db->table_name($this->db_groups). - " SET del=1, changed=".$this->db->now(). - " WHERE contactgroup_id=?". - " AND user_id=?", + $this->db->query( + "UPDATE " . $this->db->table_name($this->db_groups) + . " SET del = 1, changed = " . $this->db->now() + . " WHERE contactgroup_id = ?" + . " AND user_id = ?", $gid, $this->user_id ); @@ -873,7 +888,6 @@ return $this->db->affected_rows(); } - /** * Rename a specific contact group *
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_csv2vcard.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_csv2vcard.php
Changed
@@ -47,7 +47,7 @@ //'business_street_2' => '', //'business_street_3' => '', 'car_phone' => 'phone:car', - 'categories' => 'categories', + 'categories' => 'groups', //'children' => '', 'company' => 'organization', //'company_main_phone' => '', @@ -146,6 +146,9 @@ 'work_title' => 'jobtitle', 'work_zip' => 'zipcode:work', 'group' => 'groups', + + // GMail + 'groups' => 'groups', ); /** @@ -427,6 +430,11 @@ $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d']; } + // categories/groups separator in vCard is ',' not ';' + if (!empty($contact['groups'])) { + $contact['groups'] = str_replace(';', ',', $contact['groups']); + } + // Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00" foreach (array('birthday', 'anniversary') as $key) { if (!empty($contact[$key])) {
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_db.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_db.php
Changed
@@ -392,7 +392,7 @@ */ protected function _query($query, $offset, $numrows, $params) { - $query = trim($query); + $query = ltrim($query); $this->db_connect($this->dsn_select($query), true); @@ -405,27 +405,28 @@ $query = $this->set_limit($query, $numrows, $offset); } - $params = (array) $params; - // Because in Roundcube we mostly use queries that are // executed only once, we will not use prepared queries $pos = 0; $idx = 0; - while ($pos = strpos($query, '?', $pos)) { - if ($query[$pos+1] == '?') { // skip escaped ? - $pos += 2; - } - else { - $val = $this->quote($params[$idx++]); - unset($params[$idx-1]); - $query = substr_replace($query, $val, $pos, 1); - $pos += strlen($val); + if (count($params)) { + while ($pos = strpos($query, '?', $pos)) { + if ($query[$pos+1] == '?') { // skip escaped '?' + $pos += 2; + } + else { + $val = $this->quote($params[$idx++]); + unset($params[$idx-1]); + $query = substr_replace($query, $val, $pos, 1); + $pos += strlen($val); + } } } - // replace escaped ? back to normal - $query = rtrim(strtr($query, array('??' => '?')), ';'); + // replace escaped '?' back to normal, see self::quote() + $query = str_replace('??', '?', $query); + $query = rtrim($query, " \t\n\r\0\x0B;"); $this->debug($query);
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_html2text.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_html2text.php
Changed
@@ -608,7 +608,7 @@ $this->width = $p_width; // Add citation markers and create <pre> block - $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_ballback'), trim($body)); + $body = preg_replace_callback('/((?:^|\n)>*)([^\n]*)/', array($this, 'blockquote_citation_callback'), trim($body)); $body = '<pre>' . htmlspecialchars($body) . '</pre>'; $text = substr_replace($text, $body . "\n", $start, $end + 13 - $start); @@ -624,7 +624,7 @@ /** * Callback function to correctly add citation markers for blockquote contents */ - public function blockquote_citation_ballback($m) + public function blockquote_citation_callback($m) { $line = ltrim($m[2]); $space = $line[0] == '>' ? '' : ' ';
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_imap.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_imap.php
Changed
@@ -680,6 +680,41 @@ /** + * Public method for listing message flags + * + * @param string $folder Folder name + * @param array $uids Message UIDs + * @param int $mod_seq Optional MODSEQ value (of last flag update) + * + * @return array Indexed array with message flags + */ + public function list_flags($folder, $uids, $mod_seq = null) + { + if (!strlen($folder)) { + $folder = $this->folder; + } + + if (!$this->check_connection()) { + return array(); + } + + // @TODO: when cache was synchronized in this request + // we might already have asked for flag updates, use it. + + $flags = $this->conn->fetch($folder, $uids, true, array('FLAGS'), $mod_seq); + $result = array(); + + if (!empty($flags)) { + foreach ($flags as $message) { + $result[$message->uid] = $message->flags; + } + } + + return $result; + } + + + /** * Public method for listing headers * * @param string $folder Folder name @@ -2121,7 +2156,7 @@ // convert charset (if text or message part) if ($body && preg_match('/^(text|message)$/', $o_part->ctype_primary)) { // Remove NULL characters if any (#1486189) - if (strpos($body, "\x00") !== false) { + if ($formatted && strpos($body, "\x00") !== false) { $body = str_replace("\x00", '', $body); } @@ -2843,12 +2878,21 @@ /** * Filter the given list of folders according to access rights + * + * For performance reasons we assume user has full rights + * on all personal folders. */ protected function filter_rights($a_folders, $rights) { $regex = '/('.$rights.')/'; + foreach ($a_folders as $idx => $folder) { + if ($this->folder_namespace($folder) == 'personal') { + continue; + } + $myrights = join('', (array)$this->my_rights($folder)); + if ($myrights !== null && !preg_match($regex, $myrights)) { unset($a_folders[$idx]); } @@ -3848,9 +3892,12 @@ /** * Sort folders first by default folders and then in alphabethical order * - * @param array $a_folders Folders list + * @param array $a_folders Folders list + * @param bool $skip_default Skip default folders handling + * + * @return array Sorted list */ - protected function sort_folder_list($a_folders) + public function sort_folder_list($a_folders, $skip_default = false) { $a_out = $a_defaults = $folders = array(); @@ -3862,7 +3909,7 @@ continue; } - if (($p = array_search($folder, $this->default_folders)) !== false && !$a_defaults[$p]) { + if (!$skip_default && ($p = array_search($folder, $this->default_folders)) !== false && !$a_defaults[$p]) { $a_defaults[$p] = $folder; } else {
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_imap_cache.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_imap_cache.php
Changed
@@ -1250,10 +1250,8 @@ unset($msg->replaces); - if (is_array($msg->structure->parts)) { - foreach ($msg->structure->parts as $part) { - $this->message_object_prepare($part, $size); - } + if (is_object($msg->structure)) { + $this->message_object_prepare($msg->structure, $size); } if (is_array($msg->parts)) {
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_ldap.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_ldap.php
Changed
@@ -52,7 +52,7 @@ * * @var array */ - private static $group_types = array( + private $group_types = array( 'group' => 'member', 'groupofnames' => 'member', 'kolabgroupofnames' => 'member', @@ -94,6 +94,9 @@ $this->prop['groups']['name_attr'] = 'cn'; if (empty($this->prop['groups']['scope'])) $this->prop['groups']['scope'] = 'sub'; + // extend group objectclass => member attribute mapping + if (!empty($this->prop['groups']['class_member_attr'])) + $this->group_types = array_merge($this->group_types, $this->prop['groups']['class_member_attr']); // add group name attrib to the list of attributes to be fetched $fetch_attributes[] = $this->prop['groups']['name_attr']; @@ -292,6 +295,14 @@ 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_attribs = array('uid'); + if ($search_bind_attrib = (array)$this->prop['search_bind_attrib']) { + foreach ($search_bind_attrib as $r => $attr) { + $search_attribs[] = $attr; + $replaces[$r] = ''; + } + } + $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); @@ -321,10 +332,18 @@ } } - $res = $ldap->search($search_base_dn, $search_filter, 'sub', array('uid')); + $res = $ldap->search($search_base_dn, $search_filter, 'sub', $search_attribs); if ($res) { $res->rewind(); $replaces['%dn'] = $res->get_dn(); + + // add more replacements from 'search_bind_attrib' config + if ($search_bind_attrib) { + $res = $res->current(); + foreach ($search_bind_attrib as $r => $attr) { + $replaces[$r] = $res[$attr][0]; + } + } } if ($ldap != $this->ldap) { @@ -355,6 +374,23 @@ $this->base_dn = strtr($this->base_dn, $replaces); $this->groups_base_dn = strtr($this->groups_base_dn, $replaces); + // replace placeholders in filter settings + if (!empty($this->prop['filter'])) + $this->prop['filter'] = strtr($this->prop['filter'], $replaces); + if (!empty($this->prop['groups']['filter'])) + $this->prop['groups']['filter'] = strtr($this->prop['groups']['filter'], $replaces); + if (!empty($this->prop['groups']['member_filter'])) + $this->prop['groups']['member_filter'] = strtr($this->prop['groups']['member_filter'], $replaces); + + if (!empty($this->prop['group_filters'])) { + foreach ($this->prop['group_filters'] as $i => $gf) { + if (!empty($gf['base_dn'])) + $this->prop['group_filters'][$i]['base_dn'] = strtr($gf['base_dn'], $replaces); + if (!empty($gf['filter'])) + $this->prop['group_filters'][$i]['filter'] = strtr($gf['filter'], $replaces); + } + } + if (empty($bind_user)) { $bind_user = $u; } @@ -559,9 +595,10 @@ /** * Get all members of the given group * - * @param string Group DN - * @param array Group entries (if called recursively) - * @return array Accumulated group members + * @param string Group DN + * @param boolean Count only + * @param array Group entries (if called recursively) + * @return array Accumulated group members */ function list_group_members($dn, $count = false, $entries = null) { @@ -569,7 +606,7 @@ // fetch group object if (empty($entries)) { - $attribs = array('dn','objectClass','member','uniqueMember','memberURL'); + $attribs = array_merge(array('dn','objectClass','memberURL'), array_values($this->group_types)); $entries = $this->ldap->read_entries($dn, '(objectClass=*)', $attribs); if ($entries === false) { return $group_members; @@ -581,17 +618,17 @@ $attrs = array(); foreach ((array)$entry['objectclass'] as $objectclass) { - if (strtolower($objectclass) == 'groupofurls') { - $members = $this->_list_group_memberurl($dn, $entry, $count); - $group_members = array_merge($group_members, $members); - } - else if (($member_attr = $this->get_group_member_attr(array($objectclass), '')) + if (($member_attr = $this->get_group_member_attr(array($objectclass), '')) && ($member_attr = strtolower($member_attr)) && !in_array($member_attr, $attrs) ) { $members = $this->_list_group_members($dn, $entry, $member_attr, $count); $group_members = array_merge($group_members, $members); $attrs[] = $member_attr; } + else if (!empty($entry['memberurl'])) { + $members = $this->_list_group_memberurl($dn, $entry, $count); + $group_members = array_merge($group_members, $members); + } if ($this->prop['sizelimit'] && count($group_members) > $this->prop['sizelimit']) { break 2; @@ -608,6 +645,7 @@ * @param string Group DN * @param array Group entry * @param string Member attribute to use + * @param boolean Count only * @return array Accumulated group members */ private function _list_group_members($dn, $entry, $attr, $count) @@ -621,8 +659,7 @@ // read these attributes for all members $attrib = $count ? array('dn','objectClass') : $this->prop['list_attributes']; - $attrib[] = 'member'; - $attrib[] = 'uniqueMember'; + $attrib = array_merge($attrib, array_values($this->group_types)); $attrib[] = 'memberURL'; $filter = $this->prop['groups']['member_filter'] ? $this->prop['groups']['member_filter'] : '(objectclass=*)'; @@ -669,7 +706,7 @@ if ($result = $this->ldap->search($m[1], $filter, $m[2], $attrs, $this->group_data)) { $entries = $result->entries(); for ($j = 0; $j < $entries['count']; $j++) { - if (self::is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count))) + if ($this->is_group_entry($entries[$j]) && ($nested_group_members = $this->list_group_members($entries[$j]['dn'], $count))) $group_members = array_merge($group_members, $nested_group_members); else $group_members[] = $entries[$j]; @@ -1287,8 +1324,10 @@ /** * Remove all contact records + * + * @param bool $with_groups Delete also groups if enabled */ - function delete_all() + function delete_all($with_groups = false) { // searching for contact entries $dn_list = $this->ldap->list_entries($this->base_dn, $this->prop['filter'] ? $this->prop['filter'] : '(objectclass=*)'); @@ -1299,6 +1338,16 @@ } $this->delete($dn_list); } + + if ($with_groups && $this->groups && ($groups = $this->_fetch_groups()) && count($groups)) { + foreach ($groups as $group) { + $this->ldap->delete($group['dn']); + } + + if ($this->cache) { + $this->cache->remove('groups'); + } + } } /** @@ -1354,7 +1403,7 @@ $out[$this->primary_key] = self::dn_encode($rec['dn']); // determine record type - if (self::is_group_entry($rec)) { + if ($this->is_group_entry($rec)) { $out['_type'] = 'group'; $out['readonly'] = true; $fieldmap['name'] = $this->group_data['name_attr'] ? $this->group_data['name_attr'] : $this->prop['groups']['name_attr']; @@ -1479,11 +1528,11 @@ /** * Determines whether the given LDAP entry is a group record */ - private static function is_group_entry($entry) + private function is_group_entry($entry) { $classes = array_map('strtolower', (array)$entry['objectclass']); - return count(array_intersect(array_keys(self::$group_types), $classes)) > 0; + return count(array_intersect(array_keys($this->group_types), $classes)) > 0;
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_message.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_message.php
Changed
@@ -211,16 +211,19 @@ } $level = explode('.', $part->mime_id); + $depth = count($level); // Check if the part belongs to higher-level's multipart part - // this can be alternative/related/signed/encrypted, but not mixed + // this can be alternative/related/signed/encrypted or mixed while (array_pop($level) !== null) { - if (!count($level)) { + $parent_depth = count($level); + if (!$parent_depth) { return true; } $parent = $this->mime_parts[join('.', $level)]; - if (!preg_match('/^multipart\/(alternative|related|signed|encrypted)$/', $parent->mimetype)) { + if (!preg_match('/^multipart\/(alternative|related|signed|encrypted|mixed)$/', $parent->mimetype) + || ($parent->mimetype == 'multipart/mixed' && $parent_depth < $depth - 1)) { continue 2; } } @@ -529,8 +532,9 @@ $part_mimetype = $mail_part->real_mimetype; list($primary_type, $secondary_type) = explode('/', $part_mimetype); } - else - $part_mimetype = $mail_part->mimetype; + else { + $part_mimetype = $part_orig_mimetype = $mail_part->mimetype; + } // multipart/alternative if ($primary_type == 'multipart') {
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_mime.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_mime.php
Changed
@@ -810,7 +810,7 @@ } $mime_types = $mime_extensions = array(); - $regex = "/([\w\+\-\.\/]+)\t+([\w\s]+)/i"; + $regex = "/([\w\+\-\.\/]+)\s+([\w\s]+)/i"; foreach((array)$lines as $line) { // skip comments or mime types w/o any extensions if ($line[0] == '#' || !preg_match($regex, $line, $matches))
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_plugin.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_plugin.php
Changed
@@ -109,7 +109,7 @@ */ public function require_plugin($plugin_name) { - return $this->api->load_plugin($plugin_name); + return $this->api->load_plugin($plugin_name, true); } /**
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_plugin_api.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_plugin_api.php
Changed
@@ -35,8 +35,9 @@ public $url = 'plugins/'; public $task = ''; public $output; - public $handlers = array(); - public $allowed_prefs = array(); + public $handlers = array(); + public $allowed_prefs = array(); + public $allowed_session_prefs = array(); protected $plugins = array(); protected $tasks = array(); @@ -167,10 +168,11 @@ * Load the specified plugin * * @param string Plugin name + * @param boolean Force loading of the plugin even if it doesn't match the filter * * @return boolean True on success, false if not loaded or failure */ - public function load_plugin($plugin_name) + public function load_plugin($plugin_name, $force = false) { static $plugins_dir; @@ -196,7 +198,7 @@ // check inheritance... if (is_subclass_of($plugin, 'rcube_plugin')) { // ... task, request type and framed mode - if ((!$plugin->task || preg_match('/^('.$plugin->task.')$/i', $this->task)) + if (($force || !$plugin->task || preg_match('/^('.$plugin->task.')$/i', $this->task)) && (!$plugin->noajax || (is_object($this->output) && $this->output->type == 'html')) && (!$plugin->noframe || empty($_REQUEST['_framed'])) ) { @@ -282,6 +284,7 @@ $composer = INSTALL_PATH . "/plugins/$plugin_name/composer.json"; if (file_exists($composer) && ($json = @json_decode(file_get_contents($composer), true))) { list($info['vendor'], $info['name']) = explode('/', $json['name']); + $info['version'] = $json['version']; $info['license'] = $json['license']; if ($license_uri = $license_uris[$info['license']]) $info['license_uri'] = $license_uri;
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_session.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_session.php
Changed
@@ -34,6 +34,7 @@ private $changed; private $time_diff = 0; private $reloaded = false; + private $appends = array(); private $unsets = array(); private $gc_handlers = array(); private $cookiename = 'roundcube_sessauth'; @@ -441,8 +442,19 @@ $node = &$this->get_node(explode('.', $path), $_SESSION); - if ($key !== null) $node[$key] = $value; - else $node[] = $value; + if ($key !== null) { + $node[$key] = $value; + $path .= '.' . $key; + } + else { + $node[] = $value; + } + + $this->appends[] = $path; + + // when overwriting a previously unset variable + if ($this->unsets[$path]) + unset($this->unsets[$path]); } @@ -491,13 +503,40 @@ */ public function reload() { + // collect updated data from previous appends + $merge_data = array(); + foreach ((array)$this->appends as $var) { + $path = explode('.', $var); + $value = $this->get_node($path, $_SESSION); + $k = array_pop($path); + $node = &$this->get_node($path, $merge_data); + $node[$k] = $value; + } + if ($this->key && $this->memcache) $data = $this->mc_read($this->key); else if ($this->key) $data = $this->db_read($this->key); - if ($data) + if ($data) { session_decode($data); + + // apply appends and unsets to reloaded data + $_SESSION = array_merge_recursive($_SESSION, $merge_data); + + foreach ((array)$this->unsets as $var) { + if (isset($_SESSION[$var])) { + unset($_SESSION[$var]); + } + else { + $path = explode('.', $var); + $k = array_pop($path); + $node = &$this->get_node($path, $_SESSION); + unset($node[$k]); + } + } + } + } /**
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_spellcheck_atd.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_spellcheck_atd.php
Changed
@@ -39,6 +39,18 @@ ); /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $langs = array_values($this->langhosts); + $langs[] = 'en'; + return $langs; + } + + /** * Set content and check spelling * * @see rcube_spellcheck_engine::check()
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_spellcheck_enchant.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_spellcheck_enchant.php
Changed
@@ -31,6 +31,24 @@ private $matches = array(); /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $this->init(); + + $langs = array(); + $dicts = enchant_broker_list_dicts($this->enchant_broker); + foreach ($dicts as $dict) { + $langs[] = preg_replace('/-.*$/', '', $dict['lang_tag']); + } + + return array_unique($langs); + } + + /** * Initializes Enchant dictionary */ private function init()
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_spellcheck_engine.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_spellcheck_engine.php
Changed
@@ -43,6 +43,13 @@ } /** + * Return a list of languages supported by this backend + * + * @return array Indexed list of language codes + */ + abstract function languages(); + + /** * Set content and check spelling * * @param string $text Text content for spellchecking
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_spellcheck_googie.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_spellcheck_googie.php
Changed
@@ -26,13 +26,28 @@ */ class rcube_spellcheck_googie extends rcube_spellcheck_engine { - const GOOGLE_HOST = 'ssl://www.google.com'; - const GOOGLE_PORT = 443; + const GOOGIE_HOST = 'ssl://spell.roundcube.net'; + const GOOGIE_PORT = 443; private $matches = array(); private $content; /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + return array('am','ar','ar','bg','br','ca','cs','cy','da', + 'de_CH','de_DE','el','en_GB','en_US', + 'eo','es','et','eu','fa','fi','fr_FR','ga','gl','gl', + 'he','hr','hu','hy','is','it','ku','lt','lv','nl', + 'pl','pt_BR','pt_PT','ro','ru', + 'sk','sl','sv','uk'); + } + + /** * Set content and check spelling * * @see rcube_spellcheck_engine::check() @@ -52,25 +67,25 @@ $path = $a_uri['path'] . ($a_uri['query'] ? '?'.$a_uri['query'] : '') . $this->lang; } else { - $host = self::GOOGLE_HOST; - $port = self::GOOGLE_PORT; + $host = self::GOOGIE_HOST; + $port = self::GOOGIE_PORT; $path = '/tbproxy/spell?lang=' . $this->lang; } - // Google has some problem with spaces, use \n instead - $gtext = str_replace(' ', "\n", $text); + $path .= sprintf('&key=%06d', $_SESSION['user_id']); $gtext = '<?xml version="1.0" encoding="utf-8" ?>' .'<spellrequest textalreadyclipped="0" ignoredups="0" ignoredigits="1" ignoreallcaps="1">' - .'<text>' . $gtext . '</text>' + .'<text>' . htmlspecialchars($text, ENT_QUOTES, RCUBE_CHARSET) . '</text>' .'</spellrequest>'; $store = ''; if ($fp = fsockopen($host, $port, $errno, $errstr, 30)) { $out = "POST $path HTTP/1.0\r\n"; $out .= "Host: " . str_replace('ssl://', '', $host) . "\r\n"; + $out .= "User-Agent: Roundcube Webmail/" . RCMAIL_VERSION . " (Googiespell Wrapper)\r\n"; $out .= "Content-Length: " . strlen($gtext) . "\r\n"; - $out .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $out .= "Content-Type: text/xml\r\n"; $out .= "Connection: Close\r\n\r\n"; $out .= $gtext; fwrite($fp, $out); @@ -83,8 +98,10 @@ // parse HTTP response if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) { $http_status = $m[1]; - if ($http_status != '200') + if ($http_status != '200') { $this->error = 'HTTP ' . $m[1] . $m[2]; + $this->error .= "\n" . $store; + } } if (!$store) { @@ -92,6 +109,7 @@ } else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m) && $m[1]) { $this->error = "Error code $m[1] returned"; + $this->error .= preg_match('/<errortext>([^<]+)/', $store, $m) ? ": " . html_entity_decode($m[1]) : ''; } preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER);
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_spellcheck_pspell.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_spellcheck_pspell.php
Changed
@@ -30,6 +30,35 @@ private $matches = array(); /** + * Return a list of languages supported by this backend + * + * @see rcube_spellcheck_engine::languages() + */ + function languages() + { + $defaults = array('en'); + $langs = array(); + + // get aspell dictionaries + exec('aspell dump dicts', $dicts); + if (!empty($dicts)) { + $seen = array(); + foreach ($dicts as $lang) { + $lang = preg_replace('/-.*$/', '', $lang); + $langc = strlen($lang) == 2 ? $lang.'_'.strtoupper($lang) : $lang; + if (!$seen[$langc]++) + $langs[] = $lang; + } + $langs = array_unique($langs); + } + else { + $langs = $defaults; + } + + return $langs; + } + + /** * Initializes PSpell dictionary */ private function init()
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_spellchecker.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_spellchecker.php
Changed
@@ -65,6 +65,52 @@ } } + /** + * Return a list of supported languages + */ + function languages() + { + // trust configuration + $configured = $this->rc->config->get('spellcheck_languages'); + if (!empty($configured) && is_array($configured) && !$configured[0]) { + return $configured; + } + else if (!empty($configured)) { + $langs = (array)$configured; + } + else if ($this->backend) { + $langs = $this->backend->languages(); + } + + // load index + @include(RCUBE_LOCALIZATION_DIR . 'index.inc'); + + // add correct labels + $languages = array(); + foreach ($langs as $lang) { + $langc = strtolower(substr($lang, 0, 2)); + $alias = $rcube_language_aliases[$langc]; + if (!$alias) { + $alias = $langc.'_'.strtoupper($langc); + } + if ($rcube_languages[$lang]) { + $languages[$lang] = $rcube_languages[$lang]; + } + else if ($rcube_languages[$alias]) { + $languages[$lang] = $rcube_languages[$alias]; + } + else { + $languages[$lang] = ucfirst($lang); + } + } + + // remove possible duplicates (#1489395) + $languages = array_unique($languages); + + asort($languages); + + return $languages; + } /** * Set content and check spelling @@ -152,7 +198,7 @@ // send output $out = '<?xml version="1.0" encoding="'.RCUBE_CHARSET.'"?><spellresult charschecked="'.mb_strlen($this->content).'">'; - foreach ($this->matches as $item) { + foreach ((array)$this->matches as $item) { $out .= '<c o="'.$item[1].'" l="'.$item[2].'">'; $out .= is_array($item[4]) ? implode("\t", $item[4]) : $item[4]; $out .= '</c>'; @@ -173,7 +219,7 @@ { $result = array(); - foreach ($this->matches as $item) { + foreach ((array)$this->matches as $item) { if ($this->engine == 'pspell') { $word = $item[0]; } @@ -306,7 +352,7 @@ "UPDATE ".$this->rc->db->table_name('dictionary') ." SET data = ?" ." WHERE user_id " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") - ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", + ." AND " . $this->rc->db->quote_identifier('language') . " = ?", implode(' ', $plugin['dictionary']), $plugin['language']); } // don't store empty dict @@ -314,14 +360,14 @@ $this->rc->db->query( "DELETE FROM " . $this->rc->db->table_name('dictionary') ." WHERE user_id " . ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") - ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", + ." AND " . $this->rc->db->quote_identifier('language') . " = ?", $plugin['language']); } } else if (!empty($this->dict)) { $this->rc->db->query( "INSERT INTO " .$this->rc->db->table_name('dictionary') - ." (user_id, " . $this->rc->db->quoteIdentifier('language') . ", data) VALUES (?, ?, ?)", + ." (user_id, " . $this->rc->db->quote_identifier('language') . ", data) VALUES (?, ?, ?)", $plugin['userid'], $plugin['language'], implode(' ', $plugin['dictionary'])); } } @@ -348,7 +394,7 @@ $sql_result = $this->rc->db->query( "SELECT data FROM ".$this->rc->db->table_name('dictionary') ." WHERE user_id ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") - ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", + ." AND " . $this->rc->db->quote_identifier('language') . " = ?", $plugin['language']); if ($sql_arr = $this->rc->db->fetch_assoc($sql_result)) {
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_storage.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_storage.php
Changed
@@ -360,6 +360,18 @@ /** + * Public method for listing message flags + * + * @param string $folder Folder name + * @param array $uids Message UIDs + * @param int $mod_seq Optional MODSEQ value + * + * @return array Indexed array with message flags + */ + abstract function list_flags($folder, $uids, $mod_seq = null); + + + /** * Public method for listing headers. * * @param string $folder Folder name
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_user.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_user.php
Changed
@@ -163,8 +163,16 @@ if (!$this->ID) return false; - $config = $this->rc->config; - $old_prefs = (array)$this->get_prefs(); + $plugin = $this->rc->plugins->exec_hook('preferences_update', array( + 'userid' => $this->ID, 'prefs' => $a_user_prefs, 'old' => (array)$this->get_prefs())); + + if (!empty($plugin['abort'])) { + return; + } + + $a_user_prefs = $plugin['prefs']; + $old_prefs = $plugin['old']; + $config = $this->rc->config; // merge (partial) prefs array with existing settings $save_prefs = $a_user_prefs + $old_prefs; @@ -213,6 +221,14 @@ return false; } + /** + * Generate a unique hash to identify this user which + */ + function get_hash() + { + $key = substr($this->rc->config->get('des_key'), 1, 4); + return md5($this->data['user_id'] . $key . $this->data['username'] . '@' . $this->data['mail_host']); + } /** * Get default identity of this user @@ -249,7 +265,7 @@ "SELECT * FROM ".$this->db->table_name('identities'). " WHERE del <> 1 AND user_id = ?". ($sql_add ? " ".$sql_add : ""). - " ORDER BY ".$this->db->quoteIdentifier('standard')." DESC, name ASC, identity_id ASC", + " ORDER BY ".$this->db->quote_identifier('standard')." DESC, name ASC, identity_id ASC", $this->ID); while ($sql_arr = $this->db->fetch_assoc($sql_result)) { @@ -284,7 +300,7 @@ $query_cols = $query_params = array(); foreach ((array)$data as $col => $value) { - $query_cols[] = $this->db->quoteIdentifier($col) . ' = ?'; + $query_cols[] = $this->db->quote_identifier($col) . ' = ?'; $query_params[] = $value; } $query_params[] = $iid; @@ -320,7 +336,7 @@ $insert_cols = $insert_values = array(); foreach ((array)$data as $col => $value) { - $insert_cols[] = $this->db->quoteIdentifier($col); + $insert_cols[] = $this->db->quote_identifier($col); $insert_values[] = $value; } $insert_cols[] = 'user_id'; @@ -385,7 +401,7 @@ if ($this->ID && $iid) { $this->db->query( "UPDATE ".$this->db->table_name('identities'). - " SET ".$this->db->quoteIdentifier('standard')." = '0'". + " SET ".$this->db->quote_identifier('standard')." = '0'". " WHERE user_id = ?". " AND identity_id <> ?". " AND del <> 1", @@ -625,11 +641,11 @@ $result = array(); $sql_result = $this->db->query( - "SELECT search_id AS id, ".$this->db->quoteIdentifier('name') + "SELECT search_id AS id, ".$this->db->quote_identifier('name') ." FROM ".$this->db->table_name('searches') ." WHERE user_id = ?" - ." AND ".$this->db->quoteIdentifier('type')." = ?" - ." ORDER BY ".$this->db->quoteIdentifier('name'), + ." AND ".$this->db->quote_identifier('type')." = ?" + ." ORDER BY ".$this->db->quote_identifier('name'), (int) $this->ID, (int) $type); while ($sql_arr = $this->db->fetch_assoc($sql_result)) { @@ -657,9 +673,9 @@ } $sql_result = $this->db->query( - "SELECT ".$this->db->quoteIdentifier('name') - .", ".$this->db->quoteIdentifier('data') - .", ".$this->db->quoteIdentifier('type') + "SELECT ".$this->db->quote_identifier('name') + .", ".$this->db->quote_identifier('data') + .", ".$this->db->quote_identifier('type') ." FROM ".$this->db->table_name('searches') ." WHERE user_id = ?" ." AND search_id = ?", @@ -714,11 +730,11 @@ $insert_cols[] = 'user_id'; $insert_values[] = (int) $this->ID; - $insert_cols[] = $this->db->quoteIdentifier('type'); + $insert_cols[] = $this->db->quote_identifier('type'); $insert_values[] = (int) $data['type']; - $insert_cols[] = $this->db->quoteIdentifier('name'); + $insert_cols[] = $this->db->quote_identifier('name'); $insert_values[] = $data['name']; - $insert_cols[] = $this->db->quoteIdentifier('data'); + $insert_cols[] = $this->db->quote_identifier('data'); $insert_values[] = serialize($data['data']); $sql = "INSERT INTO ".$this->db->table_name('searches')
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_utils.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_utils.php
Changed
@@ -454,6 +454,9 @@ // cut out all contents between { and } while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { + $nested = strpos($source, '{', $pos+1); + if ($nested && $nested < $pos2) // when dealing with nested blocks (e.g. @media), take the inner one + $pos = $nested; $length = $pos2 - $pos - 1; $styles = substr($source, $pos+1, $length); @@ -619,6 +622,10 @@ */ public static function parse_host($name, $host = '') { + if (!is_string($name)) { + return $name; + } + // %n - host $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); // %t - host name without first part, e.g. %n=mail.domain.tld, %t=domain.tld @@ -639,8 +646,7 @@ } } - $name = str_replace(array('%n', '%t', '%d', '%h', '%z', '%s'), array($n, $t, $d, $h, $z, $s[2]), $name); - return $name; + return str_replace(array('%n', '%t', '%d', '%h', '%z', '%s'), array($n, $t, $d, $h, $z, $s[2]), $name); } @@ -677,9 +683,17 @@ */ public static function remote_addr() { - foreach (array('HTTP_X_FORWARDED_FOR','HTTP_X_REAL_IP','REMOTE_ADDR') as $prop) { - if (!empty($_SERVER[$prop])) - return $_SERVER[$prop]; + if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $hosts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'], 2); + return $hosts[0]; + } + + if (!empty($_SERVER['HTTP_X_REAL_IP'])) { + return $_SERVER['HTTP_X_REAL_IP']; + } + + if (!empty($_SERVER['REMOTE_ADDR'])) { + return $_SERVER['REMOTE_ADDR']; } return ''; @@ -744,40 +758,13 @@ */ 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)([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])); - } + $date = self::clean_datestr($date); // unix timestamp if (is_numeric($date)) { return (int) $date; } - // Clean malformed data - $date = preg_replace( - array( - '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal - '/[^a-z0-9\x20\x09:+-]/i', // remove any invalid characters - '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names - ), - array( - '\\1', - '', - '', - ), $date); - - $date = trim($date); - // if date parsing fails, we have a date in non-rfc format. // remove token from the end and try again while ((($ts = @strtotime($date)) === false) || ($ts < 0)) { @@ -805,8 +792,8 @@ return $date; } - $dt = false; - $date = trim($date); + $dt = false; + $date = self::clean_datestr($date); // try to parse string with DateTime first if (!empty($date)) { @@ -831,6 +818,52 @@ return $dt; } + /** + * Clean up date string for strtotime() input + * + * @param string $date Date string + * + * @return string Date string + */ + public static function clean_datestr($date) + { + $date = trim($date); + + // check for MS Outlook vCard date format YYYYMMDD + if (preg_match('/^([12][90]\d\d)([01]\d)([0123]\d)$/', $date, $m)) { + return sprintf('%04d-%02d-%02d 00:00:00', intval($m[1]), intval($m[2]), intval($m[3])); + } + + // Clean malformed data + $date = preg_replace( + array( + '/GMT\s*([+-][0-9]+)/', // support non-standard "GMTXXXX" literal + '/[^a-z0-9\x20\x09:+-\/]/i', // remove any invalid characters + '/\s*(Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s*/i', // remove weekday names + ), + array( + '\\1', + '', + '', + ), $date); + + $date = trim($date); + + // try to fix dd/mm vs. mm/dd discrepancy, we can't do more here + if (preg_match('/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/', $date, $m)) { + $mdy = $m[2] > 12 && $m[1] <= 12; + $day = $mdy ? $m[2] : $m[1]; + $month = $mdy ? $m[1] : $m[2]; + $date = sprintf('%04d-%02d-%02d 00:00:00', intval($m[3]), $month, $day); + } + // I've found that YYYY.MM.DD is recognized wrong, so here's a fix + else if (preg_match('/^(\d{4})\.(\d{1,2})\.(\d{1,2})$/', $date)) { + $date = str_replace('.', '-', $date) . ' 00:00:00'; + } + + return $date; + } + /* * Idn_to_ascii wrapper. * Intl/Idn modules version of this function doesn't work with e-mail address @@ -890,10 +923,20 @@ * * @param string Input string (UTF-8) * @param boolean True to return list of words as array + * * @return mixed Normalized string or a list of normalized tokens */ public static function normalize_string($str, $as_array = false) { + // replace 4-byte unicode characters with '?' character, + // these are not supported in default utf-8 charset on mysql, + // the chance we'd need them in searching is very low + $str = preg_replace('/(' + . '\xF0[\x90-\xBF][\x80-\xBF]{2}' + . '|[\xF1-\xF3][\x80-\xBF]{3}' + . '|\xF4[\x80-\x8F][\x80-\xBF]{2}' + . ')/', '?', $str); + // split by words $arr = self::tokenize_string($str);
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_vcard.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_vcard.php
Changed
@@ -378,7 +378,7 @@ default: if ($field == 'phone' && $this->phonetypemap[$type_uc]) { $type = $this->phonetypemap[$type_uc]; - } + } if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) { $index = count($this->raw[$tag]); @@ -518,20 +518,28 @@ */ public static function cleanup($vcard) { - // Convert special types (like Skype) to normal type='skype' classes with this simple regex ;) - $vcard = preg_replace( - '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', - '\2;type=\5\3:\4', - $vcard); - // convert Apple X-ABRELATEDNAMES into X-* fields for better compatibility $vcard = preg_replace_callback( '/item(\d+)\.(X-ABRELATEDNAMES)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', array('self', 'x_abrelatednames_callback'), $vcard); - // Remove cruft like item1.X-AB*, item1.ADR instead of ADR, and empty lines - $vcard = preg_replace(array('/^item\d*\.X-AB.*$/m', '/^item\d*\./m', "/\n+/"), array('', '', "\n"), $vcard); + // Cleanup + $vcard = preg_replace(array( + // convert special types (like Skype) to normal type='skype' classes with this simple regex ;) + '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w-() ]*)(?:>!\$_)?./s', + '/^item\d*\.X-AB.*$/m', // remove cruft like item1.X-AB* + '/^item\d*\./m', // remove item1.ADR instead of ADR + '/\n+/', // remove empty lines + '/^(N:[^;\R]*)$/m', // if N doesn't have any semicolons, add some + ), + array( + '\2;type=\5\3:\4', + '', + '', + "\n", + '\1;;;;', + ), $vcard); // convert X-WAB-GENDER to X-GENDER if (preg_match('/X-WAB-GENDER:(\d)/', $vcard, $matches)) { @@ -539,9 +547,6 @@ $vcard = preg_replace('/X-WAB-GENDER:\d/', 'X-GENDER:' . $value, $vcard); } - // if N doesn't have any semicolons, add some - $vcard = preg_replace('/^(N:[^;\R]*)$/m', '\1;;;;', $vcard); - return $vcard; } @@ -612,8 +617,8 @@ $enc = null; foreach($regs2[1] as $attrid => $attr) { + $attr = preg_replace('/[\s\t\n\r\0\x0B]/', '', $attr); if ((list($key, $value) = explode('=', $attr)) && $value) { - $value = trim($value); if ($key == 'ENCODING') { $value = strtoupper($value); // add next line(s) to value string if QP line end detected @@ -792,7 +797,7 @@ return $result; } - $s = strtr($s, $rep2); + $s = trim(strtr($s, $rep2)); } // some implementations (GMail) use non-standard backslash before colon (#1489085)
View file
kolab-syncroton-2.2.3.tar.gz/lib/ext/Roundcube/rcube_washtml.php -> kolab-syncroton-2.2.4.tar.gz/lib/ext/Roundcube/rcube_washtml.php
Changed
@@ -418,7 +418,7 @@ $html = preg_replace($html_search, $html_replace, trim($html)); //-> Replace all of those weird MS Word quotes and other high characters - $badwordchars=array( + $badwordchars = array( "\xe2\x80\x98", // left single quote "\xe2\x80\x99", // right single quote "\xe2\x80\x9c", // left double quote @@ -426,7 +426,7 @@ "\xe2\x80\x94", // em dash "\xe2\x80\xa6" // elipses ); - $fixedwordchars=array( + $fixedwordchars = array( "'", "'", '"', @@ -434,7 +434,7 @@ '—', '...' ); - $html = str_replace($badwordchars,$fixedwordchars, $html); + $html = str_replace($badwordchars, $fixedwordchars, $html); // PCRE errors handling (#1486856), should we use something like for every preg_* use? if ($html === null && ($preg_error = preg_last_error()) != PREG_NO_ERROR) { @@ -455,13 +455,16 @@ } // 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 // Don't remove MSOutlook (<!-->) conditional comments (#1489004) $html = preg_replace('/<!--[^->\[\n]+>/', '', $html); + // fix broken nested lists + self::fix_broken_lists($html); + // turn relative into absolute urls $html = self::resolve_base($html); @@ -479,7 +482,12 @@ '/[^a-z0-9_\[\]\!-]/i', // forbidden characters ), '', $tagname); - return $matches[1] . $tagname; + // fix invalid closing tags - remove any attributes (#1489446) + if ($matches[1] == '</') { + $matches[3] = ''; + } + + return $matches[1] . $tagname . $matches[3]; } /** @@ -495,5 +503,77 @@ return $body; } -} + /** + * Fix broken nested lists, they are not handled properly by DOMDocument (#1488768) + */ + public static function fix_broken_lists(&$html) + { + // do two rounds, one for <ol>, one for <ul> + foreach (array('ol', 'ul') as $tag) { + $pos = 0; + while (($pos = stripos($html, '<' . $tag, $pos)) !== false) { + $pos++; + + // make sure this is an ol/ul tag + if (!in_array($html[$pos+2], array(' ', '>'))) { + continue; + } + + $p = $pos; + $in_li = false; + $li_pos = 0; + + while (($p = strpos($html, '<', $p)) !== false) { + $tt = strtolower(substr($html, $p, 4)); + + // li open tag + if ($tt == '<li>' || $tt == '<li ') { + $in_li = true; + $p += 4; + } + // li close tag + else if ($tt == '</li' && in_array($html[$p+4], array(' ', '>'))) { + $li_pos = $p; + $p += 4; + $in_li = false; + } + // ul/ol closing tag + else if ($tt == '</' . $tag && in_array($html[$p+4], array(' ', '>'))) { + break; + } + // nested ol/ul element out of li + else if (!$in_li && $li_pos && ($tt == '<ol>' || $tt == '<ol ' || $tt == '<ul>' || $tt == '<ul ')) { + // find closing tag of this ul/ol element + $element = substr($tt, 1, 2); + $cpos = $p; + do { + $tpos = stripos($html, '<' . $element, $cpos+1); + $cpos = stripos($html, '</' . $element, $cpos+1); + } + while ($tpos !== false && $cpos !== false && $cpos > $tpos); + + // not found, this is invalid HTML, skip it + if ($cpos === false) { + break; + } + + // get element content + $end = strpos($html, '>', $cpos); + $len = $end - $p + 1; + $element = substr($html, $p, $len); + + // move element to the end of the last li + $html = substr_replace($html, '', $p, $len); + $html = substr_replace($html, $element, $li_pos, 0); + + $p = $end; + } + else { + $p++; + } + } + } + } + } +}
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync.php
Changed
@@ -43,7 +43,7 @@ public $user; const CHARSET = 'UTF-8'; - const VERSION = "2.2.3"; + const VERSION = "2.2.4"; /** @@ -131,7 +131,7 @@ } // Set log directory per-user - $this->set_log_dir($_SERVER['PHP_AUTH_USER']); + $this->set_log_dir($this->username ?: $_SERVER['PHP_AUTH_USER']); // Save user password for Roundcube Framework $this->password = $_SERVER['PHP_AUTH_PW']; @@ -191,6 +191,11 @@ 'valid' => $auth['valid'], )); } + + // LDAP server failure... send 503 error + if ($auth['kolab_ldap_error']) { + self::server_error(); + } } else { $auth['pass'] = $password; @@ -198,8 +203,10 @@ // Authenticate - get Roundcube user ID if ($auth['valid'] && !$auth['abort'] - && ($userid = $this->login($auth['user'], $auth['pass'], $auth['host'])) + && ($userid = $this->login($auth['user'], $auth['pass'], $auth['host'], $err)) ) { + // set real username + $this->username = $auth['user']; return $userid; } @@ -207,6 +214,11 @@ 'host' => $auth['host'], 'user' => $auth['user'], )); + + // IMAP server failure... send 503 error + if ($err == rcube_imap_generic::ERROR_BAD) { + self::server_error(); + } } @@ -249,7 +261,7 @@ /** * Authenticates a user in IMAP and returns Roundcube user ID. */ - private function login($username, $password, $host) + private function login($username, $password, $host, &$error = null) { if (empty($username)) { return null; @@ -301,6 +313,7 @@ // authenticate user in IMAP $storage = $this->get_storage(); if (!$storage->connect($host, $username, $password, $port, $ssl)) { + $error = $storage->get_error_code(); return null; } @@ -350,15 +363,32 @@ return; } - if (!$this->config->get('activesync_user_log')) { + $this->logger->set_username($username); + + $user_debug = $this->config->get('activesync_user_debug'); + $user_log = $user_debug || $this->config->get('activesync_user_log'); + + if (!$user_log) { return; } - $log_dir = $this->config->get('log_dir'); + $log_dir = $this->config->get('log_dir'); $log_dir .= DIRECTORY_SEPARATOR . $username; + // in user_debug mode enable logging only if user directory exists + if ($user_debug) { + if (!is_dir($log_dir)) { + return; + } + } + else if (!is_dir($log_dir)) { + if (!mkdir($log_dir, 0770)) { + return; + } + } + if (!empty($_GET['DeviceId'])) { - $log_dir .= '_' . $_GET['DeviceId']; + $log_dir .= DIRECTORY_SEPARATOR . $_GET['DeviceId']; } if (!is_dir($log_dir)) { @@ -367,6 +397,27 @@ } } + // make sure we're using debug mode where possible, + if ($user_debug) { + $this->config->set('debug_level', 1); + $this->config->set('memcache_debug', true); + $this->config->set('imap_debug', true); + $this->config->set('ldap_debug', true); + $this->config->set('smtp_debug', true); + $this->config->set('sql_debug', true); + + // SQL/IMAP debug need to be set directly on the object instance + // it's already initialized/configured + if ($db = $this->get_dbh()) { + $db->set_debug(true); + } + if ($storage = $this->get_storage()) { + $storage->set_debug(true); + } + + $this->logger->mode = kolab_sync_logger::DEBUG; + } + $this->config->set('log_dir', $log_dir); // re-set PHP error logging @@ -377,6 +428,19 @@ /** + * Send HTTP 503 response. + * We send it on LDAP/IMAP server error instead of 401 (Unauth), + * so devices will not ask for new password. + */ + public static function server_error() + { + header("HTTP/1.1 503 Service Temporarily Unavailable"); + header("Retry-After: 120"); + exit; + } + + + /** * Function to be executed in script shutdown */ public function shutdown()
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync_backend.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync_backend.php
Changed
@@ -398,37 +398,8 @@ // Update local cache $this->root_meta['DEVICE'][$id] = $device; - // Subscribe to default folders - $foldertypes = kolab_storage::folders_typedata(); - - if (!empty($foldertypes)) { - $types = array( - 'mail.drafts', - 'mail.wastebasket', - 'mail.sentitems', - 'mail.outbox', - 'event.default', - 'contact.default', - 'task.default', - 'event', - 'contact', - 'task' - ); - - $foldertypes = array_intersect($foldertypes, $types); - - // get default folders - foreach ($foldertypes as $folder => $type) { - // only personal folders - if ($this->storage->folder_namespace($folder) == 'personal') { - $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; - $this->folder_set($folder, $id, $flag); - } - } - } - - // INBOX always exists - $this->folder_set('INBOX', $id, 1); + // subscribe default set of folders + $this->device_init_subscriptions($id); } return $result; @@ -535,6 +506,122 @@ return $result; } + /** + * Subscribe default set of folders on device registration + */ + private function device_init_subscriptions($deviceid) + { + // INBOX always exists + $this->folder_set('INBOX', $deviceid, 1); + + $supported_types = array( + 'mail.drafts', + 'mail.wastebasket', + 'mail.sentitems', + 'mail.outbox', + 'event.default', + 'contact.default', + 'task.default', + 'event', + 'contact', + 'task' + ); + + // This default set can be extended by adding following values: + $modes = array( + 'SUB_PERSONAL' => 1, // all subscribed folders in personal namespace + 'ALL_PERSONAL' => 2, // all folders in personal namespace + 'SUB_OTHER' => 4, // all subscribed folders in other users namespace + 'ALL_OTHER' => 8, // all folders in other users namespace + 'SUB_SHARED' => 16, // all subscribed folders in shared namespace + 'ALL_SHARED' => 32, // all folders in shared namespace + ); + + $rcube = rcube::get_instance(); + $config = $rcube->config; + $mode = (int) $config->get('activesync_init_subscriptions'); + $folders = array(); + + // Subscribe to default folders + $foldertypes = kolab_storage::folders_typedata(); + + if (!empty($foldertypes)) { + $_foldertypes = array_intersect($foldertypes, $supported_types); + + // get default folders + foreach ($_foldertypes as $folder => $type) { + // only personal folders + if ($this->storage->folder_namespace($folder) == 'personal') { + $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; + $this->folder_set($folder, $deviceid, $flag); + $folders[] = $folder; + } + } + } + + // we're in default mode, exit + if (!$mode) { + return; + } + + // below we support additionally all mail folders + $supported_types[] = 'mail'; + $supported_types[] = 'mail.junkemails'; + + // get configured special folders + $special_folders = array(); + $map = array( + 'drafts' => 'mail.drafts', + 'junk' => 'mail.junkemails', + 'sent' => 'mail.sentitems', + 'trash' => 'mail.wastebasket', + ); + + foreach ($map as $folder => $type) { + if ($folder = $config->get($folder . '_mbox')) { + $special_folders[$folder] = $type; + } + } + + // get folders list(s) + if (($mode & $modes['ALL_PERSONAL']) || ($mode & $modes['ALL_OTHER']) || ($mode & $modes['ALL_SHARED'])) { + $all_folders = $this->storage->list_folders(); + if (($mode & $modes['SUB_PERSONAL']) || ($mode & $modes['SUB_OTHER']) || ($mode & $modes['SUB_SHARED'])) { + $subscribed_folders = $this->storage->list_folders_subscribed(); + } + } + else { + $all_folders = $this->storage->list_folders_subscribed(); + } + + foreach ($all_folders as $folder) { + // folder already subscribed + if (in_array($folder, $folders)) { + continue; + } + + $type = $foldertypes[$folder] ?: 'mail'; + if ($type == 'mail' && isset($special_folders[$folder])) { + $type == $special_folders[$folder]; + } + + if (!in_array($type, $supported_types)) { + continue; + } + + $ns = strtoupper($this->storage->folder_namespace($folder)); + + // subscribe the folder according to configured mode + // and folder namespace/subscription status + if (($mode & $modes["ALL_$ns"]) + || (($mode & $modes["SUB_$ns"]) + && (!isset($subscribed_folders) || in_array($folder, $subscribed_folders))) + ) { + $flag = preg_match('/^(event|task)/', $type) ? 2 : 1; + $this->folder_set($folder, $deviceid, $flag); + } + } + } /** * Helper method to decode saved IMAP metadata
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync_data.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync_data.php
Changed
@@ -536,6 +536,7 @@ } $result = $result_type == self::RESULT_COUNT ? 0 : array(); + $found = 0; foreach ($folders as $folderid) { $foldername = $this->backend->folder_id2name($folderid, $this->device->deviceid); @@ -550,23 +551,51 @@ continue; } + $found++; + $error = false; + switch ($result_type) { case self::RESULT_COUNT: - $result += (int) $folder->count($filter); + $count = $folder->count($filter); + + if ($count === null || $count === false) { + $error = true; + } + else { + $result += (int) $count; + } break; case self::RESULT_UID: - if ($uids = $folder->get_uids($filter)) { + $uids = $folder->get_uids($filter); + + if (!is_array($uids)) { + $error = true; + } + else { $result = array_merge($result, $uids); } break; case self::RESULT_OBJECT: default: - if ($objects = $folder->select($filter)) { + $objects = $folder->select($filter); + + if (!is_array($objects)) { + $error = true; + } + else { $result = array_merge($result, $objects); } } + + if ($error) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + } + + if (!$found) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); } return $result; @@ -586,58 +615,54 @@ } /** - * get all entries changed between to dates + * get all entries changed between two dates * - * @param string $folderId + * @param string $folderId * @param DateTime $start * @param DateTime $end - * @param int $filterType + * @param int $filterType * * @return array */ public function getChangedEntries($folderId, DateTime $start, DateTime $end = null, $filter_type = null) { - $filter = $this->filter($filter_type); + $filter = $this->filter($filter_type); $filter[] = array('changed', '>', $start); if ($end) { $filter[] = array('changed', '<=', $end); } - $result = $this->searchEntries($folderId, $filter, self::RESULT_UID); - - return $result; + return $this->searchEntries($folderId, $filter, self::RESULT_UID); } /** * get count of entries changed between two dates * - * @param string $folderId + * @param string $folderId * @param DateTime $start * @param DateTime $end - * @param int $filterType + * @param int $filterType * * @return int */ public function getChangedEntriesCount($folderId, DateTime $start, DateTime $end = null, $filter_type = null) { - $filter = $this->filter($filter_type); + $filter = $this->filter($filter_type); $filter[] = array('changed', '>', $start); if ($end) { $filter[] = array('changed', '<=', $end); } - $result = $this->searchEntries($folderId, $filter, self::RESULT_COUNT); - - return $result; + return $this->searchEntries($folderId, $filter, self::RESULT_COUNT); } /** * get id's of all entries available on the server * * @param string $folderId - * @param int $filterType + * @param int $filterType * * @return array */ @@ -696,21 +721,27 @@ */ public function hasChanges(Syncroton_Backend_IContent $contentBackend, Syncroton_Model_IFolder $folder, Syncroton_Model_ISyncState $syncState) { - if ($this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype)) { - return true; - } + try { + if ($this->getChangedEntriesCount($folder->serverId, $syncState->lastsync, null, $folder->lastfiltertype)) { + return true; + } - $allClientEntries = $contentBackend->getFolderState($this->device, $folder); + $allClientEntries = $contentBackend->getFolderState($this->device, $folder); - // @TODO: Consider looping over all folders here, not in getServerEntries() and - // getChangedEntriesCount(). This way we could break the loop and not check all folders - // or at least skip redundant cache sync of the same folder - $allServerEntries = $this->getServerEntries($folder->serverId, $folder->lastfiltertype); + // @TODO: Consider looping over all folders here, not in getServerEntries() and + // getChangedEntriesCount(). This way we could break the loop and not check all folders + // or at least skip redundant cache sync of the same folder + $allServerEntries = $this->getServerEntries($folder->serverId, $folder->lastfiltertype); - $addedEntries = array_diff($allServerEntries, $allClientEntries); - $deletedEntries = array_diff($allClientEntries, $allServerEntries); + $addedEntries = array_diff($allServerEntries, $allClientEntries); + $deletedEntries = array_diff($allClientEntries, $allServerEntries); - return count($addedEntries) > 0 || count($deletedEntries) > 0; + return count($addedEntries) > 0 || count($deletedEntries) > 0; + } + catch (Exception $e) { + // return "no changes" if something failed + return false; + } } /** @@ -848,7 +879,6 @@ } } - return $folders; }
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync_data_contacts.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync_data_contacts.php
Changed
@@ -223,6 +223,15 @@ continue 2; } break; + + case 'birthday': + case 'anniversary': + if ($value) { + // convert date to string format, so libkolab will store + // it with no time and timezone what could be incorrectly re-calculated (#2555) + $value = $value->format('Y-m-d'); + } + break; } $this->setKolabDataItem($contact, $name, $value);
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync_data_email.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync_data_email.php
Changed
@@ -251,12 +251,17 @@ if (!empty($prefs[$type]['truncationSize'])) { $truncateAt = $prefs[$type]['truncationSize']; } + + $preview = (int) $prefs[$type]['preview']; $airSyncBaseType = $type; + break; } } } + $body_params = array('type' => $airSyncBaseType); + // Message body // In Sync examples there's one in which bodyPreferences is not defined // in such case Truncated=1 and there's no body sent to the client @@ -270,6 +275,8 @@ } else if ($airSyncBaseType == Syncroton_Command_Sync::BODY_TYPE_MIME) { $messageBody = $this->storage->get_raw_body($message->uid); + // make the source safe (Bug #2715, #2757) + $messageBody = kolab_sync_message::recode_message($messageBody); // strip out any non utf-8 characters $messageBody = rcube_charset::clean($messageBody); $real_length = $body_length = strlen($messageBody); @@ -281,6 +288,11 @@ $real_length = $body_length = strlen($messageBody); } + // add Preview element to the Body result + if (!empty($preview) && $body_length) { + $body_params['preview'] = $this->getPreview($messageBody, $airSyncBaseType, $preview); + } + // truncate the body if needed if ($truncateAt && $body_length > $truncateAt) { $messageBody = mb_strcut($messageBody, 0, $truncateAt); @@ -288,7 +300,6 @@ $isTruncated = 1; } - $body_params = array('type' => $airSyncBaseType); if ($isTruncated) { $body_params['truncated'] = 1; $body_params['estimatedDataSize'] = $real_length; @@ -391,6 +402,9 @@ case Syncroton_Command_Sync::FILTER_3_DAYS_BACK: $mod = '-3 days'; break; + case Syncroton_Command_Sync::FILTER_1_WEEK_BACK: + $mod = '-1 week'; + break; case Syncroton_Command_Sync::FILTER_2_WEEKS_BACK: $mod = '-2 weeks'; break; @@ -517,7 +531,7 @@ $copyuid = $this->storage->conn->data['COPYUID']; if (is_array($copyuid) && ($uid = $copyuid[1])) { - return $uid; + return $this->createMessageId($dstFolderId, $uid); } } @@ -779,6 +793,7 @@ $result = $result_type == self::RESULT_COUNT ? 0 : array(); // no sorting for best performance $sort_by = null; + $found = 0; foreach ($folders as $folder_id) { $foldername = $this->backend->folder_id2name($folder_id, $this->device->deviceid); @@ -787,6 +802,8 @@ continue; } + $found++; + $this->storage->set_folder($foldername); // Syncronize folder (if it wasn't synced in this request already) @@ -837,8 +854,8 @@ $search = $this->storage->search_once($foldername, $filter_str); - if (!($search instanceof rcube_result_index)) { - continue; + if (!($search instanceof rcube_result_index) || $search->is_error()) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); } switch ($result_type) { @@ -864,6 +881,10 @@ } } + if (!$found) { + throw new Syncroton_Exception_Status(Syncroton_Exception_Status::SERVER_ERROR); + } + if (!empty($modseq_update)) { $this->backend->modseq_set($this->device->id, $folderid, $this->syncTimeStamp, $modseq_data); @@ -1158,6 +1179,17 @@ if ($html) { if ($part->ctype_secondary == 'html') { + // charset was converted to UTF-8 in rcube_storage::get_message_part(), + // change/add charset specification in HTML accordingly + $meta = '<meta http-equiv="Content-Type" content="text/html; charset='.RCUBE_CHARSET.'" />'; + + // remove old meta tag and add the new one, making sure + // that it is placed in the head + $body = preg_replace('/<meta[^>]+charset=[a-z0-9-_]+[^>]*>/Ui', '', $body); + $body = preg_replace('/(<head[^>]*>)/Ui', '\\1'.$meta, $body, -1, $rcount); + if (!$rcount) { + $body = '<head>' . $meta . '</head>' . $body; + } } else if ($part->ctype_secondary == 'enriched') { $body = rcube_enriched::to_html($body); @@ -1186,6 +1218,26 @@ return $body; } + /** + * Converts and truncates message body for use in <Preview> + * + * @return string Truncated plain text message + */ + protected function getPreview($body, $type, $size) + { + if ($type == Syncroton_Command_Sync::BODY_TYPE_HTML) { + $txt = new rcube_html2text($body, false, true); + $body = $txt->get_text(); + } + + // size limit defined in ActiveSync protocol + if ($size > 255) { + $size = 255; + } + + return mb_strcut(trim($body), 0, $size); + } + public static function charset_to_cp($charset) { // @TODO: ?????
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync_logger.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync_logger.php
Changed
@@ -27,14 +27,14 @@ */ class kolab_sync_logger extends Zend_Log { - private static $mode; + public $mode; /** * Constructor */ function __construct($mode = null) { - self::$mode = intval($mode); + $this->mode = intval($mode); $r = new ReflectionClass($this); $this->_priorities = $r->getConstants(); @@ -43,7 +43,7 @@ public function __call($method, $params) { $method = strtoupper($method); - if ($this->_priorities[$method] <= self::$mode) { + if ($this->_priorities[$method] <= $this->mode) { $this->log(array_shift($params), $method); } } @@ -69,7 +69,7 @@ $mode = $this->_priorities[$method]; } - if ($mode > self::$mode) { + if ($mode > $this->mode) { return; } @@ -97,6 +97,26 @@ $message = var_export($message, true); } + // add user/request information to the log + if ($mode <= self::WARN) { + $device = array(); + $params = array('cmd' => 'Cmd', 'device' => 'DeviceId', 'type' => 'DeviceType'); + + if (!empty($this->username)) { + $device['user'] = $this->username; + } + + foreach ($params as $key => $val) { + if ($val = $_GET[$val]) { + $device[$key] = $val; + } + } + + if (!empty($device)) { + $message = @json_encode($device) . ' ' . $message; + } + } + $date = date($format); $logline = sprintf("[%s]: [%s] %s\n", $date, $method, $message); @@ -112,4 +132,12 @@ trigger_error($message, E_USER_ERROR); } } + + /** + * Set current user name to add into error log + */ + public function set_username($username) + { + $this->username = $username; + } }
View file
kolab-syncroton-2.2.3.tar.gz/lib/kolab_sync_message.php -> kolab-syncroton-2.2.4.tar.gz/lib/kolab_sync_message.php
Changed
@@ -140,7 +140,7 @@ */ public function set_header($name, $value) { - $name = $this->normalize_header_name($name); + $name = self::normalize_header_name($name); if ($name != 'Content-Type') { $this->headers[$name] = $value; @@ -277,6 +277,58 @@ } /** + * Parses the message source and fixes 8bit data for ActiveSync. + * This way any not UTF8 characters will be encoded before + * sending to the device. + * + * @param string $message Message source + * + * @return string Fixed message source + */ + public static function recode_message($message) + { + // @TODO: work with stream, to workaround memory issues with big messages + if (is_resource($message)) { + $message = stream_get_contents($message); + } + + list($headers, $message) = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY); + + $hdrs = self::parse_headers($headers); + + // multipart message + if (preg_match('/boundary="?([a-z0-9-_]+)"?/i', $hdrs['Content-Type'], $matches)) { + $boundary = '--' . $matches[1]; + $message = explode($boundary, $message); + + for ($x=1, $parts = count($message) - 1; $x<$parts; $x++) { + $message[$x] = "\r\n" . self::recode_message($message[$x]); + } + + return $headers . "\r\n\r\n" . implode($boundary, $message); + } + + // single part + $enc = strtolower($hdrs['Content-Transfer-Encoding']); + + // do nothing if already encoded + if ($enc != 'quoted-printable' && $enc != 'base64') { + // recode body if any non-printable-ascii characters found + if (preg_match('/[^\x20-\x7E\x0A\x0D\x09]/', $message)) { + $hdrs['Content-Transfer-Encoding'] = 'base64'; + foreach ($hdrs as $header => $header_value) { + $hdrs[$header] = $header . ': ' . $header_value; + } + + $headers = trim(implode("\r\n", $hdrs)); + $message = rtrim(chunk_split(base64_encode(rtrim($message)), 76, "\r\n")) . "\r\n"; + } + } + + return $headers . "\r\n\r\n" . $message; + } + + /** * MIME message parser * * @param string|resource $message MIME message source @@ -293,6 +345,30 @@ list($headers, $message) = preg_split('/\r?\n\r?\n/', $message, 2, PREG_SPLIT_NO_EMPTY); + $headers = self::parse_headers($headers); + + // parse Content-Type header + $ctype_parts = preg_split('/[; ]+/', $headers['Content-Type']); + $this->ctype = strtolower(array_shift($ctype_parts)); + foreach ($ctype_parts as $part) { + if (preg_match('/^([a-z-_]+)\s*=\s*(.+)$/i', trim($part), $m)) { + $this->ctype_params[strtolower($m[1])] = trim($m[2], '"'); + } + } + + if (!empty($headers['Content-Transfer-Encoding'])) { + $headers['Content-Transfer-Encoding'] = strtolower($headers['Content-Transfer-Encoding']); + } + + $this->headers = $headers; + $this->body = $message; + } + + /** + * Parse message source with headers + */ + protected static function parse_headers($headers) + { // Parse headers $headers = str_replace("\r\n", "\n", $headers); $headers = explode("\n", trim($headers)); @@ -302,7 +378,7 @@ foreach ($headers as $line) { if (ord($line[0]) <= 32) { - $lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . $line; + $lines[$ln] .= (empty($lines[$ln]) ? '' : "\r\n") . $line; } else { $lines[++$ln] = trim($line); @@ -313,31 +389,18 @@ $headers = array(); foreach ($lines as $line) { list($field, $string) = explode(':', $line, 2); - $field = $this->normalize_header_name($field); - $headers[$field] = trim($string); - } - - // parse Content-Type header - $ctype_parts = preg_split('/[; ]+/', $headers['Content-Type']); - $this->ctype = strtolower(array_shift($ctype_parts)); - foreach ($ctype_parts as $part) { - if (preg_match('/^([a-z-_]+)\s*=\s*(.+)$/i', trim($part), $m)) { - $this->ctype_params[strtolower($m[1])] = trim($m[2], '"'); + if ($field = self::normalize_header_name($field)) { + $headers[$field] = trim($string); } } - if (!empty($headers['Content-Transfer-Encoding'])) { - $headers['Content-Transfer-Encoding'] = strtolower($headers['Content-Transfer-Encoding']); - } - - $this->headers = $headers; - $this->body = $message; + return $headers; } /** * Normalize (fix) header names */ - protected function normalize_header_name($name) + protected static function normalize_header_name($name) { $headers_map = array( 'subject' => 'Subject',
View file
kolab-syncroton-2.2.3.tar.gz/lib/plugins/kolab_auth/kolab_auth.php -> kolab-syncroton-2.2.4.tar.gz/lib/plugins/kolab_auth/kolab_auth.php
Changed
@@ -149,24 +149,27 @@ if (!empty($role_plugins)) { foreach ($role_plugins as $role_dn => $plugins) { - $role_plugins[self::parse_ldap_vars($role_dn)] = $plugins; + $role_dn = self::parse_ldap_vars($role_dn); + if (!empty($role_plugins[$role_dn])) { + $role_plugins[$role_dn] = array_unique(array_merge((array)$role_plugins[$role_dn], $plugins)); + } else { + $role_plugins[$role_dn] = $plugins; + } } } if (!empty($role_settings)) { foreach ($role_settings as $role_dn => $settings) { - $role_settings[self::parse_ldap_vars($role_dn)] = $settings; + if (!empty($role_settings[$role_dn])) { + $role_settings[$role_dn] = array_merge((array)$role_settings[$role_dn], $settings); + } else { + $role_settings[$role_dn] = $settings; + } } } foreach ($_SESSION['user_roledns'] as $role_dn) { - if (isset($role_plugins[$role_dn]) && is_array($role_plugins[$role_dn])) { - foreach ($role_plugins[$role_dn] as $plugin) { - $this->require_plugin($plugin); - } - } - - if (isset($role_settings[$role_dn]) && is_array($role_settings[$role_dn])) { + if (!empty($role_settings[$role_dn]) && is_array($role_settings[$role_dn])) { foreach ($role_settings[$role_dn] as $setting_name => $setting) { if (!isset($setting['mode'])) { $setting['mode'] = 'override'; @@ -188,7 +191,7 @@ $dont_override = (array) $rcmail->config->get('dont_override'); - if (!isset($setting['allow_override']) || !$setting['allow_override']) { + if (empty($setting['allow_override'])) { $rcmail->config->set('dont_override', array_merge($dont_override, array($setting_name))); } else { @@ -202,6 +205,19 @@ $rcmail->config->set('dont_override', $_dont_override); } } + + if ($setting_name == 'skin') { + if ($rcmail->output->type == 'html') { + $rcmail->output->set_skin($setting['value']); + $rcmail->output->set_env('skin', $setting['value']); + } + } + } + } + + if (!empty($role_plugins[$role_dn])) { + foreach ((array)$role_plugins[$role_dn] as $plugin) { + $this->require_plugin($plugin); } } } @@ -339,6 +355,7 @@ $ldap = self::ldap(); if (!$ldap || !$ldap->ready) { $args['abort'] = true; + $args['kolab_ldap_error'] = true; $message = sprintf( 'Login failure for user %s from %s in session %s (error %s)', $user,
View file
kolab-syncroton-2.2.3.tar.gz/lib/plugins/kolab_auth/kolab_auth_ldap.php -> kolab-syncroton-2.2.4.tar.gz/lib/plugins/kolab_auth/kolab_auth_ldap.php
Changed
@@ -207,7 +207,7 @@ /** * Search records (simplified version of rcube_ldap::search) * - * @param mixed $fields The field name of array of field names to search in + * @param mixed $fields The field name or array of field names to search in * @param mixed $value Search value (or array of values when $fields is array) * @param int $mode Matching mode: * 0 - partial (*abc*), @@ -221,6 +221,10 @@ */ function search($fields, $value, $mode=1, $required = array(), $limit = 0) { + if (empty($fields)) { + return array(); + } + $mode = intval($mode); // use AND operator for advanced searches @@ -236,8 +240,13 @@ } foreach ((array)$fields as $idx => $field) { - $val = is_array($value) ? $value[$idx] : $value; - if ($attrs = (array) $this->fieldmap[$field]) { + $val = is_array($value) ? $value[$idx] : $value; + $attrs = (array) $this->fieldmap[$field]; + + if (empty($attrs)) { + $filter .= "($field=$wp" . rcube_ldap_generic::quote_string($val) . "$ws)"; + } + else { if (count($attrs) > 1) $filter .= '(|'; foreach ($attrs as $f) @@ -254,7 +263,13 @@ foreach ((array)$required as $field) { if (in_array($field, (array)$fields)) // required field is already in search filter continue; - if ($attrs = (array) $this->fieldmap[$field]) { + + $attrs = (array) $this->fieldmap[$field]; + + if (empty($attrs)) { + $req_filter .= "($field=*)"; + } + else { if (count($attrs) > 1) $req_filter .= '(|'; foreach ($attrs as $f)
View file
kolab-syncroton-2.2.3.tar.gz/lib/plugins/libkolab/lib/kolab_storage_cache.php -> kolab-syncroton-2.2.4.tar.gz/lib/plugins/libkolab/lib/kolab_storage_cache.php
Changed
@@ -410,6 +410,10 @@ $this->folder_id ); + if ($this->db->is_error($sql_result)) { + return null; + } + while ($sql_arr = $this->db->fetch_assoc($sql_result)) { if ($uids) { $this->uid2msg[$sql_arr['uid']] = $sql_arr['msguid']; @@ -430,7 +434,11 @@ } else { // search by object type $search = 'UNDELETED HEADER X-Kolab-Type ' . kolab_format::KTYPE_PREFIX . $filter['type']; - $index = $this->imap->search_once($this->folder->name, $search)->get(); + $index = $this->imap->search_once($this->folder->name, $search)->get(); + } + + if ($index->is_error()) { + return null; } // fetch all messages in $index from IMAP @@ -460,8 +468,6 @@ */ public function count($query = array()) { - $count = 0; - // cache is in sync, we can count records in local DB if ($this->synched) { $this->_read_folder_data(); @@ -472,14 +478,23 @@ $this->folder_id ); + if ($this->db->is_error($sql_result)) { + return null; + } + $sql_arr = $this->db->fetch_assoc($sql_result); - $count = intval($sql_arr['numrows']); + $count = intval($sql_arr['numrows']); } else { // search IMAP by object type $filter = $this->_query2assoc($query); $ctype = kolab_format::KTYPE_PREFIX . $filter['type']; - $index = $this->imap->search_once($this->folder->name, 'UNDELETED HEADER X-Kolab-Type ' . $ctype); + $index = $this->imap->search_once($this->folder->name, 'UNDELETED HEADER X-Kolab-Type ' . $ctype); + + if ($index->is_error()) { + return null; + } + $count = $index->count(); }
View file
kolab-syncroton-2.2.3.tar.gz/tests/message.php -> kolab-syncroton-2.2.4.tar.gz/tests/message.php
Changed
@@ -96,4 +96,43 @@ $result = str_replace("\r\n", "\n", $result); $this->assertEquals($append, $result); } + + /** + * Test recoding the message + */ + function test_recode_message_1() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode1'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode1.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } + + /** + * Test recoding the message + */ + function test_recode_message_2() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode2'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode2.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } + + /** + * Test recoding the message + */ + function test_recode_message_3() + { + $source = file_get_contents(TESTS_DIR . '/src/mail.recode3'); + $result = file_get_contents(TESTS_DIR . '/src/mail.recode3.out'); + + $message = kolab_sync_message::recode_message($source); + + $this->assertEquals($result, $message); + } }
View file
kolab-syncroton-2.2.4.tar.gz/tests/src/mail.recode1
Added
@@ -0,0 +1,16 @@ +X-Sieve: CMU Sieve 2.4 +X-Virus-Scanned: amavisd-new at mx.domain.de +Message-ID: <52CDD362.2020009@domain.de> +Date: Wed, 08 Jan 2014 23:38:26 +0100 +From: Daniel <daniel@domain.de> +MIME-Version: 1.0 +To: <alec@domain.de> +Subject: Bitte um =?ISO-8859-15?Q?R=FCckruf?= +Content-Type: text/plain; charset=ISO-8859-15; format=flowed +Content-Transfer-Encoding: 8bit + +Hallo Björn, +bitte rufe mich doch mal ganz dringend zurück. 0178-5217029 + +Liebe Grüße +Daniel
View file
kolab-syncroton-2.2.4.tar.gz/tests/src/mail.recode1.out
Added
@@ -0,0 +1,13 @@ +X-Sieve: CMU Sieve 2.4 +X-Virus-Scanned: amavisd-new at mx.domain.de +Message-ID: <52CDD362.2020009@domain.de> +Date: Wed, 08 Jan 2014 23:38:26 +0100 +From: Daniel <daniel@domain.de> +MIME-Version: 1.0 +To: <alec@domain.de> +Subject: Bitte um =?ISO-8859-15?Q?R=FCckruf?= +Content-Type: text/plain; charset=ISO-8859-15; format=flowed +Content-Transfer-Encoding: base64 + +SGFsbG8gQmr2cm4sDQpiaXR0ZSBydWZlIG1pY2ggZG9jaCBtYWwgZ2FueiBkcmluZ2VuZCB6dXL8 +Y2suIDAxNzgtNTIxNzAyOQ0KDQpMaWViZSBHcvzfZQ0KRGFuaWVs
View file
kolab-syncroton-2.2.4.tar.gz/tests/src/mail.recode2
Added
@@ -0,0 +1,46 @@ +Message-ID: <52B02B8F.9010500@domain.de> +Date: Tue, 17 Dec 2013 11:46:39 +0100 +From: Sender <sender@domain.de> +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101207 Thunderbird/3.1.7 +To: Verborgene_Empfaenger:; +Subject: Weihnachtsbrief +Content-Type: multipart/mixed; + boundary="------------000801030509090203070207" + +This is a multi-part message in MIME format. +--------------000801030509090203070207 +Content-Type: multipart/alternative; + boundary="------------060305070900000101080707" + + +--------------060305070900000101080707 +Content-Type: text/plain; charset=ISO-8859-15; format=flowed +Content-Transfer-Encoding: 8bit + +Herzliche Adventsgrüße + +--------------060305070900000101080707 +Content-Type: text/html; charset=ISO-8859-15 +Content-Transfer-Encoding: 8bit + +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> +<html> + <head> + <meta http-equiv="content-type" content="text/html; charset=ISO-8859-15"> + </head> + <body bgcolor="#ffffff" text="#000000"> + Herzliche Adventsgrüße<br> + </body> +</html> + +--------------060305070900000101080707-- + +--------------000801030509090203070207 +Content-Type: application/pdf; + name="Weihnachtsbrief13.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="Weihnachtsbrief13.pdf" + +JVBERi0 [...shortened...] DYKJSVFT0YK +--------------000801030509090203070207-- \ No newline at end of file
View file
kolab-syncroton-2.2.4.tar.gz/tests/src/mail.recode2.out
Added
@@ -0,0 +1,42 @@ +Message-ID: <52B02B8F.9010500@domain.de> +Date: Tue, 17 Dec 2013 11:46:39 +0100 +From: Sender <sender@domain.de> +User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.2.13) Gecko/20101207 Thunderbird/3.1.7 +To: Verborgene_Empfaenger:; +Subject: Weihnachtsbrief +Content-Type: multipart/mixed; + boundary="------------000801030509090203070207" + +This is a multi-part message in MIME format. +--------------000801030509090203070207 + +Content-Type: multipart/alternative; + boundary="------------060305070900000101080707" + + +--------------060305070900000101080707 +Content-Type: text/plain; charset=ISO-8859-15; format=flowed +Content-Transfer-Encoding: base64 + +SGVyemxpY2hlIEFkdmVudHNncvzfZQ== +--------------060305070900000101080707 +Content-Type: text/html; charset=ISO-8859-15 +Content-Transfer-Encoding: base64 + +PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMDEgVHJhbnNpdGlvbmFs +Ly9FTiI+DQo8aHRtbD4NCiAgPGhlYWQ+DQogICAgPG1ldGEgaHR0cC1lcXVpdj0iY29udGVudC10 +eXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7IGNoYXJzZXQ9SVNPLTg4NTktMTUiPg0KICA8L2hlYWQ+ +DQogIDxib2R5IGJnY29sb3I9IiNmZmZmZmYiIHRleHQ9IiMwMDAwMDAiPg0KICAgIEhlcnpsaWNo +ZSBBZHZlbnRzZ3L832U8YnI+DQogIDwvYm9keT4NCjwvaHRtbD4= +--------------060305070900000101080707-- + +--------------000801030509090203070207 + +Content-Type: application/pdf; + name="Weihnachtsbrief13.pdf" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="Weihnachtsbrief13.pdf" + +JVBERi0 [...shortened...] DYKJSVFT0YK +--------------000801030509090203070207-- \ No newline at end of file
View file
kolab-syncroton-2.2.4.tar.gz/tests/src/mail.recode3
Added
@@ -0,0 +1,11 @@ +X-Sieve: CMU Sieve 2.4 +X-Virus-Scanned: amavisd-new at mx.domain.de +Message-ID: <52CDD362.2020009@domain.de> +Date: Wed, 08 Jan 2014 23:38:26 +0100 +From: Daniel <daniel@domain.de> +MIME-Version: 1.0 +To: <alec@domain.de> +Subject: Hello +Content-Type: text/plain; charset=ISO-8859-15; format=flowed + +Hello
View file
kolab-syncroton-2.2.4.tar.gz/tests/src/mail.recode3.out
Added
@@ -0,0 +1,11 @@ +X-Sieve: CMU Sieve 2.4 +X-Virus-Scanned: amavisd-new at mx.domain.de +Message-ID: <52CDD362.2020009@domain.de> +Date: Wed, 08 Jan 2014 23:38:26 +0100 +From: Daniel <daniel@domain.de> +MIME-Version: 1.0 +To: <alec@domain.de> +Subject: Hello +Content-Type: text/plain; charset=ISO-8859-15; format=flowed + +Hello
View file
kolab-syncroton.dsc
Changed
@@ -2,7 +2,7 @@ Source: kolab-syncroton Binary: kolab-syncroton Architecture: all -Version: 2.2.3-0~kolab13 +Version: 2.2.4-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.3.tar.gz + 00000000000000000000000000000000 0 kolab-syncroton-2.2.4.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
.