Version in base suite: 1.3.8+dfsg.1-2 Base version: roundcube_1.3.8+dfsg.1-2 Target version: roundcube_1.3.10+dfsg.1-1~deb10u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/r/roundcube/roundcube_1.3.8+dfsg.1-2.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/r/roundcube/roundcube_1.3.10+dfsg.1-1~deb10u1.dsc CHANGELOG | 34 ++++++ composer.json-dist | 2 debian/changelog | 30 ++++++ debian/copyright | 7 - debian/gbp.conf | 6 - debian/patches/CVE-2018-1000071.patch | 72 ++++++++++++++ debian/patches/correct_install_path.patch | 2 debian/patches/retry_to_reach_imap_server.patch | 31 ++++++ debian/patches/series | 2 debian/patches/update_composer.patch | 2 debian/roundcube-core.config | 58 ++++++----- debian/roundcube-core.postinst | 21 ++-- debian/roundcube-plugins.install | 7 + debian/salsa-ci.yml | 7 + index.php | 4 installer/index.php | 4 installer/test.php | 10 +- jsdeps.json | 4 plugins/debug_logger/runlog/runlog.php | 6 - plugins/enigma/README | 2 plugins/enigma/lib/enigma_engine.php | 23 +++- plugins/enigma/lib/enigma_ui.php | 16 ++- plugins/enigma/localization/en_US.inc | 1 plugins/managesieve/Changelog | 1 plugins/managesieve/managesieve.php | 7 + program/include/iniset.php | 4 program/include/rcmail_install.php | 7 - program/js/app.js | 19 ++- program/js/list.js | 28 ++--- program/lib/Roundcube/bootstrap.php | 2 program/lib/Roundcube/rcube_contacts.php | 2 program/lib/Roundcube/rcube_db.php | 2 program/lib/Roundcube/rcube_html2text.php | 5 - program/lib/Roundcube/rcube_image.php | 2 program/lib/Roundcube/rcube_imap.php | 9 + program/lib/Roundcube/rcube_imap_generic.php | 104 +++++++++++---------- program/lib/Roundcube/rcube_ldap.php | 15 ++- program/lib/Roundcube/rcube_ldap_generic.php | 13 -- program/lib/Roundcube/rcube_message.php | 8 - program/lib/Roundcube/rcube_mime.php | 2 program/lib/Roundcube/rcube_utils.php | 65 +++++++++---- program/lib/Roundcube/rcube_vcard.php | 10 +- program/lib/Roundcube/rcube_washtml.php | 2 program/steps/addressbook/search.inc | 4 program/steps/mail/func.inc | 6 - program/steps/mail/get.inc | 17 +++ program/steps/mail/list.inc | 15 +-- program/steps/mail/sendmail.inc | 2 public_html/index.php | 2 public_html/plugins/debug_logger/runlog/runlog.php | 6 - public_html/plugins/enigma/README | 2 public_html/plugins/enigma/lib/enigma_engine.php | 23 +++- public_html/plugins/enigma/lib/enigma_ui.php | 16 ++- public_html/plugins/enigma/localization/en_US.inc | 1 public_html/plugins/managesieve/Changelog | 1 public_html/plugins/managesieve/managesieve.php | 7 + public_html/program/js/app.js | 19 ++- public_html/program/js/list.js | 28 ++--- public_html/skins/classic/templates/about.html | 2 public_html/skins/larry/templates/about.html | 2 skins/classic/templates/about.html | 2 skins/larry/templates/about.html | 2 62 files changed, 560 insertions(+), 255 deletions(-) diff -Nru roundcube-1.3.8+dfsg.1/CHANGELOG roundcube-1.3.10+dfsg.1/CHANGELOG --- roundcube-1.3.8+dfsg.1/CHANGELOG 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/CHANGELOG 2019-08-28 11:24:49.000000000 +0000 @@ -1,6 +1,40 @@ CHANGELOG Roundcube Webmail =========================== +RELEASE 1.3.10 +-------------- +- Managesieve: Fix so "Create filter" option does not show up when Filters menu is disabled (#6723) +- Enigma: Fix bug where revoked users/keys were not greyed out in key info +- Enigma: Fix error message when trying to encrypt with a revoked key (#6607) +- Enigma: Fix "decryption oracle" bug [CVE-2019-10740] (#6638) +- Fix compatibility with kolab/net_ldap3 > 1.0.7 (#6785) +- Fix bug where bmp images couldn't be displayed on some systems (#6728) +- Fix bug in parsing vCard data using PHP 7.3 due to an invalid regexp (#6744) +- Fix bug where bold/strong text was converted to upper-case on html-to-text conversion (6758) +- Fix bug in rcube_utils::parse_hosts() where %t, %d, %z could return only tld (#6746) +- Fix bug where Next/Prev button in mail view didn't work with multi-folder search result (#6793) +- Fix bug where selection of columns on messages list wasn't working +- Fix bug in converting multi-page Tiff images to Jpeg (#6824) +- Fix wrong messages order after returning to a multi-folder search result (#6836) +- Fix PHP 7.4 deprecation: implode() wrong parameter order (#6866) +- Fix bug where it was possible to bypass the position:fixed CSS check in received messages (#6898) +- Fix bug where some strict remote URIs in url() style were unintentionally blocked (#6899) +- Fix bug where it was possible to bypass the CSS jail in HTML messages using :root pseudo-class (#6897) +- Fix bug where it was possible to bypass href URI check with data:application/xhtml+xml URIs (#6896) + +RELEASE 1.3.9 +------------- +- Fix TinyMCE download location (#6694) +- Fix bug where a message/rfc822 part without a filename wasn't listed on the attachments list (#6494) +- Fix handling of empty entries in vCard import (#6564) +- Fix bug in parsing some IMAP command responses that include unsolicited replies (#6577) +- Fix PHP 7.2 compatibility in debug_logger plugin (#6586) +- Fix so ANY record is not used for email domain validation, use A, MX, CNAME, AAAA instead (#6581) +- Fix so mime_content_type check in Installer uses files that should always be available (i.e. from program/resources) (#6599) +- Fix missing CSRF token on a link to download too-big message part (#6621) +- Fix bug when aborting dragging with ESC key didn't stop the move action (#6623) +- Fix bug where next row wasn't selected after deleting a collapsed thread (#6655) + RELEASE 1.3.8 ------------- - Fix PHP warnings on dummy QUOTA responses in Courier-IMAP 4.17.1 (#6374) diff -Nru roundcube-1.3.8+dfsg.1/composer.json-dist roundcube-1.3.10+dfsg.1/composer.json-dist --- roundcube-1.3.8+dfsg.1/composer.json-dist 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/composer.json-dist 2019-08-28 11:24:50.000000000 +0000 @@ -30,6 +30,6 @@ }, "suggest": { "pear/net_ldap2": "~2.2.0 required for connecting to LDAP", - "kolab/Net_LDAP3": "dev-master required for connecting to LDAP" + "kolab/net_ldap3": "dev-master required for connecting to LDAP" } } diff -Nru roundcube-1.3.8+dfsg.1/debian/changelog roundcube-1.3.10+dfsg.1/debian/changelog --- roundcube-1.3.8+dfsg.1/debian/changelog 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/changelog 2019-12-24 19:45:55.000000000 +0000 @@ -1,3 +1,33 @@ +roundcube (1.3.10+dfsg.1-1~deb10u1) buster; urgency=medium + + * d/control: revert bump of Standards-Version, as we want to release to + stable. + * d/upstream/signing-key.asc: revert Minimize OpenPGP certificate. + * Add patch to Fix "Retry to connect to IMAP server" (Closes: #947320) + + -- Sandro Knauß Tue, 24 Dec 2019 20:45:55 +0100 + +roundcube (1.3.10+dfsg.1-1) unstable; urgency=medium + + * New upstream release: (Closes: #927713) + - Fixes CVE-2019-10740 + + [ Guilhem Moulin ] + * Backport fix for CVE-2018-1000071: Insecure Permissions vulnerability in + enigma plugin that can result in exfiltration of gpg private key. + https://github.com/roundcube/roundcubemail/issues/6173 (Closes: #897014) + * New upstream release (1.3.9). (Closes: #898068) + * d/roundcube-core.config: Honor debconf setting roundcube/language, by + skipping the relevant part at pre-configure stage. (Closes: #923142) + * d/roundcube-core.postinst: Create temporary configuration file atomically. + * d/upstream/signing-key.asc: Minimize OpenPGP certificate. + * Add new plugins to roundcube-plugins: 'attachment_reminder' (closes: + #918126), 'example_addressbook', 'identicon', 'identity_select' and + 'redundant_attachments'. + * d/control: Bump Standards-Version to 4.3.0 (no changes needed). + + -- Beowulf Wed, 18 Dec 2019 00:26:48 +0100 + roundcube (1.3.8+dfsg.1-2) unstable; urgency=medium * debian/roundcube-plugins.maintscript: diff -Nru roundcube-1.3.8+dfsg.1/debian/copyright roundcube-1.3.10+dfsg.1/debian/copyright --- roundcube-1.3.8+dfsg.1/debian/copyright 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/copyright 2019-12-18 00:11:49.000000000 +0000 @@ -50,9 +50,10 @@ License: LGPL-2.1 Comment: Source - see debian/missing-sources/README -Files: plugins/enigma/enigma.php - plugins/enigma/lib/* - plugins/redundant_attachments/redundant_attachments.php +Files: plugins/additional_message_headers/* + plugins/database_attachments/* + plugins/debug_logger/* + plugins/redundant_attachments/* Copyright: Copyright (C) 2011, Kolab Systems AG Copyright (C) 2011, The Roundcube Dev Team License: GPL-2 diff -Nru roundcube-1.3.8+dfsg.1/debian/gbp.conf roundcube-1.3.10+dfsg.1/debian/gbp.conf --- roundcube-1.3.8+dfsg.1/debian/gbp.conf 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/gbp.conf 2019-12-18 00:15:30.000000000 +0000 @@ -1,3 +1,5 @@ [DEFAULT] -debian-branch=master -upstream-branch=upstream +debian-branch=debian/buster +upstream-branch=upstream-1.3.x +pristine-tar=True +compression=xz diff -Nru roundcube-1.3.8+dfsg.1/debian/patches/CVE-2018-1000071.patch roundcube-1.3.10+dfsg.1/debian/patches/CVE-2018-1000071.patch --- roundcube-1.3.8+dfsg.1/debian/patches/CVE-2018-1000071.patch 1970-01-01 00:00:00.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/patches/CVE-2018-1000071.patch 2019-12-18 00:15:30.000000000 +0000 @@ -0,0 +1,72 @@ +commit 48417c5fc9f6eb4b90500c09596606d489c700b5 +Author: Aleksander Machniak +Date: Sun Mar 4 09:14:43 2018 +0100 + + Remove default for enigma_pgp_homedir (#6173) + + To make the default installation more secure force users to set the folder. + Added notes that it should be secured or not accessible from the web browser. + +--- + plugins/enigma/README | 15 +++++++++++++-- + plugins/enigma/config.inc.php.dist | 4 ++-- + plugins/enigma/home/.htaccess | 7 ------- + plugins/enigma/lib/enigma_driver_gnupg.php | 2 +- + 4 files changed, 16 insertions(+), 12 deletions(-) + +--- a/plugins/enigma/config.inc.php.dist ++++ b/plugins/enigma/config.inc.php.dist +@@ -12,8 +12,8 @@ $config['enigma_smime_driver'] = 'phpssl + // Enables logging of enigma operations (including Crypt_GPG debug info) + $config['enigma_debug'] = false; + +-// Keys directory for all users. Default 'enigma/home'. +-// Must be writeable by PHP process ++// REQUIRED! Keys directory for all users. ++// Must be writeable by PHP process, and not in the web server document root + $config['enigma_pgp_homedir'] = null; + + // Location of gpg binary. By default it will be auto-detected. +--- a/plugins/enigma/home/.htaccess ++++ /dev/null +@@ -1,7 +0,0 @@ +-# deny webserver access to this directory +- +- Require all denied +- +- +- Deny from all +- +--- a/plugins/enigma/lib/enigma_driver_gnupg.php ++++ b/plugins/enigma/lib/enigma_driver_gnupg.php +@@ -40,7 +40,7 @@ class enigma_driver_gnupg extends enigma + */ + function init() + { +- $homedir = $this->rc->config->get('enigma_pgp_homedir', INSTALL_PATH . 'plugins/enigma/home'); ++ $homedir = $this->rc->config->get('enigma_pgp_homedir'); + $debug = $this->rc->config->get('enigma_debug'); + $binary = $this->rc->config->get('enigma_pgp_binary'); + $agent = $this->rc->config->get('enigma_pgp_agent'); +--- a/plugins/enigma/README ++++ b/plugins/enigma/README +@@ -21,9 +21,19 @@ Implemented features: + + Attaching public keys to email + + Key server(s) support (search, import) + ++INSTALLATION ++------------ ++ ++1. Rename config.inc.php.dist to config.inc.php. ++2. Create a directory for keys storage that is writeable for the PHP process. ++ This directory should be out of the document root, so it is not accessible ++ from the web browser. Set it's location in $config['enigma_pgp_homedir']. ++3. Make sure GnuPG is installed. ++ + + TODO: + ----- ++ + - Handling of big messages with temp files (? - security) + - Key info in contact details page (optional) + - Extended key management: diff -Nru roundcube-1.3.8+dfsg.1/debian/patches/correct_install_path.patch roundcube-1.3.10+dfsg.1/debian/patches/correct_install_path.patch --- roundcube-1.3.8+dfsg.1/debian/patches/correct_install_path.patch 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/patches/correct_install_path.patch 2019-12-18 00:11:49.000000000 +0000 @@ -6,7 +6,7 @@ --- a/program/include/iniset.php +++ b/program/include/iniset.php -@@ -25,7 +25,7 @@ define('RCMAIL_VERSION', '1.3.3'); +@@ -25,7 +25,7 @@ define('RCMAIL_VERSION', '1.3.9'); define('RCMAIL_START', microtime(true)); if (!defined('INSTALL_PATH')) { diff -Nru roundcube-1.3.8+dfsg.1/debian/patches/retry_to_reach_imap_server.patch roundcube-1.3.10+dfsg.1/debian/patches/retry_to_reach_imap_server.patch --- roundcube-1.3.8+dfsg.1/debian/patches/retry_to_reach_imap_server.patch 1970-01-01 00:00:00.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/patches/retry_to_reach_imap_server.patch 2019-12-24 16:32:16.000000000 +0000 @@ -0,0 +1,31 @@ +Description: Retries to connect to IMAP server. + As it may happen, that an IMAP server will have temporally issues and answers + with "Empty startup greeting". +Author: Hefee +Last-Update: 2019-12-24 + +--- +--- a/program/lib/Roundcube/rcube_imap.php ++++ b/program/lib/Roundcube/rcube_imap.php +@@ -144,7 +144,11 @@ class rcube_imap extends rcube_storage + + $attempt = 0; + do { +- $data = $this->plugins->exec_hook('storage_connect', ++ if ($attempt > 0) { ++ usleep(rand(1000, 100000)); ++ } ++ rcube::write_log('imap','Connecting to IMAP server attempt:'.$attempt); ++ $data = $this->plugins->exec_hook('storage_connect', + array_merge($this->options, array('host' => $host, 'user' => $user, + 'attempt' => ++$attempt))); + +@@ -156,7 +160,7 @@ class rcube_imap extends rcube_storage + rcube_utils::parse_socket_options($data['socket_options'], $data['host']); + + $this->conn->connect($data['host'], $data['user'], $pass, $data); +- } while(!$this->conn->connected() && $data['retry']); ++ } while(!$this->conn->connected() && $data['attempt'] < 6); + + $config = array( + 'host' => $data['host'], diff -Nru roundcube-1.3.8+dfsg.1/debian/patches/series roundcube-1.3.10+dfsg.1/debian/patches/series --- roundcube-1.3.8+dfsg.1/debian/patches/series 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/patches/series 2019-12-24 16:32:16.000000000 +0000 @@ -13,3 +13,5 @@ upstream-Add-get-and-extract-arguments-and-CACHEDIR-env-varia.patch update_jsdeps.json htaccess-assume-php7.patch +CVE-2018-1000071.patch +retry_to_reach_imap_server.patch diff -Nru roundcube-1.3.8+dfsg.1/debian/patches/update_composer.patch roundcube-1.3.10+dfsg.1/debian/patches/update_composer.patch --- roundcube-1.3.8+dfsg.1/debian/patches/update_composer.patch 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/patches/update_composer.patch 2019-12-18 00:11:49.000000000 +0000 @@ -45,6 +45,6 @@ - "pear/net_ldap2": "~2.2.0 required for connecting to LDAP", + "pear-pear.php.net/net_ldap2": ">=2.2.0", + "pear-pear.php.net/crypt_gpg": ">=1.6.0", - "kolab/Net_LDAP3": "dev-master required for connecting to LDAP" + "kolab/net_ldap3": "dev-master required for connecting to LDAP" } } diff -Nru roundcube-1.3.8+dfsg.1/debian/roundcube-core.config roundcube-1.3.10+dfsg.1/debian/roundcube-core.config --- roundcube-1.3.8+dfsg.1/debian/roundcube-core.config 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/roundcube-core.config 2019-12-18 00:01:02.000000000 +0000 @@ -7,38 +7,42 @@ db_input medium roundcube/hosts || true db_go || true -# Retrieve all available languages -instd_langs=$(echo /usr/share/roundcube/program/localization/*/messages.inc | \ - sed 's+[^ ]*/\([^ ]*\)/messages.inc+\1,+g' | sed 's+,$++') -db_subst roundcube/language languages $instd_langs -# First try to get the current choice in case of preseeding or if the -# question has already been asked +if [ "$1" = "configure" -a "$DPKG_MAINTSCRIPT_NAME" = "postinst" ] || \ + [ "$1" = "reconfigure" ]; then + # Retrieve all available languages + instd_langs=$(echo /usr/share/roundcube/program/localization/*/messages.inc | \ + sed 's+[^ ]*/\([^ ]*\)/messages.inc+\1,+g' | sed 's+,$++') + db_subst roundcube/language languages $instd_langs + # First try to get the current choice in case of preseeding or if the + # question has already been asked db_get roundcube/language || true locale="$RET" -if [ -n "$locale" -a -d "/usr/share/roundcube/program/localization/$locale" ]; then - # We get our answer (db_set should be useless in fact) - db_set roundcube/language $locale -else - # Either we never answered the question or the locale does not - # exist any more. In both cases, we do as if we never seen the - # question. - db_fset roundcube/language seen false - # Try to guess the locale - locale=$(echo $LANG | sed 's/[@\.].*//') - if [ -d /usr/share/roundcube/program/localization/$locale ]; then - db_set roundcube/language $locale + if [ -n "$locale" ] && [ -d "/usr/share/roundcube/program/localization/$locale" ]; then + # We get our answer (db_set should be useless in fact) + db_set roundcube/language $locale else - locale=$(echo $locale | sed 's/_.*//') - if [ -d /usr/share/roundcube/program/localization/$locale ]; then - db_set roundcube/language $locale - else - db_set roundcube/language en_US - fi + # Either we never answered the question or the locale does not + # exist any more. In both cases, we do as if we never seen the + # question. + db_fset roundcube/language seen false + # Try to guess the locale + locale=$(echo $LANG | sed 's/[@\.].*//') + if [ -d /usr/share/roundcube/program/localization/$locale ]; then + db_set roundcube/language $locale + else + locale=$(echo $locale | sed 's/_.*//') + if [ -d /usr/share/roundcube/program/localization/$locale ]; then + db_set roundcube/language $locale + else + db_set roundcube/language en_US + fi + fi fi + # Ask the question + db_input medium roundcube/language || true + db_go || true fi -# Ask the question -db_input medium roundcube/language || true -db_go || true + if [ -f /usr/share/dbconfig-common/dpkg/config ]; then dbc_dbtypes="mysql, pgsql, sqlite3" diff -Nru roundcube-1.3.8+dfsg.1/debian/roundcube-core.postinst roundcube-1.3.10+dfsg.1/debian/roundcube-core.postinst --- roundcube-1.3.8+dfsg.1/debian/roundcube-core.postinst 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/roundcube-core.postinst 2019-12-18 00:11:49.000000000 +0000 @@ -164,9 +164,6 @@ hosts="''" fi - db_get roundcube/language || true - language="$RET" - # Get current 3DES key from config file [ -f /etc/roundcube/config.inc.php ] && { deskey=$(sed -n "s+^\$config\['des_key'\] = '\(.*\)';\$+\1+p" \ @@ -181,12 +178,10 @@ done #create config.inc.php - touch $CONFFILE.ucftmp - chmod 640 $CONFFILE.ucftmp - chown root:www-data $CONFFILE.ucftmp + install -oroot -gwww-data -m0640 /dev/null "$CONFFILE.ucftmp" # Put hosts, language and key in config file - cat $BASEFILE | while read line; do + while read line; do case "$line" in "\$config['default_host'] = "*) printf "\$config['default_host'] = %s;\n" "${hosts}" @@ -194,14 +189,18 @@ "\$config['des_key'] = "*) printf "\$config['des_key'] = '%s';\n" "${deskey}" ;; - "\$config['language'] = "*) - printf "\$config['language'] = '%s';\n" "${language}" - ;; *) printf "%s\n" "$line" ;; esac - done >> $CONFFILE.ucftmp + done <"$BASEFILE" >"$CONFFILE.ucftmp" + + if db_fget roundcube/language seen && [ "$RET" = "true" ] && \ + db_get roundcube/language && [ -n "$RET" ]; then + echo "// the default locale setting (leave empty for auto-detection)" + echo "// RFC1766 formatted language name like en_US, de_DE, de_CH, fr_FR, pt_BR" + printf "\$config['language'] = '%s';\n" "$RET" + fi >>"$CONFFILE.ucftmp" # Register new config file if [ ! -f /etc/roundcube/config.inc.php ]; then diff -Nru roundcube-1.3.8+dfsg.1/debian/roundcube-plugins.install roundcube-1.3.10+dfsg.1/debian/roundcube-plugins.install --- roundcube-1.3.8+dfsg.1/debian/roundcube-plugins.install 2018-11-05 03:38:45.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/roundcube-plugins.install 2019-12-18 00:01:02.000000000 +0000 @@ -1,20 +1,25 @@ plugins/acl/ usr/share/roundcube/plugins plugins/additional_message_headers/ usr/share/roundcube/plugins plugins/archive/ usr/share/roundcube/plugins +plugins/attachment_reminder/ usr/share/roundcube/plugins plugins/autologon/ usr/share/roundcube/plugins plugins/database_attachments/ usr/share/roundcube/plugins plugins/debug_logger/ usr/share/roundcube/plugins plugins/emoticons/ usr/share/roundcube/plugins plugins/enigma/ usr/share/roundcube/plugins +plugins/example_addressbook/ usr/share/roundcube/plugins plugins/help/ usr/share/roundcube/plugins plugins/hide_blockquote/ usr/share/roundcube/plugins plugins/http_authentication/ usr/share/roundcube/plugins +plugins/identicon/ usr/share/roundcube/plugins +plugins/identity_select/ usr/share/roundcube/plugins plugins/managesieve/ usr/share/roundcube/plugins plugins/markasjunk/ usr/share/roundcube/plugins plugins/new_user_dialog/ usr/share/roundcube/plugins plugins/new_user_identity/ usr/share/roundcube/plugins plugins/newmail_notifier/ usr/share/roundcube/plugins -plugins/password /usr/share/roundcube/plugins +plugins/password/ /usr/share/roundcube/plugins +plugins/redundant_attachments/ usr/share/roundcube/plugins plugins/show_additional_headers/ usr/share/roundcube/plugins plugins/squirrelmail_usercopy/ usr/share/roundcube/plugins plugins/subscriptions_option/ usr/share/roundcube/plugins diff -Nru roundcube-1.3.8+dfsg.1/debian/salsa-ci.yml roundcube-1.3.10+dfsg.1/debian/salsa-ci.yml --- roundcube-1.3.8+dfsg.1/debian/salsa-ci.yml 1970-01-01 00:00:00.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/debian/salsa-ci.yml 2019-12-18 00:15:30.000000000 +0000 @@ -0,0 +1,7 @@ +--- +include: + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml + - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml + +variables: + RELEASE: 'buster' diff -Nru roundcube-1.3.8+dfsg.1/index.php roundcube-1.3.10+dfsg.1/index.php --- roundcube-1.3.8+dfsg.1/index.php 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/index.php 2019-08-28 11:24:49.000000000 +0000 @@ -2,9 +2,9 @@ /** +-------------------------------------------------------------------------+ | Roundcube Webmail IMAP Client | - | Version 1.3.8 | + | Version 1.3.10 | | | - | Copyright (C) 2005-2018, The Roundcube Dev Team | + | Copyright (C) 2005-2019, The Roundcube Dev Team | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU General Public License (with exceptions | diff -Nru roundcube-1.3.8+dfsg.1/installer/index.php roundcube-1.3.10+dfsg.1/installer/index.php --- roundcube-1.3.8+dfsg.1/installer/index.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/installer/index.php 2019-08-28 11:24:50.000000000 +0000 @@ -3,9 +3,9 @@ /** +-------------------------------------------------------------------------+ | Roundcube Webmail setup tool | - | Version 1.3.8 | + | Version 1.3.10 | | | - | Copyright (C) 2009-2015, The Roundcube Dev Team | + | Copyright (C) 2009-2019, The Roundcube Dev Team | | | | This program is free software: you can redistribute it and/or modify | | it under the terms of the GNU General Public License (with exceptions | diff -Nru roundcube-1.3.8+dfsg.1/installer/test.php roundcube-1.3.10+dfsg.1/installer/test.php --- roundcube-1.3.8+dfsg.1/installer/test.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/installer/test.php 2019-08-28 11:24:50.000000000 +0000 @@ -165,7 +165,7 @@ echo '
  • ' . join("
  • \n
  • ", $err) . "
"; $select = $RCI->versions_select(array('name' => 'version')); $select->add('0.9 or newer', ''); - echo '

You should run the update queries to get the schema fixed.

Version to update from: ' . $select->show() . ' 

'; + echo '

You should run the update queries to get the schema fixed.

Version to update from: ' . $select->show('') . ' 

'; $db_working = false; } else { @@ -288,8 +288,8 @@ echo '

Trying to send email...
'; - $from = idn_to_ascii(trim($_POST['_from'])); - $to = idn_to_ascii(trim($_POST['_to'])); + $from = rcube_utils::idn_to_ascii(trim($_POST['_from'])); + $to = rcube_utils::idn_to_ascii(trim($_POST['_to'])); if (preg_match('/^' . $RCI->email_pattern . '$/i', $from) && preg_match('/^' . $RCI->email_pattern . '$/i', $to) @@ -413,8 +413,8 @@ $imap_port = 993; } - $imap_host = idn_to_ascii($imap_host); - $imap_user = idn_to_ascii($_POST['_user']); + $imap_host = rcube_utils::idn_to_ascii($imap_host); + $imap_user = rcube_utils::idn_to_ascii($_POST['_user']); $imap = new rcube_imap(null); $imap->set_options(array( diff -Nru roundcube-1.3.8+dfsg.1/jsdeps.json roundcube-1.3.10+dfsg.1/jsdeps.json --- roundcube-1.3.8+dfsg.1/jsdeps.json 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/jsdeps.json 2019-08-28 11:24:50.000000000 +0000 @@ -36,7 +36,7 @@ { "lib": "tinymce", "version": "4.5.8", - "url": "http://download.ephox.com/tinymce/community/tinymce_4.5.8.zip", + "url": "https://download.tiny.cloud/tinymce/community/tinymce_4.5.8.zip", "dest": "program/js", "sha1": "08b0757264adb86066940bbafb7aa9ec0c7c6685", "license": "LGPL", @@ -56,7 +56,7 @@ { "lib": "tinymce-langs", "version": "4.5.8", - "url": "https://tinymce-services.azurewebsites.net/1/i18n/download?langs=ar,hy,az,eu,be,bs,bg_BG,ca,zh_CN,zh_TW,hr,cs,cs_CZ,da,nl,en_CA,en_GB,eo,et,fo,fi,fr_FR,fr_CH,gd,gl,ka_GE,de,de_AT,el,he_IL,hi_IN,hu_HU,is_IS,id,ga,it,ja,kab,km_KH,ko_KR,ku,ku_IQ,lv,lt,lb,mk_MK,ml_IN,nb_NO,oc,fa,fa_IR,pl,pt_BR,pt_PT,ro,ru,sk,sl_SI,es,es_MX,sv_SE,tg,ta,ta_IN,tt,th_TH,tr,tr_TR,ug,uk,uk_UA,vi,vi_VN,cy", + "url": "https://www.tiny.cloud/docs-4x/language/tinymce4x_languages.zip", "dest": "program/js/tinymce" }, { diff -Nru roundcube-1.3.8+dfsg.1/plugins/debug_logger/runlog/runlog.php roundcube-1.3.10+dfsg.1/plugins/debug_logger/runlog/runlog.php --- roundcube-1.3.8+dfsg.1/plugins/debug_logger/runlog/runlog.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/debug_logger/runlog/runlog.php 2019-08-28 11:24:50.000000000 +0000 @@ -19,7 +19,7 @@ public $timestamp = "d-M-Y H:i:s O"; public $max_line_size = 150; - function runlog() + function __construct() { $this->start_time = microtime(true); } @@ -71,9 +71,6 @@ foreach ($this->tag_count as $tag => $count){ $tag_report .= "$tag: $count, "; } - if (!empty($tag_report)) { -// $tag_report = "\n$tag_report\n"; - } $end_txt = sprintf("end: $name - %0.4f seconds $tag_report", $this->run_log[$lastk]['duration']); $this->print_to_console($end_txt, $this->run_log[$lastk]['tag'], 'end'); $this->print_to_file($end_txt, $this->run_log[$lastk]['tag'], 'end'); @@ -223,7 +220,6 @@ return $buf; } - function __destruct() { foreach ($this->file_handles as $handle) { diff -Nru roundcube-1.3.8+dfsg.1/plugins/enigma/README roundcube-1.3.10+dfsg.1/plugins/enigma/README --- roundcube-1.3.8+dfsg.1/plugins/enigma/README 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/enigma/README 2019-08-28 11:24:50.000000000 +0000 @@ -58,7 +58,7 @@ Possible reasons: - non-working loader in shebang (#! /usr/bin/env php) Make sure it works for the user the php scripts are executed upon - (i.e. apache, www-date, etc.) + (i.e. apache, www-data, etc.) - SELinux setting, try command: setsebool -P httpd_unified 0 Note: pinentry is used with gpg >= 2.0 and <= 2.1.12. diff -Nru roundcube-1.3.8+dfsg.1/plugins/enigma/lib/enigma_engine.php roundcube-1.3.10+dfsg.1/plugins/enigma/lib/enigma_engine.php --- roundcube-1.3.8+dfsg.1/plugins/enigma/lib/enigma_engine.php 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/enigma/lib/enigma_engine.php 2019-08-28 11:24:50.000000000 +0000 @@ -266,10 +266,6 @@ $recipients = array_merge($recipients, $mime->getRecipients()); } - if (empty($recipients)) { - return new enigma_error(enigma_error::KEYNOTFOUND); - } - $recipients = array_unique($recipients); // find recipient public keys @@ -373,17 +369,36 @@ */ function part_structure($p, $body = null) { + static $got_content = false; + + // Prevent from "decryption oracle" [CVE-2019-10740] (#6638) + // On mail compose (edit/reply/forward) we support encrypted content only + // in the first "content part" of the message. + if ($got_content && $this->rc->task == 'mail' && $this->rc->action == 'compose') { + return; + } + + // Don't be tempted to support encryption in text/html parts + // Because of EFAIL vulnerability we should never support this (#6289) + if ($p['mimetype'] == 'text/plain' || $p['mimetype'] == 'application/pgp') { $this->parse_plain($p, $body); + $got_content = true; } else if ($p['mimetype'] == 'multipart/signed') { $this->parse_signed($p, $body); + $got_content = true; } else if ($p['mimetype'] == 'multipart/encrypted') { $this->parse_encrypted($p); + $got_content = true; } else if ($p['mimetype'] == 'application/pkcs7-mime') { $this->parse_encrypted($p); + $got_content = true; + } + else { + $got_content = $p['structure']->type === 'content'; } return $p; diff -Nru roundcube-1.3.8+dfsg.1/plugins/enigma/lib/enigma_ui.php roundcube-1.3.10+dfsg.1/plugins/enigma/lib/enigma_ui.php --- roundcube-1.3.8+dfsg.1/plugins/enigma/lib/enigma_ui.php 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/enigma/lib/enigma_ui.php 2019-08-28 11:24:50.000000000 +0000 @@ -423,12 +423,12 @@ } } + $table->set_row_attribs($subkey->revoked || ($subkey->expires && $subkey->expires < $now) ? 'deleted' : ''); $table->add('id', $subkey->get_short_id()); $table->add('algo', $algo); $table->add('created', $subkey->created ? $this->rc->format_date($subkey->created, $date_format, false) : ''); $table->add('expires', $subkey->expires ? $this->rc->format_date($subkey->expires, $date_format, false) : $this->enigma->gettext('expiresnever')); $table->add('usage', implode(',', $usage)); - $table->set_row_attribs($subkey->revoked || ($subkey->expires && $subkey->expires < $now) ? 'deleted' : ''); } $out .= html::tag('fieldset', null, @@ -448,9 +448,9 @@ } $username .= ' <' . $user->email . '>'; + $table->set_row_attribs($user->revoked || !$user->valid ? 'deleted' : ''); $table->add('id', rcube::Q(trim($username))); $table->add('valid', $this->enigma->gettext($user->valid ? 'valid' : 'unknown')); - $table->set_row_attribs($user->revoked || !$user->valid ? 'deleted' : ''); } $out .= html::tag('fieldset', null, @@ -732,7 +732,7 @@ } $table->add('title', html::label('key-name', rcube::Q($this->enigma->gettext('newkeyident')))); - $table->add(null, implode($identities, "\n")); + $table->add(null, implode("\n", $identities)); // Key size $select = new html_select(array('name' => 'size', 'id' => 'key-size')); @@ -1100,10 +1100,14 @@ if ($mode && ($status instanceof enigma_error)) { $code = $status->getCode(); - if ($code == enigma_error::KEYNOTFOUND) { - $vars = array('email' => $status->getData('missing')); - $msg = 'enigma.' . $mode . 'nokey'; + if ($email = $status->getData('missing')) { + $vars = array('email' => $email); + $msg = 'enigma.' . $mode . 'nokey'; + } + else { + $msg = 'enigma.' . ($encrypt_enable ? 'encryptnoprivkey' : 'signnokey'); + } } else if ($code == enigma_error::BADPASS) { $this->password_prompt($status); diff -Nru roundcube-1.3.8+dfsg.1/plugins/enigma/localization/en_US.inc roundcube-1.3.10+dfsg.1/plugins/enigma/localization/en_US.inc --- roundcube-1.3.8+dfsg.1/plugins/enigma/localization/en_US.inc 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/enigma/localization/en_US.inc 2019-08-28 11:24:50.000000000 +0000 @@ -112,6 +112,7 @@ $messages['signnopass'] = 'Signing failed. Key password required.'; $messages['encrypterror'] = 'Encryption failed.'; $messages['encryptnokey'] = 'Encryption failed. Public key not found for $email.'; +$messages['encryptnoprivkey'] = 'Encryption failed. Private key not found.'; $messages['nokeysfound'] = 'No keys found'; $messages['keynotfound'] = 'Key not found!'; $messages['keyopenerror'] = 'Unable to get key information! Internal error.'; diff -Nru roundcube-1.3.8+dfsg.1/plugins/managesieve/Changelog roundcube-1.3.10+dfsg.1/plugins/managesieve/Changelog --- roundcube-1.3.8+dfsg.1/plugins/managesieve/Changelog 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/managesieve/Changelog 2019-08-28 11:24:50.000000000 +0000 @@ -1,3 +1,4 @@ +- Fix so "Create filter" option does not show up when Filters menu is disabled (#6723) - Fix bug where show_real_foldernames setting wasn't respected (#6422) - Fix bug where text: syntax was forced for strings longer than 1024 characters (#6143) - Fix missing Save button in Edit Filter Set page of Classic skin (#6154) diff -Nru roundcube-1.3.8+dfsg.1/plugins/managesieve/managesieve.php roundcube-1.3.10+dfsg.1/plugins/managesieve/managesieve.php --- roundcube-1.3.8+dfsg.1/plugins/managesieve/managesieve.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/plugins/managesieve/managesieve.php 2019-08-28 11:24:50.000000000 +0000 @@ -138,6 +138,13 @@ return; } + $this->load_config(); + + $vacation_mode = (int) $this->rc->config->get('managesieve_vacation'); + if ($vacation_mode == 2) { + return; + } + // use jQuery for popup window $this->require_plugin('jqueryui'); diff -Nru roundcube-1.3.8+dfsg.1/program/include/iniset.php roundcube-1.3.10+dfsg.1/program/include/iniset.php --- roundcube-1.3.8+dfsg.1/program/include/iniset.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/include/iniset.php 2019-08-28 11:24:50.000000000 +0000 @@ -5,7 +5,7 @@ | program/include/iniset.php | | | | This file is part of the Roundcube Webmail client | - | Copyright (C) 2008-2017, The Roundcube Dev Team | + | Copyright (C) 2008-2019, The Roundcube Dev Team | | | | Licensed under the GNU General Public License version 3 or | | any later version with exceptions for skins & plugins. | @@ -21,7 +21,7 @@ */ // application constants -define('RCMAIL_VERSION', '1.3.8'); +define('RCMAIL_VERSION', '1.3.10'); define('RCMAIL_START', microtime(true)); if (!defined('INSTALL_PATH')) { diff -Nru roundcube-1.3.8+dfsg.1/program/include/rcmail_install.php roundcube-1.3.10+dfsg.1/program/include/rcmail_install.php --- roundcube-1.3.8+dfsg.1/program/include/rcmail_install.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/include/rcmail_install.php 2019-08-28 11:24:50.000000000 +0000 @@ -519,10 +519,9 @@ { $errors = array(); $files = array( - 'skins/larry/images/roundcube_logo.png' => 'image/png', - 'program/resources/blank.tiff' => 'image/tiff', - 'program/resources/blocked.gif' => 'image/gif', - 'skins/larry/README' => 'text/plain', + 'program/resources/tinymce/video.png' => 'image/png', + 'program/resources/blank.tiff' => 'image/tiff', + 'program/resources/blocked.gif' => 'image/gif', ); foreach ($files as $path => $expected) { diff -Nru roundcube-1.3.8+dfsg.1/program/js/app.js roundcube-1.3.10+dfsg.1/program/js/app.js --- roundcube-1.3.8+dfsg.1/program/js/app.js 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/js/app.js 2019-08-28 11:24:50.000000000 +0000 @@ -1604,6 +1604,7 @@ if (menu) { $(menu).hide(); } + this.command(action, this.env.drag_target); this.env.drag_target = null; }; @@ -1633,7 +1634,8 @@ else if (list = this.contact_list) model = this.env.contactfolders; - if (this.drag_active && model && this.env.last_folder_target) { + // Note: we accept only mouse events to ignore dragging aborts with ESC key (#6623) + if (this.drag_active && model && this.env.last_folder_target && !rcube_event.is_keyboard(e)) { var target = model[this.env.last_folder_target]; list.draglayer.hide(); @@ -1718,7 +1720,7 @@ // remove focus from list widgets if (window.rcube_list_widget && rcube_list_widget._instances.length) { - $.each(rcube_list_widget._instances, function(i,list){ + $.each(rcube_list_widget._instances, function(i,list) { if (list && !rcube_mouse_is_over(e, list.list.parentNode)) list.blur(); }); @@ -1733,7 +1735,7 @@ } // reset popup menus; delayed to have updated menu_stack data - setTimeout(function(e){ + setTimeout(function(e) { var obj, skip, config, id, i, parents = $(target).parents(); for (i = ref.menu_stack.length - 1; i >= 0; i--) { id = ref.menu_stack[i]; @@ -9059,8 +9061,15 @@ // get the IMP mailbox of the message with the given UID this.get_message_mailbox = function(uid) { - var msg = (this.env.messages && uid ? this.env.messages[uid] : null) || {}; - return msg.mbox || this.env.mailbox; + var msg; + + if (this.env.messages && uid && (msg = this.env.messages[uid]) && msg.mbox) + return msg.mbox; + + if (/^[0-9]+-(.*)$/.test(uid)) + return RegExp.$1; + + return this.env.mailbox; }; // build request parameters from single message id (maybe with mailbox name) diff -Nru roundcube-1.3.8+dfsg.1/program/js/list.js roundcube-1.3.10+dfsg.1/program/js/list.js --- roundcube-1.3.8+dfsg.1/program/js/list.js 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/js/list.js 2019-08-28 11:24:50.000000000 +0000 @@ -355,8 +355,11 @@ node.style.display = 'none'; + // Specify removed row uid in the select_next argument. + // It's needed because after removing a set of rows + // reference to the last selected message is lost. if (sel_next) - this.select_next(); + this.select_next(uid); delete this.rows[uid]; this.rowcount--; @@ -579,6 +582,7 @@ rcube_event.add_listener({event:'mousemove', object:this, method:'drag_mouse_move'}); rcube_event.add_listener({event:'mouseup', object:this, method:'drag_mouse_up'}); + if (bw.touch) { rcube_event.add_listener({event:'touchmove', object:this, method:'drag_mouse_move'}); rcube_event.add_listener({event:'touchend', object:this, method:'drag_mouse_up'}); @@ -586,6 +590,7 @@ // enable dragging over iframes this.add_dragfix(); + this.focus(); } return false; @@ -875,12 +880,12 @@ /** * get first/next/previous/last rows that are not hidden */ -get_next_row: function() +get_next_row: function(uid) { if (!this.rowcount) return false; - var last_selected_row = this.rows[this.last_selected], + var last_selected_row = this.rows[uid || this.last_selected], new_row = last_selected_row ? last_selected_row.obj.nextSibling : null; while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) @@ -889,12 +894,12 @@ return new_row; }, -get_prev_row: function() +get_prev_row: function(uid) { if (!this.rowcount) return false; - var last_selected_row = this.rows[this.last_selected], + var last_selected_row = this.rows[uid || this.last_selected], new_row = last_selected_row ? last_selected_row.obj.previousSibling : null; while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) @@ -1029,15 +1034,12 @@ /** - * Select row next to the last selected one. + * Select row next to the specified or last selected one * Either below or above. */ -select_next: function() +select_next: function(uid) { - var next_row = this.get_next_row(), - prev_row = this.get_prev_row(), - new_row = (next_row) ? next_row : prev_row; - + var new_row = this.get_next_row(uid) || this.get_prev_row(uid); if (new_row) this.select_row(new_row.uid, false, false); }, @@ -1323,9 +1325,7 @@ */ key_press: function(e) { - var target = e.target || {}; - - if (!this.focused || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT') + if (!this.focused || $(e.target).is('input,textarea,select')) return true; var keyCode = rcube_event.get_keycode(e), diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/bootstrap.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/bootstrap.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/bootstrap.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/bootstrap.php 2019-08-28 11:24:50.000000000 +0000 @@ -53,7 +53,7 @@ } // framework constants -define('RCUBE_VERSION', '1.3.8'); +define('RCUBE_VERSION', '1.3.10'); define('RCUBE_CHARSET', 'UTF-8'); if (!defined('RCUBE_LIB_DIR')) { diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_contacts.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_contacts.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_contacts.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_contacts.php 2019-08-28 11:24:50.000000000 +0000 @@ -356,7 +356,7 @@ if (!empty($post_search) || !empty($required)) { $ids = array(0); // build key name regexp - $regexp = '/^(' . implode(array_keys($post_search), '|') . ')(?:.*)$/'; + $regexp = '/^(' . implode('|', array_keys($post_search)) . ')(?:.*)$/'; // use initial WHERE clause, to limit records number if possible if (!empty($where)) $this->set_search_set($where); diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_db.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_db.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_db.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_db.php 2019-08-28 11:24:50.000000000 +0000 @@ -914,7 +914,7 @@ $name[] = $start . $elem . $end; } - return implode($name, '.'); + return implode('.', $name); } /** diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_html2text.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_html2text.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_html2text.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_html2text.php 2019-08-28 11:24:50.000000000 +0000 @@ -248,8 +248,6 @@ protected $callback_search = array( '/<(a) [^>]*href=("|\')([^"\']+)\2[^>]*>(.*?)<\/a>/i', // '/<(h)[123456]( [^>]*)?>(.*?)<\/h[123456]>/i', // h1 - h6 - '/<(b)( [^>]*)?>(.*?)<\/b>/i', // - '/<(strong)( [^>]*)?>(.*?)<\/strong>/i', // '/<(th)( [^>]*)?>(.*?)<\/th>/i', // and ); @@ -659,9 +657,6 @@ public function tags_preg_callback($matches) { switch (strtolower($matches[1])) { - case 'b': - case 'strong': - return $this->_toupper($matches[3]); case 'th': return $this->_toupper("\t\t". $matches[3] ."\n"); case 'h': diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_image.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_image.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_image.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_image.php 2019-08-28 11:24:50.000000000 +0000 @@ -324,7 +324,7 @@ $p['out'] = $filename; $p['type'] = self::$extensions[$type]; - $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -quality 75 {in} {type}:{out}', $p); + $result = rcube::exec($convert . ' 2>&1 -colorspace sRGB -strip -flatten -quality 75 {in} {type}:{out}', $p); if ($result === '') { chmod($filename, 0600); diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_imap.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_imap.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_imap.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_imap.php 2019-08-28 11:24:50.000000000 +0000 @@ -1056,8 +1056,10 @@ } // slice resultset first... + $index = array_slice($search_set->get(), $from, $slice_length); $fetch = array(); - foreach (array_slice($search_set->get(), $from, $slice_length) as $msg_id) { + + foreach ($index as $msg_id) { list($uid, $folder) = explode('-', $msg_id, 2); $fetch[$folder][] = $uid; } @@ -1067,6 +1069,11 @@ foreach ($fetch as $folder => $a_index) { $a_msg_headers = array_merge($a_msg_headers, array_values($this->fetch_headers($folder, $a_index))); } + + // Re-sort the result according to the original search set order + usort($a_msg_headers, function($a, $b) use ($index) { + return array_search($a->uid . '-' . $a->folder, $index) - array_search($b->uid . '-' . $b->folder, $index); + }); } if ($slice) { diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_imap_generic.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_imap_generic.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_imap_generic.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_imap_generic.php 2019-08-28 11:24:50.000000000 +0000 @@ -1237,10 +1237,10 @@ $items[] = 'UNSEEN'; } - list($code, $response) = $this->execute('STATUS', array($this->escape($mailbox), - '(' . implode(' ', $items) . ')')); + list($code, $response) = $this->execute('STATUS', + array($this->escape($mailbox), '(' . implode(' ', $items) . ')'), 0, '/^\* STATUS /i'); - if ($code == self::ERROR_OK && preg_match('/^\* STATUS /i', $response)) { + if ($code == self::ERROR_OK && $response) { $result = array(); $response = substr($response, 9); // remove prefix "* STATUS " @@ -1703,11 +1703,11 @@ } } - list($code, $response) = $this->execute('ID', array( - !empty($args) ? '(' . implode(' ', (array) $args) . ')' : $this->escape(null) - )); + list($code, $response) = $this->execute('ID', + array(!empty($args) ? '(' . implode(' ', (array) $args) . ')' : $this->escape(null)), + 0, '/^\* ID /i'); - if ($code == self::ERROR_OK && preg_match('/^\* ID /i', $response)) { + if ($code == self::ERROR_OK && $response) { $response = substr($response, 5); // remove prefix "* ID " $items = $this->tokenizeResponse($response, 1); $result = null; @@ -1758,9 +1758,9 @@ } } - list($code, $response) = $this->execute('ENABLE', $extension); + list($code, $response) = $this->execute('ENABLE', $extension, 0, '/^\* ENABLED /i'); - if ($code == self::ERROR_OK && preg_match('/^\* ENABLED /i', $response)) { + if ($code == self::ERROR_OK && $response) { $response = substr($response, 10); // remove prefix "* ENABLED " $result = (array) $this->tokenizeResponse($response); @@ -3114,7 +3114,7 @@ // * QUOTA user/sample (STORAGE 654 9765) // a0001 OK Completed - list($code, $response) = $this->execute('GETQUOTAROOT', array($this->escape($mailbox))); + list($code, $response) = $this->execute('GETQUOTAROOT', array($this->escape($mailbox)), 0, '/^\* QUOTA /i'); $result = false; $min_free = PHP_INT_MAX; @@ -3122,41 +3122,39 @@ if ($code == self::ERROR_OK) { foreach (explode("\n", $response) as $line) { - if (preg_match('/^\* QUOTA /', $line)) { - list(, , $quota_root) = $this->tokenizeResponse($line, 3); + list(, , $quota_root) = $this->tokenizeResponse($line, 3); - $quotas = $this->tokenizeResponse($line, 1); + $quotas = $this->tokenizeResponse($line, 1); - if (empty($quotas)) { - continue; - } + if (empty($quotas)) { + continue; + } - foreach (array_chunk($quotas, 3) as $quota) { - list($type, $used, $total) = $quota; - $type = strtolower($type); + foreach (array_chunk($quotas, 3) as $quota) { + list($type, $used, $total) = $quota; + $type = strtolower($type); - if ($type && $total) { - $all[$quota_root][$type]['used'] = intval($used); - $all[$quota_root][$type]['total'] = intval($total); - } + if ($type && $total) { + $all[$quota_root][$type]['used'] = intval($used); + $all[$quota_root][$type]['total'] = intval($total); } + } - if (empty($all[$quota_root]['storage'])) { - continue; - } + if (empty($all[$quota_root]['storage'])) { + continue; + } - $used = $all[$quota_root]['storage']['used']; - $total = $all[$quota_root]['storage']['total']; - $free = $total - $used; - - // calculate lowest available space from all storage quotas - if ($free < $min_free) { - $min_free = $free; - $result['used'] = $used; - $result['total'] = $total; - $result['percent'] = min(100, round(($used/max(1,$total))*100)); - $result['free'] = 100 - $result['percent']; - } + $used = $all[$quota_root]['storage']['used']; + $total = $all[$quota_root]['storage']['total']; + $free = $total - $used; + + // calculate lowest available space from all storage quotas + if ($free < $min_free) { + $min_free = $free; + $result['used'] = $used; + $result['total'] = $total; + $result['percent'] = min(100, round(($used/max(1,$total))*100)); + $result['free'] = 100 - $result['percent']; } } } @@ -3221,9 +3219,9 @@ */ public function getACL($mailbox) { - list($code, $response) = $this->execute('GETACL', array($this->escape($mailbox))); + list($code, $response) = $this->execute('GETACL', array($this->escape($mailbox)), 0, '/^\* ACL /i'); - if ($code == self::ERROR_OK && preg_match('/^\* ACL /i', $response)) { + if ($code == self::ERROR_OK && $response) { // Parse server response (remove "* ACL ") $response = substr($response, 6); $ret = $this->tokenizeResponse($response); @@ -3258,10 +3256,10 @@ */ public function listRights($mailbox, $user) { - list($code, $response) = $this->execute('LISTRIGHTS', array( - $this->escape($mailbox), $this->escape($user))); + list($code, $response) = $this->execute('LISTRIGHTS', + array($this->escape($mailbox), $this->escape($user)), 0, '/^\* LISTRIGHTS /i'); - if ($code == self::ERROR_OK && preg_match('/^\* LISTRIGHTS /i', $response)) { + if ($code == self::ERROR_OK && $response) { // Parse server response (remove "* LISTRIGHTS ") $response = substr($response, 13); @@ -3287,9 +3285,9 @@ */ public function myRights($mailbox) { - list($code, $response) = $this->execute('MYRIGHTS', array($this->escape($mailbox))); + list($code, $response) = $this->execute('MYRIGHTS', array($this->escape($mailbox)), 0, '/^\* MYRIGHTS /i'); - if ($code == self::ERROR_OK && preg_match('/^\* MYRIGHTS /i', $response)) { + if ($code == self::ERROR_OK && $response) { // Parse server response (remove "* MYRIGHTS ") $response = substr($response, 11); @@ -3704,11 +3702,12 @@ * @param string $command IMAP command * @param array $arguments Command arguments * @param int $options Execution options + * @param string $filter Line filter (regexp) * * @return mixed Response code or list of response code and data * @since 0.5-beta */ - public function execute($command, $arguments=array(), $options=0) + public function execute($command, $arguments = array(), $options = 0, $filter = null) { $tag = $this->nextTag(); $query = $tag . ' ' . $command; @@ -3735,7 +3734,10 @@ $line = $this->readLine(4096); if ($response !== null) { - $response .= $line; + // TODO: Better string literals handling with filter + if (!$filter || preg_match($filter, $line)) { + $response .= $line; + } } // parse untagged response for [COPYUID 1204196876 3456:3457 123:124] (RFC6851) @@ -3751,8 +3753,12 @@ // Remove last line from response if ($response) { - $line_len = min(strlen($response), strlen($line) + 2); - $response = substr($response, 0, -$line_len); + if (!$filter) { + $line_len = min(strlen($response), strlen($line)); + $response = substr($response, 0, -$line_len); + } + + $response = rtrim($response, "\r\n"); } // optional CAPABILITY response diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_ldap.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_ldap.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_ldap.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_ldap.php 2019-08-28 11:24:50.000000000 +0000 @@ -1009,7 +1009,7 @@ if ($this->ready && $dn) { $dn = self::dn_decode($dn); - if ($rec = $this->ldap->get_entry($dn)) { + if ($rec = $this->ldap->get_entry($dn, $this->prop['attributes'])) { $rec = array_change_key_case($rec, CASE_LOWER); } @@ -1530,8 +1530,15 @@ foreach ($fieldmap as $rf => $lf) { - for ($i=0; $i < $rec[$lf]['count']; $i++) { - if (!($value = $rec[$lf][$i])) + // we might be dealing with normalized and non-normalized data + $entry = $rec[$lf]; + if (!is_array($entry) || !isset($entry['count'])) { + $entry = (array) $entry; + $entry['count'] = count($entry); + } + + for ($i=0; $i < $entry['count']; $i++) { + if (!($value = $entry[$i])) continue; list($col, $subtype) = explode(':', $rf); @@ -1543,7 +1550,7 @@ $out['address' . ($subtype ? ':' : '') . $subtype][$i][$col] = $value; else if ($col == 'address' && strpos($value, '$') !== false) // address data is represented as string separated with $ list($out[$rf][$i]['street'], $out[$rf][$i]['locality'], $out[$rf][$i]['zipcode'], $out[$rf][$i]['country']) = explode('$', $value); - else if ($rec[$lf]['count'] > 1) + else if ($entry['count'] > 1) $out[$rf][] = $value; else $out[$rf] = $value; diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_ldap_generic.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_ldap_generic.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_ldap_generic.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_ldap_generic.php 2019-08-28 11:24:50.000000000 +0000 @@ -55,19 +55,6 @@ } /** - * Get a specific LDAP entry, identified by its DN - * - * @param string $dn Record identifier - * @param array $attributes Attributes to return - * - * @return array Hash array - */ - function get_entry($dn, $attributes = array()) - { - return parent::get_entry($dn, !empty($attributes) ? $attributes : $this->attributes); - } - - /** * Prints debug/error info to the log */ public function log($level, $msg) diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_message.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_message.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_message.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_message.php 2019-08-28 11:24:50.000000000 +0000 @@ -769,12 +769,12 @@ // multipart/alternative or message/rfc822 if ($primary_type == 'multipart' || $part_mimetype == 'message/rfc822') { - $this->parse_structure($mail_part, true); - - // list message/rfc822 as attachment as well (mostly .eml) - if ($primary_type == 'message' && !empty($mail_part->filename)) { + // list message/rfc822 as attachment as well + if ($part_mimetype == 'message/rfc822') { $this->add_part($mail_part, 'attachment'); } + + $this->parse_structure($mail_part, true); } // part text/[plain|html] or delivery status else if ((($part_mimetype == 'text/plain' || $part_mimetype == 'text/html') && $mail_part->disposition != 'attachment') || diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_mime.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_mime.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_mime.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_mime.php 2019-08-28 11:24:50.000000000 +0000 @@ -844,6 +844,8 @@ 'image/jpg' => array('jpg', 'jpeg', 'jpe'), 'image/pjpeg' => array('jpg', 'jpeg', 'jpe'), 'image/tiff' => array('tif'), + 'image/bmp' => array('bmp'), + 'image/x-ms-bmp' => array('bmp'), 'message/rfc822' => array('eml'), 'text/x-mail' => array('eml'), ); diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_utils.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_utils.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_utils.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_utils.php 2019-08-28 11:24:50.000000000 +0000 @@ -119,18 +119,16 @@ $rcube = rcube::get_instance(); - if (!$dns_check || !$rcube->config->get('email_dns_check')) { + if (!$dns_check || !function_exists('checkdnsrr') || !$rcube->config->get('email_dns_check')) { return true; } - // find MX record(s) - if (!function_exists('getmxrr') || getmxrr($domain_part, $mx_records)) { - return true; - } - - // find any DNS record - if (!function_exists('checkdnsrr') || checkdnsrr($domain_part, 'ANY')) { - return true; + // Check DNS record(s) + // Note: We can't use ANY (#6581) + foreach (array('A', 'MX', 'CNAME', 'AAAA') as $type) { + if (checkdnsrr($domain_part, $type)) { + return true; + } } } @@ -390,7 +388,7 @@ return '/* evil! */'; } - $strict_url_regexp = '!url\s*\([ "\'](https?:)//[a-z0-9/._+-]+["\' ]\)!Uims'; + $strict_url_regexp = '!url\s*\(\s*["\']?(https?:)//[a-z0-9/._+-]+["\']?\s*\)!Uims'; // cut out all contents between { and } while (($pos = strpos($source, '{', $last_pos)) && ($pos2 = strpos($source, '}', $pos))) { @@ -401,7 +399,7 @@ $styles = substr($source, $pos+1, $length); // Convert position:fixed to position:absolute (#5264) - $styles = preg_replace('/position:[\s\r\n]*fixed/i', 'position: absolute', $styles); + $styles = preg_replace('/position[^a-z]*:[\s\r\n]*fixed/i', 'position: absolute', $styles); // check every line of a style block... if ($allow_remote) { @@ -431,7 +429,7 @@ $source = substr_replace($source, $repl, $pos+1, $length); $last_pos = $pos2 - ($length - strlen($repl)); } - +/* // remove html comments and add #container to each tag selector. // also replace body definition because we also stripped off the tag $source = preg_replace( @@ -449,6 +447,39 @@ $container_id, ), $source); +*/ + // remove html comments + $source = preg_replace('/(^\s*<\!--)|(-->\s*$)/m', '', $source); + + // add #container to each tag selector + if ($container_id) { + // (?!##str) below is to not match with ##str_replacement_0## + // from rcube_string_replacer used above, this is needed for + // cases like @media { body { position: fixed; } } (#5811) + $regexp = '/(^\s*|,\s*|\}\s*|\{\s*)((?!##str):?[a-z0-9\._#\*\[][a-z0-9\._:\(\)#=~ \[\]"\|\>\+\$\^-]*)/im'; + $callback = function($matches) use ($container_id, $prefix) { + $replace = $matches[2]; + + if (stripos($replace, ':root') === 0) { + $replace = substr($replace, 5); + } + + $replace = "#$container_id " . $replace; + + // Remove redundant spaces (for simpler testing) + $replace = preg_replace('/\s+/', ' ', $replace); + + return str_replace($matches[2], $replace, $matches[0]); + }; + + $source = preg_replace_callback($regexp, $callback, $source); + } + + // replace body definition because we also stripped off the tag + if ($container_id) { + $regexp = '/#' . preg_quote($container_id, '/') . '\s+body/i'; + $source = preg_replace($regexp, "#$container_id", $source); + } // put block contents back in $source = $replacements->resolve($source); @@ -569,13 +600,15 @@ // %n - host $n = preg_replace('/:\d+$/', '', $_SERVER['SERVER_NAME']); // %t - host name without first part, e.g. %n=mail.domain.tld, %t=domain.tld - $t = preg_replace('/^[^\.]+\./', '', $n); - // %d - domain name without first part - $d = preg_replace('/^[^\.]+\./', '', $_SERVER['HTTP_HOST']); + // If %n=domain.tld then %t=domain.tld as well (remains valid) + $t = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $n); + // %d - domain name without first part (up to domain.tld) + $d = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $_SERVER['HTTP_HOST']); // %h - IMAP host $h = $_SESSION['storage_host'] ?: $host; // %z - IMAP domain without first part, e.g. %h=imap.domain.tld, %z=domain.tld - $z = preg_replace('/^[^\.]+\./', '', $h); + // If %h=domain.tld then %z=domain.tld as well (remains valid) + $z = preg_replace('/^[^.]+\.(?![^.]+$)/', '', $h); // %s - domain name after the '@' from e-mail address provided at login screen. // Returns FALSE if an invalid email is provided if (strpos($name, '%s') !== false) { diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_vcard.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_vcard.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_vcard.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_vcard.php 2019-08-28 11:24:50.000000000 +0000 @@ -535,8 +535,8 @@ '/item(\d+)\.(TEL|EMAIL|URL)([^:]*?):(.*?)item\1.X-ABLabel:(?:_\$!<)?([\w() -]*)(?:>!\$_)?./si', '/^item\d*\.X-AB.*$/mi', // remove cruft like item1.X-AB* '/^item\d*\./mi', // remove item1.ADR instead of ADR - '/\n+/', // remove empty lines - '/^(N:[^;\R]*)$/m', // if N doesn't have any semicolons, add some + '/\n+/', // remove empty lines + '/^(N:[^;\r\n]*)$/m', // if N doesn't have any semicolons, add some ), array( '\2;type=\5\3:\4', @@ -673,8 +673,10 @@ $data = self::vcard_unquote($data); } - $entry = array_merge($entry, (array) $data); - $result[$field][] = $entry; + if (is_array($data) || (is_string($data) && strlen($data))) { + $entry = array_merge($entry, (array) $data); + $result[$field][] = $entry; + } } } diff -Nru roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_washtml.php roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_washtml.php --- roundcube-1.3.8+dfsg.1/program/lib/Roundcube/rcube_washtml.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/lib/Roundcube/rcube_washtml.php 2019-08-28 11:24:50.000000000 +0000 @@ -318,7 +318,7 @@ $out = $this->wash_uri($value, true); } else if ($this->is_link_attribute($node->nodeName, $key)) { - if (!preg_match('!^(javascript|vbscript|data:text)!i', $value) + if (!preg_match('!^(javascript|vbscript|data:)!i', $value) && preg_match('!^([a-z][a-z0-9.+-]+:|//|#).+!i', $value) ) { $out = $value; diff -Nru roundcube-1.3.8+dfsg.1/program/steps/addressbook/search.inc roundcube-1.3.10+dfsg.1/program/steps/addressbook/search.inc --- roundcube-1.3.8+dfsg.1/program/steps/addressbook/search.inc 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/steps/addressbook/search.inc 2019-08-28 11:24:50.000000000 +0000 @@ -209,8 +209,8 @@ // search request ID $search_request = md5('addr' - .(is_array($fields) ? implode($fields, ',') : $fields) - .(is_array($search) ? implode($search, ',') : $search)); + .(is_array($fields) ? implode(',', $fields) : $fields) + .(is_array($search) ? implode(',', $search) : $search)); // save search settings in session $_SESSION['search'][$search_request] = $search_set; diff -Nru roundcube-1.3.8+dfsg.1/program/steps/mail/func.inc roundcube-1.3.10+dfsg.1/program/steps/mail/func.inc --- roundcube-1.3.8+dfsg.1/program/steps/mail/func.inc 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/steps/mail/func.inc 2019-08-28 11:24:50.000000000 +0000 @@ -1250,6 +1250,7 @@ $safe_mode = $MESSAGE->is_safe || intval($_GET['_safe']); $out = ''; $part_no = 0; + $token = $RCMAIL->get_request_token(); $header_attrib = array(); foreach ($attrib as $attr => $value) { @@ -1283,12 +1284,11 @@ else if (!$part->size) { continue; } - // Check if we have enough memory to handle the message in it // #1487424: we need up to 10x more memory than the body else if (!rcube_utils::mem_check($part->size * 10)) { $out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' ' - . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id + . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part='.$part->mime_id.'&_token='.$token .'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download'))); continue; } @@ -1333,7 +1333,7 @@ // #1487424: we need up to 10x more memory than the body if (!rcube_utils::mem_check(strlen($MESSAGE->body) * 10)) { $out .= html::span('part-notice', $RCMAIL->gettext('messagetoobig'). ' ' - . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0' + . html::a('?_task=mail&_action=get&_download=1&_uid='.$MESSAGE->uid.'&_part=0&_token='.$token .'&_mbox='. urlencode($MESSAGE->folder), $RCMAIL->gettext('download'))); } else { diff -Nru roundcube-1.3.8+dfsg.1/program/steps/mail/get.inc roundcube-1.3.10+dfsg.1/program/steps/mail/get.inc --- roundcube-1.3.8+dfsg.1/program/steps/mail/get.inc 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/steps/mail/get.inc 2019-08-28 11:24:50.000000000 +0000 @@ -133,7 +133,7 @@ list($real_ctype_primary, $real_ctype_secondary) = explode('/', $real_mimetype); // accept text/plain with any extension - if ($real_mimetype == 'text/plain' && $real_mimetype == $mimetype) { + if ($real_mimetype == 'text/plain' && rcmail_mimetype_compare($real_mimetype, $mimetype)) { $valid_extension = true; } // ignore differences in text/* mimetypes. Filetype detection isn't very reliable here @@ -163,7 +163,7 @@ // "fix" real mimetype the same way the original is before comparison $real_mimetype = rcmail_fix_mimetype($real_mimetype); - $valid = $real_mimetype == $mimetype && $valid_extension; + $valid = $valid_extension && rcmail_mimetype_compare($real_mimetype, $mimetype); } else { $real_mimetype = $mimetype; @@ -306,6 +306,19 @@ /** + * Compares two mimetype strings with making sure that + * e.g. image/bmp and image/x-ms-bmp are treated as equal. + */ +function rcmail_mimetype_compare($type1, $type2) +{ + $regexp = '~/(x-ms-|x-)~'; + $type1 = preg_replace($regexp, '/', $type1); + $type2 = preg_replace($regexp, '/', $type2); + + return $type1 === $type2; +} + +/** * Attachment properties table */ function rcmail_message_part_controls($attrib) diff -Nru roundcube-1.3.8+dfsg.1/program/steps/mail/list.inc roundcube-1.3.10+dfsg.1/program/steps/mail/list.inc --- roundcube-1.3.8+dfsg.1/program/steps/mail/list.inc 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/steps/mail/list.inc 2019-08-28 11:24:50.000000000 +0000 @@ -40,6 +40,14 @@ } } +// is there a set of columns for this request? +if ($cols = rcube_utils::get_input_value('_cols', rcube_utils::INPUT_GET)) { + $_SESSION['list_attrib']['columns'] = explode(',', $cols); + if (!in_array('list_cols', $dont_override)) { + $save_arr['list_cols'] = explode(',', $cols); + } +} + // register layout change if ($layout = rcube_utils::get_input_value('_layout', rcube_utils::INPUT_GET)) { $OUTPUT->set_env('layout', $layout); @@ -47,13 +55,6 @@ // force header replace on layout change $cols = $_SESSION['list_attrib']['columns']; } -// is there a set of columns for this request? -else if ($cols = rcube_utils::get_input_value('_cols', rcube_utils::INPUT_GET)) { - $_SESSION['list_attrib']['columns'] = explode(',', $cols); - if (!in_array('list_cols', $dont_override)) { - $save_arr['list_cols'] = explode(',', $cols); - } -} if (!empty($save_arr)) { $RCMAIL->user->save_prefs($save_arr); diff -Nru roundcube-1.3.8+dfsg.1/program/steps/mail/sendmail.inc roundcube-1.3.10+dfsg.1/program/steps/mail/sendmail.inc --- roundcube-1.3.8+dfsg.1/program/steps/mail/sendmail.inc 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/program/steps/mail/sendmail.inc 2019-08-28 11:24:50.000000000 +0000 @@ -276,7 +276,7 @@ } // append doctype and html/body wrappers - $bstyle = !empty($bstyle) ? (" style='" . implode($bstyle, '; ') . "'") : ''; + $bstyle = !empty($bstyle) ? (" style='" . implode('; ', $bstyle) . "'") : ''; $message_body = '' . '' . "\r\n" . $message_body; diff -Nru roundcube-1.3.8+dfsg.1/public_html/index.php roundcube-1.3.10+dfsg.1/public_html/index.php --- roundcube-1.3.8+dfsg.1/public_html/index.php 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/index.php 2019-08-28 11:24:49.000000000 +0000 @@ -3,7 +3,7 @@ /* +-----------------------------------------------------------------------+ | Roundcube Webmail IMAP Client | - | Version 1.3.8 | + | Version 1.3.10 | | | | Copyright (C) 2005-2017, The Roundcube Dev Team | | | diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/debug_logger/runlog/runlog.php roundcube-1.3.10+dfsg.1/public_html/plugins/debug_logger/runlog/runlog.php --- roundcube-1.3.8+dfsg.1/public_html/plugins/debug_logger/runlog/runlog.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/debug_logger/runlog/runlog.php 2019-08-28 11:24:50.000000000 +0000 @@ -19,7 +19,7 @@ public $timestamp = "d-M-Y H:i:s O"; public $max_line_size = 150; - function runlog() + function __construct() { $this->start_time = microtime(true); } @@ -71,9 +71,6 @@ foreach ($this->tag_count as $tag => $count){ $tag_report .= "$tag: $count, "; } - if (!empty($tag_report)) { -// $tag_report = "\n$tag_report\n"; - } $end_txt = sprintf("end: $name - %0.4f seconds $tag_report", $this->run_log[$lastk]['duration']); $this->print_to_console($end_txt, $this->run_log[$lastk]['tag'], 'end'); $this->print_to_file($end_txt, $this->run_log[$lastk]['tag'], 'end'); @@ -223,7 +220,6 @@ return $buf; } - function __destruct() { foreach ($this->file_handles as $handle) { diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/README roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/README --- roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/README 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/README 2019-08-28 11:24:50.000000000 +0000 @@ -58,7 +58,7 @@ Possible reasons: - non-working loader in shebang (#! /usr/bin/env php) Make sure it works for the user the php scripts are executed upon - (i.e. apache, www-date, etc.) + (i.e. apache, www-data, etc.) - SELinux setting, try command: setsebool -P httpd_unified 0 Note: pinentry is used with gpg >= 2.0 and <= 2.1.12. diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/lib/enigma_engine.php roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/lib/enigma_engine.php --- roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/lib/enigma_engine.php 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/lib/enigma_engine.php 2019-08-28 11:24:50.000000000 +0000 @@ -266,10 +266,6 @@ $recipients = array_merge($recipients, $mime->getRecipients()); } - if (empty($recipients)) { - return new enigma_error(enigma_error::KEYNOTFOUND); - } - $recipients = array_unique($recipients); // find recipient public keys @@ -373,17 +369,36 @@ */ function part_structure($p, $body = null) { + static $got_content = false; + + // Prevent from "decryption oracle" [CVE-2019-10740] (#6638) + // On mail compose (edit/reply/forward) we support encrypted content only + // in the first "content part" of the message. + if ($got_content && $this->rc->task == 'mail' && $this->rc->action == 'compose') { + return; + } + + // Don't be tempted to support encryption in text/html parts + // Because of EFAIL vulnerability we should never support this (#6289) + if ($p['mimetype'] == 'text/plain' || $p['mimetype'] == 'application/pgp') { $this->parse_plain($p, $body); + $got_content = true; } else if ($p['mimetype'] == 'multipart/signed') { $this->parse_signed($p, $body); + $got_content = true; } else if ($p['mimetype'] == 'multipart/encrypted') { $this->parse_encrypted($p); + $got_content = true; } else if ($p['mimetype'] == 'application/pkcs7-mime') { $this->parse_encrypted($p); + $got_content = true; + } + else { + $got_content = $p['structure']->type === 'content'; } return $p; diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/lib/enigma_ui.php roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/lib/enigma_ui.php --- roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/lib/enigma_ui.php 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/lib/enigma_ui.php 2019-08-28 11:24:50.000000000 +0000 @@ -423,12 +423,12 @@ } } + $table->set_row_attribs($subkey->revoked || ($subkey->expires && $subkey->expires < $now) ? 'deleted' : ''); $table->add('id', $subkey->get_short_id()); $table->add('algo', $algo); $table->add('created', $subkey->created ? $this->rc->format_date($subkey->created, $date_format, false) : ''); $table->add('expires', $subkey->expires ? $this->rc->format_date($subkey->expires, $date_format, false) : $this->enigma->gettext('expiresnever')); $table->add('usage', implode(',', $usage)); - $table->set_row_attribs($subkey->revoked || ($subkey->expires && $subkey->expires < $now) ? 'deleted' : ''); } $out .= html::tag('fieldset', null, @@ -448,9 +448,9 @@ } $username .= ' <' . $user->email . '>'; + $table->set_row_attribs($user->revoked || !$user->valid ? 'deleted' : ''); $table->add('id', rcube::Q(trim($username))); $table->add('valid', $this->enigma->gettext($user->valid ? 'valid' : 'unknown')); - $table->set_row_attribs($user->revoked || !$user->valid ? 'deleted' : ''); } $out .= html::tag('fieldset', null, @@ -732,7 +732,7 @@ } $table->add('title', html::label('key-name', rcube::Q($this->enigma->gettext('newkeyident')))); - $table->add(null, implode($identities, "\n")); + $table->add(null, implode("\n", $identities)); // Key size $select = new html_select(array('name' => 'size', 'id' => 'key-size')); @@ -1100,10 +1100,14 @@ if ($mode && ($status instanceof enigma_error)) { $code = $status->getCode(); - if ($code == enigma_error::KEYNOTFOUND) { - $vars = array('email' => $status->getData('missing')); - $msg = 'enigma.' . $mode . 'nokey'; + if ($email = $status->getData('missing')) { + $vars = array('email' => $email); + $msg = 'enigma.' . $mode . 'nokey'; + } + else { + $msg = 'enigma.' . ($encrypt_enable ? 'encryptnoprivkey' : 'signnokey'); + } } else if ($code == enigma_error::BADPASS) { $this->password_prompt($status); diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/localization/en_US.inc roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/localization/en_US.inc --- roundcube-1.3.8+dfsg.1/public_html/plugins/enigma/localization/en_US.inc 2018-10-23 11:12:53.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/enigma/localization/en_US.inc 2019-08-28 11:24:50.000000000 +0000 @@ -112,6 +112,7 @@ $messages['signnopass'] = 'Signing failed. Key password required.'; $messages['encrypterror'] = 'Encryption failed.'; $messages['encryptnokey'] = 'Encryption failed. Public key not found for $email.'; +$messages['encryptnoprivkey'] = 'Encryption failed. Private key not found.'; $messages['nokeysfound'] = 'No keys found'; $messages['keynotfound'] = 'Key not found!'; $messages['keyopenerror'] = 'Unable to get key information! Internal error.'; diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/managesieve/Changelog roundcube-1.3.10+dfsg.1/public_html/plugins/managesieve/Changelog --- roundcube-1.3.8+dfsg.1/public_html/plugins/managesieve/Changelog 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/managesieve/Changelog 2019-08-28 11:24:50.000000000 +0000 @@ -1,3 +1,4 @@ +- Fix so "Create filter" option does not show up when Filters menu is disabled (#6723) - Fix bug where show_real_foldernames setting wasn't respected (#6422) - Fix bug where text: syntax was forced for strings longer than 1024 characters (#6143) - Fix missing Save button in Edit Filter Set page of Classic skin (#6154) diff -Nru roundcube-1.3.8+dfsg.1/public_html/plugins/managesieve/managesieve.php roundcube-1.3.10+dfsg.1/public_html/plugins/managesieve/managesieve.php --- roundcube-1.3.8+dfsg.1/public_html/plugins/managesieve/managesieve.php 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/plugins/managesieve/managesieve.php 2019-08-28 11:24:50.000000000 +0000 @@ -138,6 +138,13 @@ return; } + $this->load_config(); + + $vacation_mode = (int) $this->rc->config->get('managesieve_vacation'); + if ($vacation_mode == 2) { + return; + } + // use jQuery for popup window $this->require_plugin('jqueryui'); diff -Nru roundcube-1.3.8+dfsg.1/public_html/program/js/app.js roundcube-1.3.10+dfsg.1/public_html/program/js/app.js --- roundcube-1.3.8+dfsg.1/public_html/program/js/app.js 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/program/js/app.js 2019-08-28 11:24:50.000000000 +0000 @@ -1604,6 +1604,7 @@ if (menu) { $(menu).hide(); } + this.command(action, this.env.drag_target); this.env.drag_target = null; }; @@ -1633,7 +1634,8 @@ else if (list = this.contact_list) model = this.env.contactfolders; - if (this.drag_active && model && this.env.last_folder_target) { + // Note: we accept only mouse events to ignore dragging aborts with ESC key (#6623) + if (this.drag_active && model && this.env.last_folder_target && !rcube_event.is_keyboard(e)) { var target = model[this.env.last_folder_target]; list.draglayer.hide(); @@ -1718,7 +1720,7 @@ // remove focus from list widgets if (window.rcube_list_widget && rcube_list_widget._instances.length) { - $.each(rcube_list_widget._instances, function(i,list){ + $.each(rcube_list_widget._instances, function(i,list) { if (list && !rcube_mouse_is_over(e, list.list.parentNode)) list.blur(); }); @@ -1733,7 +1735,7 @@ } // reset popup menus; delayed to have updated menu_stack data - setTimeout(function(e){ + setTimeout(function(e) { var obj, skip, config, id, i, parents = $(target).parents(); for (i = ref.menu_stack.length - 1; i >= 0; i--) { id = ref.menu_stack[i]; @@ -9059,8 +9061,15 @@ // get the IMP mailbox of the message with the given UID this.get_message_mailbox = function(uid) { - var msg = (this.env.messages && uid ? this.env.messages[uid] : null) || {}; - return msg.mbox || this.env.mailbox; + var msg; + + if (this.env.messages && uid && (msg = this.env.messages[uid]) && msg.mbox) + return msg.mbox; + + if (/^[0-9]+-(.*)$/.test(uid)) + return RegExp.$1; + + return this.env.mailbox; }; // build request parameters from single message id (maybe with mailbox name) diff -Nru roundcube-1.3.8+dfsg.1/public_html/program/js/list.js roundcube-1.3.10+dfsg.1/public_html/program/js/list.js --- roundcube-1.3.8+dfsg.1/public_html/program/js/list.js 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/program/js/list.js 2019-08-28 11:24:50.000000000 +0000 @@ -355,8 +355,11 @@ node.style.display = 'none'; + // Specify removed row uid in the select_next argument. + // It's needed because after removing a set of rows + // reference to the last selected message is lost. if (sel_next) - this.select_next(); + this.select_next(uid); delete this.rows[uid]; this.rowcount--; @@ -579,6 +582,7 @@ rcube_event.add_listener({event:'mousemove', object:this, method:'drag_mouse_move'}); rcube_event.add_listener({event:'mouseup', object:this, method:'drag_mouse_up'}); + if (bw.touch) { rcube_event.add_listener({event:'touchmove', object:this, method:'drag_mouse_move'}); rcube_event.add_listener({event:'touchend', object:this, method:'drag_mouse_up'}); @@ -586,6 +590,7 @@ // enable dragging over iframes this.add_dragfix(); + this.focus(); } return false; @@ -875,12 +880,12 @@ /** * get first/next/previous/last rows that are not hidden */ -get_next_row: function() +get_next_row: function(uid) { if (!this.rowcount) return false; - var last_selected_row = this.rows[this.last_selected], + var last_selected_row = this.rows[uid || this.last_selected], new_row = last_selected_row ? last_selected_row.obj.nextSibling : null; while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) @@ -889,12 +894,12 @@ return new_row; }, -get_prev_row: function() +get_prev_row: function(uid) { if (!this.rowcount) return false; - var last_selected_row = this.rows[this.last_selected], + var last_selected_row = this.rows[uid || this.last_selected], new_row = last_selected_row ? last_selected_row.obj.previousSibling : null; while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) @@ -1029,15 +1034,12 @@ /** - * Select row next to the last selected one. + * Select row next to the specified or last selected one * Either below or above. */ -select_next: function() +select_next: function(uid) { - var next_row = this.get_next_row(), - prev_row = this.get_prev_row(), - new_row = (next_row) ? next_row : prev_row; - + var new_row = this.get_next_row(uid) || this.get_prev_row(uid); if (new_row) this.select_row(new_row.uid, false, false); }, @@ -1323,9 +1325,7 @@ */ key_press: function(e) { - var target = e.target || {}; - - if (!this.focused || target.nodeName == 'INPUT' || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT') + if (!this.focused || $(e.target).is('input,textarea,select')) return true; var keyCode = rcube_event.get_keycode(e), diff -Nru roundcube-1.3.8+dfsg.1/public_html/skins/classic/templates/about.html roundcube-1.3.10+dfsg.1/public_html/skins/classic/templates/about.html --- roundcube-1.3.8+dfsg.1/public_html/skins/classic/templates/about.html 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/skins/classic/templates/about.html 2019-08-28 11:24:50.000000000 +0000 @@ -20,7 +20,7 @@

Roundcube Webmail

- +

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.
diff -Nru roundcube-1.3.8+dfsg.1/public_html/skins/larry/templates/about.html roundcube-1.3.10+dfsg.1/public_html/skins/larry/templates/about.html --- roundcube-1.3.8+dfsg.1/public_html/skins/larry/templates/about.html 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/public_html/skins/larry/templates/about.html 2019-08-28 11:24:50.000000000 +0000 @@ -14,7 +14,7 @@

Roundcube Webmail

- +

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.
diff -Nru roundcube-1.3.8+dfsg.1/skins/classic/templates/about.html roundcube-1.3.10+dfsg.1/skins/classic/templates/about.html --- roundcube-1.3.8+dfsg.1/skins/classic/templates/about.html 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/skins/classic/templates/about.html 2019-08-28 11:24:50.000000000 +0000 @@ -20,7 +20,7 @@

Roundcube Webmail

- +

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.
diff -Nru roundcube-1.3.8+dfsg.1/skins/larry/templates/about.html roundcube-1.3.10+dfsg.1/skins/larry/templates/about.html --- roundcube-1.3.8+dfsg.1/skins/larry/templates/about.html 2018-10-23 11:12:54.000000000 +0000 +++ roundcube-1.3.10+dfsg.1/skins/larry/templates/about.html 2019-08-28 11:24:50.000000000 +0000 @@ -14,7 +14,7 @@

Roundcube Webmail

- +

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.