summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <machniak@kolabsys.com>2015-02-04 11:23:13 (GMT)
committerAleksander Machniak <machniak@kolabsys.com>2015-02-04 11:23:13 (GMT)
commit11e93ffa1f329a2cbcb9544e4962c6b58051cdba (patch)
tree866497817155b211cc3c3931a40321fb4c752986
parent5990b21898f7a5b5a19edbfd79c4cf83eb510d11 (diff)
downloadkolab-chwala-11e93ffa1f329a2cbcb9544e4962c6b58051cdba.tar.gz
Update kolab plugins
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/composer.json30
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/config.inc.php.dist57
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/kolab_auth.php266
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/kolab_auth_ldap.php83
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/bg_BG.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/de_CH.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/de_DE.inc8
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/en_US.inc9
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/es_ES.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/et_EE.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/fr_FR.inc8
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/ja_JP.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/nl_NL.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/pl_PL.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/pt_BR.inc7
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/localization/ru_RU.inc8
-rw-r--r--lib/drivers/kolab/plugins/kolab_auth/package.xml63
-rw-r--r--lib/drivers/kolab/plugins/libkolab/SQL/mysql.initial.sql18
-rw-r--r--lib/drivers/kolab/plugins/libkolab/SQL/mysql/2014112700.sql2
-rw-r--r--lib/drivers/kolab/plugins/libkolab/SQL/mysql/2015011600.sql8
-rw-r--r--lib/drivers/kolab/plugins/libkolab/SQL/oracle.initial.sql20
-rw-r--r--lib/drivers/kolab/plugins/libkolab/SQL/oracle/2015011600.sql40
-rwxr-xr-xlib/drivers/kolab/plugins/libkolab/bin/readcache.sh150
-rw-r--r--lib/drivers/kolab/plugins/libkolab/composer.json2
-rw-r--r--lib/drivers/kolab/plugins/libkolab/config.inc.php.dist1
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_bonnie_api.php2
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_format.php2
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_format_configuration.php14
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_format_event.php12
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_format_xcal.php9
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_storage.php52
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_cache.php125
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_config.php26
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder.php125
-rw-r--r--lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder_api.php22
-rw-r--r--lib/drivers/kolab/plugins/libkolab/package.xml101
36 files changed, 936 insertions, 383 deletions
diff --git a/lib/drivers/kolab/plugins/kolab_auth/composer.json b/lib/drivers/kolab/plugins/kolab_auth/composer.json
new file mode 100644
index 0000000..3e7012f
--- /dev/null
+++ b/lib/drivers/kolab/plugins/kolab_auth/composer.json
@@ -0,0 +1,30 @@
+{
+ "name": "kolab/kolab_auth",
+ "type": "roundcube-plugin",
+ "description": "Kolab authentication",
+ "homepage": "http://git.kolab.org/roundcubemail-plugins-kolab/",
+ "license": "AGPLv3",
+ "version": "3.2.2",
+ "authors": [
+ {
+ "name": "Thomas Bruederli",
+ "email": "bruederli@kolabsys.com",
+ "role": "Lead"
+ },
+ {
+ "name": "Aleksander Machniak",
+ "email": "machniak@kolabsys.com",
+ "role": "Lead"
+ }
+ ],
+ "repositories": [
+ {
+ "type": "composer",
+ "url": "http://plugins.roundcube.net"
+ }
+ ],
+ "require": {
+ "php": ">=5.3.0",
+ "roundcube/plugin-installer": ">=0.1.3"
+ }
+}
diff --git a/lib/drivers/kolab/plugins/kolab_auth/config.inc.php.dist b/lib/drivers/kolab/plugins/kolab_auth/config.inc.php.dist
index e7b9d15..8c01d56 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/config.inc.php.dist
+++ b/lib/drivers/kolab/plugins/kolab_auth/config.inc.php.dist
@@ -13,44 +13,55 @@
// With this %dc variable in base_dn and groups/base_dn will be
// replaced with DN string of resolved domain
//---------------------------------------------------------------------
-$rcmail_config['kolab_auth_addressbook'] = '';
+$config['kolab_auth_addressbook'] = '';
// This will overwrite defined filter
-$rcmail_config['kolab_auth_filter'] = '(&(objectClass=kolabInetOrgPerson)(|(uid=%u)(mail=%fu)(alias=%fu)))';
+$config['kolab_auth_filter'] = '(&(objectClass=kolabInetOrgPerson)(|(uid=%u)(mail=%fu)(alias=%fu)))';
-// Use this fields (from fieldmap configuration) to get authentication ID
-$rcmail_config['kolab_auth_login'] = 'email';
+// Use this field (from fieldmap configuration) to get authentication ID. Don't use an array here!
+$config['kolab_auth_login'] = 'email';
-// Use this fields (from fieldmap configuration) for default identity.
+// Use these fields (from fieldmap configuration) for default identity.
// If the value array contains more than one field, first non-empty will be used
// Note: These aren't LDAP attributes, but field names in config
// Note: If there's more than one email address, as many identities will be created
-$rcmail_config['kolab_auth_name'] = array('name', 'cn');
-$rcmail_config['kolab_auth_email'] = array('email');
-$rcmail_config['kolab_auth_organization'] = array('organization');
+$config['kolab_auth_name'] = array('name', 'cn');
+$config['kolab_auth_email'] = array('email');
+$config['kolab_auth_organization'] = array('organization');
+
+// Role field (from fieldmap configuration)
+$config['kolab_auth_role'] = 'role';
+
+// Template for user names displayed in the UI.
+// You can use all attributes from the 'fieldmap' property of the 'kolab_auth_addressbook' configuration
+$config['kolab_auth_user_displayname'] = '{name} ({ou})';
// Login and password of the admin user. Enables "Login As" feature.
-$rcmail_config['kolab_auth_admin_login'] = '';
-$rcmail_config['kolab_auth_admin_password'] = '';
+$config['kolab_auth_admin_login'] = '';
+$config['kolab_auth_admin_password'] = '';
// Enable audit logging for abuse of administrative privileges.
-$rcmail_config['kolab_auth_auditlog'] = true;
-
-// Role field (from fieldmap configuration)
-$rcmail_config['kolab_auth_role'] = 'role';
-// The required value for the role attribute to contain should the user be allowed
-// to login as another user.
-$rcmail_config['kolab_auth_role_value'] = '';
+$config['kolab_auth_auditlog'] = false;
-// Administrative group name to which user must be assigned to
-// which adds privilege to login as another user.
-$rcmail_config['kolab_auth_group'] = '';
+// As set of rules to define the required rights on the target entry
+// which allow an admin user to login as another user (the target).
+// The effective rights value refers to either entry level attribute level rights:
+// * entry:[read|add|delete]
+// * attrib:<attribute-name>:[read|write|delete]
+$config['kolab_auth_admin_rights'] = array(
+ // Roundcube task => required effective right
+ 'settings' => 'entry:read',
+ 'mail' => 'entry:delete',
+ 'addressbook' => 'entry:delete',
+ // or use a wildcard entry like this:
+ '*' => 'entry:read',
+);
// Enable plugins on a role-by-role basis. In this example, the 'acl' plugin
// is enabled for people with a 'cn=professional-user,dc=mykolab,dc=ch' role.
//
// Note that this does NOT mean the 'acl' plugin is disabled for other people.
-$rcmail_config['kolab_auth_role_plugins'] = Array(
+$config['kolab_auth_role_plugins'] = Array(
'cn=professional-user,dc=mykolab,dc=ch' => Array(
'acl',
),
@@ -62,7 +73,7 @@ $rcmail_config['kolab_auth_role_plugins'] = Array(
// do not allow the setting to be controlled through the preferences, enable the
// html editor for professional users and allow them to override the setting in
// the preferences.
-$rcmail_config['kolab_auth_role_settings'] = Array(
+$config['kolab_auth_role_settings'] = Array(
'cn=professional-user,dc=mykolab,dc=ch' => Array(
'htmleditor' => Array(
'mode' => 'override',
@@ -75,6 +86,6 @@ $rcmail_config['kolab_auth_role_settings'] = Array(
// List of LDAP addressbooks (keys of ldap_public configuration array)
// for which base_dn variables (%dc, etc.) will be replaced according to authenticated user DN
// Note: special name '*' for all LDAP addressbooks
-$rcmail_config['kolab_auth_ldap_addressbooks'] = array('*');
+$config['kolab_auth_ldap_addressbooks'] = array('*');
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/kolab_auth.php b/lib/drivers/kolab/plugins/kolab_auth/kolab_auth.php
index 7ff5761..033d5b1 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/kolab_auth.php
+++ b/lib/drivers/kolab/plugins/kolab_auth/kolab_auth.php
@@ -31,6 +31,7 @@
class kolab_auth extends rcube_plugin
{
static $ldap;
+ private $username;
private $data = array();
public function init()
@@ -56,11 +57,12 @@ class kolab_auth extends rcube_plugin
// Hook to modify some configuration, e.g. ldap
$this->add_hook('config_get', array($this, 'config_get'));
- // Enable debug logs per-user, this enables logging only after
- // user has logged in
- if (!empty($_SESSION['username']) && $rcmail->config->get('kolab_auth_auditlog')) {
- $this->add_hook('write_log', array($this, 'write_log'));
+ // Hook to modify logging directory
+ $this->add_hook('write_log', array($this, 'write_log'));
+ $this->username = $_SESSION['username'];
+ // Enable debug logs (per-user), when logged as another user
+ if (!empty($_SESSION['kolab_auth_admin']) && $rcmail->config->get('kolab_auth_auditlog')) {
$rcmail->config->set('debug_level', 1);
$rcmail->config->set('devel_mode', true);
$rcmail->config->set('smtp_log', true);
@@ -81,8 +83,30 @@ class kolab_auth extends rcube_plugin
}
}
+ /**
+ * Startup hook handler
+ */
public function startup($args)
{
+ // Check access rights when logged in as another user
+ if (!empty($_SESSION['kolab_auth_admin']) && $args['task'] != 'login' && $args['task'] != 'logout') {
+ // access to specified task is forbidden,
+ // redirect to the first task on the list
+ if (!empty($_SESSION['kolab_auth_allowed_tasks'])) {
+ $tasks = (array)$_SESSION['kolab_auth_allowed_tasks'];
+ if (!in_array($args['task'], $tasks) && !in_array('*', $tasks)) {
+ header('Location: ?_task=' . array_shift($tasks));
+ die;
+ }
+
+ // add script that will remove disabled taskbar buttons
+ if (!in_array('*', $tasks)) {
+ $this->add_hook('render_page', array($this, 'render_page'));
+ }
+ }
+ }
+
+ // load per-user settings
$this->load_user_role_plugins_and_settings();
return $args;
@@ -101,21 +125,36 @@ class kolab_auth extends rcube_plugin
foreach ($args['result'] as $name => $config) {
if (in_array($name, $kolab_books) || in_array('*', $kolab_books)) {
- $args['result'][$name]['base_dn'] = self::parse_ldap_vars($config['base_dn']);
- $args['result'][$name]['search_base_dn'] = self::parse_ldap_vars($config['search_base_dn']);
- $args['result'][$name]['bind_dn'] = str_replace('%dn', $_SESSION['kolab_dn'], $config['bind_dn']);
-
- if (!empty($config['groups'])) {
- $args['result'][$name]['groups']['base_dn'] = self::parse_ldap_vars($config['groups']['base_dn']);
- }
+ $args['result'][$name] = $this->patch_ldap_config($config);
}
}
}
+ else if ($args['name'] == 'kolab_users_directory' && !empty($args['result'])) {
+ $args['result'] = $this->patch_ldap_config($args['result']);
+ }
return $args;
}
/**
+ * Helper method to patch the given LDAP directory config with user-specific values
+ */
+ protected function patch_ldap_config($config)
+ {
+ if (is_array($config)) {
+ $config['base_dn'] = self::parse_ldap_vars($config['base_dn']);
+ $config['search_base_dn'] = self::parse_ldap_vars($config['search_base_dn']);
+ $config['bind_dn'] = str_replace('%dn', $_SESSION['kolab_dn'], $config['bind_dn']);
+
+ if (!empty($config['groups'])) {
+ $config['groups']['base_dn'] = self::parse_ldap_vars($config['groups']['base_dn']);
+ }
+ }
+
+ return $config;
+ }
+
+ /**
* Modifies list of plugins and settings according to
* specified LDAP roles
*/
@@ -155,24 +194,28 @@ class kolab_auth extends rcube_plugin
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;
+ $role_dn = self::parse_ldap_vars($role_dn);
+ 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';
@@ -194,7 +237,7 @@ class kolab_auth extends rcube_plugin
$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 {
@@ -208,6 +251,19 @@ class kolab_auth extends rcube_plugin
$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->api->load_plugin($plugin);
}
}
}
@@ -225,37 +281,29 @@ class kolab_auth extends rcube_plugin
return $args;
}
- $line = sprintf("[%s]: %s\n", $args['date'], $args['line']);
-
// log_driver == 'file' is assumed here
$log_dir = $rcmail->config->get('log_dir', RCUBE_INSTALL_PATH . 'logs');
- $log_path = $log_dir.'/'.strtolower($_SESSION['kolab_auth_admin']).'/'.strtolower($_SESSION['username']);
- // Append original username + target username
- if (!is_dir($log_path)) {
+ // Append original username + target username for audit-logging
+ if ($rcmail->config->get('kolab_auth_auditlog') && !empty($_SESSION['kolab_auth_admin'])) {
+ $args['dir'] = $log_dir . '/' . strtolower($_SESSION['kolab_auth_admin']) . '/' . strtolower($this->username);
+
// Attempt to create the directory
- if (@mkdir($log_path, 0750, true)) {
- $log_dir = $log_path;
+ if (!is_dir($args['dir'])) {
+ @mkdir($args['dir'], 0750, true);
}
}
- else {
- $log_dir = $log_path;
- }
-
- // try to open specific log file for writing
- $logfile = $log_dir.'/'.$args['name'];
-
- if ($fp = fopen($logfile, 'a')) {
- fwrite($fp, $line);
- fflush($fp);
- fclose($fp);
- }
- else {
- trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING);
+ // Define the user log directory if a username is provided
+ else if ($rcmail->config->get('per_user_logging') && !empty($this->username)) {
+ $user_log_dir = $log_dir . '/' . strtolower($this->username);
+ if (is_writable($user_log_dir)) {
+ $args['dir'] = $user_log_dir;
+ }
+ else if ($args['name'] != 'errors') {
+ $args['abort'] = true; // don't log if unauthenticed
+ }
}
- $args['abort'] = true;
-
return $args;
}
@@ -337,9 +385,13 @@ class kolab_auth extends rcube_plugin
return $args;
}
+ // temporarily set the current username to the one submitted
+ $this->username = $user;
+
$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,
@@ -414,24 +466,69 @@ class kolab_auth extends rcube_plugin
return $args;
}
- // check if the original user has/belongs to administrative role/group
$isadmin = false;
- $group = $rcmail->config->get('kolab_auth_group');
- $role_dn = $rcmail->config->get('kolab_auth_role_value');
-
- // check role attribute
- if (!empty($role_attr) && !empty($role_dn) && !empty($record[$role_attr])) {
- $role_dn = $ldap->parse_vars($role_dn, $user, $host);
- if (in_array($role_dn, (array)$record[$role_attr])) {
- $isadmin = true;
+ $admin_rights = $rcmail->config->get('kolab_auth_admin_rights', array());
+
+ // @deprecated: fall-back to the old check if the original user has/belongs to administrative role/group
+ if (empty($admin_rights)) {
+ $group = $rcmail->config->get('kolab_auth_group');
+ $role_dn = $rcmail->config->get('kolab_auth_role_value');
+
+ // check role attribute
+ if (!empty($role_attr) && !empty($role_dn) && !empty($record[$role_attr])) {
+ $role_dn = $ldap->parse_vars($role_dn, $user, $host);
+ if (in_array($role_dn, (array)$record[$role_attr])) {
+ $isadmin = true;
+ }
+ }
+
+ // check group
+ if (!$isadmin && !empty($group)) {
+ $groups = $ldap->get_user_groups($record['dn'], $user, $host);
+ if (in_array($group, $groups)) {
+ $isadmin = true;
+ }
+ }
+
+ if ($isadmin) {
+ // user has admin privileges privilage, get "login as" user credentials
+ $target_entry = $ldap->get_user_record($loginas, $host);
+ $allowed_tasks = $rcmail->config->get('kolab_auth_allowed_tasks');
}
}
+ else {
+ // get "login as" user credentials
+ $target_entry = $ldap->get_user_record($loginas, $host);
+
+ if (!empty($target_entry)) {
+ // get effective rights to determine login-as permissions
+ $effective_rights = (array)$ldap->effective_rights($target_entry['dn']);
+
+ if (!empty($effective_rights)) {
+ $effective_rights['attrib'] = $effective_rights['attributeLevelRights'];
+ $effective_rights['entry'] = $effective_rights['entryLevelRights'];
+
+ // compare the rights with the permissions mapping
+ $allowed_tasks = array();
+ foreach ($admin_rights as $task => $perms) {
+ $perms_ = explode(':', $perms);
+ $type = array_shift($perms_);
+ $req = array_pop($perms_);
+ $attrib = array_pop($perms_);
+
+ if (array_key_exists($type, $effective_rights)) {
+ if ($type == 'entry' && in_array($req, $effective_rights[$type])) {
+ $allowed_tasks[] = $task;
+ }
+ else if ($type == 'attrib' && array_key_exists($attrib, $effective_rights[$type]) &&
+ in_array($req, $effective_rights[$type][$attrib])) {
+ $allowed_tasks[] = $task;
+ }
+ }
+ }
- // check group
- if (!$isadmin && !empty($group)) {
- $groups = $ldap->get_user_groups($record['dn'], $user, $host);
- if (in_array($group, $groups)) {
- $isadmin = true;
+ $isadmin = !empty($allowed_tasks);
+ }
}
}
@@ -443,22 +540,22 @@ class kolab_auth extends rcube_plugin
$origname = $user;
}
- $record = null;
-
- // user has the privilage, get "login as" user credentials
- if ($isadmin) {
- $record = $ldap->get_user_record($loginas, $host);
- }
+ if (!$isadmin || empty($target_entry)) {
+ $this->add_texts('localization/');
- if (empty($record)) {
$args['abort'] = true;
+ $args['error'] = $this->gettext(array(
+ 'name' => 'loginasnotallowed',
+ 'vars' => array('user' => Q($loginas)),
+ ));
+
$message = sprintf(
'Login failure for user %s (as user %s) from %s in session %s (error %s)',
$user,
$loginas,
rcube_utils::remote_ip(),
session_id(),
- "No user record found for '" . $loginas . "'"
+ "No privileges to login as '" . $loginas . "'"
);
rcube::write_log('userlogins', $message);
@@ -466,12 +563,16 @@ class kolab_auth extends rcube_plugin
return $args;
}
- $args['user'] = $loginas;
+ // replace $record with target entry
+ $record = $target_entry;
+
+ $args['user'] = $this->username = $loginas;
// Mark session to use SASL proxy for IMAP authentication
$_SESSION['kolab_auth_admin'] = strtolower($origname);
$_SESSION['kolab_auth_login'] = $rcmail->encrypt($admin_login);
$_SESSION['kolab_auth_password'] = $rcmail->encrypt($admin_pass);
+ $_SESSION['kolab_auth_allowed_tasks'] = $allowed_tasks;
}
// Store UID and DN of logged user in session for use by other plugins
@@ -489,7 +590,7 @@ class kolab_auth extends rcube_plugin
$this->data['user_login'] = is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr];
}
if ($this->data['user_login']) {
- $args['user'] = $this->data['user_login'];
+ $args['user'] = $this->username = $this->data['user_login'];
}
// User name for identity (first log in)
@@ -522,6 +623,9 @@ class kolab_auth extends rcube_plugin
$args['user'], $origname, rcube_utils::remote_ip()));
}
+ // load per-user settings/plugins
+ $this->load_user_role_plugins_and_settings();
+
return $args;
}
@@ -566,8 +670,8 @@ class kolab_auth extends rcube_plugin
$admin_login = $rcmail->decrypt($_SESSION['kolab_auth_login']);
$admin_pass = $rcmail->decrypt($_SESSION['kolab_auth_password']);
- $args['options']['smtp_auth_cid'] = $admin_login;
- $args['options']['smtp_auth_pw'] = $admin_pass;
+ $args['smtp_auth_cid'] = $admin_login;
+ $args['smtp_auth_pw'] = $admin_pass;
}
return $args;
@@ -616,6 +720,28 @@ class kolab_auth extends rcube_plugin
}
/**
+ * Action executed before the page is rendered to add an onload script
+ * that will remove all taskbar buttons for disabled tasks
+ */
+ public function render_page($args)
+ {
+ $rcmail = rcube::get_instance();
+ $tasks = (array)$_SESSION['kolab_auth_allowed_tasks'];
+ $tasks[] = 'logout';
+
+ // disable buttons in taskbar
+ $script = "
+ \$('a').filter(function() {
+ var ev = \$(this).attr('onclick');
+ return ev && ev.match(/'switch-task','([a-z]+)'/)
+ && \$.inArray(RegExp.\$1, " . json_encode($tasks) . ") < 0;
+ }).remove();
+ ";
+
+ $rcmail->output->add_script($script, 'docready');
+ }
+
+ /**
* Initializes LDAP object and connects to LDAP server
*/
public static function ldap()
diff --git a/lib/drivers/kolab/plugins/kolab_auth/kolab_auth_ldap.php b/lib/drivers/kolab/plugins/kolab_auth/kolab_auth_ldap.php
index b9b3e4a..431133b 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/kolab_auth_ldap.php
+++ b/lib/drivers/kolab/plugins/kolab_auth/kolab_auth_ldap.php
@@ -28,17 +28,22 @@
class kolab_auth_ldap extends rcube_ldap_generic
{
private $icache = array();
+ private $conf = array();
+ private $fieldmap = array();
function __construct($p)
{
$rcmail = rcube::get_instance();
- $this->debug = (bool) $rcmail->config->get('ldap_debug');
+ $this->conf = $p;
+ $this->conf['kolab_auth_user_displayname'] = $rcmail->config->get('kolab_auth_user_displayname', '{name}');
+
$this->fieldmap = $p['fieldmap'];
$this->fieldmap['uid'] = 'uid';
$p['attributes'] = array_values($this->fieldmap);
+ $p['debug'] = (bool) $rcmail->config->get('ldap_debug');
// Connect to the server (with bind)
parent::__construct($p);
@@ -52,8 +57,6 @@ class kolab_auth_ldap extends rcube_ldap_generic
*/
private function _connect()
{
- $rcube = rcube::get_instance();
-
// try to connect + bind for every host configured
// with OpenLDAP 2.x ldap_connect() always succeeds but ldap_bind will fail if host isn't reachable
// see http://www.php.net/manual/en/function.ldap-connect.php
@@ -152,11 +155,10 @@ class kolab_auth_ldap extends rcube_ldap_generic
$groups = array();
foreach ($result as $entry) {
+ $dn = $entry['dn'];
$entry = rcube_ldap_generic::normalize_entry($entry);
- if (!$entry['dn']) {
- $entry['dn'] = $result->get_dn();
- }
- $groups[$entry['dn']] = $entry[$name_attr];
+
+ $groups[$dn] = $entry[$name_attr];
}
return $groups;
@@ -197,7 +199,9 @@ class kolab_auth_ldap extends rcube_ldap_generic
foreach ($this->fieldmap as $field => $attr) {
if (array_key_exists($field, $entry)) {
$entry[$attr] = $entry[$field];
- unset($entry[$field]);
+ if ($attr != $field) {
+ unset($entry[$field]);
+ }
}
}
@@ -207,20 +211,24 @@ class kolab_auth_ldap extends rcube_ldap_generic
/**
* 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*),
* 1 - strict (=),
* 2 - prefix (abc*)
- * @param boolean $select True if results are requested, False if count only
* @param array $required List of fields that cannot be empty
* @param int $limit Number of records
+ * @param int $count Returns the number of records found
*
* @return array List or false on error
*/
- function search($fields, $value, $mode=1, $required = array(), $limit = 0)
+ function dosearch($fields, $value, $mode=1, $required = array(), $limit = 0, &$count = 0)
{
+ if (empty($fields)) {
+ return array();
+ }
+
$mode = intval($mode);
// use AND operator for advanced searches
@@ -236,8 +244,13 @@ class kolab_auth_ldap extends rcube_ldap_generic
}
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 +267,13 @@ class kolab_auth_ldap extends rcube_ldap_generic
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)
@@ -281,13 +300,15 @@ class kolab_auth_ldap extends rcube_ldap_generic
$attrs = array_values($this->fieldmap);
$list = array();
- if ($result = parent::search($base_dn, $filter, $scope, $attrs)) {
+ if ($result = $this->search($base_dn, $filter, $scope, $attrs)) {
+ $count = $result->count();
$i = 0;
foreach ($result as $entry) {
if ($limit && $limit <= $i) {
break;
}
- $dn = $result->get_dn();
+
+ $dn = $entry['dn'];
$entry = rcube_ldap_generic::normalize_entry($entry);
$list[$dn] = $this->field_mapping($dn, $entry);
$i++;
@@ -314,11 +335,26 @@ class kolab_auth_ldap extends rcube_ldap_generic
// fields mapping
foreach ($this->fieldmap as $field => $attr) {
- if (isset($entry[$attr])) {
+ // $entry might be indexed by lower-case attribute names
+ $attr_lc = strtolower($attr);
+ if (isset($entry[$attr_lc])) {
+ $entry[$field] = $entry[$attr_lc];
+ }
+ else if (isset($entry[$attr])) {
$entry[$field] = $entry[$attr];
}
}
+ // compose display name according to config
+ if (empty($this->fieldmap['displayname'])) {
+ $entry['displayname'] = rcube_addressbook::compose_search_name(
+ $entry,
+ $entry['email'],
+ $entry['name'],
+ $this->conf['kolab_auth_user_displayname']
+ );
+ }
+
return $entry;
}
@@ -473,6 +509,19 @@ class kolab_auth_ldap extends rcube_ldap_generic
}
/**
+ * Register additional fields
+ */
+ public function extend_fieldmap($map)
+ {
+ foreach ((array)$map as $name => $attr) {
+ if (!in_array($attr, $this->attributes)) {
+ $this->attributes[] = $attr;
+ $this->fieldmap[$name] = $attr;
+ }
+ }
+ }
+
+ /**
* HTML-safe DN string encoding
*
* @param string $str DN string
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/bg_BG.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/bg_BG.inc
index 1f7a573..01e1ac2 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/bg_BG.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/bg_BG.inc
@@ -1,3 +1,10 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Влизане като';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/de_CH.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/de_CH.inc
index 5e85a01..0332070 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/de_CH.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/de_CH.inc
@@ -1,3 +1,10 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Anmelden als';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/de_DE.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/de_DE.inc
index 5e85a01..3918e6e 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/de_DE.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/de_DE.inc
@@ -1,3 +1,11 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Anmelden als';
+$labels['loginasnotallowed'] = 'Keine Privilegien zum Anmelden als $user';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/en_US.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/en_US.inc
index e1adb3f..4882bdc 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/en_US.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/en_US.inc
@@ -1,5 +1,14 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
+
$labels['loginas'] = 'Login As';
+$labels['loginasnotallowed'] = 'No privileges to login as $user';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/es_ES.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/es_ES.inc
index acb6c35..ed203e6 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/es_ES.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/es_ES.inc
@@ -1,2 +1,9 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/et_EE.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/et_EE.inc
index acb6c35..ed203e6 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/et_EE.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/et_EE.inc
@@ -1,2 +1,9 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/fr_FR.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/fr_FR.inc
index 6f72695..6538f5b 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/fr_FR.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/fr_FR.inc
@@ -1,3 +1,11 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Se connecter en tant que';
+$labels['loginasnotallowed'] = 'Pas de privilège de se connecter comme $utilisateur';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/ja_JP.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/ja_JP.inc
index ed0358a..e360737 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/ja_JP.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/ja_JP.inc
@@ -1,3 +1,10 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'ログイン';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/nl_NL.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/nl_NL.inc
index a98283f..ea3a1c0 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/nl_NL.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/nl_NL.inc
@@ -1,3 +1,10 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Log in als';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/pl_PL.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/pl_PL.inc
index 124c373..ca67859 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/pl_PL.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/pl_PL.inc
@@ -1,3 +1,10 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Zaloguj jako';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/pt_BR.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/pt_BR.inc
index 26e9541..e594c2e 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/pt_BR.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/pt_BR.inc
@@ -1,3 +1,10 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Logar como';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/localization/ru_RU.inc b/lib/drivers/kolab/plugins/kolab_auth/localization/ru_RU.inc
index 9e28c12..ac9e5a7 100644
--- a/lib/drivers/kolab/plugins/kolab_auth/localization/ru_RU.inc
+++ b/lib/drivers/kolab/plugins/kolab_auth/localization/ru_RU.inc
@@ -1,3 +1,11 @@
<?php
+/**
+ * Localizations for the Kolab Auth plugin
+ *
+ * Copyright (C) 2014, Kolab Systems AG
+ *
+ * For translation see https://www.transifex.com/projects/p/kolab/resource/kolab_auth/
+ */
$labels['loginas'] = 'Войти как';
+$labels['loginasnotallowed'] = 'Нет привилегий войти как $user';
?>
diff --git a/lib/drivers/kolab/plugins/kolab_auth/package.xml b/lib/drivers/kolab/plugins/kolab_auth/package.xml
deleted file mode 100644
index 5a2093b..0000000
--- a/lib/drivers/kolab/plugins/kolab_auth/package.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
- http://pear.php.net/dtd/tasks-1.0.xsd
- http://pear.php.net/dtd/package-2.0
- http://pear.php.net/dtd/package-2.0.xsd">
- <name>kolab_auth</name>
- <uri>http://git.kolab.org/roundcubemail-plugins-kolab/</uri>
- <summary>Kolab Authentication</summary>
- <description>
- Authenticates on LDAP server, finds canonized authentication ID for IMAP
- and for new users creates identity based on LDAP information.
- Supports impersonate feature (login as another user). To use this feature
- imap_auth_type/smtp_auth_type must be set to DIGEST-MD5 or PLAIN.
- </description>
- <lead>
- <name>Aleksander Machniak</name>
- <user>machniak</user>
- <email>machniak@kolabsys.com</email>
- <active>yes</active>
- </lead>
- <date>2013-10-04</date>
- <version>
- <release>1.0</release>
- <api>1.0</api>
- </version>
- <stability>
- <release>stable</release>
- <api>stable</api>
- </stability>
- <license uri="http://www.gnu.org/licenses/agpl.html">GNU AGPLv3</license>
- <notes>-</notes>
- <contents>
- <dir baseinstalldir="/" name="/">
- <file name="kolab_auth.php" role="php">
- <tasks:replace from="@name@" to="name" type="package-info"/>
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="kolab_auth_ldap.php" role="php">
- <tasks:replace from="@name@" to="name" type="package-info"/>
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="config.inc.php.dist" role="data"></file>
- <file name="LICENSE" role="data"></file>
-
- <file name="localization/de_CH.inc" role="data"></file>
- <file name="localization/de_DE.inc" role="data"></file>
- <file name="localization/en_US.inc" role="data"></file>
- <file name="localization/pl_PL.inc" role="data"></file>
- </dir>
- <!-- / -->
- </contents>
- <dependencies>
- <required>
- <php>
- <min>5.2.1</min>
- </php>
- <pearinstaller>
- <min>1.7.0</min>
- </pearinstaller>
- </required>
- </dependencies>
- <phprelease/>
-</package>
diff --git a/lib/drivers/kolab/plugins/libkolab/SQL/mysql.initial.sql b/lib/drivers/kolab/plugins/libkolab/SQL/mysql.initial.sql
index 2aa046d..98e7e78 100644
--- a/lib/drivers/kolab/plugins/libkolab/SQL/mysql.initial.sql
+++ b/lib/drivers/kolab/plugins/libkolab/SQL/mysql.initial.sql
@@ -31,7 +31,7 @@ CREATE TABLE `kolab_cache_contact` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
`name` VARCHAR(255) NOT NULL,
@@ -55,7 +55,7 @@ CREATE TABLE `kolab_cache_event` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`dtstart` DATETIME,
`dtend` DATETIME,
@@ -75,7 +75,7 @@ CREATE TABLE `kolab_cache_task` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`dtstart` DATETIME,
`dtend` DATETIME,
@@ -95,7 +95,7 @@ CREATE TABLE `kolab_cache_journal` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`dtstart` DATETIME,
`dtend` DATETIME,
@@ -115,7 +115,7 @@ CREATE TABLE `kolab_cache_note` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
CONSTRAINT `fk_kolab_cache_note_folder` FOREIGN KEY (`folder_id`)
REFERENCES `kolab_folders`(`folder_id`) ON DELETE CASCADE ON UPDATE CASCADE,
@@ -133,7 +133,7 @@ CREATE TABLE `kolab_cache_file` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`filename` varchar(255) DEFAULT NULL,
CONSTRAINT `fk_kolab_cache_file_folder` FOREIGN KEY (`folder_id`)
@@ -153,7 +153,7 @@ CREATE TABLE `kolab_cache_configuration` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`type` VARCHAR(32) CHARACTER SET ascii NOT NULL,
CONSTRAINT `fk_kolab_cache_configuration_folder` FOREIGN KEY (`folder_id`)
@@ -173,7 +173,7 @@ CREATE TABLE `kolab_cache_freebusy` (
`changed` DATETIME DEFAULT NULL,
`data` LONGTEXT NOT NULL,
`xml` LONGBLOB NOT NULL,
- `tags` VARCHAR(255) NOT NULL,
+ `tags` TEXT NOT NULL,
`words` TEXT NOT NULL,
`dtstart` DATETIME,
`dtend` DATETIME,
@@ -184,4 +184,4 @@ CREATE TABLE `kolab_cache_freebusy` (
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2014021000');
+INSERT INTO `system` (`name`, `value`) VALUES ('libkolab-version', '2015011600');
diff --git a/lib/drivers/kolab/plugins/libkolab/SQL/mysql/2014112700.sql b/lib/drivers/kolab/plugins/libkolab/SQL/mysql/2014112700.sql
new file mode 100644
index 0000000..90c77b8
--- /dev/null
+++ b/lib/drivers/kolab/plugins/libkolab/SQL/mysql/2014112700.sql
@@ -0,0 +1,2 @@
+-- delete cache entries for old folder identifiers
+DELETE FROM `kolab_folders` WHERE `resource` LIKE 'imap://anonymous@%';
diff --git a/lib/drivers/kolab/plugins/libkolab/SQL/mysql/2015011600.sql b/lib/drivers/kolab/plugins/libkolab/SQL/mysql/2015011600.sql
new file mode 100644
index 0000000..be523ae
--- /dev/null
+++ b/lib/drivers/kolab/plugins/libkolab/SQL/mysql/2015011600.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `kolab_cache_contact` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_event` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_task` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_journal` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_note` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_file` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_configuration` MODIFY `tags` text NOT NULL;
+ALTER TABLE `kolab_cache_freebusy` MODIFY `tags` text NOT NULL;
diff --git a/lib/drivers/kolab/plugins/libkolab/SQL/oracle.initial.sql b/lib/drivers/kolab/plugins/libkolab/SQL/oracle.initial.sql
index 2c078cb..8f1ed64 100644
--- a/lib/drivers/kolab/plugins/libkolab/SQL/oracle.initial.sql
+++ b/lib/drivers/kolab/plugins/libkolab/SQL/oracle.initial.sql
@@ -25,7 +25,7 @@ BEFORE INSERT ON "kolab_folders" FOR EACH ROW
BEGIN
:NEW."folder_id" := "kolab_folders_seq".nextval;
END;
-
+/
CREATE TABLE "kolab_cache_contact" (
"folder_id" number NOT NULL
@@ -36,7 +36,7 @@ CREATE TABLE "kolab_cache_contact" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"type" varchar(32) NOT NULL,
"name" varchar(255) DEFAULT NULL,
@@ -59,7 +59,7 @@ CREATE TABLE "kolab_cache_event" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"dtstart" timestamp DEFAULT NULL,
"dtend" timestamp DEFAULT NULL,
@@ -78,7 +78,7 @@ CREATE TABLE "kolab_cache_task" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"dtstart" timestamp DEFAULT NULL,
"dtend" timestamp DEFAULT NULL,
@@ -97,7 +97,7 @@ CREATE TABLE "kolab_cache_journal" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"dtstart" timestamp DEFAULT NULL,
"dtend" timestamp DEFAULT NULL,
@@ -116,7 +116,7 @@ CREATE TABLE "kolab_cache_note" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
PRIMARY KEY ("folder_id", "msguid")
);
@@ -133,7 +133,7 @@ CREATE TABLE "kolab_cache_file" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"filename" varchar(255) DEFAULT NULL,
PRIMARY KEY ("folder_id", "msguid")
@@ -152,7 +152,7 @@ CREATE TABLE "kolab_cache_configuration" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"type" varchar(32) NOT NULL,
PRIMARY KEY ("folder_id", "msguid")
@@ -171,7 +171,7 @@ CREATE TABLE "kolab_cache_freebusy" (
"changed" timestamp DEFAULT NULL,
"data" clob NOT NULL,
"xml" clob NOT NULL,
- "tags" varchar(255) DEFAULT NULL,
+ "tags" clob DEFAULT NULL,
"words" clob DEFAULT NULL,
"dtstart" timestamp DEFAULT NULL,
"dtend" timestamp DEFAULT NULL,
@@ -181,4 +181,4 @@ CREATE TABLE "kolab_cache_freebusy" (
CREATE INDEX "kolab_cache_fb_uid2msguid" ON "kolab_cache_freebusy" ("folder_id", "uid", "msguid");
-INSERT INTO "system" ("name", "value") VALUES ('libkolab-version', '2014021000');
+INSERT INTO "system" ("name", "value") VALUES ('libkolab-version', '2015011600');
diff --git a/lib/drivers/kolab/plugins/libkolab/SQL/oracle/2015011600.sql b/lib/drivers/kolab/plugins/libkolab/SQL/oracle/2015011600.sql
new file mode 100644
index 0000000..69f7953
--- /dev/null
+++ b/lib/drivers/kolab/plugins/libkolab/SQL/oracle/2015011600.sql
@@ -0,0 +1,40 @@
+-- direct change from varchar to clob does not work, need temp column (#4257)
+ALTER TABLE "kolab_cache_contact" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_contact" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_contact" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_contact" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_event" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_event" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_event" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_event" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_task" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_task" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_task" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_task" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_journal" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_journal" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_journal" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_journal" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_note" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_note" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_note" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_note" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_file" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_file" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_file" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_file" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_configuration" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_configuration" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_configuration" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_configuration" RENAME COLUMN "tags1" TO "tags";
+
+ALTER TABLE "kolab_cache_freebusy" ADD "tags1" clob DEFAULT NULL;
+UPDATE "kolab_cache_freebusy" SET "tags1" = "tags";
+ALTER TABLE "kolab_cache_freebusy" DROP COLUMN "tags";
+ALTER TABLE "kolab_cache_freebusy" RENAME COLUMN "tags1" TO "tags";
diff --git a/lib/drivers/kolab/plugins/libkolab/bin/readcache.sh b/lib/drivers/kolab/plugins/libkolab/bin/readcache.sh
new file mode 100755
index 0000000..7e6a3a3
--- /dev/null
+++ b/lib/drivers/kolab/plugins/libkolab/bin/readcache.sh
@@ -0,0 +1,150 @@
+#!/usr/bin/env php
+<?php
+
+/**
+ * Kolab storage cache testing script
+ *
+ * @author Thomas Bruederli <bruederli@kolabsys.com>
+ *
+ * Copyright (C) 2014, Kolab Systems AG <contact@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+define('INSTALL_PATH', realpath('.') . '/' );
+ini_set('display_errors', 1);
+libxml_use_internal_errors(true);
+
+if (!file_exists(INSTALL_PATH . 'program/include/clisetup.php'))
+ die("Execute this from the Roundcube installation dir!\n\n");
+
+require_once INSTALL_PATH . 'program/include/clisetup.php';
+
+function print_usage()
+{
+ print "Usage: readcache.sh [OPTIONS] FOLDER\n";
+ print "-h, --host IMAP host name\n";
+ print "-l, --limit Limit the number of records to be listed\n";
+}
+
+// read arguments
+$opts = get_opt(array(
+ 'h' => 'host',
+ 'l' => 'limit',
+ 'v' => 'verbose',
+));
+
+$folder = $opts[0];
+$imap_host = $opts['host'];
+
+$rcmail = rcube::get_instance(rcube::INIT_WITH_DB | rcube::INIT_WITH_PLUGINS);
+
+if (empty($imap_host)) {
+ $default_host = $rcmail->config->get('default_host');
+ if (is_array($default_host)) {
+ list($k,$v) = each($default_host);
+ $imap_host = is_numeric($k) ? $v : $k;
+ }
+ else {
+ $imap_host = $default_host;
+ }
+
+ // strip protocol prefix
+ $imap_host = preg_replace('!^[a-z]+://!', '', $imap_host);
+}
+
+if (empty($folder) || empty($imap_host)) {
+ print_usage();
+ exit;
+}
+
+// connect to database
+$db = $rcmail->get_dbh();
+$db->db_connect('r');
+if (!$db->is_connected() || $db->is_error())
+ die("No DB connection\n");
+
+
+// resolve folder_id
+if (!is_numeric($folder)) {
+ if (strpos($folder, '@')) {
+ list($mailbox, $domain) = explode('@', $folder);
+ list($username, $subpath) = explode('/', preg_replace('!^user/!', '', $mailbox), 2);
+ $folder_uri = 'imap://' . urlencode($username.'@'.$domain) . '@' . $imap_host . '/' . $subpath;
+ }
+ else {
+ die("Invalid mailbox identifier! Example: user/john.doe/Calendar@example.org\n");
+ }
+
+ print "Resolving folder $folder_uri...";
+ $sql_result = $db->query('SELECT * FROM `kolab_folders` WHERE `resource`=?', $folder_uri);
+ if ($sql_result && ($folder_data = $db->fetch_assoc($sql_result))) {
+ $folder_id = $folder_data['folder_id'];
+ print $folder_id;
+ }
+ print "\n";
+}
+else {
+ $folder_id = intval($folder);
+ $sql_result = $db->query('SELECT * FROM `kolab_folders` WHERE `folder_id`=?', $folder_id);
+ if ($sql_result) {
+ $folder_data = $db->fetch_assoc($sql_result);
+ }
+}
+
+if (empty($folder_data)) {
+ die("Can't find cache mailbox for '$folder'\n");
+}
+
+print "Querying cache for folder $folder_id ($folder_data[type])...\n";
+
+$extra_cols = array(
+ 'event' => array('dtstart','dtend'),
+ 'contact' => array('type'),
+);
+
+$cache_table = $db->table_name('kolab_cache_' . $folder_data['type']);
+$extra_cols_ = $extra_cols[$folder_data['type']] ?: array();
+$sql_arr = $db->fetch_assoc($db->query("SELECT COUNT(*) as cnt FROM `$cache_table` WHERE `folder_id`=?", intval($folder_id)));
+
+print "CTag = " . $folder_data['ctag'] . "\n";
+print "Lock = " . $folder_data['synclock'] . "\n";
+print "Count = " . $sql_arr['cnt'] . "\n";
+print "----------------------------------------------------------------------------------\n";
+print "<MSG>\t<UUID>\t<CHANGED>\t<DATA>\t<XML>\t";
+print join("\t", array_map(function($c) { return '<' . strtoupper($c) . '>'; }, $extra_cols_));
+print "\n----------------------------------------------------------------------------------\n";
+
+$result = $db->limitquery("SELECT * FROM `$cache_table` WHERE `folder_id`=?", 0, $opts['limit'], intval($folder_id));
+while ($result && ($sql_arr = $db->fetch_assoc($result))) {
+ print $sql_arr['msguid'] . "\t" . $sql_arr['uid'] . "\t" . $sql_arr['changed'];
+
+ // try to unserialize data block
+ $object = @unserialize(@base64_decode($sql_arr['data']));
+ print "\t" . ($object === false ? 'FAIL!' : ($object['uid'] == $sql_arr['uid'] ? 'OK' : '!!!'));
+
+ // check XML validity
+ $xml = simplexml_load_string($sql_arr['xml']);
+ print "\t" . ($xml === false ? 'FAIL!' : 'OK');
+
+ // print extra cols
+ array_walk($extra_cols_, function($c) use ($sql_arr) {
+ print "\t" . $sql_arr[$c];
+ });
+
+ print "\n";
+}
+
+print "----------------------------------------------------------------------------------\n";
+echo "Done.\n";
diff --git a/lib/drivers/kolab/plugins/libkolab/composer.json b/lib/drivers/kolab/plugins/libkolab/composer.json
index 8926037..b458df6 100644
--- a/lib/drivers/kolab/plugins/libkolab/composer.json
+++ b/lib/drivers/kolab/plugins/libkolab/composer.json
@@ -4,7 +4,7 @@
"description": "Plugin to setup a basic environment for the interaction with a Kolab server.",
"homepage": "http://git.kolab.org/roundcubemail-plugins-kolab/",
"license": "AGPLv3",
- "version": "1.1.0",
+ "version": "3.2.3",
"authors": [
{
"name": "Thomas Bruederli",
diff --git a/lib/drivers/kolab/plugins/libkolab/config.inc.php.dist b/lib/drivers/kolab/plugins/libkolab/config.inc.php.dist
index 79d2aa8..7efa8d1 100644
--- a/lib/drivers/kolab/plugins/libkolab/config.inc.php.dist
+++ b/lib/drivers/kolab/plugins/libkolab/config.inc.php.dist
@@ -38,6 +38,7 @@ $config['kolab_messages_cache_bypass'] = 0;
// LDAP directory to find avilable users for folder sharing.
// Either contains an array with LDAP addressbook configuration or refers to entry in $config['ldap_public'].
// If not specified, the configuraton from 'kolab_auth_addressbook' will be used.
+// Should be provided for multi-domain setups with placeholders like %dc, %d, %u, %fu or %dn.
$config['kolab_users_directory'] = null;
// Filter to be used for resolving user folders in LDAP.
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_bonnie_api.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_bonnie_api.php
index 23dafd8..e8ac131 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_bonnie_api.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_bonnie_api.php
@@ -36,7 +36,7 @@ class kolab_bonnie_api
*/
public function __construct($config)
{
- $this->config = $confg;
+ $this->config = $config;
$this->client = new kolab_bonnie_api_client($config['uri'], $config['timeout'] ?: 5, (bool)$config['debug']);
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format.php
index 8c6b1d4..625483b 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format.php
@@ -223,7 +223,7 @@ abstract class kolab_format
if ($tz) $datetime->setTimezone($tz);
}
else if (is_string($datetime) && strlen($datetime)) {
- $datetime = new DateTime($datetime, $tz ?: null);
+ $datetime = $tz ? new DateTime($datetime, $tz) : new DateTime($datetime);
}
}
catch (Exception $e) {}
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_configuration.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_configuration.php
index 4b06302..ceb7ebb 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_configuration.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_configuration.php
@@ -24,7 +24,7 @@
class kolab_format_configuration extends kolab_format
{
- public $CTYPE = 'application/x-vnd.kolab.configuration';
+ public $CTYPE = 'application/vnd.kolab+xml';
public $CTYPEv2 = 'application/x-vnd.kolab.configuration';
protected $objclass = 'Configuration';
@@ -48,9 +48,6 @@ class kolab_format_configuration extends kolab_format
*/
public function set(&$object)
{
- // set common object properties
- parent::set($object);
-
// read type-specific properties
switch ($object['type']) {
case 'dictionary':
@@ -126,7 +123,12 @@ class kolab_format_configuration extends kolab_format
}
// adjust content-type string
- $this->CTYPE = $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type'];
+ $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type'];
+
+ // reset old object data, otherwise set() will overwrite current data (#4095)
+ $this->xmldata = null;
+ // set common object properties
+ parent::set($object);
// cache this data
$this->data = $object;
@@ -222,7 +224,7 @@ class kolab_format_configuration extends kolab_format
// adjust content-type string
if ($object['type']) {
- $this->CTYPE = $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type'];
+ $this->CTYPEv2 = 'application/x-vnd.kolab.configuration.' . $object['type'];
}
$this->data = $object;
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_event.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_event.php
index c233f44..8cad89a 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_event.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_event.php
@@ -96,11 +96,13 @@ class kolab_format_event extends kolab_format_xcal
// save recurrence exceptions
if (is_array($object['recurrence']) && $object['recurrence']['EXCEPTIONS']) {
$vexceptions = new vectorevent;
- foreach((array)$object['recurrence']['EXCEPTIONS'] as $exception) {
+ foreach((array)$object['recurrence']['EXCEPTIONS'] as $i => $exception) {
$exevent = new kolab_format_event;
- $exevent->set($this->compact_exception($exception, $object)); // only save differing values
+ $exevent->set(($compacted = $this->compact_exception($exception, $object))); // only save differing values
$exevent->obj->setRecurrenceID(self::get_datetime($exception['start'], null, true), (bool)$exception['thisandfuture']);
$vexceptions->push($exevent->obj);
+ // write cleaned-up exception data back to memory/cache
+ $object['recurrence']['EXCEPTIONS'][$i] = $this->expand_exception($compacted, $object);
}
$this->obj->setExceptions($vexceptions);
}
@@ -217,6 +219,12 @@ class kolab_format_event extends kolab_format_xcal
}
}
+ foreach ($master as $prop => $value) {
+ if (isset($exception[$prop]) && gettype($exception[$prop]) == gettype($value) && $exception[$prop] == $value) {
+ unset($exception[$prop]);
+ }
+ }
+
return $exception;
}
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_xcal.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_xcal.php
index 08f27d0..ad54505 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_xcal.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_format_xcal.php
@@ -364,14 +364,17 @@ abstract class kolab_format_xcal extends kolab_format
$cr = new ContactReference(ContactReference::EmailReference, $attendee['email']);
$cr->setName($attendee['name']);
+ // set attendee RSVP if missing
+ if (!isset($attendee['rsvp'])) {
+ $object['attendees'][$i]['rsvp'] = $attendee['rsvp'] = true;
+ }
+
$att = new Attendee;
$att->setContact($cr);
$att->setPartStat($this->part_status_map[$attendee['status']]);
$att->setRole($this->role_map[$attendee['role']] ? $this->role_map[$attendee['role']] : kolabformat::Required);
$att->setCutype($this->cutype_map[$attendee['cutype']] ? $this->cutype_map[$attendee['cutype']] : kolabformat::CutypeIndividual);
- $att->setRSVP((bool)$attendee['rsvp'] || $reschedule);
-
- $object['attendees'][$i]['rsvp'] = $attendee['rsvp'] || $reschedule;
+ $att->setRSVP((bool)$attendee['rsvp']);
if (!empty($attendee['delegated-from'])) {
$vdelegators = new vectorcontactref;
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage.php
index dfd1887..47c1e4b 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage.php
@@ -35,6 +35,11 @@ class kolab_storage
const UID_KEY_PRIVATE = '/private/vendor/kolab/uniqueid';
const UID_KEY_CYRUS = '/shared/vendor/cmu/cyrus-imapd/uniqueid';
+ const ERROR_IMAP_CONN = 1;
+ const ERROR_CACHE_DB = 2;
+ const ERROR_NO_PERMISSION = 3;
+ const ERROR_INVALID_FOLDER = 4;
+
public static $version = '3.0';
public static $last_error;
public static $encode_ids = false;
@@ -139,7 +144,6 @@ class kolab_storage
return self::$ldap;
}
-
/**
* Get a list of storage folders for the given data type
*
@@ -154,7 +158,7 @@ class kolab_storage
if (self::setup()) {
foreach ((array)self::list_folders('', '*', $type, $subscribed, $folderdata) as $foldername) {
- $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
+ $folders[$foldername] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
}
}
@@ -171,26 +175,26 @@ class kolab_storage
{
if (self::setup()) {
foreach ((array)self::list_folders('', '*', $type . '.default', false, $folderdata) as $foldername) {
- return new kolab_storage_folder($foldername, $folderdata[$foldername]);
+ return new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
}
}
return null;
}
-
/**
* Getter for a specific storage folder
*
- * @param string IMAP folder to access (UTF7-IMAP)
+ * @param string IMAP folder to access (UTF7-IMAP)
+ * @param string Expected folder type
+ *
* @return object kolab_storage_folder The folder object
*/
- public static function get_folder($folder)
+ public static function get_folder($folder, $type = null)
{
- return self::setup() ? new kolab_storage_folder($folder) : null;
+ return self::setup() ? new kolab_storage_folder($folder, $type) : null;
}
-
/**
* Getter for a single Kolab object, identified by its UID.
* This will search all folders storing objects of the given type.
@@ -203,11 +207,11 @@ class kolab_storage
{
self::setup();
$folder = null;
- foreach ((array)self::list_folders('', '*', $type) as $foldername) {
+ foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
if (!$folder)
- $folder = new kolab_storage_folder($foldername);
+ $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
else
- $folder->set_folder($foldername);
+ $folder->set_folder($foldername, $type, $folderdata[$foldername]);
if ($object = $folder->get_object($uid, '*'))
return $object;
@@ -230,11 +234,11 @@ class kolab_storage
$folder = null;
$result = array();
- foreach ((array)self::list_folders('', '*', $type) as $foldername) {
+ foreach ((array)self::list_folders('', '*', $type, null, $folderdata) as $foldername) {
if (!$folder)
- $folder = new kolab_storage_folder($foldername);
+ $folder = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
else
- $folder->set_folder($foldername);
+ $folder->set_folder($foldername, $type, $folderdata[$foldername]);
foreach ($folder->select($query, '*') as $object) {
$result[] = $object;
@@ -403,13 +407,13 @@ class kolab_storage
'oldname' => $oldname, 'newname' => $newname));
$oldfolder = self::get_folder($oldname);
- $active = self::folder_is_active($oldname);
- $success = self::$imap->rename_folder($oldname, $newname);
+ $active = self::folder_is_active($oldname);
+ $success = self::$imap->rename_folder($oldname, $newname);
self::$last_error = self::$imap->get_error_str();
// pass active state to new folder name
if ($success && $active) {
- self::set_state($oldnam, false);
+ self::set_state($oldname, false);
self::set_state($newname, true);
}
@@ -901,7 +905,7 @@ class kolab_storage
!self::folder_is_subscribed($foldername, true) &&
!in_array(self::$imap->folder_namespace($foldername), (array)$exclude_ns)
) {
- $folders[] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
+ $folders[] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
}
}
@@ -974,7 +978,7 @@ class kolab_storage
$parent_parent = join($delim, $path);
if (!$refs[$parent]) {
if ($folder->type && self::folder_type($parent) == $folder->type) {
- $refs[$parent] = new kolab_storage_folder($parent, $folder->type);
+ $refs[$parent] = new kolab_storage_folder($parent, $folder->type, $folder->type);
$refs[$parent]->parent = $parent_parent;
}
else if ($parent_parent == $other_ns) {
@@ -1086,7 +1090,7 @@ class kolab_storage
return $types[self::CTYPE_KEY_PRIVATE];
}
else if (!empty($types[self::CTYPE_KEY])) {
- list($ctype, $suffix) = explode('.', $types[self::CTYPE_KEY]);
+ list($ctype, ) = explode('.', $types[self::CTYPE_KEY]);
return $ctype;
}
return null;
@@ -1193,7 +1197,7 @@ class kolab_storage
}
}
else if (self::$imap->subscribe($folder)) {
- self::$subscriptions === null;
+ self::$subscriptions = null;
return true;
}
@@ -1221,7 +1225,7 @@ class kolab_storage
return true;
}
else if (self::$imap->unsubscribe($folder)) {
- self::$subscriptions === null;
+ self::$subscriptions = null;
return true;
}
@@ -1464,7 +1468,7 @@ class kolab_storage
$user_attrib = self::$config->get('kolab_users_id_attrib', self::$config->get('kolab_auth_login', 'mail'));
array_walk($results, function(&$user, $dn) use ($root, $user_attrib) {
- list($localpart, $domain) = explode('@', $user[$user_attrib]);
+ list($localpart, ) = explode('@', $user[$user_attrib]);
$user['kolabtargetfolder'] = $root . $localpart;
});
@@ -1542,7 +1546,7 @@ class kolab_storage
foreach ($folders as $userfolder) {
foreach ((array)self::list_folders($userfolder->name . $delimiter, '*', $type, false, $folderdata) as $foldername) {
if (!$folders[$foldername]) {
- $folders[$foldername] = new kolab_storage_folder($foldername, $folderdata[$foldername]);
+ $folders[$foldername] = new kolab_storage_folder($foldername, $type, $folderdata[$foldername]);
$userfolder->children[] = $folders[$foldername];
}
}
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_cache.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_cache.php
index bced3b3..227fa4e 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_cache.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_cache.php
@@ -26,6 +26,8 @@ class kolab_storage_cache
{
const DB_DATE_FORMAT = 'Y-m-d H:i:s';
+ public $sync_complete = false;
+
protected $db;
protected $imap;
protected $folder;
@@ -46,6 +48,7 @@ class kolab_storage_cache
protected $extra_cols = array();
protected $order_by = null;
protected $limit = null;
+ protected $error = 0;
/**
@@ -78,6 +81,7 @@ class kolab_storage_cache
$this->db = $rcmail->get_dbh();
$this->imap = $rcmail->get_storage();
$this->enabled = $rcmail->config->get('kolab_cache', false);
+ $this->folders_table = $this->db->table_name('kolab_folders');
if ($this->enabled) {
// always read folder cache and lock state from DB master
@@ -96,8 +100,7 @@ class kolab_storage_cache
*/
public function select_by_id($folder_id)
{
- $folders_table = $this->db->table_name('kolab_folders', true);
- $sql_arr = $this->db->fetch_assoc($this->db->query("SELECT * FROM $folders_table WHERE `folder_id` = ?", $folder_id));
+ $sql_arr = $this->db->fetch_assoc($this->db->query("SELECT * FROM `{$this->folders_table}` WHERE `folder_id` = ?", $folder_id));
if ($sql_arr) {
$this->metadata = $sql_arr;
$this->folder_id = $sql_arr['folder_id'];
@@ -118,14 +121,13 @@ class kolab_storage_cache
{
$this->folder = $storage_folder;
- if (empty($this->folder->name)) {
+ if (empty($this->folder->name) || !$this->folder->valid) {
$this->ready = false;
return;
}
// compose fully qualified ressource uri for this instance
$this->resource_uri = $this->folder->get_resource_uri();
- $this->folders_table = $this->db->table_name('kolab_folders');
$this->cache_table = $this->db->table_name('kolab_cache_' . $this->folder->type);
$this->ready = $this->enabled && !empty($this->folder->type);
$this->folder_id = null;
@@ -149,6 +151,16 @@ class kolab_storage_cache
}
/**
+ * Returns code of last error
+ *
+ * @return int Error code
+ */
+ public function get_error()
+ {
+ return $this->error;
+ }
+
+ /**
* Synchronize local cache data with remote
*/
public function synchronize()
@@ -158,7 +170,14 @@ class kolab_storage_cache
return;
// increase time limit
- @set_time_limit($this->max_sync_lock_time);
+ @set_time_limit($this->max_sync_lock_time - 60);
+
+ // get effective time limit we have for synchronization (~70% of the execution time)
+ $time_limit = ini_get('max_execution_time') * 0.7;
+ $sync_start = time();
+
+ // assume sync will be completed
+ $this->sync_complete = true;
if (!$this->ready) {
// kolab cache is disabled, synchronize IMAP mailbox cache only
@@ -195,13 +214,19 @@ class kolab_storage_cache
$old_index = array();
while ($sql_arr = $this->db->fetch_assoc($sql_result)) {
$old_index[] = $sql_arr['msguid'];
- $this->uid2msg[$sql_arr['uid']] = $sql_arr['msguid'];
}
// fetch new objects from imap
+ $i = 0;
foreach (array_diff($imap_index, $old_index) as $msguid) {
if ($object = $this->folder->read_object($msguid, '*')) {
$this->_extended_insert($msguid, $object);
+
+ // check time limit and abort sync if running too long
+ if (++$i % 50 == 0 && time() - $sync_start > $time_limit) {
+ $this->sync_complete = false;
+ break;
+ }
}
}
$this->_extended_insert(0, null);
@@ -217,7 +242,9 @@ class kolab_storage_cache
}
// update ctag value (will be written to database in _sync_unlock())
- $this->metadata['ctag'] = $this->folder->get_ctag();
+ if ($this->sync_complete) {
+ $this->metadata['ctag'] = $this->folder->get_ctag();
+ }
}
$this->bypass(false);
@@ -227,6 +254,7 @@ class kolab_storage_cache
}
}
+ $this->check_error();
$this->synched = time();
}
@@ -243,7 +271,12 @@ class kolab_storage_cache
{
// delegate to another cache instance
if ($foldername && $foldername != $this->folder->name) {
- return kolab_storage::get_folder($foldername)->cache->get($msguid, $type);
+ $success = false;
+ if ($targetfolder = kolab_storage::get_folder($foldername)) {
+ $success = $targetfolder->cache->get($msguid, $type);
+ $this->error = $targetfolder->cache->get_error();
+ }
+ return $success;
}
// load object if not in memory
@@ -272,6 +305,7 @@ class kolab_storage_cache
}
}
+ $this->check_error();
return $this->objects[$msguid];
}
@@ -291,8 +325,11 @@ class kolab_storage_cache
// delegate to another cache instance
if ($foldername && $foldername != $this->folder->name) {
- kolab_storage::get_folder($foldername)->cache->set($msguid, $object);
- return;
+ if ($targetfolder = kolab_storage::get_folder($foldername)) {
+ $targetfolder->cache->set($msguid, $object);
+ $this->error = $targetfolder->cache->get_error();
+ }
+ return;
}
// remove old entry
@@ -310,6 +347,8 @@ class kolab_storage_cache
// ...or set in-memory cache to false
$this->objects[$msguid] = $object;
}
+
+ $this->check_error();
}
@@ -368,6 +407,8 @@ class kolab_storage_cache
// keep a copy in memory for fast access
$this->objects = array($msguid => $object);
$this->uid2msg = array($object['uid'] => $msguid);
+
+ $this->check_error();
}
@@ -407,13 +448,14 @@ class kolab_storage_cache
}
unset($this->uid2msg[$uid]);
+ $this->check_error();
}
/**
* Remove all objects from local cache
*/
- public function purge($type = null)
+ public function purge()
{
if (!$this->ready) {
return true;
@@ -440,15 +482,20 @@ class kolab_storage_cache
return;
}
- $target = kolab_storage::get_folder($new_folder);
+ if ($target = kolab_storage::get_folder($new_folder)) {
+ // resolve new message UID in target folder
+ $this->db->query(
+ "UPDATE `{$this->folders_table}` SET `resource` = ? ".
+ "WHERE `resource` = ?",
+ $target->get_resource_uri(),
+ $this->resource_uri
+ );
- // resolve new message UID in target folder
- $this->db->query(
- "UPDATE `{$this->folders_table}` SET `resource` = ? ".
- "WHERE `resource` = ?",
- $target->get_resource_uri(),
- $this->resource_uri
- );
+ $this->check_error();
+ }
+ else {
+ $this->error = kolab_storage::ERROR_IMAP_CONN;
+ }
}
/**
@@ -513,6 +560,7 @@ class kolab_storage_cache
}
if ($index->is_error()) {
+ $this->check_error();
if ($uids) {
return null;
}
@@ -535,6 +583,8 @@ class kolab_storage_cache
}
}
+ $this->check_error();
+
return $result;
}
@@ -577,6 +627,7 @@ class kolab_storage_cache
}
if ($index->is_error()) {
+ $this->check_error();
return null;
}
@@ -585,6 +636,7 @@ class kolab_storage_cache
$count = $index->count();
}
+ $this->check_error();
return $count;
}
@@ -918,24 +970,29 @@ class kolab_storage_cache
return;
$this->_read_folder_data();
- $sql_query = "SELECT `synclock`, `ctag` FROM `{$this->folders_table}` WHERE `folder_id` = ?";
// abort if database is not set-up
if ($this->db->is_error()) {
+ $this->check_error();
$this->ready = false;
return;
}
- $this->synclock = true;
+ $read_query = "SELECT `synclock`, `ctag` FROM `{$this->folders_table}` WHERE `folder_id` = ?";
+ $write_query = "UPDATE `{$this->folders_table}` SET `synclock` = ? WHERE `folder_id` = ? AND `synclock` = ?";
- // wait if locked (expire locks after 10 minutes)
- while ($this->metadata && intval($this->metadata['synclock']) > 0 && $this->metadata['synclock'] + $this->max_sync_lock_time > time()) {
+ // wait if locked (expire locks after 10 minutes) ...
+ // ... or if setting lock fails (another process meanwhile set it)
+ while (
+ (intval($this->metadata['synclock']) + $this->max_sync_lock_time > time()) ||
+ (($res = $this->db->query($write_query, time(), $this->folder_id, intval($this->metadata['synclock']))) &&
+ !($affected = $this->db->affected_rows($res)))
+ ) {
usleep(500000);
- $this->metadata = $this->db->fetch_assoc($this->db->query($sql_query, $this->folder_id));
+ $this->metadata = $this->db->fetch_assoc($this->db->query($read_query, $this->folder_id));
}
- // set lock
- $this->db->query("UPDATE `{$this->folders_table}` SET `synclock` = ? WHERE `folder_id` = ?", time(), $this->folder_id);
+ $this->synclock = $affected > 0;
}
/**
@@ -956,6 +1013,22 @@ class kolab_storage_cache
}
/**
+ * Check IMAP connection error state
+ */
+ protected function check_error()
+ {
+ if (($err_code = $this->imap->get_error_code()) < 0) {
+ $this->error = kolab_storage::ERROR_IMAP_CONN;
+ if (($res_code = $this->imap->get_response_code()) !== 0 && in_array($res_code, array(rcube_storage::NOPERM, rcube_storage::READONLY))) {
+ $this->error = kolab_storage::ERROR_NO_PERMISSION;
+ }
+ }
+ else if ($this->db->is_error()) {
+ $this->error = kolab_storage::ERROR_CACHE_DB;
+ }
+ }
+
+ /**
* Resolve an object UID into an IMAP message UID
*
* @param string Kolab object UID
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_config.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_config.php
index d58e3c0..036b827 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_config.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_config.php
@@ -837,4 +837,30 @@ class kolab_storage_config
return self::build_member_url($params);
}
+
+ /**
+ * Resolve the email message reference from the given URI
+ */
+ public function get_message_reference($uri, $rel = null)
+ {
+ if ($linkref = self::parse_member_url($uri)) {
+ $linkref['subject'] = $linkref['params']['subject'];
+ $linkref['uri'] = $uri;
+
+ $rcmail = rcube::get_instance();
+ if (method_exists($rcmail, 'url')) {
+ $linkref['mailurl'] = $rcmail->url(array(
+ 'task' => 'mail',
+ 'action' => 'show',
+ 'mbox' => $linkref['folder'],
+ 'uid' => $linkref['uid'],
+ 'rel' => $rel,
+ ));
+ }
+
+ unset($linkref['params']);
+ }
+
+ return $linkref;
+ }
}
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder.php
index 2435fa3..ab3c63f 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder.php
@@ -30,18 +30,28 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public $cache;
- private $type_annotation;
- private $resource_uri;
+ /**
+ * Indicate validity status
+ * @var boolean
+ */
+ public $valid = false;
+
+ protected $error = 0;
+
+ protected $resource_uri;
/**
* Default constructor
+ *
+ * @param string The folder name/path
+ * @param string Expected folder type
*/
- function __construct($name, $type = null)
+ function __construct($name, $type = null, $type_annotation = null)
{
parent::__construct($name);
$this->imap->set_options(array('skip_deleted' => true));
- $this->set_folder($name, $type);
+ $this->set_folder($name, $type, $type_annotation);
}
@@ -49,30 +59,63 @@ class kolab_storage_folder extends kolab_storage_folder_api
* Set the IMAP folder this instance connects to
*
* @param string The folder name/path
+ * @param string Expected folder type
* @param string Optional folder type if known
*/
- public function set_folder($name, $type = null)
+ public function set_folder($name, $type = null, $type_annotation = null)
{
- $this->type_annotation = $type ? $type : kolab_storage::folder_type($name);
+ if (empty($type_annotation)) {
+ $type_annotation = kolab_storage::folder_type($name);
+ }
$oldtype = $this->type;
- list($this->type, $suffix) = explode('.', $this->type_annotation);
+ list($this->type, $suffix) = explode('.', $type_annotation);
$this->default = $suffix == 'default';
$this->subtype = $this->default ? '' : $suffix;
$this->name = $name;
$this->id = kolab_storage::folder_id($name);
+ $this->valid = !empty($this->type) && $this->type != 'mail' && (!$type || $this->type == $type);
+
+ if (!$this->valid) {
+ $this->error = $this->imap->get_error_code() < 0 ? kolab_storage::ERROR_IMAP_CONN : kolab_storage::ERROR_INVALID_FOLDER;
+ }
// reset cached object properties
$this->owner = $this->namespace = $this->resource_uri = $this->info = $this->idata = null;
- // get a new cache instance of folder type changed
- if (!$this->cache || $type != $oldtype)
+ // get a new cache instance if folder type changed
+ if (!$this->cache || $this->type != $oldtype)
$this->cache = kolab_storage_cache::factory($this);
+ else
+ $this->cache->set_folder($this);
$this->imap->set_folder($this->name);
- $this->cache->set_folder($this);
}
+ /**
+ * Returns code of last error
+ *
+ * @return int Error code
+ */
+ public function get_error()
+ {
+ return $this->error ?: $this->cache->get_error();
+ }
+
+ /**
+ * Check IMAP connection error state
+ */
+ public function check_error()
+ {
+ if (($err_code = $this->imap->get_error_code()) < 0) {
+ $this->error = kolab_storage::ERROR_IMAP_CONN;
+ if (($res_code = $this->imap->get_response_code()) !== 0 && in_array($res_code, array(rcube_storage::NOPERM, rcube_storage::READONLY))) {
+ $this->error = kolab_storage::ERROR_NO_PERMISSION;
+ }
+ }
+
+ return $this->error;
+ }
/**
* Compose a unique resource URI for this IMAP folder
@@ -97,7 +140,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
}
// compose fully qualified ressource uri for this instance
- $this->resource_uri = 'imap://' . urlencode($this->get_owner()) . '@' . $this->imap->options['host'] . '/' . $subpath;
+ $this->resource_uri = 'imap://' . urlencode($this->get_owner(true)) . '@' . $this->imap->options['host'] . '/' . $subpath;
return $this->resource_uri;
}
@@ -138,6 +181,8 @@ class kolab_storage_folder extends kolab_storage_folder_api
if (!($success = $this->set_metadata(array(kolab_storage::UID_KEY_SHARED => $uid)))) {
$success = $this->set_metadata(array(kolab_storage::UID_KEY_PRIVATE => $uid));
}
+
+ $this->check_error();
return $success;
}
@@ -147,6 +192,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
public function get_ctag()
{
$fdata = $this->get_imap_data();
+ $this->check_error();
return sprintf('%d-%d-%d', $fdata['UIDVALIDITY'], $fdata['HIGHESTMODSEQ'], $fdata['UIDNEXT']);
}
@@ -204,6 +250,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function count($query = null)
{
+ if (!$this->valid) {
+ return 0;
+ }
+
// synchronize cache first
$this->cache->synchronize();
@@ -221,6 +271,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
{
if (!$type) $type = $this->type;
+ if (!$this->valid) {
+ return array();
+ }
+
// synchronize caches
$this->cache->synchronize();
@@ -238,9 +292,14 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function select($query = array())
{
+ if (!$this->valid) {
+ return array();
+ }
+
// check query argument
- if (empty($query))
+ if (empty($query)) {
return $this->get_objects();
+ }
// synchronize caches
$this->cache->synchronize();
@@ -258,6 +317,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function get_uids($query = array())
{
+ if (!$this->valid) {
+ return array();
+ }
+
// synchronize caches
$this->cache->synchronize();
@@ -319,6 +382,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function get_object($uid, $type = null)
{
+ if (!$this->valid) {
+ return false;
+ }
+
// synchronize caches
$this->cache->synchronize();
@@ -348,7 +415,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function get_attachment($uid, $part, $mailbox = null, $print = false, $fp = null, $skip_charset_conv = false)
{
- if ($msguid = ($mailbox ? $uid : $this->cache->uid2msguid($uid))) {
+ if ($this->valid && ($msguid = ($mailbox ? $uid : $this->cache->uid2msguid($uid)))) {
$this->imap->set_folder($mailbox ? $mailbox : $this->name);
if (substr($part, 0, 2) == 'i:') {
@@ -360,7 +427,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
$object['_formatobj']->get_attachments($object);
}
- foreach ($object['_attachments'] as $k => $attach) {
+ foreach ($object['_attachments'] as $attach) {
if ($attach['id'] == $part) {
if ($print) echo $attach['content'];
else if ($fp) fwrite($fp, $attach['content']);
@@ -392,6 +459,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function read_object($msguid, $type = null, $folder = null)
{
+ if (!$this->valid) {
+ return false;
+ }
+
if (!$type) $type = $this->type;
if (!$folder) $folder = $this->name;
@@ -444,7 +515,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
// get XML part
foreach ((array)$message->attachments as $part) {
if (!$xml && ($part->mimetype == $content_type || preg_match('!application/([a-z.]+\+)?xml!', $part->mimetype))) {
- $xml = $part->body ? $part->body : $message->get_part_content($part->mime_id);
+ $xml = $message->get_part_body($part->mime_id, true);
}
else if ($part->filename || $part->content_id) {
$key = $part->content_id ? trim($part->content_id, '<>') : $part->filename;
@@ -537,6 +608,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function save(&$object, $type = null, $uid = null)
{
+ if (!$this->valid) {
+ return false;
+ }
+
if (!$type)
$type = $this->type;
@@ -732,6 +807,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function delete($object, $expunge = true)
{
+ if (!$this->valid) {
+ return false;
+ }
+
$msguid = is_array($object) ? $object['_msguid'] : $this->cache->uid2msguid($object);
$success = false;
@@ -759,6 +838,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function delete_all()
{
+ if (!$this->valid) {
+ return false;
+ }
+
$this->cache->purge();
$this->cache->bypass(true);
$result = $this->imap->clear_folder($this->name);
@@ -776,6 +859,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function undelete($uid)
{
+ if (!$this->valid) {
+ return false;
+ }
+
if ($msguid = $this->cache->uid2msguid($uid, true)) {
$this->cache->bypass(true);
$result = $this->imap->set_flag($msguid, 'UNDELETED', $this->name);
@@ -799,6 +886,10 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
public function move($uid, $target_folder)
{
+ if (!$this->valid) {
+ return false;
+ }
+
if (is_string($target_folder))
$target_folder = kolab_storage::get_folder($target_folder);
@@ -882,7 +973,7 @@ class kolab_storage_folder extends kolab_storage_folder_api
if (!empty($object['_attachments']) && ($mem_limit = parse_bytes(ini_get('memory_limit'))) > 0) {
$memory = function_exists('memory_get_usage') ? memory_get_usage() : 16*1024*1024; // safe value: 16MB
- foreach ($object['_attachments'] as $id => $attachment) {
+ foreach ($object['_attachments'] as $attachment) {
$memory += $attachment['size'];
}
@@ -1054,8 +1145,6 @@ class kolab_storage_folder extends kolab_storage_folder_api
*/
private function trigger_url($url, $auth_user = null, $auth_passwd = null)
{
- require_once('HTTP/Request2.php');
-
try {
$request = libkolab::http_request($url);
diff --git a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder_api.php b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder_api.php
index ea603b1..7280389 100644
--- a/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder_api.php
+++ b/lib/drivers/kolab/plugins/libkolab/lib/kolab_storage_folder_api.php
@@ -85,9 +85,10 @@ abstract class kolab_storage_folder_api
/**
* Returns the owner of the folder.
*
+ * @param boolean Return a fully qualified owner name (i.e. including domain for shared folders)
* @return string The owner of this folder.
*/
- public function get_owner()
+ public function get_owner($fully_qualified = false)
{
// return cached value
if (isset($this->owner))
@@ -106,16 +107,21 @@ abstract class kolab_storage_folder_api
break;
default:
- list($prefix, $user) = explode($this->imap->get_hierarchy_delimiter(), $info['name']);
- if (strpos($user, '@') === false) {
- $domain = strstr($rcmail->get_user_name(), '@');
- if (!empty($domain))
- $user .= $domain;
- }
- $this->owner = $user;
+ list($prefix, $this->owner) = explode($this->imap->get_hierarchy_delimiter(), $info['name']);
+ $fully_qualified = true; // enforce email addresses (backwards compatibility)
break;
}
+ if ($fully_qualified && strpos($this->owner, '@') === false) {
+ // extract domain from current user name
+ $domain = strstr($rcmail->get_user_name(), '@');
+ // fall back to mail_domain config option
+ if (empty($domain) && ($mdomain = $rcmail->config->mail_domain($this->imap->options['host']))) {
+ $domain = '@' . $mdomain;
+ }
+ $this->owner .= $domain;
+ }
+
return $this->owner;
}
diff --git a/lib/drivers/kolab/plugins/libkolab/package.xml b/lib/drivers/kolab/plugins/libkolab/package.xml
deleted file mode 100644
index cd3e3a0..0000000
--- a/lib/drivers/kolab/plugins/libkolab/package.xml
+++ /dev/null
@@ -1,101 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0
- http://pear.php.net/dtd/tasks-1.0.xsd
- http://pear.php.net/dtd/package-2.0
- http://pear.php.net/dtd/package-2.0.xsd">
- <name>libkolab</name>
- <uri>http://git.kolab.org/roundcubemail-plugins-kolab/</uri>
- <summary>Kolab core library</summary>
- <description>Plugin to setup a basic environment for the interaction with a Kolab server.</description>
- <lead>
- <name>Thomas Bruederli</name>
- <user>bruederli</user>
- <email>bruederli@kolabsys.com</email>
- <active>yes</active>
- </lead>
- <developer>
- <name>Alensader Machniak</name>
- <user>machniak</user>
- <email>machniak@kolabsys.com</email>
- <active>yes</active>
- </developer>
- <date>2013-04-19</date>
- <version>
- <release>0.9</release>
- <api>0.9</api>
- </version>
- <stability>
- <release>stable</release>
- <api>stable</api>
- </stability>
- <license uri="http://www.gnu.org/licenses/agpl.html">GNU AGPLv3</license>
- <notes>-</notes>
- <contents>
- <dir baseinstalldir="/" name="/">
- <file name="libkolab.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_configuration.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_contact.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_distributionlist.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_event.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_file.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_journal.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_note.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_task.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_format_xcal.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_storage.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_storage_cache.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_storage_folder.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
- <file name="lib/kolab_date_recurrence.php" role="php">
- <tasks:replace from="@package_version@" to="version" type="package-info"/>
- </file>
-
- <file name="bin/modcache.php" role="php"></file>
-
- <file name="config.inc.php.dist" role="data"></file>
- <file name="LICENSE" role="data"></file>
- <file name="README" role="data"></file>
- <file name="UPGRADING" role="data"></file>
- </dir>
- <!-- / -->
- </contents>
- <dependencies>
- <required>
- <php>
- <min>5.3.1</min>
- </php>
- <pearinstaller>
- <min>1.7.0</min>
- </pearinstaller>
- </required>
- </dependencies>
- <phprelease/>
-</package>