2 commits - lib/ext lib/init.php lib/kolab_sync_backend.php lib/kolab_sync_data_email.php lib/kolab_sync.php
Aleksander Machniak
machniak at kolabsys.com
Mon Nov 26 11:59:25 CET 2012
lib/ext/Roundcube/bootstrap.php | 493 ++++++++
lib/ext/Roundcube/html.php | 9
lib/ext/Roundcube/rcube.php | 84 -
lib/ext/Roundcube/rcube_addressbook.php | 9
lib/ext/Roundcube/rcube_base_replacer.php | 5
lib/ext/Roundcube/rcube_browser.php | 3
lib/ext/Roundcube/rcube_cache.php | 4
lib/ext/Roundcube/rcube_charset.php | 66 -
lib/ext/Roundcube/rcube_config.php | 39
lib/ext/Roundcube/rcube_contacts.php | 3
lib/ext/Roundcube/rcube_content_filter.php | 3
lib/ext/Roundcube/rcube_csv2vcard.php | 382 ++++++
lib/ext/Roundcube/rcube_db.php | 9
lib/ext/Roundcube/rcube_db_mssql.php | 5
lib/ext/Roundcube/rcube_db_mysql.php | 4
lib/ext/Roundcube/rcube_db_pgsql.php | 5
lib/ext/Roundcube/rcube_db_sqlite.php | 7
lib/ext/Roundcube/rcube_db_sqlsrv.php | 5
lib/ext/Roundcube/rcube_image.php | 29
lib/ext/Roundcube/rcube_imap.php | 22
lib/ext/Roundcube/rcube_imap_cache.php | 4
lib/ext/Roundcube/rcube_imap_generic.php | 19
lib/ext/Roundcube/rcube_ldap.php | 39
lib/ext/Roundcube/rcube_message.php | 23
lib/ext/Roundcube/rcube_message_header.php | 6
lib/ext/Roundcube/rcube_message_part.php | 4
lib/ext/Roundcube/rcube_mime.php | 35
lib/ext/Roundcube/rcube_output.php | 283 ----
lib/ext/Roundcube/rcube_output_html.php | 1672 ----------------------------
lib/ext/Roundcube/rcube_output_json.php | 257 ----
lib/ext/Roundcube/rcube_plugin.php | 3
lib/ext/Roundcube/rcube_plugin_api.php | 15
lib/ext/Roundcube/rcube_result_index.php | 3
lib/ext/Roundcube/rcube_result_set.php | 3
lib/ext/Roundcube/rcube_result_thread.php | 3
lib/ext/Roundcube/rcube_session.php | 23
lib/ext/Roundcube/rcube_smtp.php | 7
lib/ext/Roundcube/rcube_spellchecker.php | 3
lib/ext/Roundcube/rcube_storage.php | 8
lib/ext/Roundcube/rcube_string_replacer.php | 33
lib/ext/Roundcube/rcube_user.php | 54
lib/ext/Roundcube/rcube_utils.php | 100 +
lib/ext/Roundcube/rcube_vcard.php | 70 -
lib/init.php | 44
lib/kolab_sync.php | 7
lib/kolab_sync_backend.php | 10
lib/kolab_sync_data_email.php | 7
47 files changed, 1393 insertions(+), 2528 deletions(-)
New commits:
commit 75ace1ac33498c7292cdc1eba0770833bb26b134
Author: Aleksander Machniak <alec at alec.pl>
Date: Mon Nov 26 11:58:14 2012 +0100
Update Roundcube Framework, fix SMTP auth (#1380)
diff --git a/lib/ext/Roundcube/bootstrap.php b/lib/ext/Roundcube/bootstrap.php
new file mode 100644
index 0000000..47020c1
--- /dev/null
+++ b/lib/ext/Roundcube/bootstrap.php
@@ -0,0 +1,493 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/bootstrap.php |
+ | |
+ | This file is part of the Roundcube PHP suite |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | CONTENTS: |
+ | Roundcube Framework Initialization |
+ | |
+ +-----------------------------------------------------------------------+
+ | Author: Thomas Bruederli <roundcube at gmail.com> |
+ | Author: Aleksander Machniak <alec at alec.pl> |
+ +-----------------------------------------------------------------------+
+*/
+
+
+/**
+ * Roundcube Framework Initialization
+ *
+ * @package Framework
+ * @subpackage Core
+ */
+
+$config = array(
+ 'error_reporting' => E_ALL &~ (E_NOTICE | E_STRICT),
+ // Some users are not using Installer, so we'll check some
+ // critical PHP settings here. Only these, which doesn't provide
+ // an error/warning in the logs later. See (#1486307).
+ 'mbstring.func_overload' => 0,
+ 'suhosin.session.encrypt' => 0,
+ 'session.auto_start' => 0,
+ 'file_uploads' => 1,
+ 'magic_quotes_runtime' => 0,
+ 'magic_quotes_sybase' => 0, // #1488506
+);
+foreach ($config as $optname => $optval) {
+ if ($optval != ini_get($optname) && @ini_set($optname, $optval) === false) {
+ die("ERROR: Wrong '$optname' option value and it wasn't possible to set it to required value ($optval).\n"
+ ."Check your PHP configuration (including php_admin_flag).");
+ }
+}
+
+// framework constants
+define('RCUBE_VERSION', '0.9-git');
+define('RCMAIL_CHARSET', 'UTF-8');
+
+if (!defined('RCUBE_LIB_DIR')) {
+ define('RCUBE_LIB_DIR', dirname(__FILE__).'/');
+}
+
+if (!defined('RCUBE_INSTALL_PATH')) {
+ define('RCUBE_INSTALL_PATH', RCUBE_LIB_DIR);
+}
+
+if (!defined('RCUBE_CONFIG_DIR')) {
+ define('RCUBE_CONFIG_DIR', RCUBE_INSTALL_PATH . 'config/');
+}
+
+if (!defined('RCUBE_PLUGINS_DIR')) {
+ define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/');
+}
+
+if (!defined('RCUBE_LOCALIZATION_DIR')) {
+ define('RCUBE_LOCALIZATION_DIR', RCUBE_INSTALL_PATH . 'localization/');
+}
+
+// set internal encoding for mbstring extension
+if (extension_loaded('mbstring')) {
+ mb_internal_encoding(RCMAIL_CHARSET);
+ @mb_regex_encoding(RCMAIL_CHARSET);
+}
+
+// Register autoloader
+spl_autoload_register('rcube_autoload');
+
+// set PEAR error handling (will also load the PEAR main class)
+PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
+
+
+
+/**
+ * Similar function as in_array() but case-insensitive
+ *
+ * @param string $needle Needle value
+ * @param array $heystack Array to search in
+ *
+ * @return boolean True if found, False if not
+ */
+function in_array_nocase($needle, $haystack)
+{
+ $needle = mb_strtolower($needle);
+ foreach ((array)$haystack as $value) {
+ if ($needle === mb_strtolower($value)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+/**
+ * Parse a human readable string for a number of bytes.
+ *
+ * @param string $str Input string
+ *
+ * @return float Number of bytes
+ */
+function parse_bytes($str)
+{
+ if (is_numeric($str)) {
+ return floatval($str);
+ }
+
+ if (preg_match('/([0-9\.]+)\s*([a-z]*)/i', $str, $regs)) {
+ $bytes = floatval($regs[1]);
+ switch (strtolower($regs[2])) {
+ case 'g':
+ case 'gb':
+ $bytes *= 1073741824;
+ break;
+ case 'm':
+ case 'mb':
+ $bytes *= 1048576;
+ break;
+ case 'k':
+ case 'kb':
+ $bytes *= 1024;
+ break;
+ }
+ }
+
+ return floatval($bytes);
+}
+
+
+/**
+ * Make sure the string ends with a slash
+ */
+function slashify($str)
+{
+ return unslashify($str).'/';
+}
+
+
+/**
+ * Remove slashes at the end of the string
+ */
+function unslashify($str)
+{
+ return preg_replace('/\/+$/', '', $str);
+}
+
+
+/**
+ * Returns number of seconds for a specified offset string.
+ *
+ * @param string $str String representation of the offset (e.g. 20min, 5h, 2days, 1week)
+ *
+ * @return int Number of seconds
+ */
+function get_offset_sec($str)
+{
+ if (preg_match('/^([0-9]+)\s*([smhdw])/i', $str, $regs)) {
+ $amount = (int) $regs[1];
+ $unit = strtolower($regs[2]);
+ }
+ else {
+ $amount = (int) $str;
+ $unit = 's';
+ }
+
+ switch ($unit) {
+ case 'w':
+ $amount *= 7;
+ case 'd':
+ $amount *= 24;
+ case 'h':
+ $amount *= 60;
+ case 'm':
+ $amount *= 60;
+ }
+
+ return $amount;
+}
+
+
+/**
+ * Create a unix timestamp with a specified offset from now.
+ *
+ * @param string $offset_str String representation of the offset (e.g. 20min, 5h, 2days)
+ * @param int $factor Factor to multiply with the offset
+ *
+ * @return int Unix timestamp
+ */
+function get_offset_time($offset_str, $factor=1)
+{
+ return time() + get_offset_sec($offset_str) * $factor;
+}
+
+
+/**
+ * Truncate string if it is longer than the allowed length.
+ * Replace the middle or the ending part of a string with a placeholder.
+ *
+ * @param string $str Input string
+ * @param int $maxlength Max. length
+ * @param string $placeholder Replace removed chars with this
+ * @param bool $ending Set to True if string should be truncated from the end
+ *
+ * @return string Abbreviated string
+ */
+function abbreviate_string($str, $maxlength, $placeholder='...', $ending=false)
+{
+ $length = mb_strlen($str);
+
+ if ($length > $maxlength) {
+ if ($ending) {
+ return mb_substr($str, 0, $maxlength) . $placeholder;
+ }
+
+ $placeholder_length = mb_strlen($placeholder);
+ $first_part_length = floor(($maxlength - $placeholder_length)/2);
+ $second_starting_location = $length - $maxlength + $first_part_length + $placeholder_length;
+
+ $str = mb_substr($str, 0, $first_part_length) . $placeholder . mb_substr($str, $second_starting_location);
+ }
+
+ return $str;
+}
+
+
+/**
+ * Get all keys from array (recursive).
+ *
+ * @param array $array Input array
+ *
+ * @return array List of array keys
+ */
+function array_keys_recursive($array)
+{
+ $keys = array();
+
+ if (!empty($array) && is_array($array)) {
+ foreach ($array as $key => $child) {
+ $keys[] = $key;
+ foreach (array_keys_recursive($child) as $val) {
+ $keys[] = $val;
+ }
+ }
+ }
+
+ return $keys;
+}
+
+
+/**
+ * Remove all non-ascii and non-word chars except ., -, _
+ */
+function asciiwords($str, $css_id = false, $replace_with = '')
+{
+ $allowed = 'a-z0-9\_\-' . (!$css_id ? '\.' : '');
+ return preg_replace("/[^$allowed]/i", $replace_with, $str);
+}
+
+
+/**
+ * Check if a string contains only ascii characters
+ *
+ * @param string $str String to check
+ * @param bool $control_chars Includes control characters
+ *
+ * @return bool
+ */
+function is_ascii($str, $control_chars = true)
+{
+ $regexp = $control_chars ? '/[^\x00-\x7F]/' : '/[^\x20-\x7E]/';
+ return preg_match($regexp, $str) ? false : true;
+}
+
+
+/**
+ * Remove single and double quotes from a given string
+ *
+ * @param string Input value
+ *
+ * @return string Dequoted string
+ */
+function strip_quotes($str)
+{
+ return str_replace(array("'", '"'), '', $str);
+}
+
+
+/**
+ * Remove new lines characters from given string
+ *
+ * @param string $str Input value
+ *
+ * @return string Stripped string
+ */
+function strip_newlines($str)
+{
+ return preg_replace('/[\r\n]/', '', $str);
+}
+
+
+/**
+ * Compose a valid representation of name and e-mail address
+ *
+ * @param string $email E-mail address
+ * @param string $name Person name
+ *
+ * @return string Formatted string
+ */
+function format_email_recipient($email, $name = '')
+{
+ $email = trim($email);
+
+ if ($name && $name != $email) {
+ // Special chars as defined by RFC 822 need to in quoted string (or escaped).
+ if (preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name)) {
+ $name = '"'.addcslashes($name, '"').'"';
+ }
+
+ return "$name <$email>";
+ }
+
+ return $email;
+}
+
+
+/**
+ * Format e-mail address
+ *
+ * @param string $email E-mail address
+ *
+ * @return string Formatted e-mail address
+ */
+function format_email($email)
+{
+ $email = trim($email);
+ $parts = explode('@', $email);
+ $count = count($parts);
+
+ if ($count > 1) {
+ $parts[$count-1] = mb_strtolower($parts[$count-1]);
+
+ $email = implode('@', $parts);
+ }
+
+ return $email;
+}
+
+
+/**
+ * mbstring replacement functions
+ */
+if (!extension_loaded('mbstring'))
+{
+ function mb_strlen($str)
+ {
+ return strlen($str);
+ }
+
+ function mb_strtolower($str)
+ {
+ return strtolower($str);
+ }
+
+ function mb_strtoupper($str)
+ {
+ return strtoupper($str);
+ }
+
+ function mb_substr($str, $start, $len=null)
+ {
+ return substr($str, $start, $len);
+ }
+
+ function mb_strpos($haystack, $needle, $offset=0)
+ {
+ return strpos($haystack, $needle, $offset);
+ }
+
+ function mb_strrpos($haystack, $needle, $offset=0)
+ {
+ return strrpos($haystack, $needle, $offset);
+ }
+}
+
+/**
+ * intl replacement functions
+ */
+
+if (!function_exists('idn_to_utf8'))
+{
+ function idn_to_utf8($domain, $flags=null)
+ {
+ static $idn, $loaded;
+
+ if (!$loaded) {
+ $idn = new Net_IDNA2();
+ $loaded = true;
+ }
+
+ if ($idn && $domain && preg_match('/(^|\.)xn--/i', $domain)) {
+ try {
+ $domain = $idn->decode($domain);
+ }
+ catch (Exception $e) {
+ }
+ }
+ return $domain;
+ }
+}
+
+if (!function_exists('idn_to_ascii'))
+{
+ function idn_to_ascii($domain, $flags=null)
+ {
+ static $idn, $loaded;
+
+ if (!$loaded) {
+ $idn = new Net_IDNA2();
+ $loaded = true;
+ }
+
+ if ($idn && $domain && preg_match('/[^\x20-\x7E]/', $domain)) {
+ try {
+ $domain = $idn->encode($domain);
+ }
+ catch (Exception $e) {
+ }
+ }
+ return $domain;
+ }
+}
+
+/**
+ * Use PHP5 autoload for dynamic class loading
+ *
+ * @todo Make Zend, PEAR etc play with this
+ * @todo Make our classes conform to a more straight forward CS.
+ */
+function rcube_autoload($classname)
+{
+ $filename = preg_replace(
+ array(
+ '/Mail_(.+)/',
+ '/Net_(.+)/',
+ '/Auth_(.+)/',
+ '/^html_.+/',
+ '/^rcube(.*)/',
+ '/^utf8$/',
+ ),
+ array(
+ 'Mail/\\1',
+ 'Net/\\1',
+ 'Auth/\\1',
+ 'Roundcube/html',
+ 'Roundcube/rcube\\1',
+ 'utf8.class',
+ ),
+ $classname
+ );
+
+ if ($fp = @fopen("$filename.php", 'r', true)) {
+ fclose($fp);
+ include_once "$filename.php";
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Local callback function for PEAR errors
+ */
+function rcube_pear_error($err)
+{
+ error_log(sprintf("%s (%s): %s",
+ $err->getMessage(),
+ $err->getCode(),
+ $err->getUserinfo()), 0);
+}
diff --git a/lib/ext/Roundcube/html.php b/lib/ext/Roundcube/html.php
index 2349852..8ff685a 100644
--- a/lib/ext/Roundcube/html.php
+++ b/lib/ext/Roundcube/html.php
@@ -23,7 +23,8 @@
/**
* Class for HTML code creation
*
- * @package HTML
+ * @package Framework
+ * @subpackage HTML
*/
class html
{
@@ -252,9 +253,9 @@ class html
* @return string HTML code
* @see html::tag()
*/
- public static function br()
+ public static function br($attrib = array())
{
- return self::tag('br');
+ return self::tag('br', $attrib);
}
/**
@@ -334,7 +335,7 @@ class html
*/
public static function quote($str)
{
- return htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
+ return @htmlspecialchars($str, ENT_COMPAT, RCMAIL_CHARSET);
}
}
diff --git a/lib/ext/Roundcube/rcube.php b/lib/ext/Roundcube/rcube.php
index 0e40b3c..c798465 100644
--- a/lib/ext/Roundcube/rcube.php
+++ b/lib/ext/Roundcube/rcube.php
@@ -434,6 +434,9 @@ class rcube
$this->session->register_gc_handler(array($this, 'temp_gc'));
$this->session->register_gc_handler(array($this, 'cache_gc'));
+ $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME']));
+ $this->session->set_ip_check($this->config->get('ip_check'));
+
// start PHP session (if not in CLI mode)
if ($_SERVER['REMOTE_ADDR']) {
session_start();
@@ -442,33 +445,6 @@ class rcube
/**
- * Configure session object internals
- */
- public function session_configure()
- {
- if (!$this->session) {
- return;
- }
-
- $lifetime = $this->config->get('session_lifetime', 0) * 60;
- $keep_alive = $this->config->get('keep_alive');
-
- // set keep-alive/check-recent interval
- if ($keep_alive) {
- // be sure that it's less than session lifetime
- if ($lifetime) {
- $keep_alive = min($keep_alive, $lifetime - 30);
- }
- $keep_alive = max(60, $keep_alive);
- $this->session->set_keep_alive($keep_alive);
- }
-
- $this->session->set_secret($this->config->get('des_key') . dirname($_SERVER['SCRIPT_NAME']));
- $this->session->set_ip_check($this->config->get('ip_check'));
- }
-
-
- /**
* Garbage collector function for temp files.
* Remove temp files older than two days
*/
@@ -620,8 +596,8 @@ class rcube
ob_start();
// get english labels (these should be complete)
- @include(INSTALL_PATH . 'program/localization/en_US/labels.inc');
- @include(INSTALL_PATH . 'program/localization/en_US/messages.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'en_US/labels.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'en_US/messages.inc');
if (is_array($labels))
$this->texts = $labels;
@@ -629,9 +605,9 @@ class rcube
$this->texts = array_merge($this->texts, $messages);
// include user language files
- if ($lang != 'en' && $lang != 'en_US' && is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
- include_once(INSTALL_PATH . 'program/localization/' . $lang . '/labels.inc');
- include_once(INSTALL_PATH . 'program/localization/' . $lang . '/messages.inc');
+ if ($lang != 'en' && $lang != 'en_US' && is_dir(RCUBE_LOCALIZATION_DIR . $lang)) {
+ include_once(RCUBE_LOCALIZATION_DIR . $lang . '/labels.inc');
+ include_once(RCUBE_LOCALIZATION_DIR . $lang . '/messages.inc');
if (is_array($labels))
$this->texts = array_merge($this->texts, $labels);
@@ -669,7 +645,7 @@ class rcube
}
if (empty($rcube_languages)) {
- @include(INSTALL_PATH . 'program/localization/index.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'index.inc');
}
// check if we have an alias for that language
@@ -690,7 +666,7 @@ class rcube
}
}
- if (!isset($rcube_languages[$lang]) || !is_dir(INSTALL_PATH . 'program/localization/' . $lang)) {
+ if (!isset($rcube_languages[$lang]) || !is_dir(RCUBE_LOCALIZATION_DIR . $lang)) {
$lang = 'en_US';
}
@@ -708,11 +684,11 @@ class rcube
static $sa_languages = array();
if (!sizeof($sa_languages)) {
- @include(INSTALL_PATH . 'program/localization/index.inc');
+ @include(RCUBE_LOCALIZATION_DIR . 'index.inc');
- if ($dh = @opendir(INSTALL_PATH . 'program/localization')) {
+ if ($dh = @opendir(RCUBE_LOCALIZATION_DIR)) {
while (($name = readdir($dh)) !== false) {
- if ($name[0] == '.' || !is_dir(INSTALL_PATH . 'program/localization/' . $name)) {
+ if ($name[0] == '.' || !is_dir(RCUBE_LOCALIZATION_DIR . $name)) {
continue;
}
@@ -1041,7 +1017,7 @@ class rcube
$log_dir = self::$instance ? self::$instance->config->get('log_dir') : null;
if (empty($log_dir)) {
- $log_dir = INSTALL_PATH . 'logs';
+ $log_dir = RCUBE_INSTALL_PATH . 'logs';
}
// try to open specific log file for writing
@@ -1227,8 +1203,38 @@ class rcube
if (is_object($this->user)) {
return $this->user->get_username();
}
+ else if (isset($_SESSION['username'])) {
+ return $_SESSION['username'];
+ }
+ }
- return null;
+
+ /**
+ * Getter for logged user email (derived from user name not identity).
+ *
+ * @return string User email address
+ */
+ public function get_user_email()
+ {
+ if (is_object($this->user)) {
+ return $this->user->get_username('mail');
+ }
+ }
+
+
+ /**
+ * Getter for logged user password.
+ *
+ * @return string User password
+ */
+ public function get_user_password()
+ {
+ if ($this->password) {
+ return $this->password;
+ }
+ else if ($_SESSION['password']) {
+ return $this->decrypt($_SESSION['password']);
+ }
}
}
diff --git a/lib/ext/Roundcube/rcube_addressbook.php b/lib/ext/Roundcube/rcube_addressbook.php
index 892ae26..d14fc58 100644
--- a/lib/ext/Roundcube/rcube_addressbook.php
+++ b/lib/ext/Roundcube/rcube_addressbook.php
@@ -23,7 +23,8 @@
/**
* Abstract skeleton of an address book/repository
*
- * @package Addressbook
+ * @package Framework
+ * @subpackage Addressbook
*/
abstract class rcube_addressbook
{
@@ -208,7 +209,7 @@ abstract class rcube_addressbook
*/
public function validate(&$save_data, $autofix = false)
{
- $rcmail = rcmail::get_instance();
+ $rcmail = rcube::get_instance();
// check validity of email addresses
foreach ($this->get_col_values('email', $save_data, true) as $email) {
@@ -466,7 +467,7 @@ abstract class rcube_addressbook
*/
public static function compose_display_name($contact, $full_email = false)
{
- $contact = rcmail::get_instance()->plugins->exec_hook('contact_displayname', $contact);
+ $contact = rcube::get_instance()->plugins->exec_hook('contact_displayname', $contact);
$fn = $contact['name'];
if (!$fn) // default display name composition according to vcard standard
@@ -503,7 +504,7 @@ abstract class rcube_addressbook
static $compose_mode;
if (!isset($compose_mode)) // cache this
- $compose_mode = rcmail::get_instance()->config->get('addressbook_name_listing', 0);
+ $compose_mode = rcube::get_instance()->config->get('addressbook_name_listing', 0);
if ($compose_mode == 3)
$fn = join(' ', array($contact['surname'] . ',', $contact['firstname'], $contact['middlename']));
diff --git a/lib/ext/Roundcube/rcube_base_replacer.php b/lib/ext/Roundcube/rcube_base_replacer.php
index 4ec3675..b2a0fc1 100644
--- a/lib/ext/Roundcube/rcube_base_replacer.php
+++ b/lib/ext/Roundcube/rcube_base_replacer.php
@@ -23,8 +23,9 @@
* Helper class to turn relative urls into absolute ones
* using a predefined base
*
- * @package Core
- * @author Thomas Bruederli <roundcube at gmail.com>
+ * @package Framework
+ * @subpackage Core
+ * @author Thomas Bruederli <roundcube at gmail.com>
*/
class rcube_base_replacer
{
diff --git a/lib/ext/Roundcube/rcube_browser.php b/lib/ext/Roundcube/rcube_browser.php
index 7cfae70..154e7ef 100644
--- a/lib/ext/Roundcube/rcube_browser.php
+++ b/lib/ext/Roundcube/rcube_browser.php
@@ -22,7 +22,8 @@
/**
* Provide details about the client's browser based on the User-Agent header
*
- * @package Core
+ * @package Framework
+ * @subpackage Core
*/
class rcube_browser
{
diff --git a/lib/ext/Roundcube/rcube_cache.php b/lib/ext/Roundcube/rcube_cache.php
index 4e60dea..3e1ce4f 100644
--- a/lib/ext/Roundcube/rcube_cache.php
+++ b/lib/ext/Roundcube/rcube_cache.php
@@ -25,10 +25,10 @@
/**
* Interface class for accessing Roundcube cache
*
- * @package Cache
+ * @package Framework
+ * @subpackage Cache
* @author Thomas Bruederli <roundcube at gmail.com>
* @author Aleksander Machniak <alec at alec.pl>
- * @version 1.1
*/
class rcube_cache
{
diff --git a/lib/ext/Roundcube/rcube_charset.php b/lib/ext/Roundcube/rcube_charset.php
index ff4c2bb..e8cce00 100644
--- a/lib/ext/Roundcube/rcube_charset.php
+++ b/lib/ext/Roundcube/rcube_charset.php
@@ -25,10 +25,11 @@
/**
* Character sets conversion functionality
*
- * @package Core
- * @author Thomas Bruederli <roundcube at gmail.com>
- * @author Aleksander Machniak <alec at alec.pl>
- * @author Edmund Grimley Evans <edmundo at rano.org>
+ * @package Framework
+ * @subpackage Core
+ * @author Thomas Bruederli <roundcube at gmail.com>
+ * @author Aleksander Machniak <alec at alec.pl>
+ * @author Edmund Grimley Evans <edmundo at rano.org>
*/
class rcube_charset
{
@@ -655,22 +656,49 @@ class rcube_charset
*/
public static function detect($string, $failover='')
{
- if (!function_exists('mb_detect_encoding')) {
- return $failover;
- }
-
- // FIXME: the order is important, because sometimes
- // iso string is detected as euc-jp and etc.
- $enc = array(
- 'UTF-8', 'SJIS', 'BIG5', 'GB2312',
- 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
- 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
- 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
- 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R',
- 'ISO-2022-KR', 'ISO-2022-JP'
- );
+ if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian
+ if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian
+ if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian
+ if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian
+ if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8';
+
+ // heuristics
+ if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE';
+ if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE';
+ if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE';
+ if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE';
+
+ if (function_exists('mb_detect_encoding')) {
+ // FIXME: the order is important, because sometimes
+ // iso string is detected as euc-jp and etc.
+ $enc = array(
+ 'UTF-8', 'SJIS', 'GB2312',
+ 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3', 'ISO-8859-4',
+ 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
+ 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
+ 'WINDOWS-1252', 'WINDOWS-1251', 'EUC-JP', 'EUC-TW', 'KOI8-R', 'BIG5',
+ 'ISO-2022-KR', 'ISO-2022-JP',
+ );
- $result = mb_detect_encoding($string, join(',', $enc));
+ $result = mb_detect_encoding($string, join(',', $enc));
+ }
+ else {
+ // No match, check for UTF-8
+ // from http://w3.org/International/questions/qa-forms-utf-8.html
+ if (preg_match('/\A(
+ [\x09\x0A\x0D\x20-\x7E]
+ | [\xC2-\xDF][\x80-\xBF]
+ | \xE0[\xA0-\xBF][\x80-\xBF]
+ | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}
+ | \xED[\x80-\x9F][\x80-\xBF]
+ | \xF0[\x90-\xBF][\x80-\xBF]{2}
+ | [\xF1-\xF3][\x80-\xBF]{3}
+ | \xF4[\x80-\x8F][\x80-\xBF]{2}
+ )*\z/xs', substr($string, 0, 2048))
+ ) {
+ return 'UTF-8';
+ }
+ }
return $result ? $result : $failover;
}
diff --git a/lib/ext/Roundcube/rcube_config.php b/lib/ext/Roundcube/rcube_config.php
index b9fd955..8112d2e 100644
--- a/lib/ext/Roundcube/rcube_config.php
+++ b/lib/ext/Roundcube/rcube_config.php
@@ -22,7 +22,8 @@
/**
* Configuration class for Roundcube
*
- * @package Core
+ * @package Framework
+ * @subpackage Core
*/
class rcube_config
{
@@ -43,6 +44,8 @@ class rcube_config
'mail_pagesize' => 'pagesize',
'addressbook_pagesize' => 'pagesize',
'reply_mode' => 'top_posting',
+ 'refresh_interval' => 'keep_alive',
+ 'min_refresh_interval' => 'min_keep_alive',
);
@@ -68,11 +71,11 @@ class rcube_config
private function load()
{
// load main config file
- if (!$this->load_from_file(RCMAIL_CONFIG_DIR . '/main.inc.php'))
+ if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'main.inc.php'))
$this->errors[] = 'main.inc.php was not found.';
// load database config
- if (!$this->load_from_file(RCMAIL_CONFIG_DIR . '/db.inc.php'))
+ if (!$this->load_from_file(RCUBE_CONFIG_DIR . 'db.inc.php'))
$this->errors[] = 'db.inc.php was not found.';
// load host-specific configuration
@@ -93,8 +96,8 @@ class rcube_config
$this->prop['skin'] = self::DEFAULT_SKIN;
// fix paths
- $this->prop['log_dir'] = $this->prop['log_dir'] ? realpath(unslashify($this->prop['log_dir'])) : INSTALL_PATH . 'logs';
- $this->prop['temp_dir'] = $this->prop['temp_dir'] ? realpath(unslashify($this->prop['temp_dir'])) : INSTALL_PATH . 'temp';
+ $this->prop['log_dir'] = $this->prop['log_dir'] ? realpath(unslashify($this->prop['log_dir'])) : RCUBE_INSTALL_PATH . 'logs';
+ $this->prop['temp_dir'] = $this->prop['temp_dir'] ? realpath(unslashify($this->prop['temp_dir'])) : RCUBE_INSTALL_PATH . 'temp';
// fix default imap folders encoding
foreach (array('drafts_mbox', 'junk_mbox', 'sent_mbox', 'trash_mbox') as $folder)
@@ -153,7 +156,7 @@ class rcube_config
}
if ($fname) {
- $this->load_from_file(RCMAIL_CONFIG_DIR . '/' . $fname);
+ $this->load_from_file(RCUBE_CONFIG_DIR . $fname);
}
}
@@ -204,8 +207,15 @@ class rcube_config
$rcube = rcube::get_instance();
- if ($name == 'timezone' && isset($this->prop['_timezone_value']))
+ if ($name == 'timezone' && isset($this->prop['_timezone_value'])) {
$result = $this->prop['_timezone_value'];
+ }
+ else if ($name == 'client_mimetypes') {
+ if ($result == null && $def == null)
+ $result = 'text/plain,text/html,text/xml,image/jpeg,image/gif,image/png,image/bmp,image/tiff,application/x-javascript,application/pdf,application/x-shockwave-flash';
+ if ($result && is_string($result))
+ $result = explode(',', $result);
+ }
$plugin = $rcube->plugins->exec_hook('config_get', array(
'name' => $name, 'default' => $def, 'result' => $result));
@@ -412,7 +422,20 @@ class rcube_config
*/
private function client_timezone()
{
- return isset($_SESSION['timezone']) && ($ctz = timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0)) ? $ctz : date_default_timezone_get();
+ if (isset($_SESSION['timezone']) && is_numeric($_SESSION['timezone'])
+ && ($ctz = timezone_name_from_abbr("", $_SESSION['timezone'] * 3600, 0))) {
+ return $ctz;
+ }
+ else if (!empty($_SESSION['timezone'])) {
+ try {
+ $tz = timezone_open($_SESSION['timezone']);
+ return $tz->getName();
+ }
+ catch (Exception $e) { /* gracefully ignore */ }
+ }
+
+ // fallback to server's timezone
+ return date_default_timezone_get();
}
}
diff --git a/lib/ext/Roundcube/rcube_contacts.php b/lib/ext/Roundcube/rcube_contacts.php
index 534a65c..e4500c7 100644
--- a/lib/ext/Roundcube/rcube_contacts.php
+++ b/lib/ext/Roundcube/rcube_contacts.php
@@ -23,7 +23,8 @@
/**
* Model class for the local address book database
*
- * @package Addressbook
+ * @package Framework
+ * @subpackage Addressbook
*/
class rcube_contacts extends rcube_addressbook
{
diff --git a/lib/ext/Roundcube/rcube_content_filter.php b/lib/ext/Roundcube/rcube_content_filter.php
index 36e61a2..99916a3 100644
--- a/lib/ext/Roundcube/rcube_content_filter.php
+++ b/lib/ext/Roundcube/rcube_content_filter.php
@@ -21,6 +21,9 @@
/**
* PHP stream filter to detect html/javascript code in attachments
+ *
+ * @package Framework
+ * @subpackage Core
*/
class rcube_content_filter extends php_user_filter
{
diff --git a/lib/ext/Roundcube/rcube_csv2vcard.php b/lib/ext/Roundcube/rcube_csv2vcard.php
new file mode 100644
index 0000000..ec7a3ab
--- /dev/null
+++ b/lib/ext/Roundcube/rcube_csv2vcard.php
@@ -0,0 +1,382 @@
+<?php
+
+/*
+ +-----------------------------------------------------------------------+
+ | program/include/rcube_csv2vcard.php |
+ | |
+ | This file is part of the Roundcube Webmail client |
+ | Copyright (C) 2008-2012, The Roundcube Dev Team |
+ | |
+ | Licensed under the GNU General Public License version 3 or |
+ | any later version with exceptions for skins & plugins. |
+ | See the README file for a full license statement. |
+ | |
+ | PURPOSE: |
+ | CSV to vCard data conversion |
+ +-----------------------------------------------------------------------+
+ | Author: Aleksander Machniak <alec at alec.pl> |
+ +-----------------------------------------------------------------------+
+*/
+
+/**
+ * CSV to vCard data converter
+ *
+ * @package Framework
+ * @subpackage Addressbook
+ * @author Aleksander Machniak <alec at alec.pl>
+ */
+class rcube_csv2vcard
+{
+ /**
+ * CSV to vCard fields mapping
+ *
+ * @var array
+ */
+ protected $csv2vcard_map = array(
+ // MS Outlook 2010
+ 'anniversary' => 'anniversary',
+ 'assistants_name' => 'assistant',
+ 'assistants_phone' => 'phone:assistant',
+ 'birthday' => 'birthday',
+ 'business_city' => 'locality:work',
+ 'business_countryregion' => 'country:work',
+ 'business_fax' => 'phone:work,fax',
+ 'business_phone' => 'phone:work',
+ 'business_phone_2' => 'phone:work2',
+ 'business_postal_code' => 'zipcode:work',
+ 'business_state' => 'region:work',
+ 'business_street' => 'street:work',
+ //'business_street_2' => '',
+ //'business_street_3' => '',
+ 'car_phone' => 'phone:car',
+ 'categories' => 'categories',
+ //'children' => '',
+ 'company' => 'organization',
+ //'company_main_phone' => '',
+ 'department' => 'department',
+ //'email_2_address' => '', //@TODO
+ //'email_2_type' => '',
+ //'email_3_address' => '', //@TODO
+ //'email_3_type' => '',
+ 'email_address' => 'email:main',
+ //'email_type' => '',
+ 'first_name' => 'firstname',
+ 'gender' => 'gender',
+ 'home_city' => 'locality:home',
+ 'home_countryregion' => 'country:home',
+ 'home_fax' => 'phone:home,fax',
+ 'home_phone' => 'phone:home',
+ 'home_phone_2' => 'phone:home2',
+ 'home_postal_code' => 'zipcode:home',
+ 'home_state' => 'region:home',
+ 'home_street' => 'street:home',
+ //'home_street_2' => '',
+ //'home_street_3' => '',
+ //'initials' => '',
+ //'isdn' => '',
+ 'job_title' => 'jobtitle',
+ //'keywords' => '',
+ //'language' => '',
+ 'last_name' => 'surname',
+ //'location' => '',
+ 'managers_name' => 'manager',
+ 'middle_name' => 'middlename',
+ //'mileage' => '',
+ 'mobile_phone' => 'phone:cell',
+ 'notes' => 'notes',
+ //'office_location' => '',
+ 'other_city' => 'locality:other',
+ 'other_countryregion' => 'country:other',
+ 'other_fax' => 'phone:other,fax',
+ 'other_phone' => 'phone:other',
+ 'other_postal_code' => 'zipcode:other',
+ 'other_state' => 'region:other',
+ 'other_street' => 'street:other',
+ //'other_street_2' => '',
+ //'other_street_3' => '',
+ 'pager' => 'phone:pager',
+ 'primary_phone' => 'phone:pref',
+ //'profession' => '',
+ //'radio_phone' => '',
+ 'spouse' => 'spouse',
+ 'suffix' => 'suffix',
+ 'title' => 'title',
+ 'web_page' => 'website:homepage',
+
+ // Thunderbird
+ 'birth_day' => 'birthday-d',
+ 'birth_month' => 'birthday-m',
+ 'birth_year' => 'birthday-y',
+ 'display_name' => 'displayname',
+ 'fax_number' => 'phone:fax',
+ 'home_address' => 'street:home',
+ //'home_address_2' => '',
+ 'home_country' => 'country:home',
+ 'home_zipcode' => 'zipcode:home',
+ 'mobile_number' => 'phone:cell',
+ 'nickname' => 'nickname',
+ 'organization' => 'organization',
+ 'pager_number' => 'phone:pager',
+ 'primary_email' => 'email:pref',
+ 'secondary_email' => 'email:other',
+ 'web_page_1' => 'website:homepage',
+ 'web_page_2' => 'website:other',
+ 'work_phone' => 'phone:work',
+ 'work_address' => 'street:work',
+ //'work_address_2' => '',
+ 'work_country' => 'country:work',
+ 'work_zipcode' => 'zipcode:work',
+ );
+
+ /**
+ * CSV label to text mapping for English
+ *
+ * @var array
+ */
+ protected $label_map = array(
+ // MS Outlook 2010
+ 'anniversary' => "Anniversary",
+ 'assistants_name' => "Assistant's Name",
+ 'assistants_phone' => "Assistant's Phone",
+ 'birthday' => "Birthday",
+ 'business_city' => "Business City",
+ 'business_countryregion' => "Business Country/Region",
+ 'business_fax' => "Business Fax",
+ 'business_phone' => "Business Phone",
+ 'business_phone_2' => "Business Phone 2",
+ 'business_postal_code' => "Business Postal Code",
+ 'business_state' => "Business State",
+ 'business_street' => "Business Street",
+ //'business_street_2' => "Business Street 2",
+ //'business_street_3' => "Business Street 3",
+ 'car_phone' => "Car Phone",
+ 'categories' => "Categories",
+ //'children' => "Children",
+ 'company' => "Company",
+ //'company_main_phone' => "Company Main Phone",
+ 'department' => "Department",
+ //'directory_server' => "Directory Server",
+ //'email_2_address' => "E-mail 2 Address",
+ //'email_2_type' => "E-mail 2 Type",
+ //'email_3_address' => "E-mail 3 Address",
+ //'email_3_type' => "E-mail 3 Type",
+ 'email_address' => "E-mail Address",
+ //'email_type' => "E-mail Type",
+ 'first_name' => "First Name",
+ 'gender' => "Gender",
+ 'home_city' => "Home City",
+ 'home_countryregion' => "Home Country/Region",
+ 'home_fax' => "Home Fax",
+ 'home_phone' => "Home Phone",
+ 'home_phone_2' => "Home Phone 2",
+ 'home_postal_code' => "Home Postal Code",
+ 'home_state' => "Home State",
+ 'home_street' => "Home Street",
+ //'home_street_2' => "Home Street 2",
+ //'home_street_3' => "Home Street 3",
+ //'initials' => "Initials",
+ //'isdn' => "ISDN",
+ 'job_title' => "Job Title",
+ //'keywords' => "Keywords",
+ //'language' => "Language",
+ 'last_name' => "Last Name",
+ //'location' => "Location",
+ 'managers_name' => "Manager's Name",
+ 'middle_name' => "Middle Name",
+ //'mileage' => "Mileage",
+ 'mobile_phone' => "Mobile Phone",
+ 'notes' => "Notes",
+ //'office_location' => "Office Location",
+ 'other_city' => "Other City",
+ 'other_countryregion' => "Other Country/Region",
+ 'other_fax' => "Other Fax",
+ 'other_phone' => "Other Phone",
+ 'other_postal_code' => "Other Postal Code",
+ 'other_state' => "Other State",
+ 'other_street' => "Other Street",
+ //'other_street_2' => "Other Street 2",
+ //'other_street_3' => "Other Street 3",
+ 'pager' => "Pager",
+ 'primary_phone' => "Primary Phone",
+ //'profession' => "Profession",
+ //'radio_phone' => "Radio Phone",
+ 'spouse' => "Spouse",
+ 'suffix' => "Suffix",
+ 'title' => "Title",
+ 'web_page' => "Web Page",
+
+ // Thunderbird
+ 'birth_day' => "Birth Day",
+ 'birth_month' => "Birth Month",
+ 'birth_year' => "Birth Year",
+ 'display_name' => "Display Name",
+ 'fax_number' => "Fax Number",
+ 'home_address' => "Home Address",
+ //'home_address_2' => "Home Address 2",
+ 'home_country' => "Home Country",
+ 'home_zipcode' => "Home ZipCode",
+ 'mobile_number' => "Mobile Number",
+ 'nickname' => "Nickname",
+ 'organization' => "Organization",
+ 'pager_number' => "Pager Namber",
+ 'primary_email' => "Primary Email",
+ 'secondary_email' => "Secondary Email",
+ 'web_page_1' => "Web Page 1",
+ 'web_page_2' => "Web Page 2",
+ 'work_phone' => "Work Phone",
+ 'work_address' => "Work Address",
+ //'work_address_2' => "Work Address 2",
+ 'work_country' => "Work Country",
+ 'work_zipcode' => "Work ZipCode",
+ );
+
+ protected $local_label_map = array();
+ protected $vcards = array();
+ protected $map = array();
+
+
+ /**
+ * Class constructor
+ *
+ * @param string $lang File language
+ */
+ public function __construct($lang = 'en_US')
+ {
+ // Localize fields map
+ if ($lang && $lang != 'en_US') {
+ if (file_exists(RCUBE_LOCALIZATION_DIR . "$lang/csv2vcard.inc")) {
+ include RCUBE_LOCALIZATION_DIR . "$lang/csv2vcard.inc";
+ }
+
+ if (!empty($map)) {
+ $this->local_label_map = array_merge($this->label_map, $map);
+ }
+ }
+
+ $this->label_map = array_flip($this->label_map);
+ $this->local_label_map = array_flip($this->local_label_map);
+ }
+
+ /**
+ *
+ */
+ public function import($csv)
+ {
+ // convert to UTF-8
+ $head = substr($csv, 0, 4096);
+ $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1?
+ $charset = rcube_charset::detect($head, RCMAIL_CHARSET);
+ $csv = rcube_charset::convert($csv, $charset);
+ $head = '';
+
+ $this->map = array();
+
+ // Parse file
+ foreach (preg_split("/[\r\n]+/", $csv) as $i => $line) {
+ $line = trim($line);
+ if (empty($line)) {
+ continue;
+ }
+
+ $elements = rcube_utils::explode_quoted_string(',', $line);
+
+ if (empty($elements)) {
+ continue;
+ }
+
+ // Parse header
+ if (empty($this->map)) {
+ $this->parse_header($elements);
+ if (empty($this->map)) {
+ break;
+ }
+ }
+ // Parse data row
+ else {
+ $this->csv_to_vcard($elements);
+ }
+ }
+ }
+
+ /**
+ * @return array rcube_vcard List of vcards
+ */
+ public function export()
+ {
+ return $this->vcards;
+ }
+
+ /**
+ * Parse CSV header line, detect fields mapping
+ */
+ protected function parse_header($elements)
+ {
+ $map1 = array();
+ $map2 = array();
+ $size = count($elements);
+
+ // check English labels
+ for ($i = 0; $i < $size; $i++) {
+ $label = $this->label_map[$elements[$i]];
+ if ($label && !empty($this->csv2vcard_map[$label])) {
+ $map1[$i] = $this->csv2vcard_map[$label];
+ }
+ }
+ // check localized labels
+ if (!empty($this->local_label_map)) {
+ for ($i = 0; $i < $size; $i++) {
+ $label = $this->local_label_map[$elements[$i]];
+ if ($label && !empty($this->csv2vcard_map[$label])) {
+ $map2[$i] = $this->csv2vcard_map[$label];
+ }
+ }
+ }
+
+ $this->map = count($map1) >= count($map2) ? $map1 : $map2;
+ }
+
+ /**
+ * Convert CSV data row to vCard
+ */
+ protected function csv_to_vcard($data)
+ {
+ $contact = array();
+ foreach ($this->map as $idx => $name) {
+ $value = $data[$idx];
+ if ($value !== null && $value !== '') {
+ $contact[$name] = $value;
+ }
+ }
+
+ if (empty($contact)) {
+ return;
+ }
+
+ // Handle special values
+ if (!empty($contact['birthday-d']) && !empty($contact['birthday-m']) && !empty($contact['birthday-y'])) {
+ $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d'];
+ }
+
+ foreach (array('birthday', 'anniversary') as $key) {
+ if (!empty($contact[$key]) && $contact[$key] == '0/0/00') { // @TODO: localization?
+ unset($contact[$key]);
+ }
+ }
+
+ if (!empty($contact['gender']) && ($gender = strtolower($contact['gender']))) {
+ if (!in_array($gender, array('male', 'female'))) {
+ unset($contact['gender']);
+ }
+ }
+
+ // Create vcard object
+ $vcard = new rcube_vcard();
+ foreach ($contact as $name => $value) {
+ $name = explode(':', $name);
+ $vcard->set($name[0], $value, $name[1]);
+ }
+
+ // add to the list
+ $this->vcards[] = $vcard;
+ }
+}
diff --git a/lib/ext/Roundcube/rcube_db.php b/lib/ext/Roundcube/rcube_db.php
index b066101..5d8c4a5 100644
--- a/lib/ext/Roundcube/rcube_db.php
+++ b/lib/ext/Roundcube/rcube_db.php
@@ -21,12 +21,11 @@
/**
- * Database independent query interface
+ * Database independent query interface.
+ * This is a wrapper for the PHP PDO.
*
- * This is a wrapper for the PHP PDO
- *
- * @package Database
- * @version 1.0
+ * @package Framework
+ * @sbpackage Database
*/
class rcube_db
{
diff --git a/lib/ext/Roundcube/rcube_db_mssql.php b/lib/ext/Roundcube/rcube_db_mssql.php
index 119647d..c95663c 100644
--- a/lib/ext/Roundcube/rcube_db_mssql.php
+++ b/lib/ext/Roundcube/rcube_db_mssql.php
@@ -23,11 +23,10 @@
/**
* Database independent query interface
- *
* This is a wrapper for the PHP PDO
*
- * @package Database
- * @version 1.0
+ * @package Framework
+ * @subpackage Database
*/
class rcube_db_mssql extends rcube_db
{
diff --git a/lib/ext/Roundcube/rcube_db_mysql.php b/lib/ext/Roundcube/rcube_db_mysql.php
index 6f0acba..1c5ba1d 100644
--- a/lib/ext/Roundcube/rcube_db_mysql.php
+++ b/lib/ext/Roundcube/rcube_db_mysql.php
@@ -26,8 +26,8 @@
*
* This is a wrapper for the PHP PDO
*
- * @package Database
- * @version 1.0
+ * @package Framework
+ * @subpackage Database
*/
class rcube_db_mysql extends rcube_db
{
diff --git a/lib/ext/Roundcube/rcube_db_pgsql.php b/lib/ext/Roundcube/rcube_db_pgsql.php
index 0d0caad..797860a 100644
--- a/lib/ext/Roundcube/rcube_db_pgsql.php
+++ b/lib/ext/Roundcube/rcube_db_pgsql.php
@@ -23,11 +23,10 @@
/**
* Database independent query interface
- *
* This is a wrapper for the PHP PDO
*
- * @package Database
- * @version 1.0
+ * @package Framework
+ * @subpackage Database
*/
class rcube_db_pgsql extends rcube_db
{
diff --git a/lib/ext/Roundcube/rcube_db_sqlite.php b/lib/ext/Roundcube/rcube_db_sqlite.php
index a739767..65dcb6d 100644
--- a/lib/ext/Roundcube/rcube_db_sqlite.php
+++ b/lib/ext/Roundcube/rcube_db_sqlite.php
@@ -23,11 +23,10 @@
/**
* Database independent query interface
- *
* This is a wrapper for the PHP PDO
*
- * @package Database
- * @version 1.0
+ * @package Framework
+ * @subpackage Database
*/
class rcube_db_sqlite extends rcube_db
{
@@ -67,7 +66,7 @@ class rcube_db_sqlite extends rcube_db
// Initialize database structure in file is empty
if (!empty($dsn['database']) && !filesize($dsn['database'])) {
- $data = file_get_contents(INSTALL_PATH . 'SQL/sqlite.initial.sql');
+ $data = file_get_contents(RCUBE_INSTALL_PATH . 'SQL/sqlite.initial.sql');
if (strlen($data)) {
$this->debug('INITIALIZE DATABASE');
diff --git a/lib/ext/Roundcube/rcube_db_sqlsrv.php b/lib/ext/Roundcube/rcube_db_sqlsrv.php
index e58bf07..8b6ffe8 100644
--- a/lib/ext/Roundcube/rcube_db_sqlsrv.php
+++ b/lib/ext/Roundcube/rcube_db_sqlsrv.php
@@ -23,11 +23,10 @@
/**
* Database independent query interface
- *
* This is a wrapper for the PHP PDO
*
- * @package Database
- * @version 1.0
+ * @package Framework
+ * @subpackage Database
*/
class rcube_db_sqlsrv extends rcube_db
{
diff --git a/lib/ext/Roundcube/rcube_image.php b/lib/ext/Roundcube/rcube_image.php
index 80e8bd4..b72a24c 100644
--- a/lib/ext/Roundcube/rcube_image.php
+++ b/lib/ext/Roundcube/rcube_image.php
@@ -21,6 +21,12 @@
+-----------------------------------------------------------------------+
*/
+/**
+ * Image resizer and converter
+ *
+ * @package Framework
+ * @subpackage Utils
+ */
class rcube_image
{
private $image_file;
@@ -78,10 +84,11 @@ class rcube_image
*
* @param int $size Max width/height size
* @param string $filename Output filename
+ * @param boolean $browser_compat Convert to image type displayable by any browser
*
- * @return bool True on success, False on failure
+ * @return mixed Output type on success, False on failure
*/
- public function resize($size, $filename = null)
+ public function resize($size, $filename = null, $browser_compat = false)
{
$result = false;
$rcube = rcube::get_instance();
@@ -104,15 +111,22 @@ class rcube_image
}
$type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
+ $p['intype'] = $type;
+
+ // convert to an image format every browser can display
+ if ($browser_compat && !in_array($type, array('jpg','gif','png'))) {
+ $type = 'jpg';
+ }
+
$p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
- $p['-opts'] = array('-resize' => $size.'>');
+ $p['-opts'] = array('-resize' => $p['size'].'>');
if (in_array($type, explode(',', $p['types']))) { // Valid type?
- $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p);
+ $result = rcube::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {intype}:{in} {type}:{out}', $p);
}
if ($result === '') {
- return true;
+ return $type;
}
}
@@ -148,16 +162,19 @@ class rcube_image
if ($props['gd_type'] == IMAGETYPE_JPEG) {
$result = imagejpeg($image, $filename, 75);
+ $type = 'jpg';
}
elseif($props['gd_type'] == IMAGETYPE_GIF) {
$result = imagegif($image, $filename);
+ $type = 'gid';
}
elseif($props['gd_type'] == IMAGETYPE_PNG) {
$result = imagepng($image, $filename, 6, PNG_ALL_FILTERS);
+ $type = 'png';
}
if ($result) {
- return true;
+ return $type;
}
}
diff --git a/lib/ext/Roundcube/rcube_imap.php b/lib/ext/Roundcube/rcube_imap.php
index a89fd16..ac12ec7 100644
--- a/lib/ext/Roundcube/rcube_imap.php
+++ b/lib/ext/Roundcube/rcube_imap.php
@@ -25,10 +25,10 @@
/**
* Interface class for accessing an IMAP server
*
- * @package Mail
+ * @package Framework
+ * @subpackage Storage
* @author Thomas Bruederli <roundcube at gmail.com>
* @author Aleksander Machniak <alec at alec.pl>
- * @version 2.0
*/
class rcube_imap extends rcube_storage
{
@@ -141,8 +141,8 @@ class rcube_imap extends rcube_storage
$this->set_debug(true);
$this->options['ident'] = array(
- 'name' => 'Roundcube Webmail',
- 'version' => RCMAIL_VERSION,
+ 'name' => 'Roundcube',
+ 'version' => RCUBE_VERSION,
'php' => PHP_VERSION,
'os' => PHP_OS,
'command' => $_SERVER['REQUEST_URI'],
@@ -2074,7 +2074,7 @@ class rcube_imap extends rcube_storage
if ($o_part && $o_part->size) {
$body = $this->conn->handlePartBody($this->folder, $uid, true,
- $part ? $part : 'TEXT', $o_part->encoding, $print, $fp);
+ $part ? $part : 'TEXT', $o_part->encoding, $print, $fp, $o_part->ctype_primary == 'text');
}
if ($fp || $print) {
@@ -2188,10 +2188,10 @@ class rcube_imap extends rcube_storage
$result = $this->conn->flag($folder, $uids, $flag);
}
- if ($result) {
+ if ($result && !$skip_cache) {
// reload message headers if cached
- // @TODO: update flags instead removing from cache
- if (!$skip_cache && ($mcache = $this->get_mcache_engine())) {
+ // update flags instead removing from cache
+ if ($mcache = $this->get_mcache_engine()) {
$status = strpos($flag, 'UN') !== 0;
$mflag = preg_replace('/^UN/', '', $flag);
$mcache->change_flag($folder, $all_mode ? null : explode(',', $uids),
@@ -2203,8 +2203,12 @@ class rcube_imap extends rcube_storage
$this->clear_messagecount($folder, 'SEEN');
$this->clear_messagecount($folder, 'UNSEEN');
}
- else if ($flag == 'DELETED') {
+ else if ($flag == 'DELETED' || $flag == 'UNDELETED') {
$this->clear_messagecount($folder, 'DELETED');
+ // remove cached messages
+ if ($this->options['skip_deleted']) {
+ $this->clear_message_cache($folder, $all_mode ? null : explode(',', $uids));
+ }
}
}
diff --git a/lib/ext/Roundcube/rcube_imap_cache.php b/lib/ext/Roundcube/rcube_imap_cache.php
index f36ace0..31214cf 100644
--- a/lib/ext/Roundcube/rcube_imap_cache.php
+++ b/lib/ext/Roundcube/rcube_imap_cache.php
@@ -24,10 +24,10 @@
/**
* Interface class for accessing Roundcube messages cache
*
- * @package Cache
+ * @package Framework
+ * @subpackage Storage
* @author Thomas Bruederli <roundcube at gmail.com>
* @author Aleksander Machniak <alec at alec.pl>
- * @version 1.0
*/
class rcube_imap_cache
{
diff --git a/lib/ext/Roundcube/rcube_imap_generic.php b/lib/ext/Roundcube/rcube_imap_generic.php
index 9c525dc..a0a8f3b 100644
--- a/lib/ext/Roundcube/rcube_imap_generic.php
+++ b/lib/ext/Roundcube/rcube_imap_generic.php
@@ -30,8 +30,8 @@
/**
* PHP based wrapper class to connect to an IMAP server
*
- * @package Mail
- * @author Aleksander Machniak <alec at alec.pl>
+ * @package Framework
+ * @subpackage Storage
*/
class rcube_imap_generic
{
@@ -2379,7 +2379,7 @@ class rcube_imap_generic
return $this->handlePartBody($mailbox, $id, $is_uid, $part);
}
- function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL, $formatted=true)
+ function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL, $formatted=false)
{
if (!$this->select($mailbox)) {
return false;
@@ -2417,6 +2417,7 @@ class rcube_imap_generic
}
if ($binary) {
+ // WARNING: Use $formatting argument with care, this may break binary data stream
$mode = -1;
}
@@ -3658,18 +3659,6 @@ class rcube_imap_generic
}
/**
- * Unescapes quoted-string
- *
- * @param string $string IMAP string
- *
- * @return string String
- */
- static function unEscape($string)
- {
- return stripslashes($string);
- }
-
- /**
* Set the value of the debugging flag.
*
* @param boolean $debug New value for the debugging flag.
diff --git a/lib/ext/Roundcube/rcube_ldap.php b/lib/ext/Roundcube/rcube_ldap.php
index 61a073f..c9a14d8 100644
--- a/lib/ext/Roundcube/rcube_ldap.php
+++ b/lib/ext/Roundcube/rcube_ldap.php
@@ -6,7 +6,7 @@
| |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2006-2012, The Roundcube Dev Team |
- | Copyright (C) 2011, Kolab Systems AG |
+ | Copyright (C) 2011-2012, Kolab Systems AG |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -26,7 +26,8 @@
/**
* Model class to access an LDAP address directory
*
- * @package Addressbook
+ * @package Framework
+ * @subpackage Addressbook
*/
class rcube_ldap extends rcube_addressbook
{
@@ -160,7 +161,8 @@ class rcube_ldap extends rcube_addressbook
}
// make sure LDAP_rdn field is required
- if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields'])) {
+ if (!empty($this->prop['LDAP_rdn']) && !in_array($this->prop['LDAP_rdn'], $this->prop['required_fields'])
+ && !in_array($this->prop['LDAP_rdn'], array_keys((array)$this->prop['autovalues']))) {
$this->prop['required_fields'][] = $this->prop['LDAP_rdn'];
}
@@ -267,11 +269,11 @@ class rcube_ldap extends rcube_addressbook
if ($this->prop['user_specific']) {
// No password set, use the session password
if (empty($bind_pass)) {
- $bind_pass = $rcube->decrypt($_SESSION['password']);
+ $bind_pass = $rcube->get_user_password();
}
// Get the pieces needed for variable replacement.
- if ($fu = $rcube->get_user_name())
+ if ($fu = $rcube->get_user_email())
list($u, $d) = explode('@', $fu);
else
$d = $this->mail_domain;
@@ -1086,6 +1088,9 @@ class rcube_ldap extends rcube_addressbook
$newentry = $this->_map_data($save_cols);
$newentry['objectClass'] = $this->prop['LDAP_Object_Classes'];
+ // add automatically generated attributes
+ $this->add_autovalues($newentry);
+
// Verify that the required fields are set.
$missing = null;
foreach ($this->prop['required_fields'] as $fld) {
@@ -1389,6 +1394,30 @@ class rcube_ldap extends rcube_addressbook
}
}
+ /**
+ * Generate missing attributes as configured
+ *
+ * @param array LDAP record attributes
+ */
+ protected function add_autovalues(&$attrs)
+ {
+ $attrvals = array();
+ foreach ($attrs as $k => $v) {
+ $attrvals['{'.$k.'}'] = is_array($v) ? $v[0] : $v;
+ }
+
+ foreach ((array)$this->prop['autovalues'] as $lf => $templ) {
+ if (empty($attrs[$lf])) {
+ // replace {attr} placeholders with concrete attribute values
+ $templ = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals));
+
+ if (strpos($templ, '(') !== false)
+ $attrs[$lf] = eval("return ($templ);");
+ else
+ $attrs[$lf] = $templ;
+ }
+ }
+ }
/**
* Execute the LDAP search based on the stored credentials
diff --git a/lib/ext/Roundcube/rcube_message.php b/lib/ext/Roundcube/rcube_message.php
index 4e1b5a0..87319f0 100644
--- a/lib/ext/Roundcube/rcube_message.php
+++ b/lib/ext/Roundcube/rcube_message.php
@@ -24,7 +24,8 @@
* Logical representation of a mail message with all its data
* and related functions
*
- * @package Mail
+ * @package Framework
+ * @subpackage Storage
* @author Thomas Bruederli <roundcube at gmail.com>
*/
class rcube_message
@@ -198,27 +199,29 @@ class rcube_message
* Determine if the message contains a HTML part
*
* @param bool $recursive Enables checking in all levels of the structure
+ * @param bool $enriched Enables checking for text/enriched parts too
*
* @return bool True if a HTML is available, False if not
*/
- function has_html_part($recursive = true)
+ function has_html_part($recursive = true, $enriched = false)
{
// check all message parts
foreach ($this->parts as $part) {
- if ($part->mimetype == 'text/html') {
+ if ($part->mimetype == 'text/html' || ($enriched && $part->mimetype == 'text/enriched')) {
// Level check, we'll skip e.g. HTML attachments
if (!$recursive) {
$level = explode('.', $part->mime_id);
- // Level too high
- if (count($level) > 2) {
+ // Skip if level too deep or part has a file name
+ if (count($level) > 2 || $part->filename) {
continue;
}
// HTML part can be on the lower level, if not...
if (count($level) > 1) {
- // It can be an alternative or related message part
- $parent = $this->mime_parts[0];
+ array_pop($level);
+ $parent = $this->mime_parts[join('.', $level)];
+ // ... parent isn't multipart/alternative or related
if ($parent->mimetype != 'multipart/alternative' && $parent->mimetype != 'multipart/related') {
continue;
}
@@ -269,10 +272,6 @@ class rcube_message
else if ($part->mimetype == 'text/html') {
$out = $this->get_part_content($mime_id);
- // remove special chars encoding
- $trans = array_flip(get_html_translation_table(HTML_ENTITIES));
- $out = strtr($out, $trans);
-
// create instance of html2text class
$txt = new html2text($out);
return $txt->get_text();
@@ -482,7 +481,7 @@ class rcube_message
if ($plugin['abort'])
continue;
- if ($part_mimetype == 'text/html') {
+ if ($part_mimetype == 'text/html' && $mail_part->size) {
$got_html_part = true;
}
diff --git a/lib/ext/Roundcube/rcube_message_header.php b/lib/ext/Roundcube/rcube_message_header.php
index 378fb98..445d0bd 100644
--- a/lib/ext/Roundcube/rcube_message_header.php
+++ b/lib/ext/Roundcube/rcube_message_header.php
@@ -23,8 +23,9 @@
/**
* Struct representing an e-mail message header
*
- * @package Mail
- * @author Aleksander Machniak <alec at alec.pl>
+ * @package Framework
+ * @subpackage Storage
+ * @author Aleksander Machniak <alec at alec.pl>
*/
class rcube_message_header
{
@@ -194,6 +195,7 @@ class rcube_message_header
'content-transfer-encoding' => 'encoding',
'in-reply-to' => 'in_reply_to',
'content-type' => 'ctype',
+ 'charset' => 'charset',
'references' => 'references',
'return-receipt-to' => 'mdn_to',
'disposition-notification-to' => 'mdn_to',
diff --git a/lib/ext/Roundcube/rcube_message_part.php b/lib/ext/Roundcube/rcube_message_part.php
index 80a019e..c9c9257 100644
--- a/lib/ext/Roundcube/rcube_message_part.php
+++ b/lib/ext/Roundcube/rcube_message_part.php
@@ -25,10 +25,10 @@
/**
* Class representing a message part
*
- * @package Mail
+ * @package Framework
+ * @subpackage Storage
* @author Thomas Bruederli <roundcube at gmail.com>
* @author Aleksander Machniak <alec at alec.pl>
- * @version 2.0
*/
class rcube_message_part
{
diff --git a/lib/ext/Roundcube/rcube_mime.php b/lib/ext/Roundcube/rcube_mime.php
index d8e04a9..25ee31d 100644
--- a/lib/ext/Roundcube/rcube_mime.php
+++ b/lib/ext/Roundcube/rcube_mime.php
@@ -25,9 +25,10 @@
/**
* Class for parsing MIME messages
*
- * @package Mail
- * @author Thomas Bruederli <roundcube at gmail.com>
- * @author Aleksander Machniak <alec at alec.pl>
+ * @package Framework
+ * @subpackage Storage
+ * @author Thomas Bruederli <roundcube at gmail.com>
+ * @author Aleksander Machniak <alec at alec.pl>
*/
class rcube_mime
{
@@ -528,23 +529,24 @@ class rcube_mime
*
* @param string $text Text to wrap
* @param int $length Length
+ * @param string $charset Character encoding of $text
*
* @return string Wrapped text
*/
- public static function format_flowed($text, $length = 72)
+ public static function format_flowed($text, $length = 72, $charset=null)
{
$text = preg_split('/\r?\n/', $text);
foreach ($text as $idx => $line) {
if ($line != '-- ') {
- if ($line[0] == '>' && preg_match('/^(>+)/', $line, $regs)) {
- $prefix = $regs[0];
- $level = strlen($prefix);
- $line = rtrim(substr($line, $level));
- $line = $prefix . self::wordwrap($line, $length - $level - 2, " \r\n$prefix ");
+ if ($line[0] == '>' && preg_match('/^(>+ {0,1})+/', $line, $regs)) {
+ $level = substr_count($regs[0], '>');
+ $prefix = str_repeat('>', $level) . ' ';
+ $line = rtrim(substr($line, strlen($regs[0])));
+ $line = $prefix . self::wordwrap($line, $length - $level - 2, " \r\n$prefix", false, $charset);
}
else if ($line) {
- $line = self::wordwrap(rtrim($line), $length - 2, " \r\n");
+ $line = self::wordwrap(rtrim($line), $length - 2, " \r\n", false, $charset);
// space-stuffing
$line = preg_replace('/(^|\r\n)(From| |>)/', '\\1 \\2', $line);
}
@@ -564,12 +566,16 @@ class rcube_mime
* @param int $width Line width
* @param string $break Line separator
* @param bool $cut Enable to cut word
+ * @param string $charset Charset of $string
*
* @return string Text
*/
- public static function wordwrap($string, $width=75, $break="\n", $cut=false)
+ public static function wordwrap($string, $width=75, $break="\n", $cut=false, $charset=null)
{
- $para = explode($break, $string);
+ if ($charset && function_exists('mb_internal_encoding'))
+ mb_internal_encoding($charset);
+
+ $para = preg_split('/\r?\n/', $string);
$string = '';
while (count($para)) {
@@ -623,6 +629,9 @@ class rcube_mime
}
}
+ if ($charset && function_exists('mb_internal_encoding'))
+ mb_internal_encoding(RCMAIL_CHARSET);
+
return $string;
}
@@ -644,7 +653,7 @@ class rcube_mime
{
$mime_type = null;
$mime_magic = rcube::get_instance()->config->get('mime_magic');
- $mime_ext = @include RCMAIL_CONFIG_DIR . '/mimetypes.php';
+ $mime_ext = @include RCUBE_CONFIG_DIR . '/mimetypes.php';
// use file name suffix with hard-coded mime-type map
if (is_array($mime_ext) && $name) {
diff --git a/lib/ext/Roundcube/rcube_output.php b/lib/ext/Roundcube/rcube_output.php
deleted file mode 100644
index 5c582e6..0000000
--- a/lib/ext/Roundcube/rcube_output.php
+++ /dev/null
@@ -1,283 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcube_output.php |
- | |
- | This file is part of the Roundcube PHP suite |
- | Copyright (C) 2005-2012 The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | CONTENTS: |
- | Abstract class for output generation |
- | |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube at gmail.com> |
- | Author: Aleksander Machniak <alec at alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-/**
- * Class for output generation
- *
- * @package HTML
- */
-abstract class rcube_output
-{
- public $browser;
- public $type = 'html';
- public $ajax_call = false;
- public $framed = false;
-
- protected $app;
- protected $config;
- protected $charset = RCMAIL_CHARSET;
- protected $env = array();
- protected $pagetitle = '';
- protected $object_handlers = array();
-
-
- /**
- * Object constructor
- */
- public function __construct($task = null, $framed = false)
- {
- $this->app = rcube::get_instance();
- $this->config = $this->app->config;
- $this->browser = new rcube_browser();
- }
-
-
- /**
- * Magic getter
- */
- public function __get($var)
- {
- // allow read-only access to $env
- if ($var == 'env')
- return $this->env;
-
- return null;
- }
-
- /**
- * Setter for page title
- *
- * @param string $title Page title
- */
- public function set_pagetitle($title)
- {
- $this->pagetitle = $title;
- }
-
-
- /**
- * Setter for output charset.
- * To be specified in a meta tag and sent as http-header
- *
- * @param string $charset Charset name
- */
- public function set_charset($charset)
- {
- $this->charset = $charset;
- }
-
-
- /**
- * Getter for output charset
- *
- * @return string Output charset name
- */
- public function get_charset()
- {
- return $this->charset;
- }
-
-
- /**
- * Getter for the current skin path property
- */
- public function get_skin_path()
- {
- return $this->config->get('skin_path');
- }
-
-
- /**
- * Set environment variable
- *
- * @param string $name Property name
- * @param mixed $value Property value
- */
- public function set_env($name, $value)
- {
- $this->env[$name] = $value;
- }
-
-
- /**
- * Environment variable getter.
- *
- * @param string $name Property name
- *
- * @return mixed Property value
- */
- public function get_env($name)
- {
- return $this->env[$name];
- }
-
-
- /**
- * Delete all stored env variables and commands
- */
- public function reset()
- {
- $this->env = array();
- $this->object_handlers = array();
- $this->pagetitle = '';
- }
-
-
- /**
- * Call a client method
- *
- * @param string Method to call
- * @param ... Additional arguments
- */
- abstract function command();
-
-
- /**
- * Add a localized label to the client environment
- */
- abstract function add_label();
-
-
- /**
- * Invoke display_message command
- *
- * @param string $message Message to display
- * @param string $type Message type [notice|confirm|error]
- * @param array $vars Key-value pairs to be replaced in localized text
- * @param boolean $override Override last set message
- * @param int $timeout Message displaying time in seconds
- */
- abstract function show_message($message, $type = 'notice', $vars = null, $override = true, $timeout = 0);
-
-
- /**
- * Redirect to a certain url.
- *
- * @param mixed $p Either a string with the action or url parameters as key-value pairs
- * @param int $delay Delay in seconds
- */
- abstract function redirect($p = array(), $delay = 1);
-
-
- /**
- * Send output to the client.
- */
- abstract function send();
-
-
- /**
- * Register a template object handler
- *
- * @param string Object name
- * @param string Function name to call
- * @return void
- */
- public function add_handler($obj, $func)
- {
- $this->object_handlers[$obj] = $func;
- }
-
-
- /**
- * Register a list of template object handlers
- *
- * @param array Hash array with object=>handler pairs
- * @return void
- */
- public function add_handlers($arr)
- {
- $this->object_handlers = array_merge($this->object_handlers, $arr);
- }
-
-
- /**
- * Send HTTP headers to prevent caching a page
- */
- public function nocacheing_headers()
- {
- if (headers_sent()) {
- return;
- }
-
- header("Expires: ".gmdate("D, d M Y H:i:s")." GMT");
- header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
-
- // Request browser to disable DNS prefetching (CVE-2010-0464)
- header("X-DNS-Prefetch-Control: off");
-
- // We need to set the following headers to make downloads work using IE in HTTPS mode.
- if ($this->browser->ie && rcube_utils::https_check()) {
- header('Pragma: private');
- header("Cache-Control: private, must-revalidate");
- }
- else {
- header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0");
- header("Pragma: no-cache");
- }
- }
-
- /**
- * Send header with expire date 30 days in future
- *
- * @param int Expiration time in seconds
- */
- public function future_expire_header($offset = 2600000)
- {
- if (headers_sent())
- return;
-
- header("Expires: " . gmdate("D, d M Y H:i:s", time()+$offset) . " GMT");
- header("Cache-Control: max-age=$offset");
- header("Pragma: ");
- }
-
-
- /**
- * Show error page and terminate script execution
- *
- * @param int $code Error code
- * @param string $message Error message
- */
- public function raise_error($code, $message)
- {
- // STUB: to be overloaded by specific output classes
- fputs(STDERR, "Error $code: $message\n");
- exit(-1);
- }
-
-
- /**
- * Convert a variable into a javascript object notation
- *
- * @param mixed Input value
- *
- * @return string Serialized JSON string
- */
- public static function json_serialize($input)
- {
- $input = rcube_charset::clean($input);
-
- // sometimes even using rcube_charset::clean() the input contains invalid UTF-8 sequences
- // that's why we have @ here
- return @json_encode($input);
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_output_html.php b/lib/ext/Roundcube/rcube_output_html.php
deleted file mode 100644
index 6138e2a..0000000
--- a/lib/ext/Roundcube/rcube_output_html.php
+++ /dev/null
@@ -1,1672 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcubeoutput_html.php |
- | |
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2006-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Class to handle HTML page output using a skin template. |
- | |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube at gmail.com> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * Class to create HTML page output using a skin template
- *
- * @package View
- */
-class rcube_output_html extends rcube_output
-{
- public $type = 'html';
-
- protected $message = null;
- protected $js_env = array();
- protected $js_labels = array();
- protected $js_commands = array();
- protected $plugin_skin_path;
- protected $template_name;
- protected $scripts_path = '';
- protected $script_files = array();
- protected $css_files = array();
- protected $scripts = array();
- protected $default_template = "<html>\n<head><title></title></head>\n<body></body>\n</html>";
- protected $header = '';
- protected $footer = '';
- protected $body = '';
- protected $base_path = '';
-
- // deprecated names of templates used before 0.5
- protected $deprecated_templates = array(
- 'contact' => 'showcontact',
- 'contactadd' => 'addcontact',
- 'contactedit' => 'editcontact',
- 'identityedit' => 'editidentity',
- 'messageprint' => 'printmessage',
- );
-
- /**
- * Constructor
- *
- * @todo Replace $this->config with the real rcube_config object
- */
- public function __construct($task = null, $framed = false)
- {
- parent::__construct();
-
- //$this->framed = $framed;
- $this->set_env('task', $task);
- $this->set_env('x_frame_options', $this->config->get('x_frame_options', 'sameorigin'));
-
- // add cookie info
- $this->set_env('cookie_domain', ini_get('session.cookie_domain'));
- $this->set_env('cookie_path', ini_get('session.cookie_path'));
- $this->set_env('cookie_secure', ini_get('session.cookie_secure'));
-
- // load the correct skin (in case user-defined)
- $skin = $this->config->get('skin');
- $this->set_skin($skin);
- $this->set_env('skin', $skin);
-
- // add common javascripts
- $this->add_script('var '.rcmail::JS_OBJECT_NAME.' = new rcube_webmail();', 'head_top');
-
- // don't wait for page onload. Call init at the bottom of the page (delayed)
- $this->add_script(rcmail::JS_OBJECT_NAME.'.init();', 'docready');
-
- $this->scripts_path = 'program/js/';
- $this->include_script('jquery.min.js');
- $this->include_script('common.js');
- $this->include_script('app.js');
-
- // register common UI objects
- $this->add_handlers(array(
- 'loginform' => array($this, 'login_form'),
- 'preloader' => array($this, 'preloader'),
- 'username' => array($this, 'current_username'),
- 'message' => array($this, 'message_container'),
- 'charsetselector' => array($this, 'charset_selector'),
- 'aboutcontent' => array($this, 'about_content'),
- ));
- }
-
-
- /**
- * Set environment variable
- *
- * @param string Property name
- * @param mixed Property value
- * @param boolean True if this property should be added to client environment
- */
- public function set_env($name, $value, $addtojs = true)
- {
- $this->env[$name] = $value;
- if ($addtojs || isset($this->js_env[$name])) {
- $this->js_env[$name] = $value;
- }
- }
-
-
- /**
- * Getter for the current page title
- *
- * @return string The page title
- */
- protected function get_pagetitle()
- {
- if (!empty($this->pagetitle)) {
- $title = $this->pagetitle;
- }
- else if ($this->env['task'] == 'login') {
- $title = $this->app->gettext(array(
- 'name' => 'welcome',
- 'vars' => array('product' => $this->config->get('product_name')
- )));
- }
- else {
- $title = ucfirst($this->env['task']);
- }
-
- return $title;
- }
-
-
- /**
- * Set skin
- */
- public function set_skin($skin)
- {
- $valid = false;
-
- if (!empty($skin) && is_dir('skins/'.$skin) && is_readable('skins/'.$skin)) {
- $skin_path = 'skins/'.$skin;
- $valid = true;
- }
- else {
- $skin_path = $this->config->get('skin_path');
- if (!$skin_path) {
- $skin_path = 'skins/' . rcube_config::DEFAULT_SKIN;
- }
- $valid = !$skin;
- }
-
- $this->config->set('skin_path', $skin_path);
-
- return $valid;
- }
-
-
- /**
- * Check if a specific template exists
- *
- * @param string Template name
- * @return boolean True if template exists
- */
- public function template_exists($name)
- {
- $filename = $this->config->get('skin_path') . '/templates/' . $name . '.html';
- return (is_file($filename) && is_readable($filename)) || ($this->deprecated_templates[$name] && $this->template_exists($this->deprecated_templates[$name]));
- }
-
-
- /**
- * Register a GUI object to the client script
- *
- * @param string Object name
- * @param string Object ID
- * @return void
- */
- public function add_gui_object($obj, $id)
- {
- $this->add_script(rcmail::JS_OBJECT_NAME.".gui_object('$obj', '$id');");
- }
-
-
- /**
- * Call a client method
- *
- * @param string Method to call
- * @param ... Additional arguments
- */
- public function command()
- {
- $cmd = func_get_args();
- if (strpos($cmd[0], 'plugin.') !== false)
- $this->js_commands[] = array('triggerEvent', $cmd[0], $cmd[1]);
- else
- $this->js_commands[] = $cmd;
- }
-
-
- /**
- * Add a localized label to the client environment
- */
- public function add_label()
- {
- $args = func_get_args();
- if (count($args) == 1 && is_array($args[0]))
- $args = $args[0];
-
- foreach ($args as $name) {
- $this->js_labels[$name] = $this->app->gettext($name);
- }
- }
-
-
- /**
- * Invoke display_message command
- *
- * @param string $message Message to display
- * @param string $type Message type [notice|confirm|error]
- * @param array $vars Key-value pairs to be replaced in localized text
- * @param boolean $override Override last set message
- * @param int $timeout Message display time in seconds
- * @uses self::command()
- */
- public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
- {
- if ($override || !$this->message) {
- if ($this->app->text_exists($message)) {
- if (!empty($vars))
- $vars = array_map('Q', $vars);
- $msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
- }
- else
- $msgtext = $message;
-
- $this->message = $message;
- $this->command('display_message', $msgtext, $type, $timeout * 1000);
- }
- }
-
-
- /**
- * Delete all stored env variables and commands
- */
- public function reset()
- {
- parent::reset();
- $this->js_env = array();
- $this->js_labels = array();
- $this->js_commands = array();
- $this->script_files = array();
- $this->scripts = array();
- $this->header = '';
- $this->footer = '';
- $this->body = '';
- }
-
-
- /**
- * Redirect to a certain url
- *
- * @param mixed $p Either a string with the action or url parameters as key-value pairs
- * @param int $delay Delay in seconds
- */
- public function redirect($p = array(), $delay = 1)
- {
- $location = $this->app->url($p);
- header('Location: ' . $location);
- exit;
- }
-
-
- /**
- * Send the request output to the client.
- * This will either parse a skin tempalte or send an AJAX response
- *
- * @param string Template name
- * @param boolean True if script should terminate (default)
- */
- public function send($templ = null, $exit = true)
- {
- if ($templ != 'iframe') {
- // prevent from endless loops
- if ($exit != 'recur' && $this->app->plugins->is_processing('render_page')) {
- rcube::raise_error(array('code' => 505, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => 'Recursion alert: ignoring output->send()'), true, false);
- return;
- }
- $this->parse($templ, false);
- }
- else {
- $this->framed = $templ == 'iframe' ? true : $this->framed;
- $this->write();
- }
-
- // set output asap
- ob_flush();
- flush();
-
- if ($exit) {
- exit;
- }
- }
-
-
- /**
- * Process template and write to stdOut
- *
- * @param string $template HTML template content
- */
- public function write($template = '')
- {
- // unlock interface after iframe load
- $unlock = preg_replace('/[^a-z0-9]/i', '', $_REQUEST['_unlock']);
- if ($this->framed) {
- array_unshift($this->js_commands, array('set_busy', false, null, $unlock));
- }
- else if ($unlock) {
- array_unshift($this->js_commands, array('hide_message', $unlock));
- }
-
- if (!empty($this->script_files))
- $this->set_env('request_token', $this->app->get_request_token());
-
- // write all env variables to client
- $js = $this->framed ? "if(window.parent) {\n" : '';
- $js .= $this->get_js_commands() . ($this->framed ? ' }' : '');
- $this->add_script($js, 'head_top');
-
- // send clickjacking protection headers
- $iframe = $this->framed || !empty($_REQUEST['_framed']);
- if (!headers_sent() && ($xframe = $this->app->config->get('x_frame_options', 'sameorigin')))
- header('X-Frame-Options: ' . ($iframe && $xframe == 'deny' ? 'sameorigin' : $xframe));
-
- // call super method
- $this->_write($template, $this->config->get('skin_path'));
- }
-
-
- /**
- * Parse a specific skin template and deliver to stdout (or return)
- *
- * @param string Template name
- * @param boolean Exit script
- * @param boolean Don't write to stdout, return parsed content instead
- *
- * @link http://php.net/manual/en/function.exit.php
- */
- function parse($name = 'main', $exit = true, $write = true)
- {
- $skin_path = $this->config->get('skin_path');
- $plugin = false;
- $realname = $name;
- $temp = explode('.', $name, 2);
-
- $this->plugin_skin_path = null;
- $this->template_name = $realname;
-
- if (count($temp) > 1) {
- $plugin = $temp[0];
- $name = $temp[1];
- $skin_dir = $plugin . '/skins/' . $this->config->get('skin');
- $skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
-
- // fallback to default skin
- if (!is_dir($skin_path)) {
- $skin_dir = $plugin . '/skins/default';
- $skin_path = $this->plugin_skin_path = $this->app->plugins->dir . $skin_dir;
- }
- }
-
- $path = "$skin_path/templates/$name.html";
-
- if (!is_readable($path) && $this->deprecated_templates[$realname]) {
- $path = "$skin_path/templates/".$this->deprecated_templates[$realname].".html";
- if (is_readable($path))
- rcube::raise_error(array('code' => 502, 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Using deprecated template '".$this->deprecated_templates[$realname]
- ."' in $skin_path/templates. Please rename to '".$realname."'"),
- true, false);
- }
-
- // read template file
- if (($templ = @file_get_contents($path)) === false) {
- rcube::raise_error(array(
- 'code' => 501,
- 'type' => 'php',
- 'line' => __LINE__,
- 'file' => __FILE__,
- 'message' => 'Error loading template for '.$realname
- ), true, $write);
- return false;
- }
-
- // replace all path references to plugins/... with the configured plugins dir
- // and /this/ to the current plugin skin directory
- if ($plugin) {
- $templ = preg_replace(array('/\bplugins\//', '/(["\']?)\/this\//'), array($this->app->plugins->url, '\\1'.$this->app->plugins->url.$skin_dir.'/'), $templ);
- }
-
- // parse for specialtags
- $output = $this->parse_conditions($templ);
- $output = $this->parse_xml($output);
-
- // trigger generic hook where plugins can put additional content to the page
- $hook = $this->app->plugins->exec_hook("render_page", array('template' => $realname, 'content' => $output));
-
- // save some memory
- $output = $hook['content'];
- unset($hook['content']);
-
- $output = $this->parse_with_globals($output);
-
- // make sure all <form> tags have a valid request token
- $output = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $output);
- $this->footer = preg_replace_callback('/<form\s+([^>]+)>/Ui', array($this, 'alter_form_tag'), $this->footer);
-
- if ($write) {
- // add debug console
- if ($realname != 'error' && ($this->config->get('debug_level') & 8)) {
- $this->add_footer('<div id="console" style="position:absolute;top:5px;left:5px;width:405px;padding:2px;background:white;z-index:9000;display:none">
- <a href="#toggle" onclick="con=$(\'#dbgconsole\');con[con.is(\':visible\')?\'hide\':\'show\']();return false">console</a>
- <textarea name="console" id="dbgconsole" rows="20" cols="40" style="display:none;width:400px;border:none;font-size:10px" spellcheck="false"></textarea></div>'
- );
- $this->add_script(
- "if (!window.console || !window.console.log) {\n".
- " window.console = new rcube_console();\n".
- " $('#console').show();\n".
- "}", 'foot');
- }
- $this->write(trim($output));
- }
- else {
- return $output;
- }
-
- if ($exit) {
- exit;
- }
- }
-
-
- /**
- * Return executable javascript code for all registered commands
- *
- * @return string $out
- */
- protected function get_js_commands()
- {
- $out = '';
- if (!$this->framed && !empty($this->js_env)) {
- $out .= rcmail::JS_OBJECT_NAME . '.set_env('.self::json_serialize($this->js_env).");\n";
- }
- if (!empty($this->js_labels)) {
- $this->command('add_label', $this->js_labels);
- }
- foreach ($this->js_commands as $i => $args) {
- $method = array_shift($args);
- foreach ($args as $i => $arg) {
- $args[$i] = self::json_serialize($arg);
- }
- $parent = $this->framed || preg_match('/^parent\./', $method);
- $out .= sprintf(
- "%s.%s(%s);\n",
- ($parent ? 'if(window.parent && parent.'.rcmail::JS_OBJECT_NAME.') parent.' : '') . rcmail::JS_OBJECT_NAME,
- preg_replace('/^parent\./', '', $method),
- implode(',', $args)
- );
- }
-
- return $out;
- }
-
-
- /**
- * Make URLs starting with a slash point to skin directory
- *
- * @param string Input string
- * @return string
- */
- public function abs_url($str)
- {
- if ($str[0] == '/')
- return $this->config->get('skin_path') . $str;
- else
- return $str;
- }
-
-
- /**
- * Show error page and terminate script execution
- *
- * @param int $code Error code
- * @param string $message Error message
- */
- public function raise_error($code, $message)
- {
- global $__page_content, $ERROR_CODE, $ERROR_MESSAGE;
-
- $ERROR_CODE = $code;
- $ERROR_MESSAGE = $message;
-
- include INSTALL_PATH . 'program/steps/utils/error.inc';
- exit;
- }
-
-
- /***** Template parsing methods *****/
-
- /**
- * Replace all strings ($varname)
- * with the content of the according global variable.
- */
- protected function parse_with_globals($input)
- {
- $GLOBALS['__version'] = html::quote(RCMAIL_VERSION);
- $GLOBALS['__comm_path'] = html::quote($this->app->comm_path);
- $GLOBALS['__skin_path'] = html::quote($this->config->get('skin_path'));
-
- return preg_replace_callback('/\$(__[a-z0-9_\-]+)/',
- array($this, 'globals_callback'), $input);
- }
-
-
- /**
- * Callback funtion for preg_replace_callback() in parse_with_globals()
- */
- protected function globals_callback($matches)
- {
- return $GLOBALS[$matches[1]];
- }
-
-
- /**
- * Public wrapper to dipp into template parsing.
- *
- * @param string $input
- * @return string
- * @uses rcube_output_html::parse_xml()
- * @since 0.1-rc1
- */
- public function just_parse($input)
- {
- return $this->parse_xml($input);
- }
-
-
- /**
- * Parse for conditional tags
- *
- * @param string $input
- * @return string
- */
- protected function parse_conditions($input)
- {
- $matches = preg_split('/<roundcube:(if|elseif|else|endif)\s+([^>]+)>\n?/is', $input, 2, PREG_SPLIT_DELIM_CAPTURE);
- if ($matches && count($matches) == 4) {
- if (preg_match('/^(else|endif)$/i', $matches[1])) {
- return $matches[0] . $this->parse_conditions($matches[3]);
- }
- $attrib = html::parse_attrib_string($matches[2]);
- if (isset($attrib['condition'])) {
- $condmet = $this->check_condition($attrib['condition']);
- $submatches = preg_split('/<roundcube:(elseif|else|endif)\s+([^>]+)>\n?/is', $matches[3], 2, PREG_SPLIT_DELIM_CAPTURE);
- if ($condmet) {
- $result = $submatches[0];
- $result.= ($submatches[1] != 'endif' ? preg_replace('/.*<roundcube:endif\s+[^>]+>\n?/Uis', '', $submatches[3], 1) : $submatches[3]);
- }
- else {
- $result = "<roundcube:$submatches[1] $submatches[2]>" . $submatches[3];
- }
- return $matches[0] . $this->parse_conditions($result);
- }
- rcube::raise_error(array(
- 'code' => 500,
- 'type' => 'php',
- 'line' => __LINE__,
- 'file' => __FILE__,
- 'message' => "Unable to parse conditional tag " . $matches[2]
- ), true, false);
- }
- return $input;
- }
-
-
- /**
- * Determines if a given condition is met
- *
- * @todo Get rid off eval() once I understand what this does.
- * @todo Extend this to allow real conditions, not just "set"
- * @param string Condition statement
- * @return boolean True if condition is met, False if not
- */
- protected function check_condition($condition)
- {
- return eval("return (".$this->parse_expression($condition).");");
- }
-
-
- /**
- * Inserts hidden field with CSRF-prevention-token into POST forms
- */
- protected function alter_form_tag($matches)
- {
- $out = $matches[0];
- $attrib = html::parse_attrib_string($matches[1]);
-
- if (strtolower($attrib['method']) == 'post') {
- $hidden = new html_hiddenfield(array('name' => '_token', 'value' => $this->app->get_request_token()));
- $out .= "\n" . $hidden->show();
- }
-
- return $out;
- }
-
-
- /**
- * Parses expression and replaces variables
- *
- * @param string Expression statement
- * @return string Expression value
- */
- protected function parse_expression($expression)
- {
- return preg_replace(
- array(
- '/session:([a-z0-9_]+)/i',
- '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i',
- '/env:([a-z0-9_]+)/i',
- '/request:([a-z0-9_]+)/i',
- '/cookie:([a-z0-9_]+)/i',
- '/browser:([a-z0-9_]+)/i',
- '/template:name/i',
- ),
- array(
- "\$_SESSION['\\1']",
- "\$this->app->config->get('\\1',get_boolean('\\3'))",
- "\$this->env['\\1']",
- "rcube_utils::get_input_value('\\1', rcube_utils::INPUT_GPC)",
- "\$_COOKIE['\\1']",
- "\$this->browser->{'\\1'}",
- $this->template_name,
- ),
- $expression);
- }
-
-
- /**
- * Search for special tags in input and replace them
- * with the appropriate content
- *
- * @param string Input string to parse
- * @return string Altered input string
- * @todo Use DOM-parser to traverse template HTML
- * @todo Maybe a cache.
- */
- protected function parse_xml($input)
- {
- return preg_replace_callback('/<roundcube:([-_a-z]+)\s+((?:[^>]|\\\\>)+)(?<!\\\\)>/Ui', array($this, 'xml_command'), $input);
- }
-
-
- /**
- * Callback function for parsing an xml command tag
- * and turn it into real html content
- *
- * @param array Matches array of preg_replace_callback
- * @return string Tag/Object content
- */
- protected function xml_command($matches)
- {
- $command = strtolower($matches[1]);
- $attrib = html::parse_attrib_string($matches[2]);
-
- // empty output if required condition is not met
- if (!empty($attrib['condition']) && !$this->check_condition($attrib['condition'])) {
- return '';
- }
-
- // execute command
- switch ($command) {
- // return a button
- case 'button':
- if ($attrib['name'] || $attrib['command']) {
- return $this->button($attrib);
- }
- break;
-
- // frame
- case 'frame':
- return $this->frame($attrib);
- break;
-
- // show a label
- case 'label':
- if ($attrib['name'] || $attrib['command']) {
- // @FIXME: 'noshow' is useless, remove?
- if ($attrib['noshow']) {
- return '';
- }
-
- $vars = $attrib + array('product' => $this->config->get('product_name'));
- unset($vars['name'], $vars['command']);
-
- $label = $this->app->gettext($attrib + array('vars' => $vars));
- $quoting = !empty($attrib['quoting']) ? strtolower($attrib['quoting']) : (get_boolean((string)$attrib['html']) ? 'no' : '');
-
- switch ($quoting) {
- case 'no':
- case 'raw':
- break;
- case 'javascript':
- case 'js':
- $label = rcmail::JQ($label);
- break;
- default:
- $label = html::quote($label);
- break;
- }
-
- return $label;
- }
- break;
-
- // include a file
- case 'include':
- if (!$this->plugin_skin_path || !is_file($path = realpath($this->plugin_skin_path . $attrib['file'])))
- $path = realpath(($attrib['skin_path'] ? $attrib['skin_path'] : $this->config->get('skin_path')).$attrib['file']);
-
- if (is_readable($path)) {
- if ($this->config->get('skin_include_php')) {
- $incl = $this->include_php($path);
- }
- else {
- $incl = file_get_contents($path);
- }
- $incl = $this->parse_conditions($incl);
- return $this->parse_xml($incl);
- }
- break;
-
- case 'plugin.include':
- $hook = $this->app->plugins->exec_hook("template_plugin_include", $attrib);
- return $hook['content'];
- break;
-
- // define a container block
- case 'container':
- if ($attrib['name'] && $attrib['id']) {
- $this->command('gui_container', $attrib['name'], $attrib['id']);
- // let plugins insert some content here
- $hook = $this->app->plugins->exec_hook("template_container", $attrib);
- return $hook['content'];
- }
- break;
-
- // return code for a specific application object
- case 'object':
- $object = strtolower($attrib['name']);
- $content = '';
-
- // we are calling a class/method
- if (($handler = $this->object_handlers[$object]) && is_array($handler)) {
- if ((is_object($handler[0]) && method_exists($handler[0], $handler[1])) ||
- (is_string($handler[0]) && class_exists($handler[0])))
- $content = call_user_func($handler, $attrib);
- }
- // execute object handler function
- else if (function_exists($handler)) {
- $content = call_user_func($handler, $attrib);
- }
- else if ($object == 'doctype') {
- $content = html::doctype($attrib['value']);
- }
- else if ($object == 'logo') {
- $attrib += array('alt' => $this->xml_command(array('', 'object', 'name="productname"')));
- if ($logo = $this->config->get('skin_logo'))
- $attrib['src'] = $logo;
- $content = html::img($attrib);
- }
- else if ($object == 'productname') {
- $name = $this->config->get('product_name', 'Roundcube Webmail');
- $content = html::quote($name);
- }
- else if ($object == 'version') {
- $ver = (string)RCMAIL_VERSION;
- if (is_file(INSTALL_PATH . '.svn/entries')) {
- if (preg_match('/Revision:\s(\d+)/', @shell_exec('svn info'), $regs))
- $ver .= ' [SVN r'.$regs[1].']';
- }
- else if (is_file(INSTALL_PATH . '.git/index')) {
- if (preg_match('/Date:\s+([^\n]+)/', @shell_exec('git log -1'), $regs)) {
- if ($date = date('Ymd.Hi', strtotime($regs[1]))) {
- $ver .= ' [GIT '.$date.']';
- }
- }
- }
- $content = html::quote($ver);
- }
- else if ($object == 'steptitle') {
- $content = html::quote($this->get_pagetitle());
- }
- else if ($object == 'pagetitle') {
- if ($this->config->get('devel_mode') && !empty($_SESSION['username']))
- $title = $_SESSION['username'].' :: ';
- else if ($prod_name = $this->config->get('product_name'))
- $title = $prod_name . ' :: ';
- else
- $title = '';
- $title .= $this->get_pagetitle();
- $content = html::quote($title);
- }
-
- // exec plugin hooks for this template object
- $hook = $this->app->plugins->exec_hook("template_object_$object", $attrib + array('content' => $content));
- return $hook['content'];
-
- // return code for a specified eval expression
- case 'exp':
- $value = $this->parse_expression($attrib['expression']);
- return eval("return html::quote($value);");
-
- // return variable
- case 'var':
- $var = explode(':', $attrib['name']);
- $name = $var[1];
- $value = '';
-
- switch ($var[0]) {
- case 'env':
- $value = $this->env[$name];
- break;
- case 'config':
- $value = $this->config->get($name);
- if (is_array($value) && $value[$_SESSION['storage_host']]) {
- $value = $value[$_SESSION['storage_host']];
- }
- break;
- case 'request':
- $value = rcube_utils::get_input_value($name, rcube_utils::INPUT_GPC);
- break;
- case 'session':
- $value = $_SESSION[$name];
- break;
- case 'cookie':
- $value = htmlspecialchars($_COOKIE[$name]);
- break;
- case 'browser':
- $value = $this->browser->{$name};
- break;
- }
-
- if (is_array($value)) {
- $value = implode(', ', $value);
- }
-
- return html::quote($value);
- break;
- }
- return '';
- }
-
-
- /**
- * Include a specific file and return it's contents
- *
- * @param string File path
- * @return string Contents of the processed file
- */
- protected function include_php($file)
- {
- ob_start();
- include $file;
- $out = ob_get_contents();
- ob_end_clean();
-
- return $out;
- }
-
-
- /**
- * Create and register a button
- *
- * @param array Named button attributes
- * @return string HTML button
- * @todo Remove all inline JS calls and use jQuery instead.
- * @todo Remove all sprintf()'s - they are pretty, but also slow.
- */
- public function button($attrib)
- {
- static $s_button_count = 100;
-
- // these commands can be called directly via url
- $a_static_commands = array('compose', 'list', 'preferences', 'folders', 'identities');
-
- if (!($attrib['command'] || $attrib['name'])) {
- return '';
- }
-
- // try to find out the button type
- if ($attrib['type']) {
- $attrib['type'] = strtolower($attrib['type']);
- }
- else {
- $attrib['type'] = ($attrib['image'] || $attrib['imagepas'] || $attrib['imageact']) ? 'image' : 'link';
- }
-
- $command = $attrib['command'];
-
- if ($attrib['task'])
- $command = $attrib['task'] . '.' . $command;
-
- if (!$attrib['image']) {
- $attrib['image'] = $attrib['imagepas'] ? $attrib['imagepas'] : $attrib['imageact'];
- }
-
- if (!$attrib['id']) {
- $attrib['id'] = sprintf('rcmbtn%d', $s_button_count++);
- }
- // get localized text for labels and titles
- if ($attrib['title']) {
- $attrib['title'] = html::quote($this->app->gettext($attrib['title'], $attrib['domain']));
- }
- if ($attrib['label']) {
- $attrib['label'] = html::quote($this->app->gettext($attrib['label'], $attrib['domain']));
- }
- if ($attrib['alt']) {
- $attrib['alt'] = html::quote($this->app->gettext($attrib['alt'], $attrib['domain']));
- }
-
- // set title to alt attribute for IE browsers
- if ($this->browser->ie && !$attrib['title'] && $attrib['alt']) {
- $attrib['title'] = $attrib['alt'];
- }
-
- // add empty alt attribute for XHTML compatibility
- if (!isset($attrib['alt'])) {
- $attrib['alt'] = '';
- }
-
- // register button in the system
- if ($attrib['command']) {
- $this->add_script(sprintf(
- "%s.register_button('%s', '%s', '%s', '%s', '%s', '%s');",
- rcmail::JS_OBJECT_NAME,
- $command,
- $attrib['id'],
- $attrib['type'],
- $attrib['imageact'] ? $this->abs_url($attrib['imageact']) : $attrib['classact'],
- $attrib['imagesel'] ? $this->abs_url($attrib['imagesel']) : $attrib['classsel'],
- $attrib['imageover'] ? $this->abs_url($attrib['imageover']) : ''
- ));
-
- // make valid href to specific buttons
- if (in_array($attrib['command'], rcmail::$main_tasks)) {
- $attrib['href'] = $this->app->url(array('task' => $attrib['command']));
- $attrib['onclick'] = sprintf("%s.command('switch-task','%s',null,event); return false", rcmail::JS_OBJECT_NAME, $attrib['command']);
- }
- else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) {
- $attrib['href'] = $this->app->url(array('action' => $attrib['command'], 'task' => $attrib['task']));
- }
- else if (in_array($attrib['command'], $a_static_commands)) {
- $attrib['href'] = $this->app->url(array('action' => $attrib['command']));
- }
- else if ($attrib['command'] == 'permaurl' && !empty($this->env['permaurl'])) {
- $attrib['href'] = $this->env['permaurl'];
- }
- }
-
- // overwrite attributes
- if (!$attrib['href']) {
- $attrib['href'] = '#';
- }
- if ($attrib['task']) {
- if ($attrib['classact'])
- $attrib['class'] = $attrib['classact'];
- }
- else if ($command && !$attrib['onclick']) {
- $attrib['onclick'] = sprintf(
- "return %s.command('%s','%s',this,event)",
- rcmail::JS_OBJECT_NAME,
- $command,
- $attrib['prop']
- );
- }
-
- $out = '';
-
- // generate image tag
- if ($attrib['type'] == 'image') {
- $attrib_str = html::attrib_string(
- $attrib,
- array(
- 'style', 'class', 'id', 'width', 'height', 'border', 'hspace',
- 'vspace', 'align', 'alt', 'tabindex', 'title'
- )
- );
- $btn_content = sprintf('<img src="%s"%s />', $this->abs_url($attrib['image']), $attrib_str);
- if ($attrib['label']) {
- $btn_content .= ' '.$attrib['label'];
- }
- $link_attrib = array('href', 'onclick', 'onmouseover', 'onmouseout', 'onmousedown', 'onmouseup', 'target');
- }
- else if ($attrib['type'] == 'link') {
- $btn_content = isset($attrib['content']) ? $attrib['content'] : ($attrib['label'] ? $attrib['label'] : $attrib['command']);
- $link_attrib = array('href', 'onclick', 'title', 'id', 'class', 'style', 'tabindex', 'target');
- if ($attrib['innerclass'])
- $btn_content = html::span($attrib['innerclass'], $btn_content);
- }
- else if ($attrib['type'] == 'input') {
- $attrib['type'] = 'button';
-
- if ($attrib['label']) {
- $attrib['value'] = $attrib['label'];
- }
- if ($attrib['command']) {
- $attrib['disabled'] = 'disabled';
- }
-
- $out = html::tag('input', $attrib, null, array('type', 'value', 'onclick', 'id', 'class', 'style', 'tabindex', 'disabled'));
- }
-
- // generate html code for button
- if ($btn_content) {
- $attrib_str = html::attrib_string($attrib, $link_attrib);
- $out = sprintf('<a%s>%s</a>', $attrib_str, $btn_content);
- }
-
- return $out;
- }
-
-
- /**
- * Link an external script file
- *
- * @param string File URL
- * @param string Target position [head|foot]
- */
- public function include_script($file, $position='head')
- {
- static $sa_files = array();
-
- if (!preg_match('|^https?://|i', $file) && $file[0] != '/') {
- $file = $this->scripts_path . $file;
- if ($fs = @filemtime($file)) {
- $file .= '?s=' . $fs;
- }
- }
-
- if (in_array($file, $sa_files)) {
- return;
- }
-
- $sa_files[] = $file;
-
- if (!is_array($this->script_files[$position])) {
- $this->script_files[$position] = array();
- }
-
- $this->script_files[$position][] = $file;
- }
-
-
- /**
- * Add inline javascript code
- *
- * @param string JS code snippet
- * @param string Target position [head|head_top|foot]
- */
- public function add_script($script, $position='head')
- {
- if (!isset($this->scripts[$position])) {
- $this->scripts[$position] = "\n" . rtrim($script);
- }
- else {
- $this->scripts[$position] .= "\n" . rtrim($script);
- }
- }
-
-
- /**
- * Link an external css file
- *
- * @param string File URL
- */
- public function include_css($file)
- {
- $this->css_files[] = $file;
- }
-
-
- /**
- * Add HTML code to the page header
- *
- * @param string $str HTML code
- */
- public function add_header($str)
- {
- $this->header .= "\n" . $str;
- }
-
-
- /**
- * Add HTML code to the page footer
- * To be added right befor </body>
- *
- * @param string $str HTML code
- */
- public function add_footer($str)
- {
- $this->footer .= "\n" . $str;
- }
-
-
- /**
- * Process template and write to stdOut
- *
- * @param string HTML template
- * @param string Base for absolute paths
- */
- public function _write($templ = '', $base_path = '')
- {
- $output = empty($templ) ? $this->default_template : trim($templ);
-
- // set default page title
- if (empty($this->pagetitle)) {
- $this->pagetitle = 'Roundcube Mail';
- }
-
- // replace specialchars in content
- $page_title = html::quote($this->pagetitle);
- $page_header = '';
- $page_footer = '';
-
- // include meta tag with charset
- if (!empty($this->charset)) {
- if (!headers_sent()) {
- header('Content-Type: text/html; charset=' . $this->charset);
- }
- $page_header = '<meta http-equiv="content-type"';
- $page_header.= ' content="text/html; charset=';
- $page_header.= $this->charset . '" />'."\n";
- }
-
- // definition of the code to be placed in the document header and footer
- if (is_array($this->script_files['head'])) {
- foreach ($this->script_files['head'] as $file) {
- $page_header .= html::script($file);
- }
- }
-
- $head_script = $this->scripts['head_top'] . $this->scripts['head'];
- if (!empty($head_script)) {
- $page_header .= html::script(array(), $head_script);
- }
-
- if (!empty($this->header)) {
- $page_header .= $this->header;
- }
-
- // put docready commands into page footer
- if (!empty($this->scripts['docready'])) {
- $this->add_script('$(document).ready(function(){ ' . $this->scripts['docready'] . "\n});", 'foot');
- }
-
- if (is_array($this->script_files['foot'])) {
- foreach ($this->script_files['foot'] as $file) {
- $page_footer .= html::script($file);
- }
- }
-
- if (!empty($this->footer)) {
- $page_footer .= $this->footer . "\n";
- }
-
- if (!empty($this->scripts['foot'])) {
- $page_footer .= html::script(array(), $this->scripts['foot']);
- }
-
- // find page header
- if ($hpos = stripos($output, '</head>')) {
- $page_header .= "\n";
- }
- else {
- if (!is_numeric($hpos)) {
- $hpos = stripos($output, '<body');
- }
- if (!is_numeric($hpos) && ($hpos = stripos($output, '<html'))) {
- while ($output[$hpos] != '>') {
- $hpos++;
- }
- $hpos++;
- }
- $page_header = "<head>\n<title>$page_title</title>\n$page_header\n</head>\n";
- }
-
- // add page hader
- if ($hpos) {
- $output = substr_replace($output, $page_header, $hpos, 0);
- }
- else {
- $output = $page_header . $output;
- }
-
- // add page footer
- if (($fpos = strripos($output, '</body>')) || ($fpos = strripos($output, '</html>'))) {
- $output = substr_replace($output, $page_footer."\n", $fpos, 0);
- }
- else {
- $output .= "\n".$page_footer;
- }
-
- // add css files in head, before scripts, for speed up with parallel downloads
- if (!empty($this->css_files) &&
- (($pos = stripos($output, '<script ')) || ($pos = stripos($output, '</head>')))
- ) {
- $css = '';
- foreach ($this->css_files as $file) {
- $css .= html::tag('link', array('rel' => 'stylesheet',
- 'type' => 'text/css', 'href' => $file, 'nl' => true));
- }
- $output = substr_replace($output, $css, $pos, 0);
- }
-
- $this->base_path = $base_path;
-
- // correct absolute paths in images and other tags
- // add timestamp to .js and .css filename
- $output = preg_replace_callback(
- '!(src|href|background)=(["\']?)([a-z0-9/_.-]+)(["\'\s>])!i',
- array($this, 'file_callback'), $output);
-
- // trigger hook with final HTML content to be sent
- $hook = $this->app->plugins->exec_hook("send_page", array('content' => $output));
- if (!$hook['abort']) {
- if ($this->charset != RCMAIL_CHARSET) {
- echo rcube_charset::convert($hook['content'], RCMAIL_CHARSET, $this->charset);
- }
- else {
- echo $hook['content'];
- }
- }
- }
-
-
- /**
- * Callback function for preg_replace_callback in write()
- *
- * @return string Parsed string
- */
- protected function file_callback($matches)
- {
- $file = $matches[3];
-
- // correct absolute paths
- if ($file[0] == '/') {
- $file = $this->base_path . $file;
- }
-
- // add file modification timestamp
- if (preg_match('/\.(js|css)$/', $file)) {
- if ($fs = @filemtime($file)) {
- $file .= '?s=' . $fs;
- }
- }
-
- return $matches[1] . '=' . $matches[2] . $file . $matches[4];
- }
-
-
- /**
- * Returns iframe object, registers some related env variables
- *
- * @param array $attrib HTML attributes
- *
- * @return string IFRAME element
- */
- public function frame($attrib)
- {
- if (!$attrib['id']) {
- $attrib['id'] = 'rcmframe';
- }
-
- if (!$attrib['name']) {
- $attrib['name'] = $attrib['id'];
- }
-
- $this->set_env('contentframe', $attrib['id']);
- $this->set_env('blankpage', $attrib['src'] ? $this->abs_url($attrib['src']) : 'program/resources/blank.gif');
-
- return html::iframe($attrib);
- }
-
-
- /* ************* common functions delivering gui objects ************** */
-
-
- /**
- * Create a form tag with the necessary hidden fields
- *
- * @param array Named tag parameters
- * @return string HTML code for the form
- */
- public function form_tag($attrib, $content = null)
- {
- if ($this->framed || !empty($_REQUEST['_framed'])) {
- $hiddenfield = new html_hiddenfield(array('name' => '_framed', 'value' => '1'));
- $hidden = $hiddenfield->show();
- }
-
- if (!$content)
- $attrib['noclose'] = true;
-
- return html::tag('form',
- $attrib + array('action' => "./", 'method' => "get"),
- $hidden . $content,
- array('id','class','style','name','method','action','enctype','onsubmit'));
- }
-
-
- /**
- * Build a form tag with a unique request token
- *
- * @param array Named tag parameters including 'action' and 'task' values which will be put into hidden fields
- * @param string Form content
- * @return string HTML code for the form
- */
- public function request_form($attrib, $content = '')
- {
- $hidden = new html_hiddenfield();
- if ($attrib['task']) {
- $hidden->add(array('name' => '_task', 'value' => $attrib['task']));
- }
- if ($attrib['action']) {
- $hidden->add(array('name' => '_action', 'value' => $attrib['action']));
- }
-
- unset($attrib['task'], $attrib['request']);
- $attrib['action'] = './';
-
- // we already have a <form> tag
- if ($attrib['form']) {
- if ($this->framed || !empty($_REQUEST['_framed']))
- $hidden->add(array('name' => '_framed', 'value' => '1'));
- return $hidden->show() . $content;
- }
- else
- return $this->form_tag($attrib, $hidden->show() . $content);
- }
-
-
- /**
- * GUI object 'username'
- * Showing IMAP username of the current session
- *
- * @param array Named tag parameters (currently not used)
- * @return string HTML code for the gui object
- */
- public function current_username($attrib)
- {
- static $username;
-
- // alread fetched
- if (!empty($username)) {
- return $username;
- }
-
- // Current username is an e-mail address
- if (strpos($_SESSION['username'], '@')) {
- $username = $_SESSION['username'];
- }
- // get e-mail address from default identity
- else if ($sql_arr = $this->app->user->get_identity()) {
- $username = $sql_arr['email'];
- }
- else {
- $username = $this->app->user->get_username();
- }
-
- return rcube_utils::idn_to_utf8($username);
- }
-
-
- /**
- * GUI object 'loginform'
- * Returns code for the webmail login form
- *
- * @param array Named parameters
- * @return string HTML code for the gui object
- */
- protected function login_form($attrib)
- {
- $default_host = $this->config->get('default_host');
- $autocomplete = (int) $this->config->get('login_autocomplete');
-
- $_SESSION['temp'] = true;
-
- // save original url
- $url = rcube_utils::get_input_value('_url', rcube_utils::INPUT_POST);
- if (empty($url) && !preg_match('/_(task|action)=logout/', $_SERVER['QUERY_STRING']))
- $url = $_SERVER['QUERY_STRING'];
-
- // Disable autocapitalization on iPad/iPhone (#1488609)
- $attrib['autocapitalize'] = 'off';
-
- // set atocomplete attribute
- $user_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
- $host_attrib = $autocomplete > 0 ? array() : array('autocomplete' => 'off');
- $pass_attrib = $autocomplete > 1 ? array() : array('autocomplete' => 'off');
-
- $input_task = new html_hiddenfield(array('name' => '_task', 'value' => 'login'));
- $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login'));
- $input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_'));
- $input_dst = new html_hiddenfield(array('name' => '_dstactive', 'id' => 'rcmlogindst', 'value' => '_default_'));
- $input_url = new html_hiddenfield(array('name' => '_url', 'id' => 'rcmloginurl', 'value' => $url));
- $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser')
- + $attrib + $user_attrib);
- $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd')
- + $attrib + $pass_attrib);
- $input_host = null;
-
- if (is_array($default_host) && count($default_host) > 1) {
- $input_host = new html_select(array('name' => '_host', 'id' => 'rcmloginhost'));
-
- foreach ($default_host as $key => $value) {
- if (!is_array($value)) {
- $input_host->add($value, (is_numeric($key) ? $value : $key));
- }
- else {
- $input_host = null;
- break;
- }
- }
- }
- else if (is_array($default_host) && ($host = array_pop($default_host))) {
- $hide_host = true;
- $input_host = new html_hiddenfield(array(
- 'name' => '_host', 'id' => 'rcmloginhost', 'value' => $host) + $attrib);
- }
- else if (empty($default_host)) {
- $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost')
- + $attrib + $host_attrib);
- }
-
- $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form';
- $this->add_gui_object('loginform', $form_name);
-
- // create HTML table with two cols
- $table = new html_table(array('cols' => 2));
-
- $table->add('title', html::label('rcmloginuser', html::quote($this->app->gettext('username'))));
- $table->add('input', $input_user->show(rcube_utils::get_input_value('_user', rcube_utils::INPUT_GPC)));
-
- $table->add('title', html::label('rcmloginpwd', html::quote($this->app->gettext('password'))));
- $table->add('input', $input_pass->show());
-
- // add host selection row
- if (is_object($input_host) && !$hide_host) {
- $table->add('title', html::label('rcmloginhost', html::quote($this->app->gettext('server'))));
- $table->add('input', $input_host->show(rcube_utils::get_input_value('_host', rcube_utils::INPUT_GPC)));
- }
-
- $out = $input_task->show();
- $out .= $input_action->show();
- $out .= $input_tzone->show();
- $out .= $input_dst->show();
- $out .= $input_url->show();
- $out .= $table->show();
-
- if ($hide_host) {
- $out .= $input_host->show();
- }
-
- // surround html output with a form tag
- if (empty($attrib['form'])) {
- $out = $this->form_tag(array('name' => $form_name, 'method' => 'post'), $out);
- }
-
- return $out;
- }
-
-
- /**
- * GUI object 'preloader'
- * Loads javascript code for images preloading
- *
- * @param array Named parameters
- * @return void
- */
- protected function preloader($attrib)
- {
- $images = preg_split('/[\s\t\n,]+/', $attrib['images'], -1, PREG_SPLIT_NO_EMPTY);
- $images = array_map(array($this, 'abs_url'), $images);
-
- if (empty($images) || $this->app->task == 'logout')
- return;
-
- $this->add_script('var images = ' . self::json_serialize($images) .';
- for (var i=0; i<images.length; i++) {
- img = new Image();
- img.src = images[i];
- }', 'docready');
- }
-
-
- /**
- * GUI object 'searchform'
- * Returns code for search function
- *
- * @param array Named parameters
- * @return string HTML code for the gui object
- */
- protected function search_form($attrib)
- {
- // add some labels to client
- $this->add_label('searching');
-
- $attrib['name'] = '_q';
-
- if (empty($attrib['id'])) {
- $attrib['id'] = 'rcmqsearchbox';
- }
- if ($attrib['type'] == 'search' && !$this->browser->khtml) {
- unset($attrib['type'], $attrib['results']);
- }
-
- $input_q = new html_inputfield($attrib);
- $out = $input_q->show();
-
- $this->add_gui_object('qsearchbox', $attrib['id']);
-
- // add form tag around text field
- if (empty($attrib['form'])) {
- $out = $this->form_tag(array(
- 'name' => "rcmqsearchform",
- 'onsubmit' => rcmail::JS_OBJECT_NAME . ".command('search'); return false",
- 'style' => "display:inline"),
- $out);
- }
-
- return $out;
- }
-
-
- /**
- * Builder for GUI object 'message'
- *
- * @param array Named tag parameters
- * @return string HTML code for the gui object
- */
- protected function message_container($attrib)
- {
- if (isset($attrib['id']) === false) {
- $attrib['id'] = 'rcmMessageContainer';
- }
-
- $this->add_gui_object('message', $attrib['id']);
-
- return html::div($attrib, '');
- }
-
-
- /**
- * GUI object 'charsetselector'
- *
- * @param array Named parameters for the select tag
- * @return string HTML code for the gui object
- */
- public function charset_selector($attrib)
- {
- // pass the following attributes to the form class
- $field_attrib = array('name' => '_charset');
- foreach ($attrib as $attr => $value) {
- if (in_array($attr, array('id', 'name', 'class', 'style', 'size', 'tabindex'))) {
- $field_attrib[$attr] = $value;
- }
- }
-
- $charsets = array(
- 'UTF-8' => 'UTF-8 ('.$this->app->gettext('unicode').')',
- 'US-ASCII' => 'ASCII ('.$this->app->gettext('english').')',
- 'ISO-8859-1' => 'ISO-8859-1 ('.$this->app->gettext('westerneuropean').')',
- 'ISO-8859-2' => 'ISO-8859-2 ('.$this->app->gettext('easterneuropean').')',
- 'ISO-8859-4' => 'ISO-8859-4 ('.$this->app->gettext('baltic').')',
- 'ISO-8859-5' => 'ISO-8859-5 ('.$this->app->gettext('cyrillic').')',
- 'ISO-8859-6' => 'ISO-8859-6 ('.$this->app->gettext('arabic').')',
- 'ISO-8859-7' => 'ISO-8859-7 ('.$this->app->gettext('greek').')',
- 'ISO-8859-8' => 'ISO-8859-8 ('.$this->app->gettext('hebrew').')',
- 'ISO-8859-9' => 'ISO-8859-9 ('.$this->app->gettext('turkish').')',
- 'ISO-8859-10' => 'ISO-8859-10 ('.$this->app->gettext('nordic').')',
- 'ISO-8859-11' => 'ISO-8859-11 ('.$this->app->gettext('thai').')',
- 'ISO-8859-13' => 'ISO-8859-13 ('.$this->app->gettext('baltic').')',
- 'ISO-8859-14' => 'ISO-8859-14 ('.$this->app->gettext('celtic').')',
- 'ISO-8859-15' => 'ISO-8859-15 ('.$this->app->gettext('westerneuropean').')',
- 'ISO-8859-16' => 'ISO-8859-16 ('.$this->app->gettext('southeasterneuropean').')',
- 'WINDOWS-1250' => 'Windows-1250 ('.$this->app->gettext('easterneuropean').')',
- 'WINDOWS-1251' => 'Windows-1251 ('.$this->app->gettext('cyrillic').')',
- 'WINDOWS-1252' => 'Windows-1252 ('.$this->app->gettext('westerneuropean').')',
- 'WINDOWS-1253' => 'Windows-1253 ('.$this->app->gettext('greek').')',
- 'WINDOWS-1254' => 'Windows-1254 ('.$this->app->gettext('turkish').')',
- 'WINDOWS-1255' => 'Windows-1255 ('.$this->app->gettext('hebrew').')',
- 'WINDOWS-1256' => 'Windows-1256 ('.$this->app->gettext('arabic').')',
- 'WINDOWS-1257' => 'Windows-1257 ('.$this->app->gettext('baltic').')',
- 'WINDOWS-1258' => 'Windows-1258 ('.$this->app->gettext('vietnamese').')',
- 'ISO-2022-JP' => 'ISO-2022-JP ('.$this->app->gettext('japanese').')',
- 'ISO-2022-KR' => 'ISO-2022-KR ('.$this->app->gettext('korean').')',
- 'ISO-2022-CN' => 'ISO-2022-CN ('.$this->app->gettext('chinese').')',
- 'EUC-JP' => 'EUC-JP ('.$this->app->gettext('japanese').')',
- 'EUC-KR' => 'EUC-KR ('.$this->app->gettext('korean').')',
- 'EUC-CN' => 'EUC-CN ('.$this->app->gettext('chinese').')',
- 'BIG5' => 'BIG5 ('.$this->app->gettext('chinese').')',
- 'GB2312' => 'GB2312 ('.$this->app->gettext('chinese').')',
- );
-
- if (!empty($_POST['_charset'])) {
- $set = $_POST['_charset'];
- }
- else if (!empty($attrib['selected'])) {
- $set = $attrib['selected'];
- }
- else {
- $set = $this->get_charset();
- }
-
- $set = strtoupper($set);
- if (!isset($charsets[$set])) {
- $charsets[$set] = $set;
- }
-
- $select = new html_select($field_attrib);
- $select->add(array_values($charsets), array_keys($charsets));
-
- return $select->show($set);
- }
-
- /**
- * Include content from config/about.<LANG>.html if available
- */
- protected function about_content($attrib)
- {
- $content = '';
- $filenames = array(
- 'about.' . $_SESSION['language'] . '.html',
- 'about.' . substr($_SESSION['language'], 0, 2) . '.html',
- 'about.html',
- );
- foreach ($filenames as $file) {
- $fn = RCMAIL_CONFIG_DIR . '/' . $file;
- if (is_readable($fn)) {
- $content = file_get_contents($fn);
- $content = $this->parse_conditions($content);
- $content = $this->parse_xml($content);
- break;
- }
- }
-
- return $content;
- }
-
-}
diff --git a/lib/ext/Roundcube/rcube_output_json.php b/lib/ext/Roundcube/rcube_output_json.php
deleted file mode 100644
index eb1a938..0000000
--- a/lib/ext/Roundcube/rcube_output_json.php
+++ /dev/null
@@ -1,257 +0,0 @@
-<?php
-
-/*
- +-----------------------------------------------------------------------+
- | program/include/rcube_output_json.php |
- | |
- | This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2012, The Roundcube Dev Team |
- | |
- | Licensed under the GNU General Public License version 3 or |
- | any later version with exceptions for skins & plugins. |
- | See the README file for a full license statement. |
- | |
- | PURPOSE: |
- | Class to handle JSON (AJAX) output |
- +-----------------------------------------------------------------------+
- | Author: Thomas Bruederli <roundcube at gmail.com> |
- | Author: Aleksander Machniak <alec at alec.pl> |
- +-----------------------------------------------------------------------+
-*/
-
-
-/**
- * View class to produce JSON responses
- *
- * @package View
- */
-class rcube_output_json extends rcube_output
-{
- protected $texts = array();
- protected $commands = array();
- protected $callbacks = array();
- protected $message = null;
-
- public $type = 'js';
- public $ajax_call = true;
-
-
- /**
- * Issue command to set page title
- *
- * @param string $title New page title
- */
- public function set_pagetitle($title)
- {
- if ($this->config->get('devel_mode') && !empty($_SESSION['username']))
- $name = $_SESSION['username'];
- else
- $name = $this->config->get('product_name');
-
- $this->command('set_pagetitle', empty($name) ? $title : $name.' :: '.$title);
- }
-
-
- /**
- * Register a template object handler
- *
- * @param string $obj Object name
- * @param string $func Function name to call
- */
- public function add_handler($obj, $func)
- {
- // ignore
- }
-
-
- /**
- * Register a list of template object handlers
- *
- * @param array $arr Hash array with object=>handler pairs
- */
- public function add_handlers($arr)
- {
- // ignore
- }
-
-
- /**
- * Call a client method
- *
- * @param string Method to call
- * @param ... Additional arguments
- */
- public function command()
- {
- $cmd = func_get_args();
-
- if (strpos($cmd[0], 'plugin.') === 0)
- $this->callbacks[] = $cmd;
- else
- $this->commands[] = $cmd;
- }
-
-
- /**
- * Add a localized label to the client environment
- */
- public function add_label()
- {
- $args = func_get_args();
- if (count($args) == 1 && is_array($args[0]))
- $args = $args[0];
-
- foreach ($args as $name) {
- $this->texts[$name] = $this->app->gettext($name);
- }
- }
-
-
- /**
- * Invoke display_message command
- *
- * @param string $message Message to display
- * @param string $type Message type [notice|confirm|error]
- * @param array $vars Key-value pairs to be replaced in localized text
- * @param boolean $override Override last set message
- * @param int $timeout Message displaying time in seconds
- * @uses self::command()
- */
- public function show_message($message, $type='notice', $vars=null, $override=true, $timeout=0)
- {
- if ($override || !$this->message) {
- if ($this->app->text_exists($message)) {
- if (!empty($vars)) {
- $vars = array_map(array('rcmail', 'Q'), $vars);
- }
- $msgtext = $this->app->gettext(array('name' => $message, 'vars' => $vars));
- }
- else
- $msgtext = $message;
-
- $this->message = $message;
- $this->command('display_message', $msgtext, $type, $timeout * 1000);
- }
- }
-
-
- /**
- * Delete all stored env variables and commands
- */
- public function reset()
- {
- parent::reset();
- $this->texts = array();
- $this->commands = array();
- }
-
-
- /**
- * Redirect to a certain url
- *
- * @param mixed $p Either a string with the action or url parameters as key-value pairs
- * @param int $delay Delay in seconds
- * @see rcmail::url()
- */
- public function redirect($p = array(), $delay = 1)
- {
- $location = $this->app->url($p);
- $this->remote_response(sprintf("window.setTimeout(function(){ %s.redirect('%s',true); }, %d);",
- rcmail::JS_OBJECT_NAME, $location, $delay));
- exit;
- }
-
-
- /**
- * Send an AJAX response to the client.
- */
- public function send()
- {
- $this->remote_response();
- exit;
- }
-
-
- /**
- * Show error page and terminate script execution
- *
- * @param int $code Error code
- * @param string $message Error message
- */
- public function raise_error($code, $message)
- {
- $this->show_message("Application Error ($code): $message", 'error');
- $this->remote_response();
- exit;
- }
-
-
- /**
- * Send an AJAX response with executable JS code
- *
- * @param string $add Additional JS code
- * @param boolean True if output buffer should be flushed
- * @return void
- * @deprecated
- */
- protected function remote_response($add='')
- {
- static $s_header_sent = false;
-
- if (!$s_header_sent) {
- $s_header_sent = true;
- $this->nocacheing_headers();
- header('Content-Type: text/plain; charset=' . $this->get_charset());
- }
-
- // unset default env vars
- unset($this->env['task'], $this->env['action'], $this->env['comm_path']);
-
- $rcmail = rcmail::get_instance();
- $response['action'] = $rcmail->action;
-
- if ($unlock = rcube_utils::get_input_value('_unlock', rcube_utils::INPUT_GPC)) {
- $response['unlock'] = $unlock;
- }
-
- if (!empty($this->env))
- $response['env'] = $this->env;
-
- if (!empty($this->texts))
- $response['texts'] = $this->texts;
-
- // send function calls
- $response['exec'] = $this->get_js_commands() . $add;
-
- if (!empty($this->callbacks))
- $response['callbacks'] = $this->callbacks;
-
- echo self::json_serialize($response);
- }
-
-
- /**
- * Return executable javascript code for all registered commands
- *
- * @return string $out
- */
- protected function get_js_commands()
- {
- $out = '';
-
- foreach ($this->commands as $i => $args) {
- $method = array_shift($args);
- foreach ($args as $i => $arg) {
- $args[$i] = self::json_serialize($arg);
- }
-
- $out .= sprintf(
- "this.%s(%s);\n",
- preg_replace('/^parent\./', '', $method),
- implode(',', $args)
- );
- }
-
- return $out;
- }
-}
diff --git a/lib/ext/Roundcube/rcube_plugin.php b/lib/ext/Roundcube/rcube_plugin.php
index 4508885..dbb15e8 100644
--- a/lib/ext/Roundcube/rcube_plugin.php
+++ b/lib/ext/Roundcube/rcube_plugin.php
@@ -22,7 +22,8 @@
/**
* Plugin interface class
*
- * @package PluginAPI
+ * @package Framework
+ * @subpackage PluginAPI
*/
abstract class rcube_plugin
{
diff --git a/lib/ext/Roundcube/rcube_plugin_api.php b/lib/ext/Roundcube/rcube_plugin_api.php
index 107c810..51cf5d2 100644
--- a/lib/ext/Roundcube/rcube_plugin_api.php
+++ b/lib/ext/Roundcube/rcube_plugin_api.php
@@ -20,14 +20,15 @@
*/
// location where plugins are loade from
-if (!defined('RCMAIL_PLUGINS_DIR'))
- define('RCMAIL_PLUGINS_DIR', INSTALL_PATH . 'plugins/');
+if (!defined('RCUBE_PLUGINS_DIR'))
+ define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'plugins/');
/**
* The plugin loader and global API
*
- * @package PluginAPI
+ * @package Framework
+ * @subpackage PluginAPI
*/
class rcube_plugin_api
{
@@ -100,7 +101,7 @@ class rcube_plugin_api
*/
protected function __construct()
{
- $this->dir = slashify(RCMAIL_PLUGINS_DIR);
+ $this->dir = slashify(RCUBE_PLUGINS_DIR);
}
@@ -327,7 +328,7 @@ class rcube_plugin_api
if (isset($this->actions[$action])) {
call_user_func($this->actions[$action]);
}
- else {
+ else if (rcube::get_instance()->action != 'refresh') {
rcube::raise_error(array('code' => 524, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "No handler found for action $action"), true, true);
@@ -369,6 +370,10 @@ class rcube_plugin_api
*/
public function register_task($task, $owner)
{
+ // tasks are irrelevant in framework mode
+ if (!class_exists('rcmail', false))
+ return true;
+
if ($task != asciiwords($task)) {
rcube::raise_error(array('code' => 526, 'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
diff --git a/lib/ext/Roundcube/rcube_result_index.php b/lib/ext/Roundcube/rcube_result_index.php
index 334ec85..4d1ae13 100644
--- a/lib/ext/Roundcube/rcube_result_index.php
+++ b/lib/ext/Roundcube/rcube_result_index.php
@@ -24,6 +24,9 @@
/**
* Class for accessing IMAP's SORT/SEARCH/ESEARCH result
+ *
+ * @package Framework
+ * @subpackage Storage
*/
class rcube_result_index
{
diff --git a/lib/ext/Roundcube/rcube_result_set.php b/lib/ext/Roundcube/rcube_result_set.php
index 809d874..456d1c9 100644
--- a/lib/ext/Roundcube/rcube_result_set.php
+++ b/lib/ext/Roundcube/rcube_result_set.php
@@ -24,7 +24,8 @@
* Roundcube result set class.
* Representing an address directory result set.
*
- * @package Addressbook
+ * @package Framework
+ * @subpackage Addressbook
*/
class rcube_result_set
{
diff --git a/lib/ext/Roundcube/rcube_result_thread.php b/lib/ext/Roundcube/rcube_result_thread.php
index b2325a4..c609bdc 100644
--- a/lib/ext/Roundcube/rcube_result_thread.php
+++ b/lib/ext/Roundcube/rcube_result_thread.php
@@ -24,6 +24,9 @@
/**
* Class for accessing IMAP's THREAD result
+ *
+ * @package Framework
+ * @subpackage Storage
*/
class rcube_result_thread
{
diff --git a/lib/ext/Roundcube/rcube_session.php b/lib/ext/Roundcube/rcube_session.php
index 6192466..fdbf668 100644
--- a/lib/ext/Roundcube/rcube_session.php
+++ b/lib/ext/Roundcube/rcube_session.php
@@ -24,7 +24,8 @@
/**
* Class to provide database supported session storage
*
- * @package Core
+ * @package Framework
+ * @subpackage Core
* @author Thomas Bruederli <roundcube at gmail.com>
* @author Aleksander Machniak <alec at alec.pl>
*/
@@ -43,7 +44,6 @@ class rcube_session
private $secret = '';
private $ip_check = false;
private $logging = false;
- private $keep_alive = 0;
private $memcache;
/**
@@ -525,24 +525,6 @@ class rcube_session
$this->now = $now - ($now % ($this->lifetime / 2));
}
- /**
- * Setter for keep_alive interval
- */
- public function set_keep_alive($keep_alive)
- {
- $this->keep_alive = $keep_alive;
-
- if ($this->lifetime < $keep_alive)
- $this->set_lifetime($keep_alive + 30);
- }
-
- /**
- * Getter for keep_alive interval
- */
- public function get_keep_alive()
- {
- return $this->keep_alive;
- }
/**
* Getter for remote IP saved with this session
@@ -552,6 +534,7 @@ class rcube_session
return $this->ip;
}
+
/**
* Setter for cookie encryption secret
*/
diff --git a/lib/ext/Roundcube/rcube_smtp.php b/lib/ext/Roundcube/rcube_smtp.php
index b28be52..96534c0 100644
--- a/lib/ext/Roundcube/rcube_smtp.php
+++ b/lib/ext/Roundcube/rcube_smtp.php
@@ -25,7 +25,8 @@ define('SMTP_MIME_CRLF', "\r\n");
/**
* Class to provide SMTP functionality using PEAR Net_SMTP
*
- * @package Mail
+ * @package Framework
+ * @subpackage Mail
* @author Thomas Bruederli <roundcube at gmail.com>
* @author Aleksander Machniak <alec at alec.pl>
*/
@@ -134,8 +135,8 @@ class rcube_smtp
$this->conn->setTimeout($timeout);
}
- $smtp_user = str_replace('%u', $_SESSION['username'], $CONFIG['smtp_user']);
- $smtp_pass = str_replace('%p', $rcube->decrypt($_SESSION['password']), $CONFIG['smtp_pass']);
+ $smtp_user = str_replace('%u', $rcube->get_user_name(), $CONFIG['smtp_user']);
+ $smtp_pass = str_replace('%p', $rcube->get_user_password(), $CONFIG['smtp_pass']);
$smtp_auth_type = empty($CONFIG['smtp_auth_type']) ? NULL : $CONFIG['smtp_auth_type'];
if (!empty($CONFIG['smtp_auth_cid'])) {
diff --git a/lib/ext/Roundcube/rcube_spellchecker.php b/lib/ext/Roundcube/rcube_spellchecker.php
index 219dca7..30d15d7 100644
--- a/lib/ext/Roundcube/rcube_spellchecker.php
+++ b/lib/ext/Roundcube/rcube_spellchecker.php
@@ -25,7 +25,8 @@
/**
* Helper class for spellchecking with Googielspell and PSpell support.
*
- * @package Core
+ * @package Framework
+ * @subpackage Utils
*/
class rcube_spellchecker
{
diff --git a/lib/ext/Roundcube/rcube_storage.php b/lib/ext/Roundcube/rcube_storage.php
index 933ebcc..1556aae 100644
--- a/lib/ext/Roundcube/rcube_storage.php
+++ b/lib/ext/Roundcube/rcube_storage.php
@@ -25,10 +25,10 @@
/**
* Abstract class for accessing mail messages storage server
*
- * @package Mail
- * @author Thomas Bruederli <roundcube at gmail.com>
- * @author Aleksander Machniak <alec at alec.pl>
- * @version 2.0
+ * @package Framework
+ * @subpackage Storage
+ * @author Thomas Bruederli <roundcube at gmail.com>
+ * @author Aleksander Machniak <alec at alec.pl>
*/
abstract class rcube_storage
{
diff --git a/lib/ext/Roundcube/rcube_string_replacer.php b/lib/ext/Roundcube/rcube_string_replacer.php
index c29f0e4..9af6b33 100644
--- a/lib/ext/Roundcube/rcube_string_replacer.php
+++ b/lib/ext/Roundcube/rcube_string_replacer.php
@@ -23,7 +23,8 @@
/**
* Helper class for string replacements based on preg_replace_callback
*
- * @package Core
+ * @package Framework
+ * @subpackage Utils
*/
class rcube_string_replacer
{
@@ -37,16 +38,16 @@ class rcube_string_replacer
{
// Simplified domain expression for UTF8 characters handling
// Support unicode/punycode in top-level domain part
- $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})';
+ $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.?([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-zA-Z0-9]{2,})';
$url1 = '.:;,';
- $url2 = 'a-z0-9%=#@+?!&\\/_~\\[\\]{}-';
+ $url2 = 'a-zA-Z0-9%=#$@+?!&\\/_~\\[\\]{}\*-';
- $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i";
+ $this->link_pattern = "/([\w]+:\/\/|\W[Ww][Ww][Ww]\.|^[Ww][Ww][Ww]\.)($utf_domain([$url1]?[$url2]+)*)/";
$this->mailto_pattern = "/("
."[-\w!\#\$%&\'*+~\/^`|{}=]+(?:\.[-\w!\#\$%&\'*+~\/^`|{}=]+)*" // local-part
."@$utf_domain" // domain-part
."(\?[$url1$url2]+)?" // e.g. ?subject=test...
- .")/i";
+ .")/";
}
/**
@@ -81,11 +82,11 @@ class rcube_string_replacer
$i = -1;
$scheme = strtolower($matches[1]);
- if (preg_match('!^(http|ftp|file)s?://!', $scheme)) {
+ if (preg_match('!^(http|ftp|file)s?://!i', $scheme)) {
$url = $matches[1] . $matches[2];
}
- else if (preg_match('/^(\W)www\.$/', $matches[1], $m)) {
- $url = 'www.' . $matches[2];
+ else if (preg_match('/^(\W*)(www\.)$/i', $matches[1], $m)) {
+ $url = $m[2] . $matches[2];
$url_prefix = 'http://';
$prefix = $m[1];
}
@@ -134,6 +135,22 @@ class rcube_string_replacer
}
/**
+ * Replace all defined (link|mailto) patterns with replacement string
+ *
+ * @param string $str Text
+ *
+ * @return string Text
+ */
+ public function replace($str)
+ {
+ // search for patterns like links and e-mail addresses
+ $str = preg_replace_callback($this->link_pattern, array($this, 'link_callback'), $str);
+ $str = preg_replace_callback($this->mailto_pattern, array($this, 'mailto_callback'), $str);
+
+ return $str;
+ }
+
+ /**
* Replace substituted strings with original values
*/
public function resolve($str)
diff --git a/lib/ext/Roundcube/rcube_user.php b/lib/ext/Roundcube/rcube_user.php
index 5a65a51..864f2e0 100644
--- a/lib/ext/Roundcube/rcube_user.php
+++ b/lib/ext/Roundcube/rcube_user.php
@@ -5,7 +5,7 @@
| program/include/rcube_user.inc |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2005-2010, The Roundcube Dev Team |
+ | Copyright (C) 2005-2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -17,6 +17,7 @@
| |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube at gmail.com> |
+ | Author: Aleksander Machniak <alec at alec.pl> |
+-----------------------------------------------------------------------+
*/
@@ -24,8 +25,8 @@
/**
* Class representing a system user
*
- * @package Core
- * @author Thomas Bruederli <roundcube at gmail.com>
+ * @package Framework
+ * @subpackage Core
*/
class rcube_user
{
@@ -47,6 +48,13 @@ class rcube_user
*/
private $rc;
+ /**
+ * Internal identities cache
+ *
+ * @var array
+ */
+ private $identities = array();
+
const SEARCH_ADDRESSBOOK = 1;
const SEARCH_MAIL = 2;
@@ -78,12 +86,17 @@ class rcube_user
/**
* Build a user name string (as e-mail address)
*
- * @param string $part Username part (empty or 'local' or 'domain')
+ * @param string $part Username part (empty or 'local' or 'domain', 'mail')
* @return string Full user name or its part
*/
function get_username($part = null)
{
if ($this->data['username']) {
+ // return real name
+ if (!$part) {
+ return $this->data['username'];
+ }
+
list($local, $domain) = explode('@', $this->data['username']);
// at least we should always have the local part
@@ -163,7 +176,7 @@ class rcube_user
// don't save prefs with default values if they haven't been changed yet
foreach ($a_user_prefs as $key => $value) {
- if (!isset($old_prefs[$key]) && ($value == $config->get($key)))
+ if ($value === null || (!isset($old_prefs[$key]) && ($value == $config->get($key))))
unset($save_prefs[$key]);
}
@@ -213,8 +226,14 @@ class rcube_user
*/
function get_identity($id = null)
{
- $result = $this->list_identities($id ? sprintf('AND identity_id = %d', $id) : '');
- return $result[0];
+ $id = (int)$id;
+ // cache identities for better performance
+ if (!array_key_exists($id, $this->identities)) {
+ $result = $this->list_identities($id ? 'AND identity_id = ' . $id : '');
+ $this->identities[$id] = $result[0];
+ }
+
+ return $this->identities[$id];
}
@@ -273,6 +292,8 @@ class rcube_user
call_user_func_array(array($this->db, 'query'),
array_merge(array($sql), $query_params));
+ $this->identities = array();
+
return $this->db->affected_rows();
}
@@ -305,6 +326,8 @@ class rcube_user
call_user_func_array(array($this->db, 'query'),
array_merge(array($sql), $insert_values));
+ $this->identities = array();
+
return $this->db->insert_id('identities');
}
@@ -339,6 +362,8 @@ class rcube_user
$this->ID,
$iid);
+ $this->identities = array();
+
return $this->db->affected_rows();
}
@@ -359,6 +384,8 @@ class rcube_user
" AND del <> 1",
$this->ID,
$iid);
+
+ unset($this->identities[0]);
}
}
@@ -449,6 +476,7 @@ class rcube_user
'user_name' => $user_name,
'user_email' => $user_email,
'email_list' => $email_list,
+ 'language' => $_SESSION['language'],
));
// plugin aborted this operation
@@ -462,13 +490,17 @@ class rcube_user
" VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)",
strip_newlines($data['user']),
strip_newlines($data['host']),
- strip_newlines($data['language'] ? $data['language'] : $_SESSION['language']));
+ strip_newlines($data['language']));
if ($user_id = $dbh->insert_id('users')) {
// create rcube_user instance to make plugin hooks work
- $user_instance = new rcube_user($user_id);
- $rcube->user = $user_instance;
-
+ $user_instance = new rcube_user($user_id, array(
+ 'user_id' => $user_id,
+ 'username' => $data['user'],
+ 'mail_host' => $data['host'],
+ 'language' => $data['language'],
+ ));
+ $rcube->user = $user_instance;
$mail_domain = $rcube->config->mail_domain($data['host']);
$user_name = $data['user_name'];
$user_email = $data['user_email'];
diff --git a/lib/ext/Roundcube/rcube_utils.php b/lib/ext/Roundcube/rcube_utils.php
index 2a4d4c4..df77dfe 100644
--- a/lib/ext/Roundcube/rcube_utils.php
+++ b/lib/ext/Roundcube/rcube_utils.php
@@ -24,7 +24,8 @@
/**
* Utility class providing common functions
*
- * @package Core
+ * @package Framework
+ * @subpackage Utils
*/
class rcube_utils
{
@@ -133,12 +134,12 @@ class rcube_utils
}
// find MX record(s)
- if (getmxrr($domain_part, $mx_records)) {
+ if (!function_exists('getmxrr') || getmxrr($domain_part, $mx_records)) {
return true;
}
// find any DNS record
- if (checkdnsrr($domain_part, 'ANY')) {
+ if (!function_exists('checkdnsrr') || checkdnsrr($domain_part, 'ANY')) {
return true;
}
}
@@ -761,7 +762,7 @@ class rcube_utils
}
}
- $result[] = substr($string, $p);
+ $result[] = (string) substr($string, $p);
return $result;
}
@@ -882,4 +883,95 @@ class rcube_utils
return $as_array ? $arr : join(" ", $arr);
}
+ /**
+ * Parse commandline arguments into a hash array
+ *
+ * @param array $aliases Argument alias names
+ *
+ * @return array Argument values hash
+ */
+ public static function get_opt($aliases = array())
+ {
+ $args = array();
+
+ for ($i=1; $i < count($_SERVER['argv']); $i++) {
+ $arg = $_SERVER['argv'][$i];
+ $value = true;
+ $key = null;
+
+ if ($arg[0] == '-') {
+ $key = preg_replace('/^-+/', '', $arg);
+ $sp = strpos($arg, '=');
+ if ($sp > 0) {
+ $key = substr($key, 0, $sp - 2);
+ $value = substr($arg, $sp+1);
+ }
+ else if (strlen($_SERVER['argv'][$i+1]) && $_SERVER['argv'][$i+1][0] != '-') {
+ $value = $_SERVER['argv'][++$i];
+ }
+
+ $args[$key] = is_string($value) ? preg_replace(array('/^["\']/', '/["\']$/'), '', $value) : $value;
+ }
+ else {
+ $args[] = $arg;
+ }
+
+ if ($alias = $aliases[$key]) {
+ $args[$alias] = $args[$key];
+ }
+ }
+
+ return $args;
+ }
+
+ /**
+ * Safe password prompt for command line
+ * from http://blogs.sitepoint.com/2009/05/01/interactive-cli-password-prompt-in-php/
+ *
+ * @return string Password
+ */
+ public static function prompt_silent($prompt = "Password:")
+ {
+ if (preg_match('/^win/i', PHP_OS)) {
+ $vbscript = sys_get_temp_dir() . 'prompt_password.vbs';
+ $vbcontent = 'wscript.echo(InputBox("' . addslashes($prompt) . '", "", "password here"))';
+ file_put_contents($vbscript, $vbcontent);
+
+ $command = "cscript //nologo " . escapeshellarg($vbscript);
+ $password = rtrim(shell_exec($command));
+ unlink($vbscript);
+
+ return $password;
+ }
+ else {
+ $command = "/usr/bin/env bash -c 'echo OK'";
+ if (rtrim(shell_exec($command)) !== 'OK') {
+ echo $prompt;
+ $pass = trim(fgets(STDIN));
+ echo chr(8)."\r" . $prompt . str_repeat("*", strlen($pass))."\n";
+ return $pass;
+ }
+
+ $command = "/usr/bin/env bash -c 'read -s -p \"" . addslashes($prompt) . "\" mypassword && echo \$mypassword'";
+ $password = rtrim(shell_exec($command));
+ echo "\n";
+ return $password;
+ }
+ }
+
+
+ /**
+ * Find out if the string content means true or false
+ *
+ * @param string $str Input value
+ *
+ * @return boolean Boolean value
+ */
+ public static function get_boolean($str)
+ {
+ $str = strtolower($str);
+
+ return !in_array($str, array('false', '0', 'no', 'off', 'nein', ''), true);
+ }
+
}
diff --git a/lib/ext/Roundcube/rcube_vcard.php b/lib/ext/Roundcube/rcube_vcard.php
index 00903c2..7b59e20 100644
--- a/lib/ext/Roundcube/rcube_vcard.php
+++ b/lib/ext/Roundcube/rcube_vcard.php
@@ -5,7 +5,7 @@
| program/include/rcube_vcard.php |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2011, The Roundcube Dev Team |
+ | Copyright (C) 2008-2012, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -15,6 +15,7 @@
| Logical representation of a vcard address record |
+-----------------------------------------------------------------------+
| Author: Thomas Bruederli <roundcube at gmail.com> |
+ | Author: Aleksander Machniak <alec at alec.pl> |
+-----------------------------------------------------------------------+
*/
@@ -23,8 +24,8 @@
* Logical representation of a vcard-based address record
* Provides functions to parse and export vCard data format
*
- * @package Addressbook
- * @author Thomas Bruederli <roundcube at gmail.com>
+ * @package Framework
+ * @subpackage Addressbook
*/
class rcube_vcard
{
@@ -51,7 +52,7 @@ class rcube_vcard
'edit' => 'X-AB-EDIT',
);
private $typemap = array('IPHONE' => 'mobile', 'CELL' => 'mobile', 'WORK,FAX' => 'workfax');
- private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'BUSINESSFAX' => 'WORK,FAX');
+ private $phonetypemap = array('HOME1' => 'HOME', 'BUSINESS1' => 'WORK', 'BUSINESS2' => 'WORK2', 'BUSINESSFAX' => 'WORK,FAX', 'MOBILE' => 'CELL');
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');
@@ -62,7 +63,6 @@ class rcube_vcard
public $middlename;
public $nickname;
public $organization;
- public $notes;
public $email = array();
public static $eol = "\r\n";
@@ -101,7 +101,7 @@ class rcube_vcard
($detected_charset = self::detect_encoding(self::vcard_encode($this->raw))) && $detected_charset != RCMAIL_CHARSET) {
$this->raw = self::charset_convert($this->raw, $detected_charset);
}
-
+
// consider FN empty if the same as the primary e-mail address
if ($this->raw['FN'][0][0] == $this->raw['EMAIL'][0][0])
$this->raw['FN'][0][0] = '';
@@ -265,26 +265,25 @@ class rcube_vcard
*/
public function set($field, $value, $type = 'HOME')
{
- $field = strtolower($field);
+ $field = strtolower($field);
$type_uc = strtoupper($type);
- $typemap = array_flip($this->typemap);
switch ($field) {
case 'name':
case 'displayname':
- $this->raw['FN'][0][0] = $value;
+ $this->raw['FN'][0][0] = $this->displayname = $value;
break;
case 'surname':
- $this->raw['N'][0][0] = $value;
+ $this->raw['N'][0][0] = $this->surname = $value;
break;
case 'firstname':
- $this->raw['N'][0][1] = $value;
+ $this->raw['N'][0][1] = $this->firstname = $value;
break;
case 'middlename':
- $this->raw['N'][0][2] = $value;
+ $this->raw['N'][0][2] = $this->middlename = $value;
break;
case 'prefix':
@@ -296,11 +295,11 @@ class rcube_vcard
break;
case 'nickname':
- $this->raw['NICKNAME'][0][0] = $value;
+ $this->raw['NICKNAME'][0][0] = $this->nickname = $value;
break;
case 'organization':
- $this->raw['ORG'][0][0] = $value;
+ $this->raw['ORG'][0][0] = $this->organization = $value;
break;
case 'photo':
@@ -348,8 +347,10 @@ class rcube_vcard
if (($tag = self::$fieldmap[$field]) && (is_array($value) || strlen($value))) {
$index = count($this->raw[$tag]);
$this->raw[$tag][$index] = (array)$value;
- if ($type)
+ if ($type) {
+ $typemap = array_flip($this->typemap);
$this->raw[$tag][$index]['type'] = explode(',', ($typemap[$type_uc] ? $typemap[$type_uc] : $type));
+ }
}
break;
}
@@ -784,42 +785,9 @@ class rcube_vcard
*/
private static function detect_encoding($string)
{
- if (substr($string, 0, 4) == "\0\0\xFE\xFF") return 'UTF-32BE'; // Big Endian
- if (substr($string, 0, 4) == "\xFF\xFE\0\0") return 'UTF-32LE'; // Little Endian
- if (substr($string, 0, 2) == "\xFE\xFF") return 'UTF-16BE'; // Big Endian
- if (substr($string, 0, 2) == "\xFF\xFE") return 'UTF-16LE'; // Little Endian
- if (substr($string, 0, 3) == "\xEF\xBB\xBF") return 'UTF-8';
-
- // heuristics
- if ($string[0] == "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-32BE';
- if ($string[0] != "\0" && $string[1] == "\0" && $string[2] == "\0" && $string[3] == "\0") return 'UTF-32LE';
- if ($string[0] == "\0" && $string[1] != "\0" && $string[2] == "\0" && $string[3] != "\0") return 'UTF-16BE';
- if ($string[0] != "\0" && $string[1] == "\0" && $string[2] != "\0" && $string[3] == "\0") return 'UTF-16LE';
-
- // use mb_detect_encoding()
- $encodings = array('UTF-8', 'ISO-8859-1', 'ISO-8859-2', 'ISO-8859-3',
- 'ISO-8859-4', 'ISO-8859-5', 'ISO-8859-6', 'ISO-8859-7', 'ISO-8859-8', 'ISO-8859-9',
- 'ISO-8859-10', 'ISO-8859-13', 'ISO-8859-14', 'ISO-8859-15', 'ISO-8859-16',
- 'WINDOWS-1252', 'WINDOWS-1251', 'BIG5', 'GB2312');
-
- if (function_exists('mb_detect_encoding') && ($enc = mb_detect_encoding($string, $encodings)))
- return $enc;
-
- // No match, check for UTF-8
- // from http://w3.org/International/questions/qa-forms-utf-8.html
- if (preg_match('/\A(
- [\x09\x0A\x0D\x20-\x7E]
- | [\xC2-\xDF][\x80-\xBF]
- | \xE0[\xA0-\xBF][\x80-\xBF]
- | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}
- | \xED[\x80-\x9F][\x80-\xBF]
- | \xF0[\x90-\xBF][\x80-\xBF]{2}
- | [\xF1-\xF3][\x80-\xBF]{3}
- | \xF4[\x80-\x8F][\x80-\xBF]{2}
- )*\z/xs', substr($string, 0, 2048)))
- return 'UTF-8';
-
- return rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); # fallback to Latin-1
+ $fallback = rcube::get_instance()->config->get('default_charset', 'ISO-8859-1'); // fallback to Latin-1
+
+ return rcube_charset::detect($string, $fallback);
}
}
diff --git a/lib/init.php b/lib/init.php
index 9105152..87256c6 100644
--- a/lib/init.php
+++ b/lib/init.php
@@ -23,54 +23,29 @@
+--------------------------------------------------------------------------+
*/
+define('KOLAB_SYNC_START', microtime(true));
+
// Roundcube Framework constants
-define('RCMAIL_START', microtime(true));
-define('RCMAIL_VERSION', '0.9-git');
+define('RCUBE_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 . 'lib/plugins');
-
-// PHP configuration
-$config = array(
- 'error_reporting' => E_ALL &~ (E_NOTICE | E_STRICT),
- 'mbstring.func_overload' => 0,
-// 'suhosin.session.encrypt' => 0,
-// 'session.auto_start' => 0,
-// 'file_uploads' => 1,
- 'magic_quotes_runtime' => 0,
- 'magic_quotes_sybase' => 0,
-);
-foreach ($config as $optname => $optval) {
- if ($optval != ini_get($optname) && @ini_set($optname, $optval) === false) {
- die("ERROR: Wrong '$optname' option value!");
- }
-}
+define('RCUBE_INSTALL_PATH', realpath(dirname(__FILE__) . '/../') . '/');
+define('RCUBE_PLUGINS_DIR', RCUBE_INSTALL_PATH . 'lib/plugins/');
// Define include path
-$include_path = INSTALL_PATH . 'lib' . PATH_SEPARATOR;
-$include_path .= INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR;
+$include_path = RCUBE_INSTALL_PATH . 'lib' . PATH_SEPARATOR;
+$include_path .= RCUBE_INSTALL_PATH . 'lib/ext' . PATH_SEPARATOR;
$include_path .= ini_get('include_path');
set_include_path($include_path);
// @TODO: what is a reasonable value for ActiveSync?
@set_time_limit(600);
-// set internal encoding for mbstring extension
-if (extension_loaded('mbstring')) {
- mb_internal_encoding(RCMAIL_CHARSET);
- @mb_regex_encoding(RCMAIL_CHARSET);
-}
-
// include global functions from Roundcube Framework
-require_once 'Roundcube/rcube_shared.inc';
+require_once 'Roundcube/bootstrap.php';
// Register main autoloader
spl_autoload_register('kolab_sync_autoload');
-// set PEAR error handling (will also load the PEAR main class)
-PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
-
// Autoloader for Syncroton
//require_once 'Zend/Loader/Autoloader.php';
//$autoloader = Zend_Loader_Autoloader::getInstance();
@@ -81,6 +56,7 @@ PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
*/
function kolab_sync_autoload($classname)
{
+/*
// Roundcube Framework
$filename = preg_replace(
array(
@@ -107,7 +83,7 @@ function kolab_sync_autoload($classname)
include_once "$filename.php";
return true;
}
-
+*/
// Syncroton, replacement for Zend autoloader
$filename = str_replace('_', DIRECTORY_SEPARATOR, $classname);
diff --git a/lib/kolab_sync.php b/lib/kolab_sync.php
index 27ad3d9..03001b7 100644
--- a/lib/kolab_sync.php
+++ b/lib/kolab_sync.php
@@ -129,6 +129,9 @@ class kolab_sync extends rcube
exit;
}
+ // Save user password for Roundcube Framework
+ $this->password = $_SERVER['PHP_AUTH_PW'];
+
// Register Syncroton backends
Syncroton_Registry::set('loggerBackend', $this->logger);
Syncroton_Registry::set(Syncroton_Registry::DATABASE, new kolab_sync_db);
@@ -329,8 +332,8 @@ class kolab_sync extends rcube
$query = $_SERVER['QUERY_STRING'];
$log = $query . ($mem ? ($query ? ' ' : '') . "[$mem]" : '');
- if (defined('RCMAIL_START'))
- self::print_timer(RCMAIL_START, $log);
+ if (defined('KOLAB_SYNC_START'))
+ self::print_timer(KOLAB_SYNC_START, $log);
else
self::console($log);
}
commit 54a3d2f5f53681ce3982f45ef845f8c4db9eb15b
Author: Aleksander Machniak <alec at alec.pl>
Date: Mon Nov 26 11:54:15 2012 +0100
Fix INBOX folder detection, in flat mode assign all "non-special" folders to it,
set correct folder type for INBOX
diff --git a/lib/kolab_sync_backend.php b/lib/kolab_sync_backend.php
index dd29629..46d16de 100644
--- a/lib/kolab_sync_backend.php
+++ b/lib/kolab_sync_backend.php
@@ -596,12 +596,20 @@ class kolab_sync_backend
// Folder UID
$folder_id = $this->folder_id($folder);
+ // Folder type
+ $type = self::type_kolab2activesync($type);
+ // fix type, if there's no type annotation it's detected as UNKNOWN
+ // we'll use 'mail' (12) or 'mail.inbox' (2)
+ if ($type == 1) {
+ $type = $folder == 'INBOX' ? 2 : 12;
+ }
+
// Syncroton folder data array
return array(
'serverId' => $folder_id,
'parentId' => count($items) ? self::folder_id(implode($delim, $items)) : 0,
'displayName' => rcube_charset::convert($name, 'UTF7-IMAP', kolab_sync::CHARSET),
- 'type' => self::type_kolab2activesync($type),
+ 'type' => $type,
);
}
diff --git a/lib/kolab_sync_data_email.php b/lib/kolab_sync_data_email.php
index 3f1606a..f808b5a 100644
--- a/lib/kolab_sync_data_email.php
+++ b/lib/kolab_sync_data_email.php
@@ -420,15 +420,14 @@ class kolab_sync_data_email extends kolab_sync_data implements Syncroton_Data_ID
$types = $this->folder_types;
foreach ($list as $idx => $folder) {
- if (isset($types[$folder['type']])) {
- $folder_id = $types[$folder['type']];
+ $type = $folder['type'] == 12 ? 2 : $folder['type']; // unknown to Inbox
+ if ($folder_id = $types[$type]) {
$result[$folder_id] = array(
'displayName' => $folder_id,
'serverId' => $folder_id,
'parentId' => 0,
- 'type' => $folder['type'],
+ 'type' => $type,
);
- unset($types[$folder['type']]);
}
}
More information about the commits
mailing list