- Applied fixes from trunk up to r5425

release-0.7
alecpl 13 years ago
parent ecfaed571b
commit 3fec6952dd

@ -1,6 +1,10 @@
CHANGELOG Roundcube Webmail
===========================
- Fix listing of folders in hidden namespaces (#1486796)
- Don't consider \Noselect flag when building folders tree (#1488004)
- Fix sorting autocomplete results (#1488084)
- Add option to set session name (#1486433)
- Add option to skip alternative email addresses in autocompletion
- Fix inconsistent behaviour of Compose button in Drafts folder, add Edit button for drafts
- Fix problem with parsing HTML message body with non-unicode characters (#1487813)

@ -222,6 +222,9 @@ $rcmail_config['session_lifetime'] = 10;
// session domain: .example.org
$rcmail_config['session_domain'] = '';
// session name. Default: 'roundcube_sessid'
$rcmail_config['session_name'] = null;
// Backend to use for session storage. Can either be 'db' (default) or 'memcache'
// If set to memcache, a list of servers need to be specified in 'memcache_hosts'
// Make sure the Memcache extension (http://pecl.php.net/package/memcache) version >= 2.0.0 is installed
@ -418,7 +421,7 @@ $rcmail_config['trash_mbox'] = 'Trash';
// NOTE: Use folder names with namespace prefix (INBOX. on Courier-IMAP)
$rcmail_config['default_imap_folders'] = array('INBOX', 'Drafts', 'Sent', 'Junk', 'Trash');
// automatically create the above listed default folders on login
// automatically create the above listed default folders on first login
$rcmail_config['create_default_folders'] = false;
// protect the default folders from renames, deletes, and subscription changes

@ -47,6 +47,10 @@ $rcmail_config['password_db_dsn'] = '';
// Default: "SELECT update_passwd(%c, %u)"
$rcmail_config['password_query'] = 'SELECT update_passwd(%c, %u)';
// By default domains in variables are using unicode.
// Enable this option to use punycoded names
$rcmail_config['password_idn_ascii'] = false;
// Path for dovecotpw (if not in $PATH)
// $rcmail_config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw';

@ -37,16 +37,21 @@ function password_save($curpass, $passwd)
// crypted password
if (strpos($sql, '%c') !== FALSE) {
$salt = '';
if (CRYPT_MD5) {
$len = rand(3, CRYPT_SALT_LENGTH);
if (CRYPT_MD5) {
// Always use eight salt characters for MD5 (#1488136)
$len = 8;
} else if (CRYPT_STD_DES) {
$len = 2;
} else {
return PASSWORD_CRYPT_ERROR;
}
//Restrict the character set used as salt (#1488136)
$seedchars = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
for ($i = 0; $i < $len ; $i++) {
$salt .= chr(rand(ord('.'), ord('z')));
$salt .= $seedchars[rand(0, 63)];
}
$sql = str_replace('%c', $db->quote(crypt($passwd, CRYPT_MD5 ? '$1$'.$salt.'$' : $salt)), $sql);
}
@ -125,11 +130,28 @@ function password_save($curpass, $passwd)
}
}
$local_part = $rcmail->user->get_username('local');
$domain_part = $rcmail->user->get_username('domain');
$username = $_SESSION['username'];
$host = $_SESSION['imap_host'];
// convert domains to/from punnycode
if ($rcmail->config->get('password_idn_ascii')) {
$domain_part = rcube_idn_to_ascii($domain_part);
$username = rcube_idn_to_ascii($username);
$host = rcube_idn_to_ascii($host);
}
else {
$domain_part = rcube_idn_to_utf8($domain_part);
$username = rcube_idn_to_utf8($username);
$host = rcube_idn_to_utf8($host);
}
// at least we should always have the local part
$sql = str_replace('%l', $db->quote($rcmail->user->get_username('local'), 'text'), $sql);
$sql = str_replace('%d', $db->quote($rcmail->user->get_username('domain'), 'text'), $sql);
$sql = str_replace('%u', $db->quote($_SESSION['username'],'text'), $sql);
$sql = str_replace('%h', $db->quote($_SESSION['imap_host'],'text'), $sql);
$sql = str_replace('%l', $db->quote($local_part, 'text'), $sql);
$sql = str_replace('%d', $db->quote($domain_part, 'text'), $sql);
$sql = str_replace('%u', $db->quote($username, 'text'), $sql);
$sql = str_replace('%h', $db->quote($host, 'text'), $sql);
$res = $db->query($sql, $sql_vars);

@ -27,10 +27,7 @@
</stability>
<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
<notes>
- When old and new passwords are the same, do nothing, return success (#1487823)
- Fixed Samba password hashing in 'ldap' driver
- Added 'password_change' hook for plugin actions after successful password change
- Fixed bug where 'doveadm pw' command was used as dovecotpw utility
- Added option to use punycode or unicode for domain names (#1488103)
</notes>
<contents>
<dir baseinstalldir="/" name="/">
@ -264,5 +261,25 @@
- Virtualmin driver: Add option for setting username format (#1487781)
</notes>
</release>
<release>
<date>2011-10-26</date>
<time>12:00</time>
<version>
<release>2.3</release>
<api>1.6</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
<notes>
- When old and new passwords are the same, do nothing, return success (#1487823)
- Fixed Samba password hashing in 'ldap' driver
- Added 'password_change' hook for plugin actions after successful password change
- Fixed bug where 'doveadm pw' command was used as dovecotpw utility
- Improve generated crypt() passwords (#1488136)
</notes>
</release>
</changelog>
</package>

@ -223,7 +223,7 @@ class password extends rcube_plugin
{
$config = rcmail::get_instance()->config;
$driver = $this->home.'/drivers/'.$config->get('password_driver', 'sql').'.php';
if (!is_readable($driver)) {
raise_error(array(
'code' => 600,
@ -233,7 +233,7 @@ class password extends rcube_plugin
), true, false);
return $this->gettext('internalerror');
}
include($driver);
if (!function_exists('password_save')) {
@ -270,5 +270,5 @@ class password extends rcube_plugin
}
return $reason;
}
}
}

@ -1281,11 +1281,6 @@ function rcmail_build_folder_tree(&$arrFolders, $folder, $delm='/', $path='')
$path .= $prefix.$currentFolder;
if (!isset($arrFolders[$currentFolder])) {
// Check \Noselect attribute (if attributes are in cache)
if (!$virtual && ($attrs = $RCMAIL->imap->mailbox_attributes($path))) {
$virtual = in_array('\\Noselect', $attrs);
}
$arrFolders[$currentFolder] = array(
'id' => $path,
'name' => rcube_charset_convert($currentFolder, 'UTF7-IMAP'),
@ -1313,12 +1308,14 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at
$realnames = (bool)$attrib['realnames'];
$msgcounts = $RCMAIL->imap->get_cache('messagecount');
$idx = 0;
$out = '';
foreach ($arrFolders as $key => $folder) {
$title = null;
$title = null;
$folder_class = rcmail_folder_classname($folder['id']);
$collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false;
$unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0;
if (($folder_class = rcmail_folder_classname($folder['id'])) && !$realnames) {
if ($folder_class && !$realnames) {
$foldername = rcube_label($folder_class);
}
else {
@ -1338,25 +1335,12 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at
$classes = array('mailbox');
// set special class for Sent, Drafts, Trash and Junk
if ($folder['id'] == $CONFIG['sent_mbox'])
$classes[] = 'sent';
else if ($folder['id'] == $CONFIG['drafts_mbox'])
$classes[] = 'drafts';
else if ($folder['id'] == $CONFIG['trash_mbox'])
$classes[] = 'trash';
else if ($folder['id'] == $CONFIG['junk_mbox'])
$classes[] = 'junk';
else if ($folder['id'] == 'INBOX')
$classes[] = 'inbox';
else
$classes[] = '_'.asciiwords($folder_class ? $folder_class : strtolower($folder['id']), true);
if ($folder_class)
$classes[] = $folder_class;
if ($folder['id'] == $mbox_name)
$classes[] = 'selected';
$collapsed = strpos($CONFIG['collapsed_folders'], '&'.rawurlencode($folder['id']).'&') !== false;
$unread = $msgcounts ? intval($msgcounts[$folder['id']]['UNSEEN']) : 0;
if ($folder['virtual'])
$classes[] = 'virtual';
else if ($unread)
@ -1390,7 +1374,6 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at
}
$out .= "</li>\n";
$idx++;
}
return $out;

@ -678,18 +678,21 @@ class rcmail
if (session_id())
return;
$sess_name = $this->config->get('session_name');
$sess_domain = $this->config->get('session_domain');
$lifetime = $this->config->get('session_lifetime', 0) * 60;
// set session domain
if ($domain = $this->config->get('session_domain')) {
ini_set('session.cookie_domain', $domain);
if ($sess_domain) {
ini_set('session.cookie_domain', $sess_domain);
}
// set session garbage collecting time according to session_lifetime
$lifetime = $this->config->get('session_lifetime', 0) * 60;
if ($lifetime) {
ini_set('session.gc_maxlifetime', $lifetime * 2);
}
ini_set('session.cookie_secure', rcube_https_check());
ini_set('session.name', 'roundcube_sessid');
ini_set('session.name', $sess_name ? $sess_name : 'roundcube_sessid');
ini_set('session.use_cookies', 1);
ini_set('session.use_only_cookies', 1);
ini_set('session.serialize_handler', 'php');

@ -1373,6 +1373,11 @@ class rcube_imap
$this->_messagecount($mailbox, 'ALL', true);
$result = 0;
if (empty($old)) {
return $result;
}
$new = $this->get_folder_stats($mailbox);
// got new messages
@ -2999,14 +3004,14 @@ class rcube_imap
/**
* Private method for mailbox listing
* Private method for mailbox listing (LSUB)
*
* @param string $root Optional root folder
* @param string $name Optional name pattern
* @param mixed $filter Optional filter
* @param string $rights Optional ACL requirements
*
* @return array List of mailboxes/folders
* @return array List of subscribed folders
* @see rcube_imap::list_mailboxes()
* @access private
*/
@ -3109,7 +3114,7 @@ class rcube_imap
}
else {
// retrieve list of folders from IMAP server
$a_mboxes = $this->conn->listMailboxes($root, $name);
$a_mboxes = $this->_list_unsubscribed($root, $name);
}
if (!is_array($a_mboxes)) {
@ -3143,6 +3148,70 @@ class rcube_imap
}
/**
* Private method for mailbox listing (LIST)
*
* @param string $root Optional root folder
* @param string $name Optional name pattern
*
* @return array List of folders
* @see rcube_imap::list_unsubscribed()
*/
private function _list_unsubscribed($root='', $name='*')
{
$result = $this->conn->listMailboxes($root, $name);
if (!is_array($result)) {
return array();
}
// #1486796: some server configurations doesn't
// return folders in all namespaces, we'll try to detect that situation
// and ask for these namespaces separately
if ($root == '' && $name = '*') {
$delim = $this->get_hierarchy_delimiter();
$namespace = $this->get_namespace();
$search = array();
// build list of namespace prefixes
foreach ((array)$namespace as $ns) {
if (is_array($ns)) {
foreach ($ns as $ns_data) {
if (strlen($ns_data[0])) {
$search = $ns_data[0];
}
}
}
}
if (!empty($search)) {
// go through all folders detecting namespace usage
foreach ($result as $folder) {
foreach ($search as $idx => $prefix) {
if (strpos($folder, $prefix) === 0) {
unset($search[$idx]);
}
}
if (empty($search)) {
break;
}
}
// get folders in hidden namespaces and add to the result
foreach ($search as $prefix) {
$list = $this->conn->listMailboxes($prefix, $name);
if (!empty($list)) {
$result = array_merge($result, $list);
}
}
}
}
return $result;
}
/**
* Filter the given list of folders according to access rights
*/
@ -3415,8 +3484,8 @@ class rcube_imap
foreach ($this->namespace as $type => $namespace) {
if (is_array($namespace)) {
foreach ($namespace as $ns) {
if (strlen($ns[0])) {
if ((strlen($ns[0])>1 && $mailbox == substr($ns[0], 0, -1))
if ($len = strlen($ns[0])) {
if (($len > 1 && $mailbox == substr($ns[0], 0, -1))
|| strpos($mailbox, $ns[0]) === 0
) {
return $type;

@ -542,10 +542,17 @@ function rcube_clone_object(obj)
return out;
};
// make a string URL safe
// make a string URL safe (and compatible with PHP's rawurlencode())
function urlencode(str)
{
return window.encodeURIComponent ? encodeURIComponent(str) : escape(str);
if (window.encodeURIComponent)
return encodeURIComponent(str).replace('*', '%2A');
return escape(str)
.replace('+', '%2B')
.replace('*', '%2A')
.replace('/', '%2F')
.replace('@', '%40');
};

@ -54,6 +54,7 @@ else
if (!empty($book_types) && strlen($search)) {
$contacts = array();
$sort_keys = array();
$books_num = count($book_types);
$search_lc = mb_strtolower($search);
@ -66,6 +67,7 @@ if (!empty($book_types) && strlen($search)) {
// Contact can have more than one e-mail address
$email_arr = (array)$abook->get_col_values('email', $sql_arr, true);
$email_cnt = count($email_arr);
$idx = 0;
foreach ($email_arr as $email) {
if (empty($email)) {
continue;
@ -80,7 +82,9 @@ if (!empty($book_types) && strlen($search)) {
// skip duplicates
if (!in_array($contact, $contacts)) {
$contacts[] = $contact;
$contacts[] = $contact;
$sort_keys[] = sprintf('%s %03d', $sql_arr['name'] , $idx++);
if (count($contacts) >= $MAXNUM)
break 2;
}
@ -102,15 +106,20 @@ if (!empty($book_types) && strlen($search)) {
// group (distribution list) with email address(es)
if ($group_prop['email']) {
$idx = 0;
foreach ((array)$group_prop['email'] as $email) {
$contacts[] = format_email_recipient($email, $group['name']);
$contacts[] = format_email_recipient($email, $group['name']);
$sort_keys[] = sprintf('%s %03d', $group['name'] , $idx++);
if (count($contacts) >= $MAXNUM)
break 2;
}
}
// show group with count
else if (($result = $abook->count()) && $result->count) {
$contacts[] = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id);
$contacts[] = array('name' => $group['name'] . ' (' . intval($result->count) . ')', 'id' => $group['ID'], 'source' => $id);
$sort_keys[] = $group['name'];
if (count($contacts) >= $MAXNUM)
break;
}
@ -118,17 +127,16 @@ if (!empty($book_types) && strlen($search)) {
}
}
usort($contacts, 'contact_results_sort');
if (count($contacts)) {
// sort contacts index
asort($sort_keys, SORT_LOCALE_STRING);
// re-sort contacts according to index
foreach ($sort_keys as $idx => $val) {
$sort_keys[$idx] = $contacts[$idx];
}
$contacts = array_values($sort_keys);
}
}
$OUTPUT->command('ksearch_query_results', $contacts, $search, $sid);
$OUTPUT->send();
function contact_results_sort($a, $b)
{
$name_a = is_array($a) ? $a['name'] : $a;
$name_b = is_array($b) ? $b['name'] : $b;
return strcoll(trim($name_a, '" '), trim($name_b, '" '));
}

Loading…
Cancel
Save