6 commits - config/main.inc.php.dist lib/ext lib/init.php lib/kolab lib/kolab_sync.php lib/kolab_sync_plugin_api.php
Aleksander Machniak
machniak at kolabsys.com
Wed Oct 17 14:12:56 CEST 2012
config/main.inc.php.dist | 44 +++++++
lib/ext/Roundcube/html.php | 27 +---
lib/ext/Roundcube/rcube_addressbook.php | 5
lib/ext/Roundcube/rcube_charset.php | 2
lib/ext/Roundcube/rcube_config.php | 13 +-
lib/ext/Roundcube/rcube_db.php | 2
lib/ext/Roundcube/rcube_db_mssql.php | 2
lib/ext/Roundcube/rcube_db_mysql.php | 2
lib/ext/Roundcube/rcube_db_pgsql.php | 2
lib/ext/Roundcube/rcube_db_sqlite.php | 2
lib/ext/Roundcube/rcube_db_sqlsrv.php | 2
lib/ext/Roundcube/rcube_imap.php | 45 ++++++-
lib/ext/Roundcube/rcube_imap_generic.php | 49 ++++++--
lib/ext/Roundcube/rcube_ldap.php | 98 ++++++++++------
lib/ext/Roundcube/rcube_message.php | 5
lib/ext/Roundcube/rcube_output.php | 2
lib/ext/Roundcube/rcube_output_html.php | 2
lib/ext/Roundcube/rcube_plugin.php | 2
lib/ext/Roundcube/rcube_plugin_api.php | 24 ++--
lib/ext/Roundcube/rcube_result_thread.php | 10 +
lib/ext/Roundcube/rcube_storage.php | 4
lib/ext/Roundcube/rcube_user.php | 62 ++++++----
lib/ext/Roundcube/rcube_utils.php | 5
lib/ext/Roundcube/rcube_vcard.php | 24 +++-
lib/ext/Syncroton/Model/DeviceInformation.php | 40 ++++++
lib/init.php | 1
lib/kolab/kolab_storage.php | 30 ++++-
lib/kolab_sync.php | 155 +++++++++++---------------
lib/kolab_sync_plugin_api.php | 108 ++++++++++++++++++
29 files changed, 547 insertions(+), 222 deletions(-)
New commits:
commit 5cbac26767206b31fbec96f18b22864440b7a56a
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Oct 17 14:09:21 2012 +0200
Implemented plugin API. Removed LDAP auth code - now we're using kolab_auth plugin.
Plugins should be put into RCMAIL_PLUGINS_DIR (iniset.php)
and activesync_plugins option should be used.
Note: Now we're supporting only kolab_auth plugin.
diff --git a/lib/init.php b/lib/init.php
index e41bdca..8a96b68 100644
--- a/lib/init.php
+++ b/lib/init.php
@@ -29,6 +29,7 @@ define('RCMAIL_VERSION', '0.9-git');
define('RCMAIL_CHARSET', 'UTF-8');
define('INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/');
define('RCMAIL_CONFIG_DIR', INSTALL_PATH . 'config');
+define('RCMAIL_PLUGINS_DIR', INSTALL_PATH . 'plugins');
// PHP configuration
$config = array(
diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php
index f34df68..ab0e3d5 100644
--- a/lib/kolab_sync.php
+++ b/lib/kolab_sync.php
@@ -42,10 +42,8 @@ class kolab_sync extends rcube
*/
public $user;
- private $data = array();
-
const CHARSET = 'UTF-8';
- const VERSION = "1.1";
+ const VERSION = "2.0";
/**
@@ -68,6 +66,17 @@ class kolab_sync extends rcube
// Initialize Syncroton Logger
$debug_mode = $this->config->get('activesync_debug') ? kolab_sync_logger::DEBUG : kolab_sync_logger::WARN;
$this->logger = new kolab_sync_logger($debug_mode);
+
+ // Get list of plugins
+ // WARNING: We can use only plugins that are prepared for this
+ // e.g. are not using output or rcmail objects or
+ // doesn't throw errors when using them
+ $plugins = (array)$this->config->get('activesync_plugins');
+
+ // Initialize/load plugins
+ $this->plugins = kolab_sync_plugin_api::get_instance();
+ $this->plugins->init($this, $this->task);
+ $this->plugins->load_plugins($plugins);
}
@@ -76,6 +85,8 @@ class kolab_sync extends rcube
*/
public function run()
{
+ $this->plugins->exec_hook('startup', array('task' => 'login'));
+
// when used with (f)cgi no PHP_AUTH* variables are available without defining a special rewrite rule
if (!isset($_SERVER['PHP_AUTH_USER'])) {
// "Basic didhfiefdhfu4fjfjdsa34drsdfterrde..."
@@ -136,105 +147,75 @@ class kolab_sync extends rcube
/**
- * Authenticates a user in LDAP and Roundcube
+ * Authenticates a user
+ *
+ * @param string $username User name
+ * @param string $password User password
+ *
+ * @param int User ID
*/
public function authenticate($username, $password)
{
- // Get IMAP host
- $host = $this->config->get('default_host');
- $host = rcube_utils::parse_host($host);
-
- // Get user
- $user = $this->get_ldap_user($username, $host);
-
- // Get Roundcube user ID
- $userid = $this->get_rcube_user($user, $password, $host);
-
- return $userid;
- }
-
-
- /**
- * Returns user login attribute from LDAP server
- */
- private function get_ldap_user($username, $host)
- {
- @include_once(RCMAIL_CONFIG_DIR . "/kolab_auth.inc.php");
-
- $login_attr = $this->config->get('kolab_auth_login');
- $addressbook = $this->config->get('kolab_auth_addressbook');
- $filter = $this->config->get('kolab_auth_filter');
- $filter = $this->parse_vars($filter, $username, $host);
-
- if (!is_array($addressbook)) {
- $ldap_config = (array)$this->config->get('ldap_public');
- $addressbook = $ldap_config[$addressbook];
- }
-
- if (empty($addressbook)) {
- $this->logger->warn("No address book configured to authenticate the user.");
- return null;
+ $auth = $this->plugins->exec_hook('authenticate', array(
+ 'host' => $this->select_host($username),
+ 'user' => $username,
+ 'pass' => $password,
+ 'valid' => true,
+ ));
+
+ // Authenticate - get Roundcube user ID
+ if ($auth['valid'] && !$auth['abort']
+ && ($userid = $this->login($auth['user'], $auth['pass'], $auth['host']))) {
+ return $userid;
}
- if (empty($login_attr)) {
- $this->logger->warn("No login attribute configured.");
- return null;
- }
-
- $addressbook['filter'] = $filter;
- $addressbook['sizelimit'] = 2;
-
- $this->ldap = new rcube_ldap(
- $addressbook,
- $this->config->get('ldap_debug'),
- $this->config->mail_domain($host)
- );
-
- if (!$this->ldap->ready) {
- return null;
- }
-
- // get record
- $results = $this->ldap->list_records();
-
- if (count($results->records) != 1) {
- return null;
- }
-
- if ($record = $results->records[0]) {
- return is_array($record[$login_attr]) ? $record[$login_attr][0] : $record[$login_attr];
- }
+ $this->plugins->exec_hook('login_failed', array(
+ 'host' => $auth['host'],
+ 'user' => $auth['user'],
+ ));
}
/**
- * Prepares filter query for LDAP search
+ * Storage host selection
*/
- private function parse_vars($str, $user, $host)
+ private function select_host($username)
{
- $domain = $this->config->get('username_domain');
+ // Get IMAP host
+ $host = $this->config->get('default_host');
+
+ if (is_array($host)) {
+ list($user, $domain) = explode('@', $username);
+
+ // try to select host by mail domain
+ if (!empty($domain)) {
+ foreach ($host as $storage_host => $mail_domains) {
+ if (is_array($mail_domains) && in_array_nocase($domain, $mail_domains)) {
+ $host = $storage_host;
+ break;
+ }
+ else if (stripos($storage_host, $domain) !== false || stripos(strval($mail_domains), $domain) !== false) {
+ $host = is_numeric($storage_host) ? $mail_domains : $storage_host;
+ break;
+ }
+ }
+ }
- if (!empty($domain) && strpos($user, '@') === false) {
- if (is_array($domain) && isset($domain[$host]))
- $user .= '@'.rcube_utils::parse_host($domain[$host], $host);
- else if (is_string($domain))
- $user .= '@'.rcube_utils::parse_host($domain, $host);
+ // take the first entry if $host is not found
+ if (is_array($host)) {
+ list($key, $val) = each($default_host);
+ $host = is_numeric($key) ? $val : $key;
+ }
}
- // replace variables in filter
- list($u, $d) = explode('@', $user);
- $dc = 'dc='.strtr($d, array('.' => ',dc=')); // hierarchal domain string
- $replaces = array('%dc' => $dc, '%d' => $d, '%fu' => $user, '%u' => $u);
-
- return strtr($str, $replaces);
+ return rcube_utils::parse_host($host);
}
/**
- * Returns Roundcube user ID for specified username and host.
- * Also sets IMAP connection credentials.
+ * Authenticates a user in IMAP and returns Roundcube user ID.
*/
- private function get_rcube_user($username, $password, $host)
+ private function login($username, $password, $host)
{
if (empty($username)) {
return null;
@@ -314,10 +295,6 @@ class kolab_sync extends rcube
{
parent::shutdown();
- if ($this->ldap) {
- $this->ldap->close();
- }
-
// write performance stats to logs/console
if ($this->config->get('devel_mode')) {
if (function_exists('memory_get_usage'))
@@ -325,7 +302,9 @@ class kolab_sync extends rcube
if (function_exists('memory_get_peak_usage'))
$mem .= '/' . sprintf('%.1f', memory_get_peak_usage() / 1048576);
- $log = $_SERVER['QUERY_STRING'] . ($mem ? " [$mem]" : '');
+ $query = $_SERVER['QUERY_STRING'];
+ $log = $query . ($mem ? ($query ? ' ' : '') . "[$mem]" : '');
+
if (defined('RCMAIL_START'))
self::print_timer(RCMAIL_START, $log);
else
diff --git a/lib/kolab_sync_plugin_api.php b/lib/kolab_sync_plugin_api.php
new file mode 100644
index 0000000..1b7bac4
--- /dev/null
+++ b/lib/kolab_sync_plugin_api.php
@@ -0,0 +1,108 @@
+<?php
+
+/**
+ +--------------------------------------------------------------------------+
+ | Kolab Sync (ActiveSync for Kolab) |
+ | |
+ | Copyright (C) 2011-2012, Kolab Systems AG <contact at 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/> |
+ +--------------------------------------------------------------------------+
+ | Author: Aleksander Machniak <machniak at kolabsys.com> |
+ +--------------------------------------------------------------------------+
+*/
+
+/**
+ * The plugin loader and global API
+ *
+ * @package PluginAPI
+ */
+class kolab_sync_plugin_api extends rcube_plugin_api
+{
+ /**
+ * This implements the 'singleton' design pattern
+ *
+ * @return rcube_plugin_api The one and only instance if this class
+ */
+ static function get_instance()
+ {
+ if (!self::$instance) {
+ self::$instance = new kolab_sync_plugin_api();
+ }
+
+ return self::$instance;
+ }
+
+
+ /**
+ * Initialize plugin engine
+ *
+ * This has to be done after rcmail::load_gui() or rcmail::json_init()
+ * was called because plugins need to have access to rcmail->output
+ *
+ * @param object rcube Instance of the rcube base class
+ * @param string Current application task (used for conditional plugin loading)
+ */
+ public function init($app, $task = '')
+ {
+ $this->task = $task;
+ }
+
+
+ /**
+ * Register a handler function for template objects
+ *
+ * @param string $name Object name
+ * @param string $owner Plugin name that registers this action
+ * @param mixed $callback Callback: string with global function name or array($obj, 'methodname')
+ */
+ public function register_handler($name, $owner, $callback)
+ {
+ // empty
+ }
+
+
+ /**
+ * Register this plugin to be responsible for a specific task
+ *
+ * @param string $task Task name (only characters [a-z0-9_.-] are allowed)
+ * @param string $owner Plugin name that registers this action
+ */
+ public function register_task($task, $owner)
+ {
+ $this->tasks[$task] = $owner;
+ }
+
+
+ /**
+ * Include a plugin script file in the current HTML page
+ *
+ * @param string $fn Path to script
+ */
+ public function include_script($fn)
+ {
+ //empty
+ }
+
+
+ /**
+ * Include a plugin stylesheet in the current HTML page
+ *
+ * @param string $fn Path to stylesheet
+ */
+ public function include_stylesheet($fn)
+ {
+ //empty
+ }
+}
commit 78fd935a194a584d84393febb0f62fe05e231f16
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Oct 17 13:42:10 2012 +0200
Sample config file with all activesync options
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
new file mode 100644
index 0000000..77f04ac
--- /dev/null
+++ b/config/main.inc.php.dist
@@ -0,0 +1,44 @@
+<?php
+
+// This file lists all ActiveSync-related configuration options
+
+// Enables ActiveSync protocol debuging
+$rcmail_config['activesync_debug'] = true;
+
+// 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;
+
+// Type of ActiveSync cache. Supported values: 'db', 'apc' and 'memcache'.
+// Note: This is only for some additional data like timezones mapping.
+// Main ActiveSync cache uses Roundcube SQL database
+$rcmail_config['activesync_cache'] = null;
+
+// lifetime of ActiveSync cache
+// possible units: s, m, h, d, w
+$rcmail_config['activesync_cache_lifetime'] = '10d';
+
+// List of global addressbooks (GAL)
+// Note: If empty 'autocomplete_addressbooks' setting will be used
+$rcmail_config['activesync_addressbooks'] = array();
+
+// ActiveSync => Roundcube contact fields map for GAL search
+/* Default: array(
+ 'alias' => 'nickname',
+ 'company' => 'organization',
+ 'displayName' => 'name',
+ 'emailAddress' => 'email',
+ 'firstName' => 'firstname',
+ 'lastName' => 'surname',
+ 'mobilePhone' => 'phone.mobile',
+ 'office' => 'office',
+ 'picture' => 'photo',
+ 'phone' => 'phone',
+ 'title' => 'jobtitle',
+);
+*/
+$rcmail_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();
commit b0d6e406235fa74da515b348d0e98a3acab5dd90
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Oct 17 12:51:00 2012 +0200
Fixed folder type handling in kolab_storage
diff --git a/lib/kolab/kolab_storage.php b/lib/kolab/kolab_storage.php
index 1292b8b..b29b416 100644
--- a/lib/kolab/kolab_storage.php
+++ b/lib/kolab/kolab_storage.php
@@ -191,7 +191,7 @@ class kolab_storage
if ($saved = self::$imap->create_folder($name, $subscribed)) {
// set metadata for folder type
if ($type) {
- $saved = self::$imap->set_metadata($name, array(self::CTYPE_KEY => $type));
+ $saved = self::set_folder_type($name, $type);
// revert if metadata could not be set
if (!$saved) {
@@ -595,7 +595,14 @@ class kolab_storage
*/
static function folder_select_metadata($types)
{
- return $types[self::CTYPE_KEY_PRIVATE] ?: $types[self::CTYPE_KEY];
+ if (!empty($types[self::CTYPE_KEY_PRIVATE])) {
+ return $types[self::CTYPE_KEY_PRIVATE];
+ }
+ else if (!empty($types[self::CTYPE_KEY])) {
+ list($ctype, $suffix) = explode('.', $types[self::CTYPE_KEY]);
+ return $ctype;
+ }
+ return null;
}
@@ -623,4 +630,23 @@ class kolab_storage
return 'mail';
}
+ /**
+ * Sets folder content-type.
+ *
+ * @param string $folder Folder name
+ * @param string $type Content type
+ *
+ * @return boolean True on success
+ */
+ static function set_folder_type($folder, $type='mail')
+ {
+ list($ctype, $subtype) = explode('.', $type);
+
+ $success = self::$imap->set_metadata($folder, array(self::CTYPE_KEY => $ctype, self::CTYPE_KEY_PRIVATE => $subtype ? $type : null));
+
+ if (!$success) // fallback: only set private annotation
+ $success |= self::$imap->set_metadata($folder, array(self::CTYPE_KEY_PRIVATE => $type));
+
+ return $success;
+ }
}
commit 89ff90998fe47b52c28183fedead4765e4cb9013
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Oct 17 12:50:03 2012 +0200
Small fixes in Roundcube Framework
diff --git a/lib/ext/Roundcube/rcube_message.php b/lib/ext/Roundcube/rcube_message.php
index 7bf95d1..4e1b5a0 100644
--- a/lib/ext/Roundcube/rcube_message.php
+++ b/lib/ext/Roundcube/rcube_message.php
@@ -371,9 +371,10 @@ class rcube_message
foreach ($structure->parts as $p => $sub_part) {
$sub_mimetype = $sub_part->mimetype;
- // skip empty parts
- if (!$sub_part->size)
+ // skip empty text parts
+ if (!$sub_part->size && preg_match('#^text/(plain|html|enriched)$#', $sub_mimetype)) {
continue;
+ }
// check if sub part is
if ($sub_mimetype == 'text/plain')
diff --git a/lib/ext/Roundcube/rcube_output.php b/lib/ext/Roundcube/rcube_output.php
index 9aa7c9e..5c582e6 100644
--- a/lib/ext/Roundcube/rcube_output.php
+++ b/lib/ext/Roundcube/rcube_output.php
@@ -44,7 +44,7 @@ abstract class rcube_output
*/
public function __construct($task = null, $framed = false)
{
- $this->app = rcmail::get_instance();
+ $this->app = rcube::get_instance();
$this->config = $this->app->config;
$this->browser = new rcube_browser();
}
diff --git a/lib/ext/Roundcube/rcube_plugin.php b/lib/ext/Roundcube/rcube_plugin.php
index c103573..4508885 100644
--- a/lib/ext/Roundcube/rcube_plugin.php
+++ b/lib/ext/Roundcube/rcube_plugin.php
@@ -202,7 +202,7 @@ abstract class rcube_plugin
foreach ($texts as $key => $value)
$add[$domain.'.'.$key] = $value;
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
$rcmail->load_language($lang, $add);
// add labels to client
diff --git a/lib/ext/Roundcube/rcube_plugin_api.php b/lib/ext/Roundcube/rcube_plugin_api.php
index 9ef68ca..107c810 100644
--- a/lib/ext/Roundcube/rcube_plugin_api.php
+++ b/lib/ext/Roundcube/rcube_plugin_api.php
@@ -31,7 +31,7 @@ if (!defined('RCMAIL_PLUGINS_DIR'))
*/
class rcube_plugin_api
{
- static private $instance;
+ static protected $instance;
public $dir;
public $url = 'plugins/';
@@ -39,16 +39,16 @@ class rcube_plugin_api
public $output;
public $handlers = array();
- private $plugins = array();
- private $tasks = array();
- private $actions = array();
- private $actionmap = array();
- private $objectsmap = array();
- private $template_contents = array();
- private $active_hook = false;
+ protected $plugins = array();
+ protected $tasks = array();
+ protected $actions = array();
+ protected $actionmap = array();
+ protected $objectsmap = array();
+ protected $template_contents = array();
+ protected $active_hook = false;
// Deprecated names of hooks, will be removed after 0.5-stable release
- private $deprecated_hooks = array(
+ protected $deprecated_hooks = array(
'create_user' => 'user_create',
'kill_session' => 'session_destroy',
'upload_attachment' => 'attachment_upload',
@@ -98,7 +98,7 @@ class rcube_plugin_api
/**
* Private constructor
*/
- private function __construct()
+ protected function __construct()
{
$this->dir = slashify(RCMAIL_PLUGINS_DIR);
}
@@ -470,7 +470,7 @@ class rcube_plugin_api
* @param array $attrib
* @return array
*/
- private function template_container_hook($attrib)
+ protected function template_container_hook($attrib)
{
$container = $attrib['name'];
return array('content' => $attrib['content'] . $this->template_contents[$container]);
@@ -483,7 +483,7 @@ class rcube_plugin_api
* @param string $fn Filename
* @return string
*/
- private function resource_url($fn)
+ protected function resource_url($fn)
{
if ($fn[0] != '/' && !preg_match('|^https?://|i', $fn))
return $this->url . $fn;
commit bb112bd0231b2c69016461fc0029ee3a0c12cd63
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Oct 17 09:29:42 2012 +0200
Add lost Syncroton file
diff --git a/lib/ext/Syncroton/Model/DeviceInformation.php b/lib/ext/Syncroton/Model/DeviceInformation.php
new file mode 100644
index 0000000..adab7b0
--- /dev/null
+++ b/lib/ext/Syncroton/Model/DeviceInformation.php
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Syncroton
+ *
+ * @package Model
+ * @license http://www.tine20.org/licenses/lgpl.html LGPL Version 3
+ * @copyright Copyright (c) 2012-2012 Metaways Infosystems GmbH (http://www.metaways.de)
+ * @author Lars Kneschke <l.kneschke at metaways.de>
+ */
+
+/**
+ * class to handle ActiveSync device information
+ *
+ * @package Model
+ * @property string friendlyName
+ * @property string iMEI
+ * @property string mobileOperator
+ * @property string model
+ * @property string oS
+ * @property string oSLanguage
+ * @property string phoneNumber
+ */
+
+class Syncroton_Model_DeviceInformation extends Syncroton_Model_AEntry
+{
+ protected $_xmlBaseElement = 'Set';
+
+ protected $_properties = array(
+ 'Settings' => array(
+ 'enableOutboundSMS' => array('type' => 'number'),
+ 'friendlyName' => array('type' => 'string'),
+ 'iMEI' => array('type' => 'string'),
+ 'mobileOperator' => array('type' => 'string'),
+ 'model' => array('type' => 'string'),
+ 'oS' => array('type' => 'string'),
+ 'oSLanguage' => array('type' => 'string'),
+ 'phoneNumber' => array('type' => 'string')
+ ),
+ );
+}
\ No newline at end of file
commit c5a61c1891b5c1005c80422951269fcb24d5e9ba
Author: Aleksander Machniak <alec at alec.pl>
Date: Wed Oct 17 09:29:11 2012 +0200
Update Roundcube Framework
diff --git a/lib/ext/Roundcube/html.php b/lib/ext/Roundcube/html.php
index c6507f8..2349852 100644
--- a/lib/ext/Roundcube/html.php
+++ b/lib/ext/Roundcube/html.php
@@ -295,7 +295,7 @@ class html
}
}
else {
- $attrib_arr[] = $key . '="' . self::quote($value, true) . '"';
+ $attrib_arr[] = $key . '="' . self::quote($value) . '"';
}
}
@@ -328,22 +328,13 @@ class html
/**
* Replacing specials characters in html attribute value
*
- * @param string $str Input string
- * @param bool $validate Enables double quotation prevention
+ * @param string $str Input string
*
- * @return string The quoted string
+ * @return string The quoted string
*/
- public static function quote($str, $validate = false)
+ public static function quote($str)
{
- $str = htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
-
- // avoid douple quotation of &
- // @TODO: get rid of it
- if ($validate) {
- $str = preg_replace('/&([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $str);
- }
-
- return $str;
+ return htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
}
}
@@ -559,7 +550,7 @@ class html_textarea extends html
}
if (!empty($value) && empty($this->attrib['is_escaped'])) {
- $value = self::quote($value, true);
+ $value = self::quote($value);
}
return self::tag($this->tagname, $this->attrib, $value,
@@ -635,7 +626,7 @@ class html_select extends html
$option_content = $option['text'];
if (empty($this->attrib['is_escaped'])) {
- $option_content = self::quote($option_content, true);
+ $option_content = self::quote($option_content);
}
$this->content .= self::tag('option', $attr, $option_content);
@@ -690,9 +681,9 @@ class html_table extends html
$cell->content = $cont;
$this->rows[$this->rowindex]->cells[$this->colindex] = $cell;
- $this->colindex++;
+ $this->colindex += max(1, intval($attr['colspan']));
- if ($this->attrib['cols'] && $this->colindex == $this->attrib['cols']) {
+ if ($this->attrib['cols'] && $this->colindex >= $this->attrib['cols']) {
$this->add_row();
}
}
diff --git a/lib/ext/Roundcube/rcube_addressbook.php b/lib/ext/Roundcube/rcube_addressbook.php
index f4f2553..892ae26 100644
--- a/lib/ext/Roundcube/rcube_addressbook.php
+++ b/lib/ext/Roundcube/rcube_addressbook.php
@@ -434,6 +434,11 @@ abstract class rcube_addressbook
}
}
+ // remove duplicates
+ if ($flat && !empty($out)) {
+ $out = array_unique($out);
+ }
+
return $out;
}
diff --git a/lib/ext/Roundcube/rcube_charset.php b/lib/ext/Roundcube/rcube_charset.php
index 35c6972..ff4c2bb 100644
--- a/lib/ext/Roundcube/rcube_charset.php
+++ b/lib/ext/Roundcube/rcube_charset.php
@@ -179,7 +179,7 @@ class rcube_charset
static $mbstring_sch = null;
static $conv = null;
- $to = empty($to) ? strtoupper(RCMAIL_CHARSET) : $to;
+ $to = empty($to) ? RCMAIL_CHARSET : $to;
$from = self::parse_charset($from);
// It is a common case when UTF-16 charset is used with US-ASCII content (#1488654)
diff --git a/lib/ext/Roundcube/rcube_config.php b/lib/ext/Roundcube/rcube_config.php
index 41acc80..b9fd955 100644
--- a/lib/ext/Roundcube/rcube_config.php
+++ b/lib/ext/Roundcube/rcube_config.php
@@ -123,8 +123,11 @@ class rcube_config
if ($this->prop['timezone'] == 'auto') {
$this->prop['_timezone_value'] = $this->client_timezone();
}
- else if (is_numeric($this->prop['timezone'])) {
- $this->prop['timezone'] = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0);
+ else if (is_numeric($this->prop['timezone']) && ($tz = timezone_name_from_abbr("", $this->prop['timezone'] * 3600, 0))) {
+ $this->prop['timezone'] = $tz;
+ }
+ else if (empty($this->prop['timezone'])) {
+ $this->prop['timezone'] = 'UTC';
}
// remove deprecated properties
@@ -251,8 +254,8 @@ class rcube_config
}
// convert user's timezone into the new format
- if (is_numeric($prefs['timezone'])) {
- $prefs['timezone'] = timezone_name_from_abbr('', $prefs['timezone'] * 3600, 0);
+ if (is_numeric($prefs['timezone']) && ($tz = timezone_name_from_abbr('', $prefs['timezone'] * 3600, 0))) {
+ $prefs['timezone'] = $tz;
}
// larry is the new default skin :-)
@@ -409,7 +412,7 @@ class rcube_config
*/
private function client_timezone()
{
- return isset($_SESSION['timezone']) ? timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0) : date_default_timezone_get();
+ return isset($_SESSION['timezone']) && ($ctz = timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0)) ? $ctz : date_default_timezone_get();
}
}
diff --git a/lib/ext/Roundcube/rcube_db.php b/lib/ext/Roundcube/rcube_db.php
index eb1ad31..b066101 100644
--- a/lib/ext/Roundcube/rcube_db.php
+++ b/lib/ext/Roundcube/rcube_db.php
@@ -30,6 +30,8 @@
*/
class rcube_db
{
+ public $db_provider;
+
protected $db_dsnw; // DSN for write operations
protected $db_dsnr; // DSN for read operations
protected $db_connected = false; // Already connected ?
diff --git a/lib/ext/Roundcube/rcube_db_mssql.php b/lib/ext/Roundcube/rcube_db_mssql.php
index 5cbcfab..119647d 100644
--- a/lib/ext/Roundcube/rcube_db_mssql.php
+++ b/lib/ext/Roundcube/rcube_db_mssql.php
@@ -31,6 +31,8 @@
*/
class rcube_db_mssql extends rcube_db
{
+ public $db_provider = 'mssql';
+
/**
* Driver initialization
*/
diff --git a/lib/ext/Roundcube/rcube_db_mysql.php b/lib/ext/Roundcube/rcube_db_mysql.php
index 3606ec1..2cdcf30 100644
--- a/lib/ext/Roundcube/rcube_db_mysql.php
+++ b/lib/ext/Roundcube/rcube_db_mysql.php
@@ -31,6 +31,8 @@
*/
class rcube_db_mysql extends rcube_db
{
+ public $db_provider = 'mysql';
+
/**
* Driver initialization/configuration
*/
diff --git a/lib/ext/Roundcube/rcube_db_pgsql.php b/lib/ext/Roundcube/rcube_db_pgsql.php
index 285b8e2..0d0caad 100644
--- a/lib/ext/Roundcube/rcube_db_pgsql.php
+++ b/lib/ext/Roundcube/rcube_db_pgsql.php
@@ -31,6 +31,8 @@
*/
class rcube_db_pgsql extends rcube_db
{
+ public $db_provider = 'postgres';
+
/**
* Get last inserted record ID
*
diff --git a/lib/ext/Roundcube/rcube_db_sqlite.php b/lib/ext/Roundcube/rcube_db_sqlite.php
index a9774cd..a739767 100644
--- a/lib/ext/Roundcube/rcube_db_sqlite.php
+++ b/lib/ext/Roundcube/rcube_db_sqlite.php
@@ -31,6 +31,8 @@
*/
class rcube_db_sqlite extends rcube_db
{
+ public $db_provider = 'sqlite';
+
/**
* Database character set
*/
diff --git a/lib/ext/Roundcube/rcube_db_sqlsrv.php b/lib/ext/Roundcube/rcube_db_sqlsrv.php
index feddbe7..e58bf07 100644
--- a/lib/ext/Roundcube/rcube_db_sqlsrv.php
+++ b/lib/ext/Roundcube/rcube_db_sqlsrv.php
@@ -31,6 +31,8 @@
*/
class rcube_db_sqlsrv extends rcube_db
{
+ public $db_provider = 'mssql';
+
/**
* Driver initialization
*/
diff --git a/lib/ext/Roundcube/rcube_imap.php b/lib/ext/Roundcube/rcube_imap.php
index ebf31d5..1e6cf36 100644
--- a/lib/ext/Roundcube/rcube_imap.php
+++ b/lib/ext/Roundcube/rcube_imap.php
@@ -2219,10 +2219,12 @@ class rcube_imap extends rcube_storage
* @param string $message The message source string or filename
* @param string $headers Headers string if $message contains only the body
* @param boolean $is_file True if $message is a filename
+ * @param array $flags Message flags
+ * @param mixed $date Message internal date
*
* @return int|bool Appended message UID or True on success, False on error
*/
- public function save_message($folder, &$message, $headers='', $is_file=false)
+ public function save_message($folder, &$message, $headers='', $is_file=false, $flags = array(), $date = null)
{
if (!strlen($folder)) {
$folder = $this->folder;
@@ -2233,13 +2235,17 @@ class rcube_imap extends rcube_storage
}
// make sure folder exists
- if ($this->folder_exists($folder)) {
- if ($is_file) {
- $saved = $this->conn->appendFromFile($folder, $message, $headers);
- }
- else {
- $saved = $this->conn->append($folder, $message);
- }
+ if (!$this->folder_exists($folder)) {
+ return false;
+ }
+
+ $date = $this->date_format($date);
+
+ if ($is_file) {
+ $saved = $this->conn->appendFromFile($folder, $message, $headers, $flags, $date);
+ }
+ else {
+ $saved = $this->conn->append($folder, $message, $flags, $date);
}
if ($saved) {
@@ -3982,6 +3988,29 @@ class rcube_imap extends rcube_storage
/**
+ * Converts date string/object into IMAP date/time format
+ */
+ protected function date_format($date)
+ {
+ if (empty($date)) {
+ return null;
+ }
+
+ if (!is_object($date) || !is_a($date, 'DateTime')) {
+ try {
+ $timestamp = rcube_utils::strtotime($date);
+ $date = new DateTime("@".$timestamp);
+ }
+ catch (Exception $e) {
+ return null;
+ }
+ }
+
+ return $date->format('d-M-Y H:i:s O');
+ }
+
+
+ /**
* This is our own debug handler for the IMAP connection
* @access public
*/
diff --git a/lib/ext/Roundcube/rcube_imap_generic.php b/lib/ext/Roundcube/rcube_imap_generic.php
index cce53ae..52bf0e3 100644
--- a/lib/ext/Roundcube/rcube_imap_generic.php
+++ b/lib/ext/Roundcube/rcube_imap_generic.php
@@ -2180,7 +2180,7 @@ class rcube_imap_generic
$result[$id]->encoding = $string;
break;
case 'content-type':
- $ctype_parts = preg_split('/[; ]/', $string);
+ $ctype_parts = preg_split('/[; ]+/', $string);
$result[$id]->ctype = strtolower(array_shift($ctype_parts));
if (preg_match('/charset\s*=\s*"?([a-z0-9\-\.\_]+)"?/i', $string, $regs)) {
$result[$id]->charset = $regs[1];
@@ -2540,10 +2540,12 @@ class rcube_imap_generic
*
* @param string $mailbox Mailbox name
* @param string $message Message content
+ * @param array $flags Message flags
+ * @param string $date Message internal date
*
* @return string|bool On success APPENDUID response (if available) or True, False on failure
*/
- function append($mailbox, &$message)
+ function append($mailbox, &$message, $flags = array(), $date = null)
{
unset($this->data['APPENDUID']);
@@ -2559,12 +2561,17 @@ class rcube_imap_generic
return false;
}
+ // build APPEND command
$key = $this->nextTag();
- $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox),
- $len, ($this->prefs['literal+'] ? '+' : ''));
+ $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')';
+ if (!empty($date)) {
+ $request .= ' ' . $this->escape($date);
+ }
+ $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}';
+ // send APPEND command
if ($this->putLine($request)) {
- // Don't wait when LITERAL+ is supported
+ // Do not wait when LITERAL+ is supported
if (!$this->prefs['literal+']) {
$line = $this->readReply();
@@ -2605,10 +2612,12 @@ class rcube_imap_generic
* @param string $mailbox Mailbox name
* @param string $path Path to the file with message body
* @param string $headers Message headers
+ * @param array $flags Message flags
+ * @param string $date Message internal date
*
* @return string|bool On success APPENDUID response (if available) or True, False on failure
*/
- function appendFromFile($mailbox, $path, $headers=null)
+ function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null)
{
unset($this->data['APPENDUID']);
@@ -2639,11 +2648,15 @@ class rcube_imap_generic
$len += strlen($headers) + strlen($body_separator);
}
- // send APPEND command
+ // build APPEND command
$key = $this->nextTag();
- $request = sprintf("$key APPEND %s (\\Seen) {%d%s}", $this->escape($mailbox),
- $len, ($this->prefs['literal+'] ? '+' : ''));
+ $request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')';
+ if (!empty($date)) {
+ $request .= ' ' . $this->escape($date);
+ }
+ $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}';
+ // send APPEND command
if ($this->putLine($request)) {
// Don't wait when LITERAL+ is supported
if (!$this->prefs['literal+']) {
@@ -3546,6 +3559,24 @@ class rcube_imap_generic
}
/**
+ * Converts flags array into string for inclusion in IMAP command
+ *
+ * @param array $flags Flags (see self::flags)
+ *
+ * @return string Space-separated list of flags
+ */
+ private function flagsToStr($flags)
+ {
+ foreach ((array)$flags as $idx => $flag) {
+ if ($flag = $this->flags[strtoupper($flag)]) {
+ $flags[$idx] = $flag;
+ }
+ }
+
+ return implode(' ', (array)$flags);
+ }
+
+ /**
* Converts datetime string into unix timestamp
*
* @param string $date Date string
diff --git a/lib/ext/Roundcube/rcube_ldap.php b/lib/ext/Roundcube/rcube_ldap.php
index ad2ccdd..61a073f 100644
--- a/lib/ext/Roundcube/rcube_ldap.php
+++ b/lib/ext/Roundcube/rcube_ldap.php
@@ -109,24 +109,22 @@ class rcube_ldap extends rcube_addressbook
if (!is_array($this->coltypes[$col])) {
$subtypes = $type ? array($type) : null;
- $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes);
+ $this->coltypes[$col] = array('limit' => $limit, 'subtypes' => $subtypes, 'attributes' => array($lf));
}
elseif ($type) {
$this->coltypes[$col]['subtypes'][] = $type;
+ $this->coltypes[$col]['attributes'][] = $lf;
$this->coltypes[$col]['limit'] += $limit;
}
if ($delim)
$this->coltypes[$col]['serialized'][$type] = $delim;
- if ($type && !$this->fieldmap[$col])
- $this->fieldmap[$col] = $lf;
-
- $this->fieldmap[$colv] = $lf;
+ $this->fieldmap[$colv] = $lf;
}
// support for composite address
- if ($this->fieldmap['street'] && $this->fieldmap['locality']) {
+ if ($this->coltypes['street'] && $this->coltypes['locality']) {
$this->coltypes['address'] = array(
'limit' => max(1, $this->coltypes['locality']['limit'] + $this->coltypes['address']['limit']),
'subtypes' => array_merge((array)$this->coltypes['address']['subtypes'], (array)$this->coltypes['locality']['subtypes']),
@@ -134,7 +132,7 @@ class rcube_ldap extends rcube_addressbook
) + (array)$this->coltypes['address'];
foreach (array('street','locality','zipcode','region','country') as $childcol) {
- if ($this->fieldmap[$childcol]) {
+ if ($this->coltypes[$childcol]) {
$this->coltypes['address']['childs'][$childcol] = array('type' => 'text');
unset($this->coltypes[$childcol]); // remove address child col from global coltypes list
}
@@ -468,8 +466,8 @@ class rcube_ldap extends rcube_addressbook
*/
function set_sort_order($sort_col, $sort_order = null)
{
- if ($this->fieldmap[$sort_col])
- $this->sort_col = $this->fieldmap[$sort_col];
+ if ($this->coltypes[$sort_col]['attributes'])
+ $this->sort_col = $this->coltypes[$sort_col]['attributes'][0];
}
@@ -773,8 +771,9 @@ class rcube_ldap extends rcube_addressbook
// use VLV pseudo-search for autocompletion
$rcube = rcube::get_instance();
+ $list_fields = $rcube->config->get('contactlist_fields');
- if ($this->prop['vlv_search'] && $this->conn && join(',', (array)$fields) == join(',', $rcube->config->get('contactlist_fields')))
+ if ($this->prop['vlv_search'] && $this->conn && join(',', (array)$fields) == join(',', $list_fields))
{
// add general filter to query
if (!empty($this->prop['filter']) && empty($this->filter))
@@ -802,24 +801,26 @@ class rcube_ldap extends rcube_addressbook
for ($i = 0; $i < $entries['count']; $i++) {
$rec = $this->_ldap2result($entries[$i]);
- foreach (array('email', 'name') as $f) {
- $val = mb_strtolower($rec[$f]);
- switch ($mode) {
- case 1:
- $got = ($val == $search);
- break;
- case 2:
- $got = ($search == substr($val, 0, strlen($search)));
- break;
- default:
- $got = (strpos($val, $search) !== false);
- break;
- }
+ foreach ($fields as $f) {
+ foreach ((array)$rec[$f] as $val) {
+ $val = mb_strtolower($val);
+ switch ($mode) {
+ case 1:
+ $got = ($val == $search);
+ break;
+ case 2:
+ $got = ($search == substr($val, 0, strlen($search)));
+ break;
+ default:
+ $got = (strpos($val, $search) !== false);
+ break;
+ }
- if ($got) {
- $this->result->add($rec);
- $this->result->count++;
- break;
+ if ($got) {
+ $this->result->add($rec);
+ $this->result->count++;
+ break 2;
+ }
}
}
}
@@ -858,8 +859,13 @@ class rcube_ldap extends rcube_addressbook
{
foreach ((array)$fields as $idx => $field) {
$val = is_array($value) ? $value[$idx] : $value;
- if ($f = $this->_map_field($field)) {
- $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)";
+ if ($attrs = $this->_map_field($field)) {
+ if (count($attrs) > 1)
+ $filter .= '(|';
+ foreach ($attrs as $f)
+ $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)";
+ if (count($attrs) > 1)
+ $filter .= ')';
}
}
}
@@ -867,9 +873,16 @@ class rcube_ldap extends rcube_addressbook
// add required (non empty) fields filter
$req_filter = '';
- foreach ((array)$required as $field)
- if ($f = $this->_map_field($field))
- $req_filter .= "($f=*)";
+ foreach ((array)$required as $field) {
+ if ($attrs = $this->_map_field($field)) {
+ if (count($attrs) > 1)
+ $req_filter .= '(|';
+ foreach ($attrs as $f)
+ $req_filter .= "($f=*)";
+ if (count($attrs) > 1)
+ $req_filter .= ')';
+ }
+ }
if (!empty($req_filter))
$filter = '(&' . $req_filter . $filter . ')';
@@ -1498,7 +1511,7 @@ class rcube_ldap extends rcube_addressbook
list($col, $subtype) = explode(':', $rf);
$out['_raw_attrib'][$lf][$i] = $value;
- if ($rf == 'email' && $this->mail_domain && !strpos($value, '@'))
+ if ($col == 'email' && $this->mail_domain && !strpos($value, '@'))
$out[$rf][] = sprintf('%s@%s', $value, $this->mail_domain);
else if (in_array($col, array('street','zipcode','locality','country','region')))
$out['address'.($subtype?':':'').$subtype][$i][$col] = $value;
@@ -1521,11 +1534,11 @@ class rcube_ldap extends rcube_addressbook
/**
- * Return real field name (from fields map)
+ * Return LDAP attribute(s) for the given field
*/
private function _map_field($field)
{
- return $this->fieldmap[$field];
+ return (array)$this->coltypes[$field]['attributes'];
}
@@ -1558,8 +1571,19 @@ class rcube_ldap extends rcube_addressbook
}
$ldap_data = array();
- foreach ($this->fieldmap as $col => $fld) {
- $val = $save_cols[$col];
+ foreach ($this->fieldmap as $rf => $fld) {
+ $val = $save_cols[$rf];
+
+ // check for value in base field (eg.g email instead of email:foo)
+ list($col, $subtype) = explode(':', $rf);
+ if (!$val && !empty($save_cols[$col])) {
+ $val = $save_cols[$col];
+ unset($save_cols[$col]); // only use this value once
+ }
+ else if (!$val && !$subtype) { // extract values from subtype cols
+ $val = $this->get_col_values($col, $save_cols, true);
+ }
+
if (is_array($val))
$val = array_filter($val); // remove empty entries
if ($fld && $val) {
diff --git a/lib/ext/Roundcube/rcube_message.php b/lib/ext/Roundcube/rcube_message.php
index fe2fcf3..7bf95d1 100644
--- a/lib/ext/Roundcube/rcube_message.php
+++ b/lib/ext/Roundcube/rcube_message.php
@@ -371,6 +371,10 @@ class rcube_message
foreach ($structure->parts as $p => $sub_part) {
$sub_mimetype = $sub_part->mimetype;
+ // skip empty parts
+ if (!$sub_part->size)
+ continue;
+
// check if sub part is
if ($sub_mimetype == 'text/plain')
$plain_part = $p;
diff --git a/lib/ext/Roundcube/rcube_output_html.php b/lib/ext/Roundcube/rcube_output_html.php
index 2743e77..6138e2a 100644
--- a/lib/ext/Roundcube/rcube_output_html.php
+++ b/lib/ext/Roundcube/rcube_output_html.php
@@ -527,7 +527,7 @@ class rcube_output_html extends rcube_output
{
$GLOBALS['__version'] = html::quote(RCMAIL_VERSION);
$GLOBALS['__comm_path'] = html::quote($this->app->comm_path);
- $GLOBALS['__skin_path'] = Q($this->config->get('skin_path'));
+ $GLOBALS['__skin_path'] = html::quote($this->config->get('skin_path'));
return preg_replace_callback('/\$(__[a-z0-9_\-]+)/',
array($this, 'globals_callback'), $input);
diff --git a/lib/ext/Roundcube/rcube_result_thread.php b/lib/ext/Roundcube/rcube_result_thread.php
index 09fa465..b2325a4 100644
--- a/lib/ext/Roundcube/rcube_result_thread.php
+++ b/lib/ext/Roundcube/rcube_result_thread.php
@@ -475,16 +475,18 @@ class rcube_result_thread
$items = explode(self::SEPARATOR_ITEM, $elem);
$root = (int) array_shift($items);
- $result[$elem] = $elem;
- foreach ($items as $item) {
- list($lv, $id) = explode(self::SEPARATOR_LEVEL, $item);
+ if ($root) {
+ $result[$root] = $root;
+ foreach ($items as $item) {
+ list($lv, $id) = explode(self::SEPARATOR_LEVEL, $item);
$result[$id] = $root;
+ }
}
}
// get only unique roots
$result = array_filter($result); // make sure there are no nulls
- $result = array_unique($result, SORT_NUMERIC);
+ $result = array_unique($result);
// Re-sort raw data
$result = array_fill_keys($result, null);
diff --git a/lib/ext/Roundcube/rcube_storage.php b/lib/ext/Roundcube/rcube_storage.php
index f83e240..933ebcc 100644
--- a/lib/ext/Roundcube/rcube_storage.php
+++ b/lib/ext/Roundcube/rcube_storage.php
@@ -545,10 +545,12 @@ abstract class rcube_storage
* @param string $message The message source string or filename
* @param string $headers Headers string if $message contains only the body
* @param boolean $is_file True if $message is a filename
+ * @param array $flags Message flags
+ * @param mixed $date Message internal date
*
* @return int|bool Appended message UID or True on success, False on error
*/
- abstract function save_message($folder, &$message, $headers = '', $is_file = false);
+ abstract function save_message($folder, &$message, $headers = '', $is_file = false, $flags = array(), $date = null);
/**
diff --git a/lib/ext/Roundcube/rcube_user.php b/lib/ext/Roundcube/rcube_user.php
index 29eb0f2..5a65a51 100644
--- a/lib/ext/Roundcube/rcube_user.php
+++ b/lib/ext/Roundcube/rcube_user.php
@@ -435,31 +435,33 @@ class rcube_user
{
$user_name = '';
$user_email = '';
- $rcube = rcube::get_instance();
+ $rcube = rcube::get_instance();
+ $dbh = $rcube->get_dbh();
// try to resolve user in virtuser table and file
if ($email_list = self::user2email($user, false, true)) {
$user_email = is_array($email_list[0]) ? $email_list[0]['email'] : $email_list[0];
}
- $data = $rcube->plugins->exec_hook('user_create',
- array('user'=>$user, 'user_name'=>$user_name, 'user_email'=>$user_email, 'host'=>$host));
+ $data = $rcube->plugins->exec_hook('user_create', array(
+ 'host' => $host,
+ 'user' => $user,
+ 'user_name' => $user_name,
+ 'user_email' => $user_email,
+ 'email_list' => $email_list,
+ ));
// plugin aborted this operation
- if ($data['abort'])
+ if ($data['abort']) {
return false;
-
- $user_name = $data['user_name'];
- $user_email = $data['user_email'];
-
- $dbh = $rcube->get_dbh();
+ }
$dbh->query(
"INSERT INTO ".$dbh->table_name('users').
" (created, last_login, username, mail_host, language)".
" VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)",
- strip_newlines($user),
- strip_newlines($host),
+ strip_newlines($data['user']),
+ strip_newlines($data['host']),
strip_newlines($data['language'] ? $data['language'] : $_SESSION['language']));
if ($user_id = $dbh->insert_id('users')) {
@@ -467,20 +469,25 @@ class rcube_user
$user_instance = new rcube_user($user_id);
$rcube->user = $user_instance;
- $mail_domain = $rcube->config->mail_domain($host);
-
- if ($user_email == '') {
- $user_email = strpos($user, '@') ? $user : sprintf('%s@%s', $user, $mail_domain);
- }
- if ($user_name == '') {
- $user_name = $user != $user_email ? $user : '';
- }
+ $mail_domain = $rcube->config->mail_domain($data['host']);
+ $user_name = $data['user_name'];
+ $user_email = $data['user_email'];
+ $email_list = $data['email_list'];
- if (empty($email_list))
+ if (empty($email_list)) {
+ if (empty($user_email)) {
+ $user_email = strpos($data['user'], '@') ? $user : sprintf('%s@%s', $data['user'], $mail_domain);
+ }
$email_list[] = strip_newlines($user_email);
+ }
// identities_level check
- else if (count($email_list) > 1 && $rcube->config->get('identities_level', 0) > 1)
+ else if (count($email_list) > 1 && $rcube->config->get('identities_level', 0) > 1) {
$email_list = array($email_list[0]);
+ }
+
+ if (empty($user_name)) {
+ $user_name = $data['user'];
+ }
// create new identities records
$standard = 1;
@@ -488,16 +495,21 @@ class rcube_user
$record = array();
if (is_array($row)) {
+ if (empty($row['email'])) {
+ continue;
+ }
$record = $row;
}
else {
$record['email'] = $row;
}
- if (empty($record['name']))
- $record['name'] = $user_name;
- $record['name'] = strip_newlines($record['name']);
- $record['user_id'] = $user_id;
+ if (empty($record['name'])) {
+ $record['name'] = $user_name != $record['email'] ? $user_name : '';
+ }
+
+ $record['name'] = strip_newlines($record['name']);
+ $record['user_id'] = $user_id;
$record['standard'] = $standard;
$plugin = $rcube->plugins->exec_hook('identity_create',
diff --git a/lib/ext/Roundcube/rcube_utils.php b/lib/ext/Roundcube/rcube_utils.php
index b278431..2a4d4c4 100644
--- a/lib/ext/Roundcube/rcube_utils.php
+++ b/lib/ext/Roundcube/rcube_utils.php
@@ -250,9 +250,6 @@ class rcube_utils
$out = strtr($str, $encode_arr);
- // avoid douple quotation of &
- $out = preg_replace('/&([A-Za-z]{2,6}|#[0-9]{2,4});/', '&\\1;', $out);
-
return $newlines ? nl2br($out) : $out;
}
@@ -682,7 +679,7 @@ class rcube_utils
// %s - domain name after the '@' from e-mail address provided at login screen. Returns FALSE if an invalid email is provided
if (strpos($name, '%s') !== false) {
$user_email = self::get_input_value('_user', self::INPUT_POST);
- $user_email = rcube_utils::idn_convert($user_email, true);
+ $user_email = self::idn_convert($user_email, true);
$matches = preg_match('/(.*)@([a-z0-9\.\-\[\]\:]+)/i', $user_email, $s);
if ($matches < 1 || filter_var($s[1]."@".$s[2], FILTER_VALIDATE_EMAIL) === false) {
return false;
diff --git a/lib/ext/Roundcube/rcube_vcard.php b/lib/ext/Roundcube/rcube_vcard.php
index 49b312c..00903c2 100644
--- a/lib/ext/Roundcube/rcube_vcard.php
+++ b/lib/ext/Roundcube/rcube_vcard.php
@@ -50,7 +50,7 @@ class rcube_vcard
'spouse' => 'X-SPOUSE',
'edit' => 'X-AB-EDIT',
);
- private $typemap = array('iPhone' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax');
+ private $typemap = array('IPHONE' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax');
private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'BUSINESSFAX' => 'WORK,FAX');
private $addresstypemap = array('BUSINESS' => 'WORK');
private $immap = array('X-JABBER' => 'jabber', 'X-ICQ' => 'icq', 'X-MSN' => 'msn', 'X-AIM' => 'aim', 'X-YAHOO' => 'yahoo', 'X-SKYPE' => 'skype', 'X-SKYPE-USERNAME' => 'skype');
@@ -159,7 +159,18 @@ class rcube_vcard
if (!empty($raw['type'])) {
$combined = join(',', self::array_filter((array)$raw['type'], 'internet,pref', true));
- $subtype = $typemap[$combined] ? $typemap[$combined] : ($typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]));
+ $combined = strtoupper($combined);
+
+ if ($typemap[$combined]) {
+ $subtype = $typemap[$combined];
+ }
+ else if ($typemap[$raw['type'][++$k]]) {
+ $subtype = $typemap[$raw['type'][$k]];
+ }
+ else {
+ $subtype = strtolower($raw['type'][$k]);
+ }
+
while ($k < count($raw['type']) && ($subtype == 'internet' || $subtype == 'pref'))
$subtype = $typemap[$raw['type'][++$k]] ? $typemap[$raw['type'][$k]] : strtolower($raw['type'][$k]);
}
@@ -167,8 +178,11 @@ class rcube_vcard
// read vcard 2.1 subtype
if (!$subtype) {
foreach ($raw as $k => $v) {
- if (!is_numeric($k) && $v === true && !in_array(strtolower($k), array('pref','internet','voice','base64'))) {
- $subtype = $typemap[$k] ? $typemap[$k] : strtolower($k);
+ if (!is_numeric($k) && $v === true && ($k = strtolower($k))
+ && !in_array($k, array('pref','internet','voice','base64'))
+ ) {
+ $k_uc = strtoupper($k);
+ $subtype = $typemap[$k_uc] ? $typemap[$k_uc] : $k;
break;
}
}
@@ -335,7 +349,7 @@ class rcube_vcard
$index = count($this->raw[$tag]);
$this->raw[$tag][$index] = (array)$value;
if ($type)
- $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type] ? $typemap[$type] : $type));
+ $this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type));
}
break;
}
More information about the commits
mailing list