From e8d5bdc84ecfdf6fe5008655215a258bbdf0c521 Mon Sep 17 00:00:00 2001
From: alecpl <alec@alec.pl>
Date: Thu, 03 Feb 2011 08:58:07 -0500
Subject: [PATCH] - Fix IDNA support when IDN/INTL modules are in use (#1487742)
---
program/include/rcmail.php | 282 +++++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 207 insertions(+), 75 deletions(-)
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 8fa9df7..8c80fe2 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -5,7 +5,7 @@
| program/include/rcmail.php |
| |
| This file is part of the Roundcube Webmail client |
- | Copyright (C) 2008-2010, Roundcube Dev. - Switzerland |
+ | Copyright (C) 2008-2010, The Roundcube Dev Team |
| Licensed under the GNU GPL |
| |
| PURPOSE: |
@@ -114,7 +114,8 @@
public $comm_path = './';
private $texts;
- private $books = array();
+ private $address_books = array();
+ private $action_map = array();
/**
@@ -208,7 +209,7 @@
$task = asciiwords($task);
if ($this->user && $this->user->ID)
- $task = !$task || $task == 'login' ? 'mail' : $task;
+ $task = !$task ? 'mail' : $task;
else
$task = 'login';
@@ -330,6 +331,10 @@
if ($plugin['instance'] instanceof rcube_addressbook) {
$contacts = $plugin['instance'];
}
+ // use existing instance
+ else if (isset($this->address_books[$id]) && is_a($this->address_books[$id], 'rcube_addressbook') && (!$writeable || !$this->address_books[$id]->readonly)) {
+ $contacts = $this->address_books[$id];
+ }
else if ($id && $ldap_config[$id]) {
$contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host']));
}
@@ -350,8 +355,8 @@
}
// add to the 'books' array for shutdown function
- if (!in_array($contacts, $this->books))
- $this->books[] = $contacts;
+ if (!isset($this->address_books[$id]))
+ $this->address_books[$id] = $contacts;
return $contacts;
}
@@ -372,11 +377,12 @@
// We are using the DB address book
if ($abook_type != 'ldap') {
- $contacts = new rcube_contacts($this->db, null);
+ if (!isset($this->address_books['0']))
+ $this->address_books['0'] = new rcube_contacts($this->db, $this->user->ID);
$list['0'] = array(
- 'id' => 0,
+ 'id' => '0',
'name' => rcube_label('personaladrbook'),
- 'groups' => $contacts->groups,
+ 'groups' => $this->address_books['0']->groups,
'readonly' => false,
'autocomplete' => in_array('sql', $autocomplete)
);
@@ -388,7 +394,7 @@
$list[$id] = array(
'id' => $id,
'name' => $prop['name'],
- 'groups' => false,
+ 'groups' => is_array($prop['groups']),
'readonly' => !$prop['writable'],
'autocomplete' => in_array('sql', $autocomplete)
);
@@ -397,14 +403,15 @@
$plugin = $this->plugins->exec_hook('addressbooks_list', array('sources' => $list));
$list = $plugin['sources'];
- if ($writeable && !empty($list)) {
- foreach ($list as $idx => $item) {
- if ($item['readonly']) {
+ foreach ($list as $idx => $item) {
+ // register source for shutdown function
+ if (!is_object($this->address_books[$item['id']]))
+ $this->address_books[$item['id']] = $item;
+ // remove from list if not writeable as requested
+ if ($writeable && $item['readonly'])
unset($list[$idx]);
- }
- }
}
-
+
return $list;
}
@@ -503,7 +510,7 @@
'auth_method' => $this->config->get('imap_auth_type', 'check'),
'auth_cid' => $this->config->get('imap_auth_cid'),
'auth_pw' => $this->config->get('imap_auth_pw'),
- 'debug_mode' => (bool) $this->config->get('imap_debug', 0),
+ 'debug' => (bool) $this->config->get('imap_debug', 0),
'force_caps' => (bool) $this->config->get('imap_force_caps'),
'timeout' => (int) $this->config->get('imap_timeout', 0),
);
@@ -592,10 +599,8 @@
session_start();
// set initial session vars
- if (!isset($_SESSION['auth_time'])) {
- $_SESSION['auth_time'] = time();
+ if (!$_SESSION['user_id'])
$_SESSION['temp'] = true;
- }
}
@@ -617,6 +622,9 @@
$keep_alive = max(60, $keep_alive);
$this->session->set_keep_alive($keep_alive);
}
+
+ $this->session->set_secret($this->config->get('des_key') . $_SERVER['HTTP_USER_AGENT']);
+ $this->session->set_ip_check($this->config->get('ip_check'));
}
@@ -673,24 +681,30 @@
// Check if we need to add domain
if (!empty($config['username_domain']) && strpos($username, '@') === false) {
if (is_array($config['username_domain']) && isset($config['username_domain'][$host]))
- $username .= '@'.rcube_parse_host($config['username_domain'][$host]);
+ $username .= '@'.rcube_parse_host($config['username_domain'][$host], $host);
else if (is_string($config['username_domain']))
- $username .= '@'.rcube_parse_host($config['username_domain']);
+ $username .= '@'.rcube_parse_host($config['username_domain'], $host);
+ }
+
+ // Convert username to lowercase. If IMAP backend
+ // is case-insensitive we need to store always the same username (#1487113)
+ if ($config['login_lc']) {
+ $username = mb_strtolower($username);
}
// try to resolve email address from virtuser table
- if (strpos($username, '@'))
- if ($virtuser = rcube_user::email2user($username))
- $username = $virtuser;
+ if (strpos($username, '@') && ($virtuser = rcube_user::email2user($username))) {
+ $username = $virtuser;
+ }
// Here we need IDNA ASCII
// Only rcube_contacts class is using domain names in Unicode
- $host = idn_to_ascii($host);
+ $host = rcube_idn_to_ascii($host);
if (strpos($username, '@')) {
// lowercase domain name
list($local, $domain) = explode('@', $username);
$username = $local . '@' . mb_strtolower($domain);
- $username = idn_to_ascii($username);
+ $username = rcube_idn_to_ascii($username);
}
// user already registered -> overwrite username
@@ -704,8 +718,14 @@
if (!($imap_login = $this->imap->connect($host, $username, $pass, $imap_port, $imap_ssl))) {
// try with lowercase
$username_lc = mb_strtolower($username);
- if ($username_lc != $username && ($imap_login = $this->imap->connect($host, $username_lc, $pass, $imap_port, $imap_ssl)))
- $username = $username_lc;
+ if ($username_lc != $username) {
+ // try to find user record again -> overwrite username
+ if (!$user && ($user = rcube_user::query($username_lc, $host)))
+ $username_lc = $user->data['username'];
+
+ if ($imap_login = $this->imap->connect($host, $username_lc, $pass, $imap_port, $imap_ssl))
+ $username = $username_lc;
+ }
}
// exit if IMAP login failed
@@ -748,6 +768,7 @@
// login succeeded
if (is_object($user) && $user->ID) {
$this->set_user($user);
+ $this->session_configure();
// set session vars
$_SESSION['user_id'] = $user->ID;
@@ -757,7 +778,7 @@
$_SESSION['imap_ssl'] = $imap_ssl;
$_SESSION['password'] = $this->encrypt($pass);
$_SESSION['login_time'] = mktime();
-
+
if (isset($_REQUEST['_timezone']) && $_REQUEST['_timezone'] != '_default_')
$_SESSION['timezone'] = floatval($_REQUEST['_timezone']);
@@ -782,7 +803,7 @@
if ($default_folders = $this->config->get('default_imap_folders')) {
$this->imap->set_default_mailboxes($default_folders);
}
- if (!empty($_SESSION['mbox'])) {
+ if (isset($_SESSION['mbox'])) {
$this->imap->set_mailbox($_SESSION['mbox']);
}
if (isset($_SESSION['page'])) {
@@ -917,6 +938,9 @@
if (empty($this->texts) || $lang != $_SESSION['language']) {
$this->texts = array();
+ // handle empty lines after closing PHP tag in localization files
+ 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');
@@ -936,6 +960,8 @@
if (is_array($messages))
$this->texts = array_merge($this->texts, $messages);
}
+
+ ob_end_clean();
$_SESSION['language'] = $lang;
}
@@ -975,50 +1001,14 @@
/**
- * Check the auth hash sent by the client against the local session credentials
- *
- * @return boolean True if valid, False if not
- */
- function authenticate_session()
- {
- // advanced session authentication
- if ($this->config->get('double_auth')) {
- $now = time();
- $valid = ($_COOKIE['sessauth'] == $this->get_auth_hash(session_id(), $_SESSION['auth_time']) ||
- $_COOKIE['sessauth'] == $this->get_auth_hash(session_id(), $_SESSION['last_auth']));
-
- // renew auth cookie every 5 minutes (only for GET requests)
- if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now - $_SESSION['auth_time'] > 300)) {
- $_SESSION['last_auth'] = $_SESSION['auth_time'];
- $_SESSION['auth_time'] = $now;
- rcmail::setcookie('sessauth', $this->get_auth_hash(session_id(), $now), 0);
- }
- }
- else {
- $valid = $this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] == $this->session->get_ip() : true;
- }
-
- // check session filetime
- $lifetime = $this->config->get('session_lifetime');
- $sess_ts = $this->session->get_ts();
- if (!empty($lifetime) && !empty($sess_ts) && $sess_ts + $lifetime*60 < time()) {
- $valid = false;
- }
-
- return $valid;
- }
-
-
- /**
* Destroy session data and remove cookie
*/
public function kill_session()
{
$this->plugins->exec_hook('session_destroy');
- $this->session->remove();
- $_SESSION = array('language' => $this->user->language, 'auth_time' => time(), 'temp' => true);
- rcmail::setcookie('sessauth', '-del-', time() - 60);
+ $this->session->kill();
+ $_SESSION = array('language' => $this->user->language, 'temp' => true);
$this->user->reset();
}
@@ -1032,7 +1022,7 @@
// on logout action we're not connected to imap server
if (($config['logout_purge'] && !empty($config['trash_mbox'])) || $config['logout_expunge']) {
- if (!$this->authenticate_session())
+ if (!$this->session->check_auth())
return;
$this->imap_connect();
@@ -1060,9 +1050,12 @@
if (is_object($this->smtp))
$this->smtp->disconnect();
- foreach ($this->books as $book)
- if (is_object($book))
+ foreach ($this->address_books as $book) {
+ if (!is_object($book)) // maybe an address book instance wasn't fetched using get_address_book() yet
+ $book = $this->get_address_book($book['id']);
+ if (is_a($book, 'rcube_addressbook'))
$book->close();
+ }
// before closing the database connection, write session data
if ($_SERVER['REMOTE_ADDR'])
@@ -1203,8 +1196,14 @@
if (function_exists('mcrypt_module_open') &&
($td = mcrypt_module_open(MCRYPT_TripleDES, "", MCRYPT_MODE_CBC, "")))
{
- $iv = substr($cipher, 0, mcrypt_enc_get_iv_size($td));
- $cipher = substr($cipher, mcrypt_enc_get_iv_size($td));
+ $iv_size = mcrypt_enc_get_iv_size($td);
+ $iv = substr($cipher, 0, $iv_size);
+
+ // session corruption? (#1485970)
+ if (strlen($iv) < $iv_size)
+ return '';
+
+ $cipher = substr($cipher, $iv_size);
mcrypt_generic_init($td, $this->config->get_crypto_key($key), $iv);
$clear = mdecrypt_generic($td, $cipher);
mcrypt_generic_deinit($td);
@@ -1283,6 +1282,112 @@
/**
+ * Use imagemagick or GD lib to read image properties
+ *
+ * @param string Absolute file path
+ * @return mixed Hash array with image props like type, width, height or False on error
+ */
+ public static function imageprops($filepath)
+ {
+ $rcmail = rcmail::get_instance();
+ if ($cmd = $rcmail->config->get('im_identify_path', false)) {
+ list(, $type, $size) = explode(' ', strtolower(rcmail::exec($cmd. ' 2>/dev/null {in}', array('in' => $filepath))));
+ if ($size)
+ list($width, $height) = explode('x', $size);
+ }
+ else if (function_exists('getimagesize')) {
+ $imsize = @getimagesize($filepath);
+ $width = $imsize[0];
+ $height = $imsize[1];
+ $type = preg_replace('!image/!', '', $imsize['mime']);
+ }
+
+ return $type ? array('type' => $type, 'width' => $width, 'height' => $height) : false;
+ }
+
+
+ /**
+ * Convert an image to a given size and type using imagemagick (ensures input is an image)
+ *
+ * @param $p['in'] Input filename (mandatory)
+ * @param $p['out'] Output filename (mandatory)
+ * @param $p['size'] Width x height of resulting image, e.g. "160x60"
+ * @param $p['type'] Output file type, e.g. "jpg"
+ * @param $p['-opts'] Custom command line options to ImageMagick convert
+ * @return Success of convert as true/false
+ */
+ public static function imageconvert($p)
+ {
+ $result = false;
+ $rcmail = rcmail::get_instance();
+ $convert = $rcmail->config->get('im_convert_path', false);
+ $identify = $rcmail->config->get('im_identify_path', false);
+
+ // imagemagick is required for this
+ if (!$convert)
+ return false;
+
+ if (!(($imagetype = @exif_imagetype($p['in'])) && ($type = image_type_to_extension($imagetype, false))))
+ list(, $type) = explode(' ', strtolower(rcmail::exec($identify . ' 2>/dev/null {in}', $p))); # for things like eps
+
+ $type = strtr($type, array("jpeg" => "jpg", "tiff" => "tif", "ps" => "eps", "ept" => "eps"));
+ $p += array('type' => $type, 'types' => "bmp,eps,gif,jp2,jpg,png,svg,tif", 'quality' => 75);
+ $p['-opts'] = array('-resize' => $p['size'].'>') + (array)$p['-opts'];
+
+ if (in_array($type, explode(',', $p['types']))) # Valid type?
+ $result = rcmail::exec($convert . ' 2>&1 -flatten -auto-orient -colorspace RGB -quality {quality} {-opts} {in} {type}:{out}', $p) === "";
+
+ return $result;
+ }
+
+
+ /**
+ * Construct shell command, execute it and return output as string.
+ * Keywords {keyword} are replaced with arguments
+ *
+ * @param $cmd Format string with {keywords} to be replaced
+ * @param $values (zero, one or more arrays can be passed)
+ * @return output of command. shell errors not detectable
+ */
+ public static function exec(/* $cmd, $values1 = array(), ... */)
+ {
+ $args = func_get_args();
+ $cmd = array_shift($args);
+ $values = $replacements = array();
+
+ // merge values into one array
+ foreach ($args as $arg)
+ $values += (array)$arg;
+
+ preg_match_all('/({(-?)([a-z]\w*)})/', $cmd, $matches, PREG_SET_ORDER);
+ foreach ($matches as $tags) {
+ list(, $tag, $option, $key) = $tags;
+ $parts = array();
+
+ if ($option) {
+ foreach ((array)$values["-$key"] as $key => $value) {
+ if ($value === true || $value === false || $value === null)
+ $parts[] = $value ? $key : "";
+ else foreach ((array)$value as $val)
+ $parts[] = "$key " . escapeshellarg($val);
+ }
+ }
+ else {
+ foreach ((array)$values[$key] as $value)
+ $parts[] = escapeshellarg($value);
+ }
+
+ $replacements[$tag] = join(" ", $parts);
+ }
+
+ // use strtr behaviour of going through source string once
+ $cmd = strtr($cmd, $replacements);
+
+ return (string)shell_exec($cmd);
+ }
+
+
+ /**
* Helper method to set a cookie with the current path and host settings
*
* @param string Cookie name
@@ -1299,6 +1404,33 @@
setcookie($name, $value, $exp, $cookie['path'], $cookie['domain'],
rcube_https_check(), true);
}
+
+ /**
+ * Registers action aliases for current task
+ *
+ * @param array $map Alias-to-filename hash array
+ */
+ public function register_action_map($map)
+ {
+ if (is_array($map)) {
+ foreach ($map as $idx => $val) {
+ $this->action_map[$idx] = $val;
+ }
+ }
+ }
+
+ /**
+ * Returns current action filename
+ *
+ * @param array $map Alias-to-filename hash array
+ */
+ public function get_action_file()
+ {
+ if (!empty($this->action_map[$this->action])) {
+ return $this->action_map[$this->action];
+ }
+
+ return strtr($this->action, '-', '_') . '.inc';
+ }
+
}
-
-
--
Gitblit v1.9.1