diff options
82 files changed, 1140 insertions, 388 deletions
@@ -1,12 +1,25 @@ CHANGELOG Roundcube Webmail =========================== +- Added attachment_reminder plugin +- Fix IMAP connection issue with default_socket_timeout < 0 and imap_timeout < 0 (#1489090) +- Fix various PHP code bugs found using static analysis (#1489086) +- Fix backslash character handling on vCard import (#1489085) +- Fix csv import from Thunderbird with French localization (#1489059) +- Fix messages list focus issue in Opera and Webkit (#1489058) +- Make PHP code eval() free, use create_function() +- Add option to display email address together with a name in mail preview (#1488732) +- Fix Reply-To header handling in Reply-All action (#1489037) +- Fix so Sender: address is added to Cc: field on reply to all (#1489011) +- Fix so addressbook_search_mode works also for group search (#1489079) +- Fix removal of a contact from a group in LDAP addressbook (#1489081) +- Support CSV import from Atmail (#1489045) +- Inlcude SQL query in the log on SQL error (#1489064) - Fix handling untagged responses in IMAP FETCH - "could not load message" error (#1489074) - Fix very small window size in Chrome (#1488931) - Fix list page reset when viewing a message in Larry skin (#1489076) - Fix min_refresh_interval handling on preferences save (#1489073) - Fix PDF support detection for Firefox PDF.js (#1488972) -- Fix messages list focus issue in Internet Explorer (#1489058) - Add db_prefix configuration option in place of db_table_*/db_sequence_* options - Make possible to use db_prefix for schema initialization in Installer (#1489067) - Fix updatedb.sh script so it recognizes also table prefix for external DDL files diff --git a/bin/updatecss.sh b/bin/updatecss.sh new file mode 100755 index 000000000..c477171ff --- /dev/null +++ b/bin/updatecss.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env php +<?php +/* + +-----------------------------------------------------------------------+ + | bin/updatecss.sh | + | | + | This file is part of the Roundcube Webmail client | + | Copyright (C) 2010-2013, 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: | + | Update cache-baster marks for css background images | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ +*/ + +define('INSTALL_PATH', realpath(dirname(__FILE__) . '/..') . '/' ); + +require_once INSTALL_PATH . 'program/include/clisetup.php'; + +// get arguments +$opts = rcube_utils::get_opt(array( + 'd' => 'dir', +)); + +if (empty($opts['dir'])) { + print "Skin directory not specified (--dir). Using skins/ and plugins/skins/.\n"; + + $dir = INSTALL_PATH . 'skins'; + $dir_p = INSTALL_PATH . 'plugins'; + $skins = glob("$dir/*", GLOB_ONLYDIR); + $skins_p = glob("$dir_p/*/skins/*", GLOB_ONLYDIR); + + $dirs = array_merge($skins, $skins_p); +} +// Check if directory exists +else if (!file_exists($opts['dir'])) { + rcube::raise_error("Specified directory doesn't exist.", false, true); +} +else { + $dirs = array($opts['dir']); +} + +foreach ($dirs as $dir) { + $img_dir = $dir . '/images'; + if (!file_exists($img_dir)) { + continue; + } + + $files = get_files($dir); + $images = get_images($img_dir); + $find = array(); + $replace = array(); + + // build regexps array + foreach ($images as $path => $sum) { + $path_ex = str_replace('.', '\\.', $path); + $find[] = "#url\(['\"]?images/$path_ex(\?v=[a-f0-9-\.]+)?['\"]?\)#"; + $replace[] = "url(images/$path?v=$sum)"; + } + + foreach ($files as $file) { + $file = $dir . '/' . $file; + print "File: $file\n"; + $content = file_get_contents($file); + $content = preg_replace($find, $replace, $content, -1, $count); + if ($count) { + file_put_contents($file, $content); + } + } +} + + +function get_images($dir) +{ + $images = array(); + $dh = opendir($dir); + + while ($file = readdir($dh)) { + if (preg_match('/^(.+)\.(gif|ico|png|jpg|jpeg)$/', $file, $m)) { + $filepath = "$dir/$file"; + $images[$file] = substr(md5_file($filepath), 0, 4) . '.' . filesize($filepath); + print "Image: $filepath ({$images[$file]})\n"; + } + else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) { + foreach (get_images($dir . '/' . $file) as $img => $sum) { + $images[$file . '/' . $img] = $sum; + } + } + } + + closedir($dh); + + return $images; +} + +function get_files($dir) +{ + $files = array(); + $dh = opendir($dir); + + while ($file = readdir($dh)) { + if (preg_match('/^(.+)\.(css|html)$/', $file, $m)) { + $files[] = $file; + } + else if ($file != '.' && $file != '..' && is_dir($dir . '/' . $file)) { + foreach (get_files($dir . '/' . $file) as $f) { + $files[] = $file . '/' . $f; + } + } + } + + closedir($dh); + + return $files; +} + +?> diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 5a652a5b1..05afed9b8 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -890,4 +890,7 @@ $rcmail_config['autocomplete_single'] = false; // Georgia, Helvetica, Impact, Tahoma, Terminal, Times New Roman, Trebuchet MS, Verdana $rcmail_config['default_font'] = ''; +// Enables display of email address with name instead of a name (and address in title) +$rcmail_config['message_show_email'] = false; + // end of config file diff --git a/installer/rcube_install.php b/installer/rcube_install.php index 32b6a5dd7..e7da54c2c 100644 --- a/installer/rcube_install.php +++ b/installer/rcube_install.php @@ -347,7 +347,7 @@ class rcube_install $this->config = array_merge($this->config, $current); - foreach ((array)$current['ldap_public'] as $key => $values) { + foreach (array_keys((array)$current['ldap_public']) as $key) { $this->config['ldap_public'][$key] = $current['ldap_public'][$key]; } } @@ -356,10 +356,11 @@ class rcube_install * Compare the local database schema with the reference schema * required for this version of Roundcube * - * @param boolean True if the schema schould be updated + * @param rcube_db Database object + * * @return boolean True if the schema is up-to-date, false if not or an error occured */ - function db_schema_check($DB, $update = false) + function db_schema_check($DB) { if (!$this->configured) return false; @@ -583,7 +584,7 @@ class rcube_install } else { // check if all keys are numeric $isnum = true; - foreach ($var as $key => $value) { + foreach (array_keys($var) as $key) { if (!is_numeric($key)) { $isnum = false; break; diff --git a/plugins/acl/acl.php b/plugins/acl/acl.php index 938287b1a..28139e92c 100644 --- a/plugins/acl/acl.php +++ b/plugins/acl/acl.php @@ -384,7 +384,6 @@ class acl extends rcube_plugin $table->add_header(array('class' => 'acl'.$key, 'title' => $label), $label); } - $i = 1; $js_table = array(); foreach ($acl as $user => $rights) { if ($this->rc->storage->conn->user == $user) { @@ -433,8 +432,9 @@ class acl extends rcube_plugin $acl = trim(rcube_utils::get_input_value('_acl', rcube_utils::INPUT_GPC)); $oldid = trim(rcube_utils::get_input_value('_old', rcube_utils::INPUT_GPC)); - $acl = array_intersect(str_split($acl), $this->rights_supported()); - $users = $oldid ? array($user) : explode(',', $user); + $acl = array_intersect(str_split($acl), $this->rights_supported()); + $users = $oldid ? array($user) : explode(',', $user); + $result = 0; foreach ($users as $user) { $user = trim($user); diff --git a/plugins/attachment_reminder/attachment_reminder.js b/plugins/attachment_reminder/attachment_reminder.js new file mode 100755 index 000000000..a4f3e6325 --- /dev/null +++ b/plugins/attachment_reminder/attachment_reminder.js @@ -0,0 +1,51 @@ +/* Attachment Reminder plugin script */ + +function rcmail_get_compose_message() +{ + var msg; + + if (window.tinyMCE && (ed = tinyMCE.get(rcmail.env.composebody))) { + msg = ed.getContent(); + msg = msg.replace(/<blockquote[^>]*>(.|[\r\n])*<\/blockquote>/gmi, ''); + } + else { + msg = $('#' + rcmail.env.composebody).val(); + msg = msg.replace(/^>.*$/gmi, ''); + } + + return msg; +} + +function rcmail_check_message(msg) +{ + var i, rx, keywords = rcmail.gettext('keywords', 'attachment_reminder').split(",").concat([".doc", ".pdf"]); + + $.each(keywords, function(n) { return RegExp.escape(n); }); + rx = new RegExp('(' + keywords.join('|') + ')', 'i'); + + return msg.search(rx) != -1; +} + +function rcmail_have_attachments() +{ + return rcmail.env.attachments && $('li', rcmail.gui_objects.attachmentlist).length; +} + + +if (window.rcmail) { + rcmail.addEventListener('beforesend', function(evt) { + var msg = rcmail_get_compose_message(), + subject = $('#compose-subject').val(); + + if (!rcmail_have_attachments() && (rcmail_check_message(msg) || rcmail_check_message(subject))) { + if (confirm(rcmail.gettext('forgotattachment', 'attachment_reminder'))) { + if (window.UI && UI.show_uploadform) // Larry skin + UI.show_uploadform(); + else if (window.rcmail_ui && rcmail_ui.show_popup) // classic skin + rcmail_ui.show_popup('uploadmenu', true); + + return false; + } + } + }); +} diff --git a/plugins/attachment_reminder/attachment_reminder.php b/plugins/attachment_reminder/attachment_reminder.php new file mode 100755 index 000000000..0a2597329 --- /dev/null +++ b/plugins/attachment_reminder/attachment_reminder.php @@ -0,0 +1,81 @@ +<?php +/** + * Attachement Reminder + * + * A plugin that reminds a user to attach the files + * + * @version @package_version@ + * @author Thomas Yu - Sian, Liu + * @author Aleksander Machniak <machniak@kolabsys.com> + * + * Copyright (C) 2013 Thomas Yu - Sian, Liu + * Copyright (C) 2013, Kolab Systems AG + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/> + */ + +class attachment_reminder extends rcube_plugin +{ + public $task = 'mail|settings'; + public $noajax = true; + + + function init() + { + $rcmail = rcube::get_instance(); + + if ($rcmail->task == 'mail' && $rcmail->action == 'compose') { + $this->include_script('attachment_reminder.js'); + $this->add_texts('localization/', array('keywords', 'forgotattachment')); + } + + if ($rcmail->task == 'settings') { + $dont_override = $rcmail->config->get('dont_override', array()); + + if (!in_array('attachment_reminder', $dont_override)) { + $this->add_hook('preferences_list', array($this, 'prefs_list')); + $this->add_hook('preferences_save', array($this, 'prefs_save')); + } + } + } + + function prefs_list($args) + { + if ($args['section'] == 'compose') { + $this->add_texts('localization/'); + $reminder = rcube::get_instance()->config->get('attachment_reminder'); + $field_id = 'rcmfd_attachment_reminder'; + $checkbox = new html_checkbox(array('name' => '_attachment_reminder', 'id' => $field_id, 'value' => 1)); + + $args['blocks']['main']['options']['attachment_reminder'] = array( + 'title' => html::label($field_id, rcube::Q($this->gettext('reminderoption'))), + 'content' => $checkbox->show($reminder ? 1 : 0), + ); + } + + return $args; + } + + function prefs_save($args) + { + if ($args['section'] == 'compose') { + $dont_override = rcube::get_instance()->config->get('dont_override', array()); + if (!in_array('attachment_reminder', $dont_override)) { + $args['prefs']['attachment_reminder'] = !empty($_POST['_attachment_reminder']); + } + } + return $args; + } + +} diff --git a/plugins/attachment_reminder/localization/de_CH.inc b/plugins/attachment_reminder/localization/de_CH.inc new file mode 100644 index 000000000..bf6eef721 --- /dev/null +++ b/plugins/attachment_reminder/localization/de_CH.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Haben Sie möglicherweise vergessen eine Datei anzuhängen?"; +$messages['keywords'] = "anbei,im anhang,angehängt,angefügt,beigefügt,beliegend"; diff --git a/plugins/attachment_reminder/localization/de_DE.inc b/plugins/attachment_reminder/localization/de_DE.inc new file mode 100644 index 000000000..bf6eef721 --- /dev/null +++ b/plugins/attachment_reminder/localization/de_DE.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Haben Sie möglicherweise vergessen eine Datei anzuhängen?"; +$messages['keywords'] = "anbei,im anhang,angehängt,angefügt,beigefügt,beliegend"; diff --git a/plugins/attachment_reminder/localization/en_US.inc b/plugins/attachment_reminder/localization/en_US.inc new file mode 100644 index 000000000..a736682db --- /dev/null +++ b/plugins/attachment_reminder/localization/en_US.inc @@ -0,0 +1,6 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Did you forget to attach a file?"; +$messages['reminderoption'] = "Remind about forgotten attachments"; +$messages['keywords'] = "attachment,file,attach,attached,attaching,enclosed,CV,cover letter"; diff --git a/plugins/attachment_reminder/localization/es_ES.inc b/plugins/attachment_reminder/localization/es_ES.inc new file mode 100644 index 000000000..8e3512182 --- /dev/null +++ b/plugins/attachment_reminder/localization/es_ES.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "¿Olvidó adjuntar un fichero al mensaje?"; +$messages['keywords'] = "adjunto"; diff --git a/plugins/attachment_reminder/localization/fr_FR.inc b/plugins/attachment_reminder/localization/fr_FR.inc new file mode 100644 index 000000000..ab48cc517 --- /dev/null +++ b/plugins/attachment_reminder/localization/fr_FR.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Avez vous oublié d'attacher un fichier ?"; +$messages['keywords'] = "joins,joint,attaché,CV";
\ No newline at end of file diff --git a/plugins/attachment_reminder/localization/it_IT.inc b/plugins/attachment_reminder/localization/it_IT.inc new file mode 100644 index 000000000..2807bc185 --- /dev/null +++ b/plugins/attachment_reminder/localization/it_IT.inc @@ -0,0 +1,6 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Sembra che tu abbia dimenticato di allegare un file!\nPremere Annulla per inviare lo stesso.\nOK per tornare al messaggio senza inviare."; +$messages['keywords'] = "allegato,allegati,allegata,allegate,allega,allego,alleghi,attaccato,file,attachment,attach"; + diff --git a/plugins/attachment_reminder/localization/nl_NL.inc b/plugins/attachment_reminder/localization/nl_NL.inc new file mode 100644 index 000000000..62564f103 --- /dev/null +++ b/plugins/attachment_reminder/localization/nl_NL.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Ben je vergeten het bestand bij te voegen?"; +$messages['keywords'] = "attachment,bestand,bijgaand,bijgaande,brief,bijgevoegd,bijgesloten,CV"; diff --git a/plugins/attachment_reminder/localization/pl_PL.inc b/plugins/attachment_reminder/localization/pl_PL.inc new file mode 100644 index 000000000..96f4f4989 --- /dev/null +++ b/plugins/attachment_reminder/localization/pl_PL.inc @@ -0,0 +1,6 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "Czy nie zapomniałeś załączyć pliku?"; +$messages['reminderoption'] = "Włącz przypominanie o brakującym załączniku"; +$messages['keywords'] = "załącznik,plik,załącz,CV"; diff --git a/plugins/attachment_reminder/localization/zh_CN.inc b/plugins/attachment_reminder/localization/zh_CN.inc new file mode 100644 index 000000000..27cf04b25 --- /dev/null +++ b/plugins/attachment_reminder/localization/zh_CN.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "您似乎忘記加入附件了,你確定要寄出?"; +$messages['keywords'] = "附件,附加,附檔,附上,附加檔案"; diff --git a/plugins/attachment_reminder/localization/zh_TW.inc b/plugins/attachment_reminder/localization/zh_TW.inc new file mode 100644 index 000000000..27cf04b25 --- /dev/null +++ b/plugins/attachment_reminder/localization/zh_TW.inc @@ -0,0 +1,5 @@ +<?php + +$messages = array(); +$messages['forgotattachment'] = "您似乎忘記加入附件了,你確定要寄出?"; +$messages['keywords'] = "附件,附加,附檔,附上,附加檔案"; diff --git a/plugins/attachment_reminder/package.xml b/plugins/attachment_reminder/package.xml new file mode 100644 index 000000000..43861182e --- /dev/null +++ b/plugins/attachment_reminder/package.xml @@ -0,0 +1,66 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 + http://pear.php.net/dtd/tasks-1.0.xsd + http://pear.php.net/dtd/package-2.0 + http://pear.php.net/dtd/package-2.0.xsd"> + <name>Attachment Reminder</name> + <summary>Roundcube plugin that prompts you if it looks like you wanted to attach a file but you didn't.</summary> + <description> + This Roundcube plugin reminds the user to attach a file if the composed message text indicates that there should be any. + </description> + <lead> + <name>Aleksander Machniak</name> + <user>alec</user> + <email>alec@alec.pl</email> + <active>yes</active> + </lead> + <lead> + <name>Thomas Yu - Sian , Liu</name> + <active>yes</active> + </lead> + <version> + <release>1.1</release> + <api>1.0</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl.html">GNU GPLv3+</license> + <notes>-</notes> + <contents> + <dir baseinstalldir="/" name="/"> + <file name="attachment_reminder.php" role="php"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + <file name="attachment_reminder.js" role="data"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + + <file name="localization/de_CH.inc" role="data"></file> + <file name="localization/de_DE.inc" role="data"></file> + <file name="localization/en_US.inc" role="data"></file> + <file name="localization/es_ES.inc" role="data"></file> + <file name="localization/fr_FR.inc" role="data"></file> + <file name="localization/it_IT.inc" role="data"></file> + <file name="localization/nl_NL.inc" role="data"></file> + <file name="localization/pl_PL.inc" role="data"></file> + <file name="localization/zh_CN.inc" role="data"></file> + <file name="localization/zh_TW.inc" role="data"></file> + </dir> + <!-- / --> + </contents> + <dependencies> + <required> + <php> + <min>5.2.1</min> + </php> + <pearinstaller> + <min>1.7.0</min> + </pearinstaller> + </required> + </dependencies> + <phprelease/> +</package> diff --git a/plugins/autologon/autologon.php b/plugins/autologon/autologon.php index 63ffb943e..9c7d5b6fc 100644 --- a/plugins/autologon/autologon.php +++ b/plugins/autologon/autologon.php @@ -19,8 +19,6 @@ class autologon extends rcube_plugin function startup($args) { - $rcmail = rcmail::get_instance(); - // change action to login if (empty($_SESSION['user_id']) && !empty($_GET['_autologin']) && $this->is_localhost()) $args['action'] = 'login'; @@ -37,7 +35,7 @@ class autologon extends rcube_plugin $args['cookiecheck'] = false; $args['valid'] = true; } - + return $args; } diff --git a/plugins/debug_logger/runlog/runlog.php b/plugins/debug_logger/runlog/runlog.php index c9f672615..0c766a13c 100644 --- a/plugins/debug_logger/runlog/runlog.php +++ b/plugins/debug_logger/runlog/runlog.php @@ -194,7 +194,7 @@ class runlog { public function print_totals(){ $totals = array(); - foreach ( $this->run_log as $k => $entry ) { + foreach ($this->run_log as $entry) { if ( $entry['type'] == 'start' && $entry['ended'] == true) { $totals[$entry['value']]['duration'] += $entry['duration']; $totals[$entry['value']]['count'] += 1; diff --git a/plugins/enigma/enigma.php b/plugins/enigma/enigma.php index c96b94620..25520a27d 100644 --- a/plugins/enigma/enigma.php +++ b/plugins/enigma/enigma.php @@ -47,6 +47,8 @@ class enigma extends rcube_plugin $rcmail = rcmail::get_instance(); $this->rc = $rcmail; + $section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET); + if ($this->rc->task == 'mail') { // message parse/display hooks $this->add_hook('message_part_structure', array($this, 'parse_structure')); @@ -79,7 +81,6 @@ class enigma extends rcube_plugin $this->register_action('plugin.enigma', array($this, 'preferences_ui')); // grab keys/certs management iframe requests - $section = rcube_utils::get_input_value('_section', rcube_utils::INPUT_GET); if ($this->rc->action == 'edit-prefs' && preg_match('/^enigma(certs|keys)/', $section)) { $this->load_ui(); $this->ui->init($section); @@ -148,7 +149,7 @@ class enigma extends rcube_plugin */ function parse_structure($p) { - $struct = $p['structure']; +// $struct = $p['structure']; if ($p['mimetype'] == 'text/plain' || $p['mimetype'] == 'application/pgp') { $this->parse_plain($p); @@ -390,7 +391,7 @@ class enigma extends rcube_plugin function message_load($p) { $this->message = $p['object']; - + // handle attachments vcard attachments foreach ((array)$this->message->attachments as $attachment) { if ($this->is_keys_part($attachment)) { @@ -398,7 +399,7 @@ class enigma extends rcube_plugin } } // the same with message bodies - foreach ((array)$this->message->parts as $idx => $part) { + foreach ((array)$this->message->parts as $part) { if ($this->is_keys_part($part)) { $this->keys_parts[] = $part->mime_id; $this->keys_bodies[] = $part->mime_id; diff --git a/plugins/enigma/lib/enigma_engine.php b/plugins/enigma/lib/enigma_engine.php index 220d6c0b3..8a64c07ff 100644 --- a/plugins/enigma/lib/enigma_engine.php +++ b/plugins/enigma/lib/enigma_engine.php @@ -374,17 +374,15 @@ class enigma_engine { // @TODO: Handle big bodies using (temp) files // @TODO: caching of verification result - - $sig = $this->pgp_driver->verify($msg_body, $sig_body); + $sig = $this->pgp_driver->verify($msg_body, $sig_body); - if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) - rcube::raise_error(array( + if (($sig instanceof enigma_error) && $sig->getCode() != enigma_error::E_KEYNOTFOUND) + rcube::raise_error(array( 'code' => 600, 'type' => 'php', 'file' => __FILE__, 'line' => __LINE__, - 'message' => "Enigma plugin: " . $error->getMessage() + 'message' => "Enigma plugin: " . $sig->getMessage() ), true, false); -//print_r($sig); return $sig; } @@ -399,11 +397,9 @@ class enigma_engine { // @TODO: Handle big bodies using (temp) files // @TODO: caching of verification result - + $key = ''; $pass = ''; // @TODO $result = $this->pgp_driver->decrypt($msg_body, $key, $pass); -//print_r($result); - if ($result instanceof enigma_error) { $err_code = $result->getCode(); if (!in_array($err_code, array(enigma_error::E_KEYNOTFOUND, enigma_error::E_BADPASS))) @@ -430,7 +426,7 @@ class enigma_engine { $this->load_pgp_driver(); $result = $this->pgp_driver->list_keys($pattern); - + if ($result instanceof enigma_error) { rcube::raise_error(array( 'code' => 600, 'type' => 'php', @@ -438,7 +434,7 @@ class enigma_engine 'message' => "Enigma plugin: " . $result->getMessage() ), true, false); } - + return $result; } @@ -501,9 +497,11 @@ class enigma_engine $uid = rcube_utils::get_input_value('_uid', rcube_utils::INPUT_POST); $mbox = rcube_utils::get_input_value('_mbox', rcube_utils::INPUT_POST); $mime_id = rcube_utils::get_input_value('_part', rcube_utils::INPUT_POST); + $storage = $this->rc->get_storage(); if ($uid && $mime_id) { - $part = $this->rc->storage->get_message_part($uid, $mime_id); + $storage->set_folder($mbox); + $part = $storage->get_message_part($uid, $mime_id); } if ($part && is_array($result = $this->import_key($part))) { @@ -532,16 +530,4 @@ class enigma_engine $uid, $part->mime_id, $part); } } - - /** - * Adds CSS style file to the page header. - */ - private function add_css() - { - $skin = $this->rc->config->get('skin'); - if (!file_exists($this->home . "/skins/$skin/enigma.css")) - $skin = 'default'; - - $this->include_stylesheet("skins/$skin/enigma.css"); - } } diff --git a/plugins/enigma/lib/enigma_ui.php b/plugins/enigma/lib/enigma_ui.php index 47366b7e8..adb619d0c 100644 --- a/plugins/enigma/lib/enigma_ui.php +++ b/plugins/enigma/lib/enigma_ui.php @@ -176,8 +176,7 @@ class enigma_ui $search = rcube_utils::get_input_value('_q', rcube_utils::INPUT_GPC); // define list of cols to be displayed - $a_show_cols = array('name'); - $result = array(); +// $a_show_cols = array('name'); // Get the list $list = $this->enigma->engine->list_keys($search); @@ -200,7 +199,7 @@ class enigma_ui $size = count($list); // Add rows - foreach($list as $idx => $key) { + foreach ($list as $key) { $this->rc->output->command('enigma_add_list_row', array('name' => rcube::Q($key->name), 'id' => $key->id)); } diff --git a/plugins/help/help.php b/plugins/help/help.php index 4b11dceb3..69da6828e 100644 --- a/plugins/help/help.php +++ b/plugins/help/help.php @@ -21,8 +21,6 @@ class help extends rcube_plugin function init() { - $rcmail = rcmail::get_instance(); - $this->add_texts('localization/', false); // register task diff --git a/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php b/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php index 80f590f4b..0e95b0fba 100644 --- a/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php +++ b/plugins/managesieve/lib/Roundcube/rcube_sieve_script.php @@ -206,7 +206,6 @@ class rcube_sieve_script // rules foreach ($this->content as $rule) { - $extension = ''; $script = ''; $tests = array(); $i = 0; @@ -1015,11 +1014,10 @@ class rcube_sieve_script * @param mixed $num Number of tokens to return, 0 for all * or True for all tokens until separator is found. * Separator will be returned as last token. - * @param int $in_list Enable to call recursively inside a list * * @return mixed Tokens array or string if $num=1 */ - static function tokenize(&$str, $num=0, $in_list=false) + static function tokenize(&$str, $num=0) { $result = array(); @@ -1054,7 +1052,7 @@ class rcube_sieve_script // Parenthesized list case '[': $str = substr($str, 1); - $result[] = self::tokenize($str, 0, true); + $result[] = self::tokenize($str, 0); break; case ']': $str = substr($str, 1); diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index 817fa8650..fc2a79ddb 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -1640,7 +1640,7 @@ class managesieve extends rcube_plugin .'value="' . rcube::Q($action['value']) . '" size="35" ' . $this->error_class($id, 'action', 'value', 'action_varvalue') .' />'; $out .= '<br /><span class="label">' .rcube::Q($this->gettext('setvarmodifiers')) . '</span><br />'; - foreach ($set_modifiers as $j => $s_m) { + foreach ($set_modifiers as $s_m) { $s_m_id = 'action_varmods' . $id . $s_m; $out .= sprintf('<input type="checkbox" name="_action_varmods[%s][]" value="%s" id="%s"%s />%s<br>', $id, $s_m, $s_m_id, @@ -1902,7 +1902,7 @@ class managesieve extends rcube_plugin $user_script = $_SESSION['managesieve_user_script']; // if the script is not active... - if ($user_script && ($key = array_search($name, $this->active)) === false) { + if ($user_script && array_search($name, $this->active) === false) { // ...rewrite USER file adding appropriate include command if ($this->sieve->load($user_script)) { $script = $this->sieve->script->as_array(); @@ -1920,7 +1920,7 @@ class managesieve extends rcube_plugin // get all active scripts for sorting foreach ($script as $rid => $rules) { - foreach ($rules['actions'] as $aid => $action) { + foreach ($rules['actions'] as $action) { if ($action['type'] == 'include' && empty($action['global'])) { $target = $extension ? preg_replace($regexp, '', $action['target']) : $action['target']; $list[] = $target; @@ -1988,7 +1988,7 @@ class managesieve extends rcube_plugin $name = $name.$extension; foreach ($script as $rid => $rules) { - foreach ($rules['actions'] as $aid => $action) { + foreach ($rules['actions'] as $action) { if ($action['type'] == 'include' && empty($action['global']) && $action['target'] == $name ) { diff --git a/plugins/new_user_identity/new_user_identity.php b/plugins/new_user_identity/new_user_identity.php index f98145b6c..d32051e00 100644 --- a/plugins/new_user_identity/new_user_identity.php +++ b/plugins/new_user_identity/new_user_identity.php @@ -33,8 +33,6 @@ class new_user_identity extends rcube_plugin function lookup_user_name($args) { - $rcmail = rcmail::get_instance(); - if ($this->init_ldap($args['host'])) { $results = $this->ldap->search('*', $args['user'], true); if (count($results->records) == 1) { diff --git a/plugins/password/drivers/directadmin.php b/plugins/password/drivers/directadmin.php index 8bf0dc613..44ecea406 100644 --- a/plugins/password/drivers/directadmin.php +++ b/plugins/password/drivers/directadmin.php @@ -297,7 +297,6 @@ class HTTPSocket { $status = socket_get_status($socket); $startTime = time(); $length = 0; - $prevSecond = 0; while ( !feof($socket) && !$status['timed_out'] ) { $chunk = fgets($socket,1024); diff --git a/plugins/password/drivers/pam.php b/plugins/password/drivers/pam.php index 8cd94c737..4d0ba1656 100644 --- a/plugins/password/drivers/pam.php +++ b/plugins/password/drivers/pam.php @@ -11,7 +11,8 @@ class rcube_pam_password { function save($currpass, $newpass) { - $user = $_SESSION['username']; + $user = $_SESSION['username']; + $error = ''; if (extension_loaded('pam') || extension_loaded('pam_auth')) { if (pam_auth($user, $currpass, $error, false)) { diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php index e02bff146..7a51dfe44 100644 --- a/plugins/password/drivers/sql.php +++ b/plugins/password/drivers/sql.php @@ -34,8 +34,9 @@ class rcube_sql_password $db = $rcmail->get_dbh(); } - if ($err = $db->is_error()) + if ($db->is_error()) { return PASSWORD_ERROR; + } // crypted password if (strpos($sql, '%c') !== FALSE) { @@ -183,8 +184,8 @@ class rcube_sql_password $res = $db->query($sql, $sql_vars); if (!$db->is_error()) { - if (strtolower(substr(trim($query),0,6))=='select') { - if ($result = $db->fetch_array($res)) + if (strtolower(substr(trim($sql),0,6)) == 'select') { + if ($db->fetch_array($res)) return PASSWORD_SUCCESS; } else { // This is the good case: 1 row updated diff --git a/plugins/password/drivers/xmail.php b/plugins/password/drivers/xmail.php index 37abc3001..59e467c5b 100644 --- a/plugins/password/drivers/xmail.php +++ b/plugins/password/drivers/xmail.php @@ -67,7 +67,7 @@ class XMail { function send($msg) { socket_write($this->socket,$msg); - if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { + if (substr(socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { return false; } return true; @@ -85,7 +85,7 @@ class XMail { return false; } - if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { + if (substr(socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { socket_close($this->socket); return false; } diff --git a/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php b/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php index d5d0d47ec..e882a2f37 100644 --- a/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php +++ b/plugins/squirrelmail_usercopy/squirrelmail_usercopy.php @@ -63,7 +63,7 @@ class squirrelmail_usercopy extends rcube_plugin if ($this->prefs['___sig'.$i.'___']) $ident_data['signature'] = $this->prefs['___sig'.$i.'___']; // insert identity - $identid = $rcmail->user->insert_identity($ident_data); + $rcmail->user->insert_identity($ident_data); } } diff --git a/plugins/vcard_attachments/vcard_attachments.php b/plugins/vcard_attachments/vcard_attachments.php index 4905b373e..cf7e22d3a 100644 --- a/plugins/vcard_attachments/vcard_attachments.php +++ b/plugins/vcard_attachments/vcard_attachments.php @@ -45,7 +45,7 @@ class vcard_attachments extends rcube_plugin } } // the same with message bodies - foreach ((array)$this->message->parts as $idx => $part) { + foreach ((array)$this->message->parts as $part) { if ($this->is_vcard($part)) { $this->vcard_parts[] = $part->mime_id; $this->vcard_bodies[] = $part->mime_id; @@ -63,7 +63,6 @@ class vcard_attachments extends rcube_plugin function html_output($p) { $attach_script = false; - $icon = 'plugins/vcard_attachments/' .$this->local_skin_path(). '/vcard_add_contact.png'; foreach ($this->vcard_parts as $part) { $vcards = rcube_vcard::import($this->message->get_part_content($part, null, true)); diff --git a/plugins/zipdownload/zipdownload.php b/plugins/zipdownload/zipdownload.php index 7e132bfbb..fbf1d2342 100644 --- a/plugins/zipdownload/zipdownload.php +++ b/plugins/zipdownload/zipdownload.php @@ -169,7 +169,7 @@ class zipdownload extends rcube_plugin for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) { $a_headers = $imap->list_messages($mbox_name, ($i + 1)); - foreach ($a_headers as $n => $header) { + foreach ($a_headers as $header) { if (empty($header)) continue; @@ -199,7 +199,7 @@ class zipdownload extends rcube_plugin $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); - foreach ($uids as $key => $uid){ + foreach ($uids as $uid){ $headers = $imap->get_message_headers($uid); $subject = rcube_mime::decode_mime_string((string)$headers->subject); $subject = $this->_convert_filename($subject); diff --git a/program/include/bc.php b/program/include/bc.php index df018320c..0ddfb3215 100644 --- a/program/include/bc.php +++ b/program/include/bc.php @@ -62,7 +62,7 @@ function rcmail_url($action, $p=array(), $task=null) function rcmail_temp_gc() { - $rcmail = rcmail::get_instance()->temp_gc(); + rcmail::get_instance()->temp_gc(); } function rcube_charset_convert($str, $from, $to=NULL) diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 7acb3490d..c16257d50 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -596,7 +596,7 @@ class rcmail extends rcube $post_host = rcube_utils::get_input_value('_host', rcube_utils::INPUT_POST); $post_user = rcube_utils::get_input_value('_user', rcube_utils::INPUT_POST); - list($user, $domain) = explode('@', $post_user); + list(, $domain) = explode('@', $post_user); // direct match in default_host array if ($default_host[$post_host] || in_array($post_host, array_values($default_host))) { @@ -700,28 +700,6 @@ class rcmail extends rcube /** - * Create unique authorization hash - * - * @param string Session ID - * @param int Timestamp - * @return string The generated auth hash - */ - private function get_auth_hash($sess_id, $ts) - { - $auth_string = sprintf('rcmail*sess%sR%s*Chk:%s;%s', - $sess_id, - $ts, - $this->config->get('ip_check') ? $_SERVER['REMOTE_ADDR'] : '***.***.***.***', - $_SERVER['HTTP_USER_AGENT']); - - if (function_exists('sha1')) - return sha1($auth_string); - else - return md5($auth_string); - } - - - /** * Build a valid URL to this instance of Roundcube * * @param mixed Either a string with the action or url parameters as key-value pairs @@ -1167,7 +1145,7 @@ class rcmail extends rcube */ public function table_output($attrib, $table_data, $a_show_cols, $id_col) { - $table = new html_table(/*array('cols' => count($a_show_cols))*/); + $table = new html_table($attrib); // add table header if (!$attrib['noheader']) { @@ -1532,7 +1510,7 @@ class rcmail extends rcube $collapsed = $this->config->get('collapsed_folders'); $out = ''; - foreach ($arrFolders as $key => $folder) { + foreach ($arrFolders as $folder) { $title = null; $folder_class = $this->folder_classname($folder['id']); $is_collapsed = strpos($collapsed, '&'.rawurlencode($folder['id']).'&') !== false; @@ -1618,7 +1596,7 @@ class rcmail extends rcube { $out = ''; - foreach ($arrFolders as $key => $folder) { + foreach ($arrFolders as $folder) { // skip exceptions (and its subfolders) if (!empty($opts['exceptions']) && in_array($folder['id'], $opts['exceptions'])) { continue; diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index d8996edbf..02eef2fd1 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -731,14 +731,13 @@ class rcmail_output_html extends rcmail_output /** * 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).");"); + return $this->eval_expression($condition); } @@ -760,14 +759,15 @@ class rcmail_output_html extends rcmail_output /** - * Parses expression and replaces variables + * Parse & evaluate a given expression and return its result. * - * @param string Expression statement - * @return string Expression value + * @param string Expression statement + * + * @return mixed Expression result */ - protected function parse_expression($expression) + protected function eval_expression ($expression) { - return preg_replace( + $expression = preg_replace( array( '/session:([a-z0-9_]+)/i', '/config:([a-z0-9_]+)(:([a-z0-9_]+))?/i', @@ -779,14 +779,29 @@ class rcmail_output_html extends rcmail_output ), array( "\$_SESSION['\\1']", - "\$this->app->config->get('\\1',rcube_utils::get_boolean('\\3'))", - "\$this->env['\\1']", + "\$app->config->get('\\1',rcube_utils::get_boolean('\\3'))", + "\$env['\\1']", "rcube_utils::get_input_value('\\1', rcube_utils::INPUT_GPC)", "\$_COOKIE['\\1']", - "\$this->browser->{'\\1'}", + "\$browser->{'\\1'}", $this->template_name, ), - $expression); + $expression + ); + + $fn = create_function('$app,$browser,$env', "return ($expression);"); + if (!$fn) { + rcube::raise_error(array( + 'code' => 505, + 'type' => 'php', + 'file' => __FILE__, + 'line' => __LINE__, + 'message' => "Expression parse error on: ($expression)"), true, false); + + return null; + } + + return $fn($this->app, $this->browser, $this->env); } @@ -839,7 +854,7 @@ class rcmail_output_html extends rcmail_output // show a label case 'label': if ($attrib['expression']) - $attrib['name'] = eval("return " . $this->parse_expression($attrib['expression']) .";"); + $attrib['name'] = $this->eval_expression($attrib['expression']); if ($attrib['name'] || $attrib['command']) { // @FIXME: 'noshow' is useless, remove? @@ -971,8 +986,7 @@ class rcmail_output_html extends rcmail_output // return code for a specified eval expression case 'exp': - $value = $this->parse_expression($attrib['expression']); - return eval("return html::quote($value);"); + return html::quote($this->eval_expression($attrib['expression'])); // return variable case 'var': diff --git a/program/js/app.js b/program/js/app.js index 474a1b8c3..af09572ff 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -936,16 +936,13 @@ function rcube_webmail() url._to = props; } else { - // use contact_id passed as command parameter - var n, len, a_cids = []; + var a_cids = []; + // use contact id passed as command parameter if (props) a_cids.push(props); // get selected contacts - else if (this.contact_list) { - var selection = this.contact_list.get_selection(); - for (n=0, len=selection.length; n<len; n++) - a_cids.push(selection[n]); - } + else if (this.contact_list) + a_cids = this.contact_list.get_selection(); if (a_cids.length) this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source }, true); @@ -1582,7 +1579,7 @@ function rcube_webmail() this.msglist_set_coltypes = function(list) { - var i, found, name, cols = list.list.tHead.rows[0].cells; + var i, found, name, cols = list.thead.rows[0].cells; this.env.coltypes = []; @@ -1632,13 +1629,17 @@ function rcube_webmail() this.open_window = function(url, width, height) { - var w = Math.min(width, screen.width - 10), - h = Math.min(height, screen.height - 100), - l = (screen.width - w) / 2 + (screen.left || 0), - t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20), + var dh = (window.outerHeight || 0) - (window.innerHeight || 0), + dw = (window.outerWidth || 0) - (window.innerWidth || 0), + sh = screen.availHeight || screen.height, + sw = screen.availWidth || screen.width, + w = Math.min(width, sw), + h = Math.min(height, sh), + l = Math.max(0, (sw - w) / 2 + (screen.left || 0)), + t = Math.max(0, (sh - h) / 2 + (screen.top || 0)), wname = 'rcmextwin' + new Date().getTime(), extwin = window.open(url + (url.match(/\?/) ? '&' : '?') + '_extwin=1', wname, - 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no'); + 'width='+(w-dw)+',height='+(h-dh)+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no,location=no'); // write loading... message to empty windows if (!url && extwin.document) { @@ -1732,10 +1733,7 @@ function rcube_webmail() + (flags.flagged ? ' flagged' : '') + (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '') + (message.selected ? ' selected' : ''), - // for performance use DOM instead of jQuery here - row = document.createElement('tr'); - - row.id = 'rcmrow'+uid; + row = { cols:[], style:{}, id:'rcmrow'+uid }; // message status icons css_class = 'msgicon'; @@ -1799,8 +1797,7 @@ function rcube_webmail() // add each submitted col for (n in this.env.coltypes) { c = this.env.coltypes[n]; - col = document.createElement('td'); - col.className = String(c).toLowerCase(); + col = { className: String(c).toLowerCase() }; if (c == 'flag') { css_class = (flags.flagged ? 'flagged' : 'unflagged'); @@ -1845,8 +1842,7 @@ function rcube_webmail() html = cols[c]; col.innerHTML = html; - - row.appendChild(col); + row.cols.push(col); } list.insert_row(row, attop); @@ -2209,7 +2205,7 @@ function rcube_webmail() if (root) row = rows[root] ? rows[root].obj : null; else - row = this.message_list.list.tBodies[0].firstChild; + row = this.message_list.tbody.firstChild; while (row) { if (row.nodeType == 1 && (r = rows[row.uid])) { @@ -2385,7 +2381,7 @@ function rcube_webmail() this.delete_excessive_thread_rows = function() { var rows = this.message_list.rows, - tbody = this.message_list.list.tBodies[0], + tbody = this.message_list.tbody, row = tbody.firstChild, cnt = this.env.pagesize + 1; @@ -4328,21 +4324,7 @@ function rcube_webmail() newcid = newcid+'-'+source; } - if (list.rows[cid] && (row = list.rows[cid].obj)) { - for (c=0; c<cols_arr.length; c++) - if (row.cells[c]) - $(row.cells[c]).html(cols_arr[c]); - - // cid change - if (newcid) { - newcid = this.html_identifier(newcid); - row.id = 'rcmrow' + newcid; - list.remove_row(cid); - list.init_row(row); - list.selection[0] = newcid; - row.style.display = ''; - } - } + list.update_row(cid, cols_arr, newcid, true); }; // add row to contacts list @@ -4352,7 +4334,7 @@ function rcube_webmail() return false; var c, col, list = this.contact_list, - row = document.createElement('tr'); + row = { cols:[] }; row.id = 'rcmrow'+this.html_identifier(cid); row.className = 'contact ' + (classes || ''); @@ -4362,10 +4344,10 @@ function rcube_webmail() // add each submitted col for (c in cols) { - col = document.createElement('td'); + col = {}; col.className = String(c).toLowerCase(); col.innerHTML = cols[c]; - row.appendChild(col); + row.cols.push(col); } list.insert_row(row); @@ -4471,11 +4453,22 @@ function rcube_webmail() this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); }); this.name_input_li = $('<li>').addClass(type).append(this.name_input); - var li = type == 'contactsearch' ? $('li:last', this.gui_objects.folderlist) : $('ul.groups li:last', this.get_folder_li(this.env.source,'',true)); + var ul, li; + + // find list (UL) element + if (type == 'contactsearch') + ul = this.gui_objects.folderlist; + else + ul = $('ul.groups', this.get_folder_li(this.env.source,'',true)); + + // append to the list + li = $('li:last', ul); if (li.length) this.name_input_li.insertAfter(li); - else - this.name_input_li.appendTo(type == 'contactsearch' ? this.gui_objects.folderlist : $('ul.groups', this.get_folder_li(this.env.source,'',true))); + else { + this.name_input_li.appendTo(ul); + ul.show(); // make sure the list is visible + } } this.name_input.select().focus(); @@ -4532,11 +4525,13 @@ function rcube_webmail() this.reset_add_input = function() { if (this.name_input) { + var li = this.name_input.parent(); if (this.env.group_renaming) { - var li = this.name_input.parent(); li.children().last().show(); this.env.group_renaming = false; } + else if ($('li', li.parent()).length == 1) + li.parent().hide(); this.name_input.remove(); @@ -4964,18 +4959,16 @@ function rcube_webmail() this.update_identity_row = function(id, name, add) { - var row, col, list = this.identity_list, + var list = this.identity_list, rid = this.html_identifier(id); - if (list.rows[rid] && (row = list.rows[rid].obj)) { - $(row.cells[0]).html(name); - } - else if (add) { - row = $('<tr>').attr('id', 'rcmrow'+rid).get(0); - col = $('<td>').addClass('mail').html(name).appendTo(row); - list.insert_row(row); + if (add) { + list.insert_row({ id:'rcmrow'+rid, cols:[ { className:'mail', innerHTML:name } ] }); list.select(rid); } + else { + list.update_row(rid, [ name ]); + } }; @@ -5750,7 +5743,7 @@ function rcube_webmail() this.set_message_coltypes = function(coltypes, repl, smart_col) { var list = this.message_list, - thead = list ? list.list.tHead : null, + thead = list ? list.thead : null, cell, col, n, len, th, tr; this.env.coltypes = coltypes; diff --git a/program/js/list.js b/program/js/list.js index e689c6722..fbebc8a20 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -30,6 +30,9 @@ function rcube_list_widget(list, p) this.BACKSPACE_KEY = 8; this.list = list ? list : null; + this.tagname = this.list ? this.list.nodeName.toLowerCase() : 'table'; + this.thead; + this.tbody; this.frame = null; this.rows = []; this.selection = []; @@ -56,7 +59,7 @@ function rcube_list_widget(list, p) this.focused = false; this.drag_mouse_start = null; this.dblclick_time = 600; - this.row_init = function(){}; + this.row_init = function(){}; // @deprecated; use list.addEventListener('initrow') instead // overwrite default paramaters if (p && typeof p === 'object') @@ -73,11 +76,19 @@ rcube_list_widget.prototype = { */ init: function() { - if (this.list && this.list.tBodies[0]) { + if (this.tagname == 'table' && this.list && this.list.tBodies[0]) { + this.thead = this.list.tHead; + this.tbody = this.list.tBodies[0]; + } + else if (this.tagname != 'table' && this.list) { + this.tbody = this.list; + } + + if (this.tbody) { this.rows = []; this.rowcount = 0; - var r, len, rows = this.list.tBodies[0].rows; + var r, len, rows = this.tbody.childNodes; for (r=0, len=rows.length; r<len; r++) { this.init_row(rows[r]); @@ -127,7 +138,8 @@ init_row: function(row) if (document.all) row.onselectstart = function() { return false; }; - this.row_init(this.rows[uid]); + this.row_init(this.rows[uid]); // legacy support + this.triggerEvent('initrow', this.rows[uid]); } }, @@ -137,16 +149,16 @@ init_row: function(row) */ init_header: function() { - if (this.list && this.list.tHead) { + if (this.thead) { this.colcount = 0; var col, r, p = this; // add events for list columns moving - if (this.column_movable && this.list.tHead && this.list.tHead.rows) { - for (r=0; r<this.list.tHead.rows[0].cells.length; r++) { + if (this.column_movable && this.thead && this.thead.rows) { + for (r=0; r<this.thead.rows[0].cells.length; r++) { if (this.column_fixed == r) continue; - col = this.list.tHead.rows[0].cells[r]; + col = this.thead.rows[0].cells[r]; col.onmousedown = function(e){ return p.drag_column(e, this); }; this.colcount++; } @@ -160,10 +172,16 @@ init_header: function() */ clear: function(sel) { - var tbody = document.createElement('tbody'); + if (this.tagname == 'table') { + var tbody = document.createElement('tbody'); + this.list.insertBefore(tbody, this.tbody); + this.list.removeChild(this.list.tBodies[1]); + this.tbody = tbody; + } + else { + $(this.row_tagname() + ':not(.thead)', this.tbody).remove(); + } - this.list.insertBefore(tbody, this.list.tBodies[0]); - this.list.removeChild(this.list.tBodies[1]); this.rows = []; this.rowcount = 0; @@ -181,12 +199,12 @@ clear: function(sel) */ remove_row: function(uid, sel_next) { - var obj = this.rows[uid] ? this.rows[uid].obj : null; + var node = this.rows[uid] ? this.rows[uid].obj : null; - if (!obj) + if (!node) return; - obj.style.display = 'none'; + node.style.display = 'none'; if (sel_next) this.select_next(); @@ -201,9 +219,28 @@ remove_row: function(uid, sel_next) */ insert_row: function(row, before) { - var tbody = this.list.tBodies[0]; + var tbody = this.tbody; + + // create a real dom node first + if (row.nodeName === undefined) { + // for performance reasons use DOM instead of jQuery here + var domrow = document.createElement(this.row_tagname()); + if (row.id) domrow.id = row.id; + if (row.className) domrow.className = row.className; + if (row.style) $.extend(domrow.style, row.style); + + for (var domcell, col, i=0; row.cols && i < row.cols.length; i++) { + col = row.cols[i]; + domcell = document.createElement(this.col_tagname()); + if (col.className) domcell.className = col.className; + if (col.innerHTML) domcell.innerHTML = col.innerHTML; + domrow.appendChild(domcell); + } + + row = domrow; + } - if (before && tbody.rows.length) + if (before && tbody.childNodes.length) tbody.insertBefore(row, (typeof before == 'object' && before.parentNode == tbody) ? before : tbody.firstChild); else tbody.appendChild(row); @@ -212,6 +249,28 @@ insert_row: function(row, before) this.rowcount++; }, +/** + * + */ +update_row: function(id, cols, newid, select) +{ + var row = this.rows[id]; + if (!row) return false; + + var domrow = row.obj; + for (var domcell, col, i=0; cols && i < cols.length; i++) { + this.get_cell(domrow, i).html(cols[i]); + } + + if (newid) { + delete this.rows[id]; + domrow.id = 'rcmrow' + newid; + this.init_row(domrow); + + if (select) + this.selection[0] = newid; + } +}, /** @@ -230,9 +289,9 @@ focus: function(e) } // Un-focus already focused elements (#1487123, #1487316, #1488600, #1488620) + // It looks that window.focus() does the job for all browsers, but not Firefox (#1489058) $(':focus:not(body)').blur(); - // un-focus iframe bodies (#1489058), this doesn't work in Opera and Chrome - $('iframe').contents().find('body').blur(); + window.focus(); if (e || (e = window.event)) rcube_event.cancel(e); @@ -271,8 +330,8 @@ drag_column: function(e, col) this.add_dragfix(); // find selected column number - for (var i=0; i<this.list.tHead.rows[0].cells.length; i++) { - if (col == this.list.tHead.rows[0].cells[i]) { + for (var i=0; i<this.thead.rows[0].cells.length; i++) { + if (col == this.thead.rows[0].cells[i]) { this.selected_column = i; break; } @@ -451,7 +510,7 @@ expand: function(row) this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); } else { - var tbody = this.list.tBodies[0]; + var tbody = this.tbody; new_row = tbody.firstChild; depth = 0; last_expanded_parent_depth = 0; @@ -504,7 +563,7 @@ collapse_all: function(row) return false; } else { - new_row = this.list.tBodies[0].firstChild; + new_row = this.tbody.firstChild; depth = 0; } @@ -543,7 +602,7 @@ expand_all: function(row) this.triggerEvent('expandcollapse', { uid:row.uid, expanded:row.expanded, obj:row.obj }); } else { - new_row = this.list.tBodies[0].firstChild; + new_row = this.tbody.firstChild; depth = 0; } @@ -611,7 +670,7 @@ get_prev_row: function() get_first_row: function() { if (this.rowcount) { - var i, len, rows = this.list.tBodies[0].rows; + var i, len, rows = this.tbody.childNodes; for (i=0, len=rows.length-1; i<len; i++) if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) @@ -624,7 +683,7 @@ get_first_row: function() get_last_row: function() { if (this.rowcount) { - var i, rows = this.list.tBodies[0].rows; + var i, rows = this.tbody.childNodes; for (i=rows.length-1; i>=0; i--) if (rows[i].id && String(rows[i].id).match(/^rcmrow([a-z0-9\-_=\+\/]+)/i) && this.rows[RegExp.$1] != null) @@ -634,6 +693,22 @@ get_last_row: function() return null; }, +row_tagname: function() +{ + var row_tagnames = { table:'tr', ul:'li', '*':'div' }; + return row_tagnames[this.tagname] || row_tagnames['*']; +}, + +col_tagname: function() +{ + var col_tagnames = { table:'td', '*':'span' }; + return col_tagnames[this.tagname] || col_tagnames['*']; +}, + +get_cell: function(row, index) +{ + return $(this.col_tagname(), row).eq(index); +}, /** * selects or unselects the proper row depending on the modifier key pressed @@ -781,19 +856,19 @@ shift_select: function(id, control) this.shift_start = id; var n, i, j, to_row = this.rows[id], - from_rowIndex = this.rows[this.shift_start].obj.rowIndex, - to_rowIndex = to_row.obj.rowIndex; + from_rowIndex = this._rowIndex(this.rows[this.shift_start].obj), + to_rowIndex = this._rowIndex(to_row.obj); if (!to_row.expanded && to_row.has_children) if (to_row = this.rows[(this.row_children(id)).pop()]) - to_rowIndex = to_row.obj.rowIndex; + to_rowIndex = this._rowIndex(to_row.obj); i = ((from_rowIndex < to_rowIndex) ? from_rowIndex : to_rowIndex), j = ((from_rowIndex > to_rowIndex) ? from_rowIndex : to_rowIndex); // iterate through the entire message list for (n in this.rows) { - if (this.rows[n].obj.rowIndex >= i && this.rows[n].obj.rowIndex <= j) { + if (this._rowIndex(this.rows[n].obj) >= i && this._rowIndex(this.rows[n].obj) <= j) { if (!this.in_selection(n)) { this.highlight_row(n, true); } @@ -806,6 +881,13 @@ shift_select: function(id, control) } }, +/** + * Helper method to emulate the rowIndex property of non-tr elements + */ +_rowIndex: function(obj) +{ + return (obj.rowIndex !== undefined) ? obj.rowIndex : $(obj).prevAll().length; +}, /** * Check if given id is part of the current selection @@ -1150,7 +1232,7 @@ drag_mouse_move: function(e) this.draglayer.html(''); // get subjects of selected messages - var i, n, obj; + var i, n, obj, me; for (n=0; n<this.selection.length; n++) { // only show 12 lines if (n>12) { @@ -1158,29 +1240,28 @@ drag_mouse_move: function(e) break; } + me = this; if (obj = this.rows[this.selection[n]].obj) { - for (i=0; i<obj.childNodes.length; i++) { - if (obj.childNodes[i].nodeName == 'TD') { - if (n == 0) - this.drag_start_pos = $(obj.childNodes[i]).offset(); + $('> '+this.col_tagname(), obj).each(function(i,elem){ + if (n == 0) + me.drag_start_pos = $(elem).offset(); - if (this.subject_col < 0 || (this.subject_col >= 0 && this.subject_col == i)) { - var subject = $(obj.childNodes[i]).text(); - - if (!subject) - break; + if (me.subject_col < 0 || (me.subject_col >= 0 && me.subject_col == i)) { + var subject = $(elem).text(); + if (subject) { // remove leading spaces subject = $.trim(subject); // truncate line to 50 characters subject = (subject.length > 50 ? subject.substring(0, 50) + '...' : subject); var entry = $('<div>').text(subject); - this.draglayer.append(entry); - break; + me.draglayer.append(entry); } + + return false; // break } - } + }); } } @@ -1255,7 +1336,7 @@ column_drag_mouse_move: function(e) if (!this.col_draglayer) { var lpos = $(this.list).offset(), - cells = this.list.tHead.rows[0].cells; + cells = this.thead.rows[0].cells; // create dragging layer this.col_draglayer = $('<div>').attr('id', 'rcmcoldraglayer') @@ -1411,7 +1492,11 @@ del_dragfix: function() */ column_replace: function(from, to) { - var len, cells = this.list.tHead.rows[0].cells, + // only supported for <table> lists + if (!this.thead || !this.thead.rows) + return; + + var len, cells = this.thead.rows[0].cells, elem = cells[from], before = cells[to], td = document.createElement('td'); @@ -1424,8 +1509,8 @@ column_replace: function(from, to) cells[0].parentNode.replaceChild(elem, td); // replace list cells - for (r=0, len=this.list.tBodies[0].rows.length; r<len; r++) { - row = this.list.tBodies[0].rows[r]; + for (r=0, len=this.tbody.rows.length; r<len; r++) { + row = this.tbody.rows[r]; elem = row.cells[from]; before = row.cells[to]; diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php index dbc9ca51f..830ada9c2 100644 --- a/program/lib/Roundcube/html.php +++ b/program/lib/Roundcube/html.php @@ -678,6 +678,11 @@ class html_table extends html { $default_attrib = self::$doctype == 'xhtml' ? array('summary' => '', 'border' => 0) : array(); $this->attrib = array_merge($attrib, $default_attrib); + + if (!empty($attrib['tagname']) && $attrib['tagname'] != 'table') { + $this->tagname = $attrib['tagname']; + $this->allowed = self::$common_attrib; + } } /** @@ -816,19 +821,20 @@ class html_table extends html if (!empty($this->header)) { $rowcontent = ''; foreach ($this->header as $c => $col) { - $rowcontent .= self::tag('td', $col->attrib, $col->content); + $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content); } - $thead = self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)); + $thead = $this->tagname == 'table' ? self::tag('thead', null, self::tag('tr', null, $rowcontent, parent::$common_attrib)) : + self::tag($this->_row_tagname(), array('class' => 'thead'), $rowcontent, parent::$common_attrib); } foreach ($this->rows as $r => $row) { $rowcontent = ''; foreach ($row->cells as $c => $col) { - $rowcontent .= self::tag('td', $col->attrib, $col->content); + $rowcontent .= self::tag($this->_col_tagname(), $col->attrib, $col->content); } if ($r < $this->rowindex || count($row->cells)) { - $tbody .= self::tag('tr', $row->attrib, $rowcontent, parent::$common_attrib); + $tbody .= self::tag($this->_row_tagname(), $row->attrib, $rowcontent, parent::$common_attrib); } } @@ -837,7 +843,7 @@ class html_table extends html } // add <tbody> - $this->content = $thead . self::tag('tbody', null, $tbody); + $this->content = $thead . ($this->tagname == 'table' ? self::tag('tbody', null, $tbody) : $tbody); unset($this->attrib['cols'], $this->attrib['rowsonly']); return parent::show(); @@ -862,4 +868,22 @@ class html_table extends html $this->rowindex = 0; } + /** + * Getter for the corresponding tag name for table row elements + */ + private function _row_tagname() + { + static $row_tagnames = array('table' => 'tr', 'ul' => 'li', '*' => 'div'); + return $row_tagnames[$this->tagname] ?: $row_tagnames['*']; + } + + /** + * Getter for the corresponding tag name for table cell elements + */ + private function _col_tagname() + { + static $col_tagnames = array('table' => 'td', '*' => 'span'); + return $col_tagnames[$this->tagname] ?: $col_tagnames['*']; + } + } diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index cbc3c6773..d23ad3687 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -309,9 +309,14 @@ abstract class rcube_addressbook * List all active contact groups of this source * * @param string Optional search string to match group name + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) + * * @return array Indexed list of contact groups, each a hash array */ - function list_groups($search = null) + function list_groups($search = null, $mode = 0) { /* empty for address books don't supporting groups */ return array(); @@ -370,9 +375,10 @@ abstract class rcube_addressbook /** * Add the given contact records the a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be added - * @return int Number of contacts added + * @param string Group identifier + * @param array|string List of contact identifiers to be added + * + * @return int Number of contacts added */ function add_to_group($group_id, $ids) { @@ -383,9 +389,10 @@ abstract class rcube_addressbook /** * Remove the given contact records from a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be removed - * @return int Number of deleted group members + * @param string Group identifier + * @param array|string List of contact identifiers to be removed + * + * @return int Number of deleted group members */ function remove_from_group($group_id, $ids) { @@ -425,7 +432,7 @@ abstract class rcube_addressbook $out = array_merge($out, (array)$values); } else { - list($f, $type) = explode(':', $c); + list(, $type) = explode(':', $c); $out[$type] = array_merge((array)$out[$type], (array)$values); } } @@ -528,7 +535,7 @@ abstract class rcube_addressbook */ public static function compose_contact_key($contact, $sort_col) { - $key = $contact[$sort_col] . ':' . $row['sourceid']; + $key = $contact[$sort_col] . ':' . $contact['sourceid']; // add email to a key to not skip contacts with the same name (#1488375) if (!empty($contact['email'])) { @@ -538,7 +545,6 @@ abstract class rcube_addressbook return $key; } - /** * Compare search value with contact data * diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index e4fd7dc10..3919cdc6e 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -137,16 +137,34 @@ class rcube_contacts extends rcube_addressbook * List all active contact groups of this source * * @param string Search string to match group name + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) + * * @return array Indexed list of contact groups, each a hash array */ - function list_groups($search = null) + function list_groups($search = null, $mode = 0) { $results = array(); if (!$this->groups) return $results; - $sql_filter = $search ? " AND " . $this->db->ilike('name', '%'.$search.'%') : ''; + if ($search) { + switch (intval($mode)) { + case 1: + $sql_filter = $this->db->ilike('name', $search); + break; + case 2: + $sql_filter = $this->db->ilike('name', $search . '%'); + break; + default: + $sql_filter = $this->db->ilike('name', '%' . $search . '%'); + } + + $sql_filter = " AND $sql_filter"; + } $sql_result = $this->db->query( "SELECT * FROM ".$this->db->table_name($this->db_groups). @@ -879,9 +897,10 @@ class rcube_contacts extends rcube_addressbook /** * Add the given contact records the a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be added - * @return int Number of contacts added + * @param string Group identifier + * @param array|string List of contact identifiers to be added + * + * @return int Number of contacts added */ function add_to_group($group_id, $ids) { @@ -926,9 +945,10 @@ class rcube_contacts extends rcube_addressbook /** * Remove the given contact records from a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be removed - * @return int Number of deleted group members + * @param string Group identifier + * @param array|string List of contact identifiers to be removed + * + * @return int Number of deleted group members */ function remove_from_group($group_id, $ids) { diff --git a/program/lib/Roundcube/rcube_csv2vcard.php b/program/lib/Roundcube/rcube_csv2vcard.php index 0d3276b84..fb8d8f103 100644 --- a/program/lib/Roundcube/rcube_csv2vcard.php +++ b/program/lib/Roundcube/rcube_csv2vcard.php @@ -130,6 +130,21 @@ class rcube_csv2vcard 'work_state' => 'region:work', 'home_city_short' => 'locality:home', 'home_state_short' => 'region:home', + + // Atmail + 'date_of_birth' => 'birthday', + 'email' => 'email:pref', + 'home_mobile' => 'phone:cell', + 'home_zip' => 'zipcode:home', + 'info' => 'notes', + 'user_photo' => 'photo', + 'url' => 'website:homepage', + 'work_company' => 'organization', + 'work_dept' => 'departament', + 'work_fax' => 'phone:work,fax', + 'work_mobile' => 'phone:work,cell', + 'work_title' => 'jobtitle', + 'work_zip' => 'zipcode:work', ); /** @@ -230,8 +245,29 @@ class rcube_csv2vcard 'work_phone' => "Work Phone", 'work_address' => "Work Address", //'work_address_2' => "Work Address 2", + 'work_city' => "Work City", 'work_country' => "Work Country", + 'work_state' => "Work State", 'work_zipcode' => "Work ZipCode", + + // Atmail + 'date_of_birth' => "Date of Birth", + 'email' => "Email", + //'email_2' => "Email2", + //'email_3' => "Email3", + //'email_4' => "Email4", + //'email_5' => "Email5", + 'home_mobile' => "Home Mobile", + 'home_zip' => "Home Zip", + 'info' => "Info", + 'user_photo' => "User Photo", + 'url' => "URL", + 'work_company' => "Work Company", + 'work_dept' => "Work Dept", + 'work_fax' => "Work Fax", + 'work_mobile' => "Work Mobile", + 'work_title' => "Work Title", + 'work_zip' => "Work Zip", ); protected $local_label_map = array(); @@ -268,7 +304,6 @@ class rcube_csv2vcard { // 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, RCUBE_CHARSET); $csv = rcube_charset::convert($csv, $charset); $head = ''; @@ -276,7 +311,7 @@ class rcube_csv2vcard $this->map = array(); // Parse file - foreach (preg_split("/[\r\n]+/", $csv) as $i => $line) { + foreach (preg_split("/[\r\n]+/", $csv) as $line) { $elements = $this->parse_line($line); if (empty($elements)) { continue; @@ -353,6 +388,12 @@ class rcube_csv2vcard if (!empty($this->local_label_map)) { for ($i = 0; $i < $size; $i++) { $label = $this->local_label_map[$elements[$i]]; + + // special localization label + if ($label && $label[0] == '_') { + $label = substr($label, 1); + } + if ($label && !empty($this->csv2vcard_map[$label])) { $map2[$i] = $this->csv2vcard_map[$label]; } @@ -384,9 +425,13 @@ class rcube_csv2vcard $contact['birthday'] = $contact['birthday-y'] .'-' .$contact['birthday-m'] . '-' . $contact['birthday-d']; } + // Empty dates, e.g. "0/0/00", "0000-00-00 00:00:00" foreach (array('birthday', 'anniversary') as $key) { - if (!empty($contact[$key]) && $contact[$key] == '0/0/00') { // @TODO: localization? - unset($contact[$key]); + if (!empty($contact[$key])) { + $date = preg_replace('/[0[:^word:]]/', '', $contact[$key]); + if (empty($date)) { + unset($contact[$key]); + } } } diff --git a/program/lib/Roundcube/rcube_db.php b/program/lib/Roundcube/rcube_db.php index d86e3dd98..4b9ab131c 100644 --- a/program/lib/Roundcube/rcube_db.php +++ b/program/lib/Roundcube/rcube_db.php @@ -128,7 +128,7 @@ class rcube_db $dsn_string = $this->dsn_string($dsn); $dsn_options = $this->dsn_options($dsn); - if ($db_pconn) { + if ($this->db_pconn) { $dsn_options[PDO::ATTR_PERSISTENT] = true; } @@ -405,21 +405,22 @@ class rcube_db $this->db_error_msg = null; // send query - $query = $this->dbh->query($query); + $result = $this->dbh->query($query); - if ($query === false) { + if ($result === false) { $error = $this->dbh->errorInfo(); $this->db_error = true; $this->db_error_msg = sprintf('[%s] %s', $error[1], $error[2]); rcube::raise_error(array('code' => 500, 'type' => 'db', 'line' => __LINE__, 'file' => __FILE__, - 'message' => $this->db_error_msg), true, false); + 'message' => $this->db_error_msg . " (SQL Query: $query)" + ), true, false); } - $this->last_result = $query; + $this->last_result = $result; - return $query; + return $result; } /** diff --git a/program/lib/Roundcube/rcube_db_mysql.php b/program/lib/Roundcube/rcube_db_mysql.php index 8ab6403c8..b2cbab271 100644 --- a/program/lib/Roundcube/rcube_db_mysql.php +++ b/program/lib/Roundcube/rcube_db_mysql.php @@ -127,7 +127,7 @@ class rcube_db_mysql extends rcube_db $result[PDO::MYSQL_ATTR_FOUND_ROWS] = true; // Enable AUTOCOMMIT mode (#1488902) - $dsn_options[PDO::ATTR_AUTOCOMMIT] = true; + $result[PDO::ATTR_AUTOCOMMIT] = true; return $result; } @@ -147,7 +147,7 @@ class rcube_db_mysql extends rcube_db $result = $this->query('SHOW VARIABLES'); - while ($sql_arr = $this->fetch_array($result)) { + while ($row = $this->fetch_array($result)) { $this->variables[$row[0]] = $row[1]; } } diff --git a/program/lib/Roundcube/rcube_enriched.php b/program/lib/Roundcube/rcube_enriched.php index 8c628c912..12deb33ce 100644 --- a/program/lib/Roundcube/rcube_enriched.php +++ b/program/lib/Roundcube/rcube_enriched.php @@ -118,7 +118,7 @@ class rcube_enriched $quoted = ''; $lines = explode('<br>', $a[2]); - foreach ($lines as $n => $line) + foreach ($lines as $line) $quoted .= '>'.$line.'<br>'; $body = $a[1].'<span class="quotes">'.$quoted.'</span>'.$a[3]; diff --git a/program/lib/Roundcube/rcube_imap.php b/program/lib/Roundcube/rcube_imap.php index c67985186..43c61fd81 100644 --- a/program/lib/Roundcube/rcube_imap.php +++ b/program/lib/Roundcube/rcube_imap.php @@ -981,7 +981,7 @@ class rcube_imap extends rcube_storage // use memory less expensive (and quick) method for big result set $index = clone $this->index('', $this->sort_field, $this->sort_order); // get messages uids for one page... - $index->slice($start_msg, min($cnt-$from, $this->page_size)); + $index->slice($from, min($cnt-$from, $this->page_size)); if ($slice) { $index->slice(-$slice, $slice); @@ -1423,8 +1423,6 @@ class rcube_imap extends rcube_storage */ protected function search_index($folder, $criteria='ALL', $charset=NULL, $sort_field=NULL) { - $orig_criteria = $criteria; - if (!$this->check_connection()) { if ($this->threading) { return new rcube_result_thread(); @@ -2727,7 +2725,7 @@ class rcube_imap extends rcube_storage // filter folders list according to rights requirements if ($rights && $this->get_capability('ACL')) { - $a_folders = $this->filter_rights($a_folders, $rights); + $a_mboxes = $this->filter_rights($a_mboxes, $rights); } // filter folders and sort them @@ -2783,7 +2781,6 @@ class rcube_imap extends rcube_storage */ private function list_folders_update(&$result, $type = null) { - $delim = $this->get_hierarchy_delimiter(); $namespace = $this->get_namespace(); $search = array(); @@ -3846,7 +3843,7 @@ class rcube_imap extends rcube_storage $delimiter = $this->get_hierarchy_delimiter(); // find default folders and skip folders starting with '.' - foreach ($a_folders as $i => $folder) { + foreach ($a_folders as $folder) { if ($folder[0] == '.') { continue; } diff --git a/program/lib/Roundcube/rcube_imap_cache.php b/program/lib/Roundcube/rcube_imap_cache.php index 748474af2..47d9aaf4a 100644 --- a/program/lib/Roundcube/rcube_imap_cache.php +++ b/program/lib/Roundcube/rcube_imap_cache.php @@ -430,7 +430,7 @@ class rcube_imap_cache ." AND uid = ?", $flags, $msg, $this->userid, $mailbox, (int) $message->uid); - if ($this->db->affected_rows()) { + if ($this->db->affected_rows($res)) { return; } } @@ -983,7 +983,7 @@ class rcube_imap_cache $uids, true, array('FLAGS'), $index['modseq'], $qresync); if (!empty($result)) { - foreach ($result as $id => $msg) { + foreach ($result as $msg) { $uid = $msg->uid; // Remove deleted message if ($this->skip_deleted && !empty($msg->flags['DELETED'])) { diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index db50ffbab..6c1b85552 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -746,7 +746,7 @@ class rcube_imap_generic } if ($this->prefs['timeout'] <= 0) { - $this->prefs['timeout'] = ini_get('default_socket_timeout'); + $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout'))); } // Connect @@ -1077,7 +1077,7 @@ class rcube_imap_generic } if (!$this->data['READ-WRITE']) { - $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'EXPUNGE'); + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); return false; } @@ -1652,7 +1652,6 @@ class rcube_imap_generic } if (!empty($criteria)) { - $modseq = stripos($criteria, 'MODSEQ') !== false; $params .= ($params ? ' ' : '') . $criteria; } else { @@ -1791,7 +1790,6 @@ class rcube_imap_generic if ($skip_deleted && preg_match('/FLAGS \(([^)]+)\)/', $line, $matches)) { $flags = explode(' ', strtoupper($matches[1])); if (in_array('\\DELETED', $flags)) { - $deleted[$id] = $id; continue; } } @@ -1936,7 +1934,7 @@ class rcube_imap_generic } if (!$this->data['READ-WRITE']) { - $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE'); + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); return false; } @@ -1997,7 +1995,7 @@ class rcube_imap_generic } if (!$this->data['READ-WRITE']) { - $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE'); + $this->setError(self::ERROR_READONLY, "Mailbox is read-only"); return false; } @@ -2172,7 +2170,7 @@ class rcube_imap_generic // create array with header field:data if (!empty($headers)) { $headers = explode("\n", trim($headers)); - foreach ($headers as $hid => $resln) { + foreach ($headers as $resln) { if (ord($resln[0]) <= 32) { $lines[$ln] .= (empty($lines[$ln]) ? '' : "\n") . trim($resln); } else { @@ -2180,7 +2178,7 @@ class rcube_imap_generic } } - while (list($lines_key, $str) = each($lines)) { + foreach ($lines as $str) { list($field, $string) = explode(':', $str, 2); $field = strtolower($field); @@ -2508,7 +2506,7 @@ class rcube_imap_generic $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\)$)/', '', $line)); for ($i=0; $i<count($tokens); $i+=2) { - if (preg_match('/^(BODY|BINARY)/i', $token)) { + if (preg_match('/^(BODY|BINARY)/i', $tokens[$i])) { $result = $tokens[$i+1]; $found = true; break; @@ -3540,7 +3538,7 @@ class rcube_imap_generic if (is_array($element)) { reset($element); - while (list($key, $value) = each($element)) { + foreach ($element as $value) { $string .= ' ' . self::r_implode($value); } } diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index a2dd163e9..70163b21c 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -169,7 +169,7 @@ class rcube_ldap extends rcube_addressbook // Build sub_fields filter if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { $this->sub_filter = ''; - foreach ($this->prop['sub_fields'] as $attr => $class) { + foreach ($this->prop['sub_fields'] as $class) { if (!empty($class)) { $class = is_array($class) ? array_pop($class) : $class; $this->sub_filter .= '(objectClass=' . $class . ')'; @@ -1035,7 +1035,6 @@ class rcube_ldap extends rcube_addressbook $mail_field = $this->fieldmap['email']; // try to extract surname and firstname from displayname - $reverse_map = array_flip($this->fieldmap); $name_parts = preg_split('/[\s,.]+/', $save_data['name']); if ($sn_field && $missing[$sn_field]) { @@ -1107,7 +1106,7 @@ class rcube_ldap extends rcube_addressbook // Remove attributes that need to be added separately (child objects) $xfields = array(); if (!empty($this->prop['sub_fields']) && is_array($this->prop['sub_fields'])) { - foreach ($this->prop['sub_fields'] as $xf => $xclass) { + foreach (array_keys($this->prop['sub_fields']) as $xf) { if (!empty($newentry[$xf])) { $xfields[$xf] = $newentry[$xf]; unset($newentry[$xf]); @@ -1170,7 +1169,7 @@ class rcube_ldap extends rcube_addressbook } } - foreach ($this->fieldmap as $col => $fld) { + foreach ($this->fieldmap as $fld) { if ($fld) { $val = $ldap_data[$fld]; $old = $old_data[$fld]; @@ -1396,6 +1395,10 @@ class rcube_ldap extends rcube_addressbook */ protected function add_autovalues(&$attrs) { + if (empty($this->prop['autovalues'])) { + return; + } + $attrvals = array(); foreach ($attrs as $k => $v) { $attrvals['{'.$k.'}'] = is_array($v) ? $v[0] : $v; @@ -1403,13 +1406,24 @@ class rcube_ldap extends rcube_addressbook 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) { + // replace {attr} placeholders with (escaped!) attribute values to be safely eval'd + $code = preg_replace('/\{\w+\}/', '', strtr($templ, array_map('addslashes', $attrvals))); + $fn = create_function('', "return ($code);"); + if (!$fn) { + rcube::raise_error(array( + 'code' => 505, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Expression parse error on: ($code)"), true, false); + continue; + } - if (strpos($templ, '(') !== false) - $attrs[$lf] = eval("return ($templ);"); - else - $attrs[$lf] = $templ; + $attrs[$lf] = $fn(); + } + else { + // replace {attr} placeholders with concrete attribute values + $attrs[$lf] = preg_replace('/\{\w+\}/', '', strtr($templ, $attrvals)); + } } } } @@ -1715,9 +1729,14 @@ class rcube_ldap extends rcube_addressbook * List all active contact groups of this source * * @param string Optional search string to match group name + * @param int Matching mode: + * 0 - partial (*abc*), + * 1 - strict (=), + * 2 - prefix (abc*) + * * @return array Indexed list of contact groups, each a hash array */ - function list_groups($search = null) + function list_groups($search = null, $mode = 0) { if (!$this->groups) return array(); @@ -1729,10 +1748,10 @@ class rcube_ldap extends rcube_addressbook $groups = array(); if ($search) { - $search = mb_strtolower($search); foreach ($group_cache as $group) { - if (strpos(mb_strtolower($group['name']), $search) !== false) + if ($this->compare_search_value('name', $group['name'], $search, $mode)) { $groups[] = $group; + } } } else @@ -1763,7 +1782,7 @@ class rcube_ldap extends rcube_addressbook $vlv_active = $this->_vlv_set_controls($this->prop['groups'], $vlv_page+1, $page_size); } - $function = $this->_scope2func($this->prop['groups']['scope'], $ns_function); + $function = $this->_scope2func($this->prop['groups']['scope']); $res = @$function($this->conn, $base_dn, $filter, array_unique(array('dn', 'objectClass', $name_attr, $email_attr, $sort_attr))); if ($res === false) { @@ -1921,9 +1940,10 @@ class rcube_ldap extends rcube_addressbook /** * Add the given contact records the a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be added - * @return int Number of contacts added + * @param string Group identifier + * @param array|string List of contact identifiers to be added + * + * @return int Number of contacts added */ function add_to_group($group_id, $contact_ids) { @@ -1937,8 +1957,8 @@ class rcube_ldap extends rcube_addressbook $group_name = $group_cache[$group_id]['name']; $member_attr = $group_cache[$group_id]['member_attr']; $group_dn = "cn=$group_name,$base_dn"; + $new_attrs = array(); - $new_attrs = array(); foreach ($contact_ids as $id) $new_attrs[$member_attr][] = self::dn_decode($id); @@ -1949,28 +1969,32 @@ class rcube_ldap extends rcube_addressbook $this->cache->remove('groups'); - return count($new_attrs['member']); + return count($new_attrs[$member_attr]); } /** * Remove the given contact records from a certain group * - * @param string Group identifier - * @param array List of contact identifiers to be removed - * @return int Number of deleted group members + * @param string Group identifier + * @param array|string List of contact identifiers to be removed + * + * @return int Number of deleted group members */ function remove_from_group($group_id, $contact_ids) { if (($group_cache = $this->cache->get('groups')) === null) $group_cache = $this->_fetch_groups(); + if (!is_array($contact_ids)) + $contact_ids = explode(',', $contact_ids); + $base_dn = $this->groups_base_dn; $group_name = $group_cache[$group_id]['name']; $member_attr = $group_cache[$group_id]['member_attr']; $group_dn = "cn=$group_name,$base_dn"; + $del_attrs = array(); - $del_attrs = array(); - foreach (explode(",", $contact_ids) as $id) + foreach ($contact_ids as $id) $del_attrs[$member_attr][] = self::dn_decode($id); if (!$this->ldap_mod_del($group_dn, $del_attrs)) { @@ -1980,7 +2004,7 @@ class rcube_ldap extends rcube_addressbook $this->cache->remove('groups'); - return count($del_attrs['member']); + return count($del_attrs[$member_attr]); } /** diff --git a/program/lib/Roundcube/rcube_message.php b/program/lib/Roundcube/rcube_message.php index 9db1fa30a..a42d3fb28 100644 --- a/program/lib/Roundcube/rcube_message.php +++ b/program/lib/Roundcube/rcube_message.php @@ -362,7 +362,7 @@ class rcube_message // parse headers from message/rfc822 part if (!isset($structure->headers['subject']) && !isset($structure->headers['from'])) { - list($headers, $dump) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768)); + list($headers, ) = explode("\r\n\r\n", $this->get_part_content($structure->mime_id, null, true, 32768)); $structure->headers = rcube_mime::parse_headers($headers); } } diff --git a/program/lib/Roundcube/rcube_mime.php b/program/lib/Roundcube/rcube_mime.php index 96296a57c..63549fbec 100644 --- a/program/lib/Roundcube/rcube_mime.php +++ b/program/lib/Roundcube/rcube_mime.php @@ -127,10 +127,11 @@ class rcube_mime * @param int $max List only this number of addresses * @param boolean $decode Decode address strings * @param string $fallback Fallback charset if none specified + * @param boolean $addronly Return flat array with e-mail addresses only * - * @return array Indexed list of addresses + * @return array Indexed list of addresses */ - static function decode_address_list($input, $max = null, $decode = true, $fallback = null) + static function decode_address_list($input, $max = null, $decode = true, $fallback = null, $addronly = false) { $a = self::parse_address_list($input, $decode, $fallback); $out = array(); @@ -145,20 +146,21 @@ class rcube_mime foreach ($a as $val) { $j++; $address = trim($val['address']); - $name = trim($val['name']); - if ($name && $address && $name != $address) - $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address); - else if ($address) - $string = $address; - else if ($name) - $string = $name; - - $out[$j] = array( - 'name' => $name, - 'mailto' => $address, - 'string' => $string - ); + if ($addronly) { + $out[$j] = $address; + } + else { + $name = trim($val['name']); + if ($name && $address && $name != $address) + $string = sprintf('%s <%s>', preg_match("/$special_chars/", $name) ? '"'.addcslashes($name, '"').'"' : $name, $address); + else if ($address) + $string = $address; + else if ($name) + $string = $name; + + $out[$j] = array('name' => $name, 'mailto' => $address, 'string' => $string); + } if ($max && $j==$max) break; @@ -476,9 +478,10 @@ class rcube_mime $q_level = 0; foreach ($text as $idx => $line) { - if ($line[0] == '>') { - // remove quote chars, store level in $q - $line = preg_replace('/^>+/', '', $line, -1, $q); + if (preg_match('/^(>+)/', $line, $m)) { + // remove quote chars + $q = strlen($m[1]); + $line = preg_replace('/^>+/', '', $line); // remove (optional) space-staffing $line = preg_replace('/^ /', '', $line); @@ -541,9 +544,10 @@ class rcube_mime foreach ($text as $idx => $line) { if ($line != '-- ') { - if ($line[0] == '>') { - // remove quote chars, store level in $level - $line = preg_replace('/^>+/', '', $line, -1, $level); + if (preg_match('/^(>+)/', $line, $m)) { + // remove quote chars + $level = strlen($m[1]); + $line = preg_replace('/^>+/', '', $line); // remove (optional) space-staffing and spaces before the line end $line = preg_replace('/(^ | +$)/', '', $line); $prefix = str_repeat('>', $level) . ' '; @@ -657,8 +661,8 @@ class rcube_mime $cutLength = $spacePos + 1; } else { - $subString = $string; - $cutLength = null; + $subString = $substr_func($string, 0, $breakPos, $charset); + $cutLength = $breakPos + 1; } } else { diff --git a/program/lib/Roundcube/rcube_output.php b/program/lib/Roundcube/rcube_output.php index b8ae86cf6..7ccf9a02e 100644 --- a/program/lib/Roundcube/rcube_output.php +++ b/program/lib/Roundcube/rcube_output.php @@ -162,7 +162,7 @@ abstract class rcube_output header("Cache-Control: private, must-revalidate"); } else { - header("Cache-Control: private, no-cache, must-revalidate, post-check=0, pre-check=0"); + header("Cache-Control: private, no-cache, no-store, must-revalidate, post-check=0, pre-check=0"); header("Pragma: no-cache"); } } diff --git a/program/lib/Roundcube/rcube_plugin_api.php b/program/lib/Roundcube/rcube_plugin_api.php index 4bb6c6677..33f04eaa5 100644 --- a/program/lib/Roundcube/rcube_plugin_api.php +++ b/program/lib/Roundcube/rcube_plugin_api.php @@ -313,7 +313,6 @@ class rcube_plugin_api $doc->loadXML($file); $xpath = new DOMXPath($doc); $xpath->registerNamespace('rc', "http://pear.php.net/dtd/package-2.0"); - $data = array(); // XPaths of plugin metadata elements $metadata = array( diff --git a/program/lib/Roundcube/rcube_smtp.php b/program/lib/Roundcube/rcube_smtp.php index 5c7d2203c..0f3ac0407 100644 --- a/program/lib/Roundcube/rcube_smtp.php +++ b/program/lib/Roundcube/rcube_smtp.php @@ -119,7 +119,7 @@ class rcube_smtp } // try to connect to server and exit on failure - $result = $this->conn->connect($smtp_timeout); + $result = $this->conn->connect($CONFIG['smtp_timeout']); if (PEAR::isError($result)) { $this->response[] = "Connection failed: ".$result->getMessage(); @@ -433,9 +433,9 @@ class rcube_smtp $recipients = rcube_utils::explode_quoted_string(',', $recipients); reset($recipients); - while (list($k, $recipient) = each($recipients)) { + foreach ($recipients as $recipient) { $a = rcube_utils::explode_quoted_string(' ', $recipient); - while (list($k2, $word) = each($a)) { + foreach ($a as $word) { if (strpos($word, "@") > 0 && $word[strlen($word)-1] != '"') { $word = preg_replace('/^<|>$/', '', trim($word)); if (in_array($word, $addresses) === false) { diff --git a/program/lib/Roundcube/rcube_spellchecker.php b/program/lib/Roundcube/rcube_spellchecker.php index 816bcad2f..60aec500f 100644 --- a/program/lib/Roundcube/rcube_spellchecker.php +++ b/program/lib/Roundcube/rcube_spellchecker.php @@ -314,11 +314,6 @@ class rcube_spellchecker if (!$this->plink) { if (!extension_loaded('pspell')) { $this->error = "Pspell extension not available"; - rcube::raise_error(array( - 'code' => 500, 'type' => 'php', - 'file' => __FILE__, 'line' => __LINE__, - 'message' => $this->error), true, false); - return; } @@ -372,9 +367,19 @@ class rcube_spellchecker fclose($fp); } + // parse HTTP response + if (preg_match('!^HTTP/1.\d (\d+)(.+)!', $store, $m)) { + $http_status = $m[1]; + if ($http_status != '200') + $this->error = 'HTTP ' . $m[1] . $m[2]; + } + if (!$store) { $this->error = "Empty result from spelling engine"; } + else if (preg_match('/<spellresult error="([^"]+)"/', $store, $m)) { + $this->error = "Error code $m[1] returned"; + } preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $store, $matches, PREG_SET_ORDER); @@ -588,7 +593,7 @@ class rcube_spellchecker if (empty($plugin['abort'])) { $dict = array(); - $this->rc->db->query( + $sql_result = $this->rc->db->query( "SELECT data FROM ".$this->rc->db->table_name('dictionary') ." WHERE user_id ". ($plugin['userid'] ? "= ".$this->rc->db->quote($plugin['userid']) : "IS NULL") ." AND " . $this->rc->db->quoteIdentifier('language') . " = ?", diff --git a/program/lib/Roundcube/rcube_utils.php b/program/lib/Roundcube/rcube_utils.php index fabe0f060..8467107fe 100644 --- a/program/lib/Roundcube/rcube_utils.php +++ b/program/lib/Roundcube/rcube_utils.php @@ -404,7 +404,7 @@ class rcube_utils $out = array(); $src = $mode == self::INPUT_GET ? $_GET : ($mode == self::INPUT_POST ? $_POST : $_REQUEST); - foreach ($src as $key => $value) { + foreach (array_keys($src) as $key) { $fname = $key[0] == '_' ? substr($key, 1) : $key; if ($ignore && !preg_match('/^(' . $ignore . ')$/', $fname)) { $out[$fname] = self::get_input_value($key, $mode); diff --git a/program/lib/Roundcube/rcube_vcard.php b/program/lib/Roundcube/rcube_vcard.php index 54bb9521d..90acb2110 100644 --- a/program/lib/Roundcube/rcube_vcard.php +++ b/program/lib/Roundcube/rcube_vcard.php @@ -90,7 +90,7 @@ class rcube_vcard */ public function __construct($vcard = null, $charset = RCUBE_CHARSET, $detect = false, $fieldmap = array()) { - if (!empty($fielmap)) { + if (!empty($fieldmap)) { $this->extend_fieldmap($fieldmap); } @@ -481,7 +481,7 @@ class rcube_vcard $vcard_block = ''; $in_vcard_block = false; - foreach (preg_split("/[\r\n]+/", $data) as $i => $line) { + foreach (preg_split("/[\r\n]+/", $data) as $line) { if ($in_vcard_block && !empty($line)) { $vcard_block .= $line . "\n"; } @@ -784,9 +784,30 @@ class rcube_vcard } return $result; } + + $s = strtr($s, $rep2); + } + + // some implementations (GMail) use non-standard backslash before colon (#1489085) + // we will handle properly any backslashed character - removing dummy backslahes + // return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';')); + + $s = str_replace("\r", '', $s); + $pos = 0; + + while (($pos = strpos($s, '\\', $pos)) !== false) { + $next = substr($s, $pos + 1, 1); + if ($next == 'n' || $next == 'N') { + $s = substr_replace($s, "\n", $pos, 2); + } + else { + $s = substr_replace($s, '', $pos, 1); + } + + $pos += 1; } - return strtr($s, array("\r" => '', '\\\\' => '\\', '\n' => "\n", '\N' => "\n", '\,' => ',', '\;' => ';')); + return $s; } /** diff --git a/program/lib/utf8.class.php b/program/lib/utf8.class.php index e0dc9e2bd..0446159c7 100644 --- a/program/lib/utf8.class.php +++ b/program/lib/utf8.class.php @@ -60,8 +60,8 @@ Class utf8 { function loadCharset($charset) { $charset = preg_replace(array('/^WINDOWS-*125([0-8])$/', '/^CP-/'), array('CP125\\1', 'CP'), $charset); - if (isset($aliases[$charset])) - $charset = $aliases[$charset]; + if (isset($this->aliases[$charset])) + $charset = $this->aliases[$charset]; $this->charset = $charset; diff --git a/program/localization/en_GB/labels.inc b/program/localization/en_GB/labels.inc index 8d5509b64..581a7171a 100644 --- a/program/localization/en_GB/labels.inc +++ b/program/localization/en_GB/labels.inc @@ -397,6 +397,7 @@ $labels['pagesize'] = 'Rows per page'; $labels['signature'] = 'Signature'; $labels['dstactive'] = 'Summer time'; $labels['showinextwin'] = 'Open message in a new window'; +$labels['showemail'] = 'Show email address with display name'; $labels['composeextwin'] = 'Compose in a new window'; $labels['htmleditor'] = 'Compose HTML messages'; $labels['htmlonreply'] = 'on reply to HTML message only'; diff --git a/program/localization/en_US/csv2vcard.inc b/program/localization/en_US/csv2vcard.inc index 5412f7e20..e7b86795b 100644 --- a/program/localization/en_US/csv2vcard.inc +++ b/program/localization/en_US/csv2vcard.inc @@ -91,3 +91,20 @@ $map['work_phone'] = "Work Phone"; $map['work_address'] = "Work Address"; $map['work_country'] = "Work Country"; $map['work_zipcode'] = "Work ZipCode"; + +// Atmail +$map['date_of_birth'] = "Date of Birth"; +$map['email'] = "Email"; +$map['home_mobile'] = "Home Mobile"; +$map['home_zip'] = "Home Zip"; +$map['info'] = "Info"; +$map['user_photo'] = "User Photo"; +$map['url'] = "URL"; +$map['work_city'] = "Work City"; +$map['work_company'] = "Work Company"; +$map['work_dept'] = "Work Dept"; +$map['work_fax'] = "Work Fax"; +$map['work_mobile'] = "Work Mobile"; +$map['work_state'] = "Work State"; +$map['work_title'] = "Work Title"; +$map['work_zip'] = "Work Zip"; diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index 3e1bde0a5..ab57007dd 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -402,6 +402,7 @@ $labels['htmleditor'] = 'Compose HTML messages'; $labels['htmlonreply'] = 'on reply to HTML message'; $labels['htmlonreplyandforward'] = 'on forward or reply to HTML message'; $labels['htmlsignature'] = 'HTML signature'; +$labels['showemail'] = 'Show email address with display name'; $labels['previewpane'] = 'Show preview pane'; $labels['skin'] = 'Interface skin'; $labels['logoutclear'] = 'Clear Trash on logout'; diff --git a/program/localization/fr_FR/csv2vcard.inc b/program/localization/fr_FR/csv2vcard.inc new file mode 100644 index 000000000..bb77001b5 --- /dev/null +++ b/program/localization/fr_FR/csv2vcard.inc @@ -0,0 +1,96 @@ +<?php + +/* + +-----------------------------------------------------------------------+ + | localization/<lang>/csv2vcard.inc | + | | + | Localization file of the Roundcube Webmail client | + | Copyright (C) 2005-2013, 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. | + | | + +-----------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + +-----------------------------------------------------------------------+ +*/ + +// This is a list of CSV column names specified in CSV file header +// These must be original texts used in Outlook/Thunderbird exported csv files +// Encoding UTF-8 + +$map = array(); + +// MS Outlook 2010 +$map['anniversary'] = "Anniversaire de mariage ou fête"; +$map['assistants_name'] = "Nom de l''assistant(e)"; +$map['assistants_phone'] = "Téléphone de l''assistant(e)"; +$map['birthday'] = "Anniversaire"; +$map['business_city'] = "Ville (bureau)"; +$map['business_countryregion'] = "Pays/Région (bureau)"; +$map['business_fax'] = "Télécopie (bureau)"; +$map['business_phone'] = "Téléphone (bureau)"; +$map['business_phone_2'] = "Téléphone 2 (bureau)"; +$map['business_postal_code'] = "Code postal (bureau)"; +$map['business_state'] = "Dép/Région (bureau)"; +$map['business_street'] = "Rue (bureau)"; +$map['car_phone'] = "Téléphone (voiture)"; +$map['categories'] = "Catégories"; +$map['company'] = "Société"; +$map['department'] = "Service"; +$map['email_address'] = "Adresse de messagerie"; +$map['first_name'] = "Prénom"; +$map['gender'] = "Sexe"; +$map['home_city'] = "Ville (domicile)"; +$map['home_countryregion'] = "Pays/Région (domicile)"; +$map['home_fax'] = "Télécopie (domicile)"; +$map['home_phone'] = "Téléphone (domicile)"; +$map['home_phone_2'] = "Téléphone 2 (domicile)"; +$map['home_postal_code'] = "Code postal (domicile)"; +$map['home_state'] = "Dép/Région (domicile)"; +$map['home_street'] = "Rue (domicile)"; +$map['job_title'] = "Profession"; +$map['last_name'] = "Nom"; +$map['managers_name'] = "Manager's Name"; +$map['middle_name'] = "Deuxième prénom"; +$map['mobile_phone'] = "Tél. mobile"; +$map['notes'] = "Notes"; +$map['other_city'] = "Ville (autre)"; +$map['other_countryregion'] = "Pays/Région (autre)"; +$map['other_fax'] = "Télécopie (autre)"; +$map['other_phone'] = "Téléphone (autre)"; +$map['other_postal_code'] = "Code postal (autre)"; +$map['other_state'] = "Dép/Région (autre)"; +$map['other_street'] = "Rue (autre)"; +$map['pager'] = "Récepteur de radiomessagerie"; +$map['primary_phone'] = "Téléphone principal"; +$map['spouse'] = "Conjoint(e)"; +$map['suffix'] = "Suffixe"; +$map['title'] = "Titre"; +$map['web_page'] = "Page Web"; + +// Thunderbird +$map['birth_day'] = "Jour"; +$map['birth_month'] = "Mois"; +$map['birth_year'] = "Année de naissance"; +$map['display_name'] = "Nom à afficher"; +$map['fax_number'] = "Fax"; +$map['home_address'] = "Adresse privée"; +$map['home_country'] = "Région"; +$map['home_zipcode'] = "Code postal"; +$map['mobile_number'] = "Portable"; +$map['nickname'] = "Surnom"; +$map['organization'] = "Société"; +$map['pager_number'] = "Pager"; +$map['primary_email'] = "Adresse électronique principale"; +$map['secondary_email'] = "Adresse électronique secondaire"; +$map['web_page_1'] = "Site Web 1"; +$map['web_page_2'] = "Site Web 2"; +$map['work_phone'] = "Tél. professionnel"; +$map['work_address'] = "Adresse professionnelle"; +$map['work_country'] = "Région"; +$map['work_zipcode'] = "Code postal"; + +// Other +$map['_home_city'] = "Ville"; diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc index ffc0b3b92..8faf76f78 100644 --- a/program/steps/addressbook/func.inc +++ b/program/steps/addressbook/func.inc @@ -167,7 +167,7 @@ function rcmail_set_sourcename($abook) // get address book name (for display) if ($abook && $_SESSION['addressbooks_count'] > 1) { $name = $abook->get_name(); - if (!$name && $source == 0) { + if (!$name) { $name = rcube_label('personaladrbook'); } $OUTPUT->set_env('sourcename', html_entity_decode($name, ENT_COMPAT, 'UTF-8')); @@ -183,7 +183,6 @@ function rcmail_directory_list($attrib) $attrib['id'] = 'rcmdirectorylist'; $out = ''; - $local_id = '0'; $jsdata = array(); $line_templ = html::tag('li', array( @@ -270,7 +269,6 @@ function rcmail_contact_groups($args) $groups_html = ''; $groups = $RCMAIL->get_address_book($args['source'])->list_groups(); - $js_id = $RCMAIL->JQ($args['source']); if (!empty($groups)) { $line_templ = html::tag('li', array( @@ -283,7 +281,6 @@ function rcmail_contact_groups($args) $is_collapsed = strpos($RCMAIL->config->get('collapsed_abooks',''), '&'.rawurlencode($args['source']).'&') !== false; $args['out'] .= html::div('treetoggle ' . ($is_collapsed ? 'collapsed' : 'expanded'), ' '); - $jsdata = array(); foreach ($groups as $group) { $groups_html .= sprintf($line_templ, rcube_utils::html_identifier('G' . $args['source'] . $group['ID'], true), @@ -297,7 +294,7 @@ function rcmail_contact_groups($args) } $args['out'] .= html::tag('ul', - array('class' => 'groups', 'style' => ($is_collapsed ? "display:none;" : null)), + array('class' => 'groups', 'style' => ($is_collapsed || empty($groups) ? "display:none;" : null)), $groups_html); return $args; diff --git a/program/steps/addressbook/import.inc b/program/steps/addressbook/import.inc index 72da15078..915aac884 100644 --- a/program/steps/addressbook/import.inc +++ b/program/steps/addressbook/import.inc @@ -88,7 +88,7 @@ function rcmail_import_confirm($attrib) $content = html::p(null, rcube_label(array( 'name' => 'importconfirm', - 'nr' => $IMORT_STATS->inserted, + 'nr' => $IMPORT_STATS->inserted, 'vars' => $vars, )) . ($IMPORT_STATS->names ? ':' : '.')); @@ -98,7 +98,7 @@ function rcmail_import_confirm($attrib) if ($IMPORT_STATS->skipped) { $content .= html::p(null, rcube_label(array( 'name' => 'importconfirmskipped', - 'nr' => $IMORT_STATS->skipped, + 'nr' => $IMPORT_STATS->skipped, 'vars' => $vars, )) . ':'); $content .= html::p('em', join(', ', array_map('Q', $IMPORT_STATS->skipped_names))); diff --git a/program/steps/addressbook/show.inc b/program/steps/addressbook/show.inc index 16be89f94..1a97c65b1 100644 --- a/program/steps/addressbook/show.inc +++ b/program/steps/addressbook/show.inc @@ -101,8 +101,6 @@ function rcmail_contact_head($attrib) return false; } - $microformats = array('name' => 'fn', 'email' => 'email'); - $form = array( 'head' => array( // section 'head' is magic! 'content' => array( @@ -177,7 +175,7 @@ function rcmail_contact_details($attrib) } -function rcmail_render_email_value($email, $col) +function rcmail_render_email_value($email) { return html::a(array( 'href' => 'mailto:' . $email, @@ -188,7 +186,7 @@ function rcmail_render_email_value($email, $col) } -function rcmail_render_url_value($url, $col) +function rcmail_render_url_value($url) { $prefix = preg_match('!^(http|ftp)s?://!', $url) ? '' : 'http://'; return html::a(array( @@ -223,7 +221,7 @@ function rcmail_contact_record_groups($contact_id) } $hiddenfields = new html_hiddenfield(array('name' => '_source', 'value' => get_input_value('_source', RCUBE_INPUT_GPC))); - $hiddenfields->add(array('name' => '_cid', 'value' => $record['ID'])); + $hiddenfields->add(array('name' => '_cid', 'value' => $contact_id)); $form_start = $RCMAIL->output->request_form(array( 'name' => "form", 'method' => "post", diff --git a/program/steps/mail/autocomplete.inc b/program/steps/mail/autocomplete.inc index 55579814c..f9e8d71a4 100644 --- a/program/steps/mail/autocomplete.inc +++ b/program/steps/mail/autocomplete.inc @@ -102,7 +102,7 @@ if (!empty($book_types) && strlen($search)) { // also list matching contact groups if ($abook->groups && count($contacts) < $MAXNUM) { - foreach ($abook->list_groups($search) as $group) { + foreach ($abook->list_groups($search, $mode) as $group) { $abook->reset(); $abook->set_group($group['ID']); $group_prop = $abook->get_group($group['ID']); diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 81b598377..c3fc715a6 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -327,6 +327,19 @@ foreach ($parts as $header) { $fvalue .= $v; if ($v = $MESSAGE->headers->cc) $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + if ($v = $MESSAGE->headers->get('Sender', false)) + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + + // When To: and Reply-To: are the same we add From: address to the list (#1489037) + if ($v = $MESSAGE->headers->from) { + $from = rcube_mime::decode_address_list($v, null, false, $MESSAGE->headers->charset, true); + $to = rcube_mime::decode_address_list($MESSAGE->headers->to, null, false, $MESSAGE->headers->charset, true); + $replyto = rcube_mime::decode_address_list($MESSAGE->headers->replyto, null, false, $MESSAGE->headers->charset, true); + + if (count($replyto) && !count(array_diff($to, $replyto)) && count(array_diff($from, $to))) { + $fvalue .= (!empty($fvalue) ? $separator : '') . $v; + } + } } } else if (in_array($compose_mode, array(RCUBE_COMPOSE_DRAFT, RCUBE_COMPOSE_EDIT))) { @@ -386,7 +399,7 @@ function rcmail_compose_headers($attrib) { global $MESSAGE; - list($form_start, $form_end) = get_form_tags($attrib); + list($form_start,) = get_form_tags($attrib); $out = ''; $part = strtolower($attrib['part']); @@ -450,7 +463,7 @@ function rcmail_compose_headers($attrib) function rcmail_compose_header_from($attrib) { - global $MESSAGE, $OUTPUT, $RCMAIL, $compose_mode; + global $MESSAGE, $OUTPUT, $RCMAIL, $COMPOSE, $compose_mode; // pass the following attributes to the form class $field_attrib = array('name' => '_from'); @@ -553,7 +566,7 @@ function rcmail_message_is_html() function rcmail_prepare_message_body() { - global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $LINE_LENGTH, $HTML_MODE; + global $RCMAIL, $MESSAGE, $COMPOSE, $compose_mode, $HTML_MODE; // use posted message body if (!empty($_POST['_message'])) { @@ -626,7 +639,7 @@ function rcmail_prepare_message_body() function rcmail_compose_part_body($part, $isHtml = false) { - global $RCMAIL, $MESSAGE, $compose_mode; + global $RCMAIL, $MESSAGE, $LINE_LENGTH, $compose_mode; // Check if we have enough memory to handle the message in it // #1487424: we need up to 10x more memory than the body @@ -702,7 +715,7 @@ function rcmail_compose_part_body($part, $isHtml = false) function rcmail_compose_body($attrib) { - global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $LINE_LENGTH, $HTML_MODE, $MESSAGE_BODY; + global $RCMAIL, $CONFIG, $OUTPUT, $MESSAGE, $compose_mode, $HTML_MODE, $MESSAGE_BODY; list($form_start, $form_end) = get_form_tags($attrib); unset($attrib['form']); @@ -886,8 +899,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml) if (!isset($COMPOSE['forward_attachments']) && is_array($MESSAGE->mime_parts)) $cid_map = rcmail_write_compose_attachments($MESSAGE, $bodyIsHtml); - $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); - $charset = $RCMAIL->output->get_charset(); + $date = format_date($MESSAGE->headers->date, $RCMAIL->config->get('date_long')); if (!$bodyIsHtml) { $prefix = "\n\n\n-------- " . rcube_label('originalmessage') . " --------\n"; @@ -941,7 +953,7 @@ function rcmail_create_forward_body($body, $bodyIsHtml) function rcmail_create_draft_body($body, $bodyIsHtml) { - global $MESSAGE, $OUTPUT, $COMPOSE; + global $MESSAGE, $COMPOSE; /** * add attachments @@ -989,7 +1001,7 @@ function rcmail_write_compose_attachments(&$message, $bodyIsHtml) global $RCMAIL, $COMPOSE, $compose_mode; $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { + foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } @@ -1076,7 +1088,7 @@ function rcmail_write_forward_attachments() $names = array(); $loaded_attachments = array(); - foreach ((array)$COMPOSE['attachments'] as $id => $attachment) { + foreach ((array)$COMPOSE['attachments'] as $attachment) { $loaded_attachments[$attachment['name'] . $attachment['mimetype']] = $attachment; } @@ -1211,10 +1223,11 @@ function rcmail_save_image($path, $mimetype='') // handle attachments in memory $data = file_get_contents($path); + $name = rcmail_basename($path); $attachment = array( 'group' => $COMPOSE['id'], - 'name' => rcmail_basename($path), + 'name' => $name, 'mimetype' => $mimetype ? $mimetype : rc_mime_content_type($path, $name), 'data' => $data, 'size' => strlen($data), @@ -1484,7 +1497,7 @@ function rcmail_editor_selector($attrib) $select->add(Q(rcube_label('plaintoggle')), 'plain'); return $select->show($useHtml ? 'html' : 'plain'); - +/* foreach ($choices as $value => $text) { $attrib['id'] = '_' . $value; $attrib['value'] = $value; @@ -1492,6 +1505,7 @@ function rcmail_editor_selector($attrib) } return $selector; +*/ } diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 60db3f310..17ab6f97d 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -224,7 +224,7 @@ function rcmail_message_list($attrib) if (!in_array('threads', $a_show_cols)) array_unshift($a_show_cols, 'threads'); - $skin_path = $_SESSION['skin_path'] = $CONFIG['skin_path']; + $_SESSION['skin_path'] = $CONFIG['skin_path']; // set client env $OUTPUT->add_gui_object('messagelist', $attrib['id']); @@ -236,15 +236,13 @@ function rcmail_message_list($attrib) $OUTPUT->include_script('list.js'); - $thead = ''; - foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) - $thead .= html::tag('td', array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); + $table = new html_table($attrib); + if (!$attrib['noheader']) { + foreach (rcmail_message_list_head($attrib, $a_show_cols) as $cell) + $table->add_header(array('class' => $cell['className'], 'id' => $cell['id']), $cell['html']); + } - return html::tag('table', - $attrib, - html::tag('thead', null, html::tag('tr', null, $thead)) . - html::tag('tbody', null, ''), - array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); + return $table->show(); } @@ -291,7 +289,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null $thead = $head_replace ? rcmail_message_list_head($_SESSION['list_attrib'], $a_show_cols) : NULL; // get name of smart From/To column in folder context - if (($f = array_search('fromto', $a_show_cols)) !== false) { + if (array_search('fromto', $a_show_cols) !== false) { $smart_col = rcmail_message_list_smart_column_name(); } @@ -307,7 +305,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $a_show_cols=null } // loop through message headers - foreach ($a_headers as $n => $header) { + foreach ($a_headers as $header) { if (empty($header)) continue; @@ -381,7 +379,6 @@ function rcmail_message_list_head($attrib, $a_show_cols) global $RCMAIL; $skin_path = $_SESSION['skin_path']; - $image_tag = html::img(array('src' => "%s%s", 'alt' => "%s")); // check to see if we have some settings for sorting $sort_col = $_SESSION['sort_col']; @@ -417,7 +414,7 @@ function rcmail_message_list_head($attrib, $a_show_cols) $cells = array(); // get name of smart From/To column in folder context - if (($f = array_search('fromto', $a_show_cols)) !== false) { + if (array_search('fromto', $a_show_cols) !== false) { $smart_col = rcmail_message_list_smart_column_name(); } @@ -897,7 +894,7 @@ function rcmail_washtml_callback($tagname, $attrib, $content, $washtml) */ function rcmail_message_headers($attrib, $headers=null) { - global $OUTPUT, $MESSAGE, $PRINT_MODE, $RCMAIL; + global $MESSAGE, $PRINT_MODE, $RCMAIL; static $sa_attrib; // keep header table attrib @@ -1082,7 +1079,7 @@ function rcmail_message_body($attrib) $header_attrib[$regs[1]] = $value; if (!empty($MESSAGE->parts)) { - foreach ($MESSAGE->parts as $i => $part) { + foreach ($MESSAGE->parts as $part) { if ($part->type == 'headers') { $out .= html::div('message-partheaders', rcmail_message_headers(sizeof($header_attrib) ? $header_attrib : null, $part->headers)); } @@ -1440,7 +1437,8 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $c = count($a_parts); $j = 0; $out = ''; - $allvalues = array(); + $allvalues = array(); + $show_email = $RCMAIL->config->get('message_show_email'); if ($addicon && !isset($_SESSION['writeable_abook'])) { $_SESSION['writeable_abook'] = $RCMAIL->get_address_sources(true) ? true : false; @@ -1453,7 +1451,7 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, $string = $part['string']; // phishing email prevention (#1488981), e.g. "valid@email.addr <phishing@email.addr>" - if ($name && $name != $mailto && strpos($name, '@')) { + if (!$show_email && $name && $name != $mailto && strpos($name, '@')) { $name = ''; } @@ -1471,13 +1469,21 @@ function rcmail_address_string($input, $max=null, $linked=false, $addicon=null, } else if (check_email($part['mailto'], false)) { if ($linked) { - $address = html::a(array( - 'href' => 'mailto:'.$mailto, - 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), - 'title' => $mailto, - 'class' => "rcmContactAddress", - ), - Q($name ? $name : $mailto)); + $attrs = array( + 'href' => 'mailto:' . $mailto, + 'onclick' => sprintf("return %s.command('compose','%s',this)", JS_OBJECT_NAME, JQ($mailto)), + 'class' => "rcmContactAddress", + ); + + if ($show_email && $name && $mailto) { + $content = Q($name ? sprintf('%s <%s>', $name, $mailto) : $mailto); + } + else { + $content = Q($name ? $name : $mailto); + $attrs['title'] = $mailto; + } + + $address = html::a($attrs, $content); } else { $address = html::span(array('title' => $mailto, 'class' => "rcmContactAddress"), @@ -1730,8 +1736,7 @@ function rcmail_send_mdn($message, &$smtp_error) $sent = rcmail_deliver_message($compose, $identity['email'], $mailto, $smtp_error, $body_file, $options); - if ($sent) - { + if ($sent) { $RCMAIL->storage->set_flag($message->uid, 'MDNSENT'); return true; } diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 1947c0f29..2ad1ba9bd 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -228,11 +228,11 @@ function rcmail_remote_objects_msg() function rcmail_message_buttons() { - global $MESSAGE, $RCMAIL, $CONFIG; + global $RCMAIL; $mbox = $RCMAIL->storage->get_folder(); $delim = $RCMAIL->storage->get_hierarchy_delimiter(); - $dbox = $CONFIG['drafts_mbox']; + $dbox = $RCMAIL->config->get('drafts_mbox'); // the message is not a draft if ($mbox != $dbox && strpos($mbox, $dbox.$delim) !== 0) { diff --git a/program/steps/settings/edit_prefs.inc b/program/steps/settings/edit_prefs.inc index 971ed60b6..468e4994d 100644 --- a/program/steps/settings/edit_prefs.inc +++ b/program/steps/settings/edit_prefs.inc @@ -40,7 +40,7 @@ function rcmail_user_prefs_form($attrib) $out = $form_start; - foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $idx => $block) { + foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $block) { if (!empty($block['options'])) { $table = new html_table(array('cols' => 2)); diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index 0c7d9063f..34a72dd95 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -283,7 +283,6 @@ function rcube_subscription_form($attrib) $noselect = false; $classes = array($i%2 ? 'even' : 'odd'); - $folder_js = Q($folder['id']); $folder_utf8 = rcube_charset_convert($folder['id'], 'UTF7-IMAP'); $display_folder = str_repeat(' ', $folder['level']) . Q($protected ? rcmail_localize_foldername($folder['id']) : $folder['name']); @@ -394,7 +393,7 @@ function rcmail_rename_folder($oldname, $newname) $a_threaded = (array) $RCMAIL->config->get('message_threading', array()); $oldprefix = '/^' . preg_quote($oldname . $delimiter, '/') . '/'; - foreach ($a_threaded as $key => $val) { + foreach (array_keys($a_threaded) as $key) { if ($key == $oldname) { unset($a_threaded[$key]); $a_threaded[$newname] = true; diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index 319c58db9..860f36c35 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -418,6 +418,17 @@ function rcmail_user_prefs($current=null) ); } + // show checkbox to show email instead of name + if (!isset($no_override['message_show_email'])) { + $field_id = 'rcmfd_message_show_email'; + $input_msgshowemail = new html_checkbox(array('name' => '_message_show_email', 'id' => $field_id, 'value' => 1)); + + $blocks['main']['options']['message_show_email'] = array( + 'title' => html::label($field_id, Q(rcube_label('showemail'))), + 'content' => $input_msgshowemail->show($config['message_show_email']?1:0), + ); + } + // show checkbox for HTML/plaintext messages if (!isset($no_override['prefer_html'])) { $field_id = 'rcmfd_htmlmsg'; diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index dfb2b13ac..3bb82aa38 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -60,6 +60,7 @@ switch ($CURR_SECTION) case 'mailview': $a_user_prefs = array( 'message_extwin' => intval($_POST['_message_extwin']), + 'message_show_email' => isset($_POST['_message_show_email']) ? TRUE : FALSE, 'prefer_html' => isset($_POST['_prefer_html']) ? TRUE : FALSE, 'inline_images' => isset($_POST['_inline_images']) ? TRUE : FALSE, 'show_images' => isset($_POST['_show_images']) ? intval($_POST['_show_images']) : 0, diff --git a/program/steps/utils/spell.inc b/program/steps/utils/spell.inc index a0dd35d27..38e4ca285 100644 --- a/program/steps/utils/spell.inc +++ b/program/steps/utils/spell.inc @@ -42,6 +42,13 @@ else { $result = $spellchecker->get_xml(); } +if ($err = $spellchecker->error()) { + rcube::raise_error(array('code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => sprintf("Spell check engine error: " . $err)), + true, false); +} + // set response length header("Content-Length: " . strlen($result)); diff --git a/program/steps/utils/spell_html.inc b/program/steps/utils/spell_html.inc index 861e4ba48..96b41e230 100644 --- a/program/steps/utils/spell_html.inc +++ b/program/steps/utils/spell_html.inc @@ -46,6 +46,11 @@ else if ($request['method'] == 'learnWord') { } if ($error = $spellchecker->error()) { + rcube::raise_error(array('code' => 500, 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => sprintf("Spell check engine error: " . $error)), + true, false); + echo '{"error":{"errstr":"' . addslashes($error) . '","errfile":"","errline":null,"errcontext":"","level":"FATAL"}}'; exit; } diff --git a/tests/Framework/Mime.php b/tests/Framework/Mime.php index 61123dd85..3035ba062 100644 --- a/tests/Framework/Mime.php +++ b/tests/Framework/Mime.php @@ -185,6 +185,10 @@ class Framework_Mime extends PHPUnit_Framework_TestCase array("----------------------------------------------------------------------------------------\nabc def123456789012345", 76), "----------------------------------------------------------------------------------------\nabc def123456789012345", ), + array( + array("-------\nabc def", 5), + "-------\nabc\ndef", + ), ); foreach ($samples as $sample) { diff --git a/tests/Framework/VCard.php b/tests/Framework/VCard.php index 15aa5d816..3353b5b13 100644 --- a/tests/Framework/VCard.php +++ b/tests/Framework/VCard.php @@ -65,6 +65,20 @@ class Framework_VCard extends PHPUnit_Framework_TestCase $this->assertEquals("prefix", $vcard['prefix'], "Decode backslash character"); } + /** + * Backslash parsing test (#1489085) + */ + function test_parse_five() + { + $vcard = "BEGIN:VCARD\nVERSION:3.0\nN:last\\\\\\a;fir\\nst\nURL:http\\://domain.tld\nEND:VCARD"; + $vcard = new rcube_vcard($vcard, null); + $vcard = $vcard->get_assoc(); + + $this->assertEquals("last\\a", $vcard['surname'], "Decode dummy backslash character"); + $this->assertEquals("fir\nst", $vcard['firstname'], "Decode backslash character"); + $this->assertEquals("http://domain.tld", $vcard['website:other'][0], "Decode dummy backslash character"); + } + function test_import() { $input = file_get_contents($this->_srcpath('apple.vcf')); diff --git a/tests/src/Csv2vcard/tb_plain.csv b/tests/src/Csv2vcard/tb_plain.csv index 94ea766c0..4c4af14ca 100644 --- a/tests/src/Csv2vcard/tb_plain.csv +++ b/tests/src/Csv2vcard/tb_plain.csv @@ -1,2 +1,2 @@ First Name,Last Name,Display Name,Nickname,Primary Email,Secondary Email,Screen Name,Work Phone,Home Phone,Fax Number,Pager Number,Mobile Number,Home Address,Home Address 2,Home City,Home State,Home ZipCode,Home Country,Work Address,Work Address 2,Work City,Work State,Work ZipCode,Work Country,Job Title,Department,Organization,Web Page 1,Web Page 2,Birth Year,Birth Month,Birth Day,Custom 1,Custom 2,Custom 3,Custom 4,Notes, -Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,city,region,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,, +Firstname,Lastname,Displayname,Nick,test@domain.tld,next@domain.tld,,phone work,phone home,fax,pager,mobile,Priv address,,City,region,xx-xxx,USA,Addr work,,Wcity,Wstate,33-333,Poland,title,department,Organization,http://page.com,http://webpage.tld,1970,11,15,,,,,, diff --git a/tests/src/Csv2vcard/tb_plain.vcf b/tests/src/Csv2vcard/tb_plain.vcf index b001c3924..2aa91adf8 100644 --- a/tests/src/Csv2vcard/tb_plain.vcf +++ b/tests/src/Csv2vcard/tb_plain.vcf @@ -16,5 +16,5 @@ URL;TYPE=homepage:http://page.com URL;TYPE=other:http://webpage.tld BDAY;VALUE=date:1970-11-15 ADR;TYPE=home:;;Priv address;City;region;xx-xxx;USA -ADR;TYPE=work:;;Addr work;;;33-333;Poland +ADR;TYPE=work:;;Addr work;Wcity;Wstate;33-333;Poland END:VCARD diff --git a/tests/src/format-flowed-unfolded.txt b/tests/src/format-flowed-unfolded.txt index 14e526be4..0af9b7130 100644 --- a/tests/src/format-flowed-unfolded.txt +++ b/tests/src/format-flowed-unfolded.txt @@ -5,7 +5,7 @@ X On XX.YY.YYYY Y:YY, Somebody wrote:
> This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed()
-> has to be careful with empty quoted lines because they might end with a
+>> has to be careful with empty quoted lines because they might end with a
> space but still shouldn't be considered as flowed!
>
> The above empty line should persist after unfolding.
diff --git a/tests/src/format-flowed.txt b/tests/src/format-flowed.txt index 359a41aec..da36064e0 100644 --- a/tests/src/format-flowed.txt +++ b/tests/src/format-flowed.txt @@ -7,7 +7,7 @@ X On XX.YY.YYYY Y:YY, Somebody wrote:
> This part is a reply wihtout any flowing lines. rcube_mime::unfold_flowed()
-> has to be careful with empty quoted lines because they might end with a
+>> has to be careful with empty quoted lines because they might end with a
> space but still shouldn't be considered as flowed!
>
> The above empty line should persist after unfolding.
|