diff --git a/framework/ActiveSync/lib/Horde/ActiveSync/Request/Sync.php b/framework/ActiveSync/lib/Horde/ActiveSync/Request/Sync.php index 7d9ddc632ce..dfe02ccbd5e 100644 --- a/framework/ActiveSync/lib/Horde/ActiveSync/Request/Sync.php +++ b/framework/ActiveSync/lib/Horde/ActiveSync/Request/Sync.php @@ -458,6 +458,7 @@ protected function _handle() $collection['mimesupport'] = 0; } + $ensure_sent = array(); if ($statusCode == self::STATUS_SUCCESS) { if (!empty($collection['clientids']) || !empty($collection['fetchids']) || !empty($collection['missing']) || !empty($collection['importfailures'])) { @@ -510,7 +511,6 @@ protected function _handle() } // Output any SYNC_MODIFY failures - $ensure_sent = array(); if (!empty($collection['importfailures'])) { foreach ($collection['importfailures'] as $id => $reason) { $this->_encoder->startTag(Horde_ActiveSync::SYNC_MODIFY); diff --git a/framework/Alarm/lib/Horde/Alarm/Sql.php b/framework/Alarm/lib/Horde/Alarm/Sql.php index 992debe7466..512cbe78bde 100644 --- a/framework/Alarm/lib/Horde/Alarm/Sql.php +++ b/framework/Alarm/lib/Horde/Alarm/Sql.php @@ -388,12 +388,12 @@ public function initialize() switch ($this->_db->adapterName()) { case 'PDO_Oci': $query = "ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'"; - $db->select($query); + $this->_db->select($query); break; case 'PDO_PostgreSQL': $query = "SET datestyle TO 'iso'"; - $db->select($query); + $this->_db->select($query); break; } } diff --git a/framework/Alarm/package.xml b/framework/Alarm/package.xml index 111a9c4c9e6..fb78128bfbc 100644 --- a/framework/Alarm/package.xml +++ b/framework/Alarm/package.xml @@ -10,10 +10,9 @@ jan@horde.org yes - 2013-03-05 - + 2013-10-21 - 2.0.5 + 2.0.6 1.0.0 @@ -845,7 +844,20 @@ stable stable - 2013-03-05 + 2013-10-21 + LGPL-2.1 + +* [mjr] Fix initializing Alarms when using PDO_Oci or PDO_PostgreSQL. + + + + + 2.0.6 + 1.0.0 + + stable + stable + 2013-10-21 LGPL-2.1 * diff --git a/framework/Core/package.xml b/framework/Core/package.xml index fd278c3371e..bfd32711c6d 100644 --- a/framework/Core/package.xml +++ b/framework/Core/package.xml @@ -28,9 +28,9 @@ mrubinsk@horde.org yes - 2013-10-15 + 2013-10-21 - 2.10.1 + 2.10.2 2.10.0 @@ -39,9 +39,7 @@ LGPL-2.1 -* [mjr] Ensure Bcc is removed from headers when sent via ActiveSync (Bug #12771). -* [mjr] Fix calculating calendars to use for SOFTDELETE commands in certain configurations (Bug #12765). -* [mms] Upgrade jQuery Mobile to v1.3.2/jQuery Core to v1.9.1. +* @@ -3193,7 +3191,7 @@ stable stable - 2013-10-15 + 2013-10-21 LGPL-2.1 * [mjr] Ensure Bcc is removed from headers when sent via ActiveSync (Bug #12771). @@ -3201,5 +3199,18 @@ * [mms] Upgrade jQuery Mobile to v1.3.2/jQuery Core to v1.9.1. + + + 2.10.2 + 2.10.0 + + stable + stable + 2013-10-21 + LGPL-2.1 + +* + + diff --git a/framework/Imap_Client/doc/Horde/Imap/Client/UPGRADING b/framework/Imap_Client/doc/Horde/Imap/Client/UPGRADING index 2582e70f825..d3041b0e99c 100644 --- a/framework/Imap_Client/doc/Horde/Imap/Client/UPGRADING +++ b/framework/Imap_Client/doc/Horde/Imap/Client/UPGRADING @@ -11,6 +11,15 @@ This lists the API changes between releases of the package. +Upgrading to 2.16.0 +=================== + + - Horde_Imap_Client_Password_Xoauth2 + + Added the class to abstract production of the necessary authentication + token for XOAUTH2 SASL authentication. + + Upgrading to 2.15.0 =================== diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Password/Xoauth2.php b/framework/Imap_Client/lib/Horde/Imap/Client/Password/Xoauth2.php new file mode 100644 index 00000000000..03bfc84a6c2 --- /dev/null +++ b/framework/Imap_Client/lib/Horde/Imap/Client/Password/Xoauth2.php @@ -0,0 +1,71 @@ + + * @category Horde + * @copyright 2013 Horde LLC + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + * @package Imap_Client + * @since 2.16.0 + */ +class Horde_Imap_Client_Password_Xoauth2 +implements Horde_Imap_Client_Base_Password +{ + /** + * Access token. + * + * @var string + */ + public $access_token; + + /** + * Username. + * + * @var string + */ + public $username; + + /** + * Constructor. + * + * @param string $username The username. + * @param string $access_token The access token. + */ + public function __construct($username, $access_token) + { + $this->username = $username; + $this->access_token = $access_token; + } + + /** + * Return the password to use for the server connection. + * + * @return string The password. + */ + public function getPassword() + { + // base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A") + // ^A represents a Control+A (\001) + return base64_encode( + 'user=' . $this->username . "\1" . + 'auth=Bearer ' . $access_token . "\1\1" + ); + } + +} diff --git a/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php b/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php index 825ebac509d..d05b6e11931 100644 --- a/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php +++ b/framework/Imap_Client/lib/Horde/Imap/Client/Socket.php @@ -4151,15 +4151,24 @@ protected function _getLine( switch ($server->status) { case $server::BAD: + case $server::NO: /* A tagged BAD response indicates that the tagged command caused * the error. This information is unknown if untagged (RFC 3501 - * [7.1.3]). */ - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::t("IMAP error reported by server."), - 0, - $server, - $pipeline - ); + * [7.1.3]) - ignore these untagged responses. + * An untagged NO response indicates a warning; ignore and assume + * that it also included response text code that is handled + * elsewhere. Throw exception if tagged; command handlers can + * catch this if able to workaround this issue (RFC 3501 + * [7.1.2]). */ + if ($server instanceof Horde_Imap_Client_Interaction_Server_Tagged) { + throw new Horde_Imap_Client_Exception_ServerResponse( + Horde_Imap_Client_Translation::t("IMAP error reported by server."), + 0, + $server, + $pipeline + ); + } + break; case $server::BYE: /* A BYE response received as part of a logout command should be @@ -4175,21 +4184,6 @@ protected function _getLine( } break; - case $server::NO: - /* An untagged NO response indicates a warning; ignore and assume - * that it also included response text code that is handled - * elsewhere. Throw exception if tagged; command handlers can - * catch this if able to workaround this issue (RFC 3501 - * [7.1.2]). */ - if ($server instanceof Horde_Imap_Client_Interaction_Server_Tagged) { - throw new Horde_Imap_Client_Exception_ServerResponse( - Horde_Imap_Client_Translation::t("IMAP error reported by server."), - 0, - $server, - $pipeline - ); - } - case $server::PREAUTH: /* The user was pre-authenticated. (RFC 3501 [7.1.4]) */ $this->_temp['preauth'] = true; diff --git a/framework/Imap_Client/package.xml b/framework/Imap_Client/package.xml index 5eb65c301a0..9cb074e5fe8 100644 --- a/framework/Imap_Client/package.xml +++ b/framework/Imap_Client/package.xml @@ -12,8 +12,8 @@ 2013-10-17 - 2.15.6 - 2.15.0 + 2.16.0 + 2.16.0 stable @@ -21,6 +21,8 @@ LGPL-2.1 +* [mms] Correctly handle untagged BAD IMAP responses. +* [mms] Added Horde_Imap_Client_Password_Xoauth2 class. * [mms] Fix harmless PHP undefined error when using with an IMAP server that supports XOAUTH2. @@ -2039,14 +2041,16 @@ - 2.15.6 - 2.15.0 + 2.16.0 + 2.16.0 stable stable 2013-10-17 LGPL-2.1 +* [mms] Correctly handle untagged BAD IMAP responses. +* [mms] Added Horde_Imap_Client_Password_Xoauth2 class. * [mms] Fix harmless PHP undefined error when using with an IMAP server that supports XOAUTH2. diff --git a/framework/Smtp/composer.json b/framework/Smtp/composer.json index 857bed6ccad..dddd039b8d2 100644 --- a/framework/Smtp/composer.json +++ b/framework/Smtp/composer.json @@ -12,7 +12,7 @@ } ], "version": "1.2.5", - "time": "2013-10-15", + "time": "2013-10-19", "repositories": [ { "type": "pear", @@ -23,6 +23,7 @@ "php": ">=5.3.0", "pear-pear.horde.org/Horde_Exception": ">=2.0.0@stable,<=3.0.0alpha1@stable", "pear-pear.horde.org/Horde_Mail": ">=2.0.0@stable,<=3.0.0alpha1@stable", + "pear-pear.horde.org/Horde_Socket_Client": ">=1.0.0@stable,<=2.0.0alpha1@stable", "pear-pear.horde.org/Horde_Support": ">=2.0.0@stable,<=3.0.0alpha1@stable" }, "suggest": { diff --git a/framework/Smtp/lib/Horde/Smtp/Filter/Data.php b/framework/Smtp/lib/Horde/Smtp/Filter/Data.php index 2ea78c12460..b65ab68085c 100644 --- a/framework/Smtp/lib/Horde/Smtp/Filter/Data.php +++ b/framework/Smtp/lib/Horde/Smtp/Filter/Data.php @@ -48,7 +48,7 @@ public function filter($in, $out, &$consumed, $closing) // EOLs need to be CRLF; double leading periods. $bucket->data = preg_replace( array("/(?:\r\n|\n|\r(?!\n))/", "/\n\./"), - array("\r\n", '..'), + array("\r\n", "\n.."), $bucket->data ); diff --git a/framework/Smtp/package.xml b/framework/Smtp/package.xml index 3243b389ce9..25db2537312 100644 --- a/framework/Smtp/package.xml +++ b/framework/Smtp/package.xml @@ -10,9 +10,9 @@ slusarz@horde.org yes - 2013-10-15 + 2013-10-19 - 1.2.5 + 1.2.6 1.2.0 @@ -59,6 +59,7 @@ + @@ -142,6 +143,7 @@ + @@ -253,7 +255,20 @@ stable stable - 2013-10-15 + 2013-10-19 + LGPL-2.1 + +* [mms] Fix escaping periods that begin a line of DATA input. + + + + + 1.2.6 + 1.2.0 + + stable + stable + 2013-10-18 LGPL-2.1 * diff --git a/framework/Smtp/test/Horde/Smtp/FilterDataTest.php b/framework/Smtp/test/Horde/Smtp/FilterDataTest.php new file mode 100644 index 00000000000..e74cb63ca12 --- /dev/null +++ b/framework/Smtp/test/Horde/Smtp/FilterDataTest.php @@ -0,0 +1,53 @@ + + * @category Horde + * @copyright 2013 Horde LLC + * @ignore + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + * @package Smtp + * @subpackage UnitTests + */ +class Horde_Smtp_FilterDataTest extends Horde_Test_Case +{ + private $stream; + + public function setUp() + { + $this->stream = fopen('php://temp', 'r+'); + stream_filter_register('horde_smtp_data', 'Horde_Smtp_Filter_Data'); + stream_filter_append($this->stream, 'horde_smtp_data', STREAM_FILTER_READ); + } + + public function tearDown() + { + fclose($this->stream); + } + + public function testLeadingPeriodsEscape() + { + fwrite($this->stream, "Foo\r\n.\r\nFoo\r\n"); + rewind($this->stream); + + $this->assertEquals( + "Foo\r\n..\r\nFoo\r\n", + stream_get_contents($this->stream) + ); + } + +} diff --git a/framework/Socket_Client/composer.json b/framework/Socket_Client/composer.json new file mode 100644 index 00000000000..0b2069920aa --- /dev/null +++ b/framework/Socket_Client/composer.json @@ -0,0 +1,29 @@ +{ + "name": "horde/horde-socket-client", + "description": "Horde Socket Client", + "type": "library", + "homepage": "http://pear.horde.org", + "license": "LGPL-2.1", + "authors": [ + { + "name": "Michael Slusarz", + "email": "slusarz@horde.org", + "role": "lead" + } + ], + "version": "1.0.0", + "time": "2013-10-19", + "repositories": [ + { + "type": "pear", + "url": "http://pear.horde.org" + } + ], + "require": { + "php": ">=5.3.0", + "pear-pear.horde.org/Horde_Exception": ">=2.0.0@stable,<=3.0.0alpha1@stable" + }, + "suggest": { + "ext-openssl": "*" + } +} diff --git a/framework/Socket_Client/package.xml b/framework/Socket_Client/package.xml index c79bff56fa3..080c856cf47 100644 --- a/framework/Socket_Client/package.xml +++ b/framework/Socket_Client/package.xml @@ -10,9 +10,9 @@ slusarz@horde.org yes - 2013-10-16 + 2013-10-19 - 1.0.0 + 1.0.1 1.0.0 @@ -21,7 +21,7 @@ LGPL-2.1 -* [mms] Initial release. +* @@ -85,11 +85,24 @@ stable stable - 2013-10-16 + 2013-10-19 LGPL-2.1 * [mms] Initial release. + + + 1.0.1 + 1.0.0 + + stable + stable + 2013-10-18 + LGPL-2.1 + +* + + diff --git a/framework/Test/lib/Horde/Test/Autoload.php b/framework/Test/lib/Horde/Test/Autoload.php index afc793355a2..5bd7ade1c78 100644 --- a/framework/Test/lib/Horde/Test/Autoload.php +++ b/framework/Test/lib/Horde/Test/Autoload.php @@ -74,7 +74,7 @@ public static function addPrefix($prefix, $path) */ public static function resolve($class) { - $filename = str_replace(array('::', '_'), '/', $class); + $filename = str_replace(array('::', '_', '\\'), '/', $class); foreach (self::$_mappings as $prefix => $path) { if ((strpos($filename, "/") === false) && ($filename == $prefix)) { diff --git a/framework/Test/package.xml b/framework/Test/package.xml index 0e19562f750..f234a05dad0 100644 --- a/framework/Test/package.xml +++ b/framework/Test/package.xml @@ -28,7 +28,7 @@ LGPL-2.1 -* +* [mms] Fix autoloading from a PHP-defined namespace. @@ -438,7 +438,7 @@ 2013-08-27 LGPL-2.1 -* +* [mms] Fix autoloading from a PHP-defined namespace. diff --git a/framework/admintools/README b/framework/admintools/README deleted file mode 100644 index 9b6174d23e0..00000000000 --- a/framework/admintools/README +++ /dev/null @@ -1,25 +0,0 @@ -========================= -Horde Administrator Tools -========================= - -Introduction ------------- - -This directory contains various utility scripts for Horde administrators. - - -Script Index ------------- - -horde-base.php - Stores common code used in other administrator scripts. - -horde-create-sequence.php - TODO - -horde-remove-pref.php - Remove all entries of a preference name/scope combination from an - SQL prefs backend. - -horde-sql-shell.php - TODO diff --git a/framework/admintools/composer.json b/framework/admintools/composer.json deleted file mode 100644 index 84fbf5fd601..00000000000 --- a/framework/admintools/composer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "horde/admintools", - "description": "Horde Administrator Tools", - "type": "library", - "homepage": "http://pear.horde.org", - "license": "LGPL-2.1", - "authors": [ - { - "name": "Chuck Hagenbuch", - "email": "chuck@horde.org", - "role": "lead" - }, - { - "name": "Jan Schneider", - "email": "jan@horde.org", - "role": "lead" - } - ], - "version": "0.3.0", - "time": "2009-12-22", - "repositories": [ - { - "type": "pear", - "url": "http://pear.horde.org" - } - ], - "require": { - "php": ">=5.3.0" - } -} diff --git a/framework/admintools/horde-base.php b/framework/admintools/horde-base.php deleted file mode 100644 index 14859a0fade..00000000000 --- a/framework/admintools/horde-base.php +++ /dev/null @@ -1,13 +0,0 @@ - 'none', - 'cli' => true -)); - -$scope = $cli->prompt('Enter value for pref_scope:'); -$name = $cli->prompt('Enter value for pref_name:'); - -/* Open the database. */ -$db = $injector->getInstance('Horde_Db_Adapter'); - -if ($live) { - $sql = 'DELETE FROM horde_prefs WHERE pref_scope = ? AND pref_name = ?'; - $values = array($scope, $name); - try { - if ($db->delete($sql, $values)) { - $cli->writeln(sprintf('Preferences "%s" deleted in scope "%s".', $name, $scope)); - } else { - $cli->writeln(sprintf('No preference "%s" found in scope "%s".', $name, $scope)); - } - } catch (Horde_Db_Exception $e) { - print_r($e); - } -} else { - $sql = 'SELECT * FROM horde_prefs WHERE pref_scope = ? AND pref_name = ?'; - $values = array($scope, $name); - try { - if ($result = $db->selectAll($sql, $values)) { - var_dump($result); - } else { - $cli->writeln(sprintf('No preference "%s" found in scope "%s".', $name, $scope)); - } - } catch (Horde_Db_Exception $e) { - print_r($e); - } -} diff --git a/framework/admintools/horde-sql-shell.php b/framework/admintools/horde-sql-shell.php deleted file mode 100755 index aa97f19ed65..00000000000 --- a/framework/admintools/horde-sql-shell.php +++ /dev/null @@ -1,33 +0,0 @@ -#!@php_bin@ - - */ - -require_once __DIR__ . '/horde-base.php'; -Horde_Registry::appInit('horde', array( - 'authentication' => 'none', - 'cli' => true -)); - -$dbh = $injector->getInstance('Horde_Db_Adapter'); - -// read sql file for statements to run -$statements = new Horde_Db_StatementParser($_SERVER['argv'][1]); -foreach ($statements as $stmt) { - echo "Running:\n " . preg_replace('/\s+/', ' ', $stmt) . "\n"; - try { - $dbh->execute($stmt); - } catch (Horde_Db_Exception $e) { - print_r($e); - exit; - } - - echo " ...done\n\n"; -} diff --git a/framework/admintools/package.xml b/framework/admintools/package.xml deleted file mode 100644 index a3645b78940..00000000000 --- a/framework/admintools/package.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - admintools - pear.horde.org - Horde Administrator Tools - This package contains scripts useful to people administering Horde installations. - - - Chuck Hagenbuch - chuck - chuck@horde.org - yes - - - Jan Schneider - jan - jan@horde.org - yes - - 2009-12-22 - - 0.3.0 - 0.3.0 - - - beta - beta - - LGPL-2.1 - -* - - - - - - - - - - - - - - - - 5.3.0 - - - 1.7.0 - - - - - - - - - - - - - 2009-12-22 - - 0.3.0 - 0.3.0 - - - beta - beta - - LGPL-2.1 - * Initial Horde 4 package. - - - - 2008-06-24 - - 0.2.0 - 0.2.0 - - - beta - beta - - LGPL-2.1 - - Add a script for creating PEAR::DB sequences - - Add scripts for dumping and updating the Horde database from MDB2_Schema XML files - - Add a script for running a series of SQL statements from STDIN on the Horde database - - Add scripts for dumping and restoring data from the Horde database - - - - diff --git a/horde/bin/horde-pref-remove.php b/horde/bin/horde-pref-remove.php new file mode 100755 index 00000000000..a52b8a30f31 --- /dev/null +++ b/horde/bin/horde-pref-remove.php @@ -0,0 +1,53 @@ +#!@php_bin@ +get('horde_dir', null, 'pear.horde.org') . '/lib/Application.php'; +} +Horde_Registry::appInit('horde', array( + 'authentication' => 'none', + 'cli' => true +)); + +$scope = $cli->prompt('Enter preference scope:'); +$name = $cli->prompt('Enter preference name:'); +$user = $cli->prompt('Enter preference user:'); + +$prefs_ob = $injector->getInstance('Horde_Core_Factory_Prefs')->create($scope, array( + 'user' => $user +)); + +$value = $prefs_ob->getValue($name); + +if (is_null($value)) { + $cli->message(sprintf('No preference "%s" found in scope "%s".', $name, $scope), 'cli.error'); +} else { + $cli->writeln(); + $cli->writeln(sprintf('Name: %s', $name)); + $cli->writeln(sprintf('Value: %s', $value)); + $cli->writeln(); + if ($cli->prompt($cli->red('Do you want to delete this preference?'), array('y' => 'Yes', 'n' => 'No'), 'n') == 'y') { + $prefs_ob->remove($name); + $cli->message($cli->green('Preference deleted.'), 'cli.success'); + } +} diff --git a/horde/bin/horde-remove-user-data b/horde/bin/horde-remove-user-data new file mode 100755 index 00000000000..d055153d700 --- /dev/null +++ b/horde/bin/horde-remove-user-data @@ -0,0 +1,54 @@ +#!/usr/bin/env php + + * @category Horde + * @copyright 2013 Horde LLC + * @license http://www.horde.org/licenses/lgpl LGPL-2 + * @package Horde + */ + +$baseFile = __DIR__ . '/../lib/Application.php'; +if (file_exists($baseFile)) { + require_once $baseFile; +} else { + require_once 'PEAR/Config.php'; + require_once PEAR_Config::singleton() + ->get('horde_dir', null, 'pear.horde.org') . '/lib/Application.php'; +} +Horde_Registry::appInit('horde', array( + 'authentication' => 'none', + 'cli' => true, + 'user_admin' => true +)); + +$cli->message('Horde directory: ' . realpath(HORDE_BASE), 'cli.message'); + +do { + $user = $cli->prompt('Username:'); +} while (!strlen($user)); + +$app = $cli->prompt('Application to remove data from (blank for all apps):'); +if (!strlen($app)) { + $app = null; +} + +$cli->writeln(); + +if (!$cli->prompt($cli->red('Are you sure you want to remove user data?'), array('y' => 'Yes', 'n' => 'No'), 'n') == 'y') { + exit(0); +} + +try { + $registry->removeUserData($user, $app); + $cli->message('Data removed.', 'cli.success'); +} catch (Horde_Exception $e) { + $cli->fatal($e->getMessage()); +} diff --git a/horde/bin/horde-sql-shell.php b/horde/bin/horde-sql-shell.php new file mode 100755 index 00000000000..a82729d92de --- /dev/null +++ b/horde/bin/horde-sql-shell.php @@ -0,0 +1,42 @@ +#!@php_bin@ + + * @category Horde + * @copyright 2007-2013 Horde LLC + * @license http://www.horde.org/licenses/lgpl LGPL-2 + * @package Horde + */ + +$baseFile = __DIR__ . '/../lib/Application.php'; +if (file_exists($baseFile)) { + require_once $baseFile; +} else { + require_once 'PEAR/Config.php'; + require_once PEAR_Config::singleton() + ->get('horde_dir', null, 'pear.horde.org') . '/lib/Application.php'; +} +Horde_Registry::appInit('horde', array( + 'authentication' => 'none', + 'cli' => true +)); + +$dbh = $injector->getInstance('Horde_Db_Adapter'); + +// read sql file for statements to run +$statements = new Horde_Db_StatementParser($_SERVER['argv'][1]); +foreach ($statements as $stmt) { + $cli->writeln('Running:'); + $cli->writeln(' ' . preg_replace('/\s+/', ' ', $stmt)); + + $dbh->execute($stmt); + $cli->writeln(' ...done.'); +} diff --git a/horde/docs/CHANGES b/horde/docs/CHANGES index e2b7a7d384f..fc7ee0dfaee 100644 --- a/horde/docs/CHANGES +++ b/horde/docs/CHANGES @@ -2,6 +2,7 @@ v5.1.5-git ---------- +[mms] Add horde-remove-user-data command-line script. [mms] Add additional syntax checking for the configuration files in the test script. [mms] Only update topbar if the underlying tree data has changed. diff --git a/horde/docs/INSTALL b/horde/docs/INSTALL index afba87ea319..5676d270186 100644 --- a/horde/docs/INSTALL +++ b/horde/docs/INSTALL @@ -806,11 +806,7 @@ anything similar to remove old files. Stale sessions are automatically pruned by PHP according to the `session.gc_probability`_, `session.gc_divisor`_, and -`session.gc_maxlifetime`_ settings located in ``php.ini``. However, the -default settings are very aggressive: the garbage collection routine runs on -average 1% of the time a page is loaded. For most installations, a lower -garbage collection rate is recommended (setting session.gc_divisor to 10,000 -or higher is much more reasonable). +`session.gc_maxlifetime`_ settings located in ``php.ini``. Translations diff --git a/horde/login.php b/horde/login.php index cc8880e001b..26595184b22 100644 --- a/horde/login.php +++ b/horde/login.php @@ -90,6 +90,10 @@ function _addAnchor($url, $type, $vars, $url_anchor = null) $logout_reason = null; } break; + +case Horde_Core_Auth_Application::REASON_SESSIONMAXTIME: + $is_auth = false; + break; } /* Change language. */ diff --git a/horde/package.xml b/horde/package.xml index 251b0815072..ca522e1bb56 100644 --- a/horde/package.xml +++ b/horde/package.xml @@ -28,7 +28,7 @@ mrubinsk@horde.org yes - 2013-10-09 + 2013-10-19 5.1.5 5.0.0 @@ -39,6 +39,7 @@ LGPL-2 +* [mms] Add horde-remove-user-data command-line script. * [mms] Add additional syntax checking for the configuration files in the test script. * [mms] Only update topbar if the underlying tree data has changed. @@ -123,6 +124,7 @@ + @@ -130,12 +132,14 @@ + + @@ -1935,10 +1939,13 @@ + + + @@ -3766,9 +3773,10 @@ stable stable - 2013-10-09 + 2013-10-19 LGPL-2 +* [mms] Add horde-remove-user-data command-line script. * [mms] Add additional syntax checking for the configuration files in the test script. * [mms] Only update topbar if the underlying tree data has changed. diff --git a/imp/basic.php b/imp/basic.php index 99bc14f3fbc..ce0b0858efe 100644 --- a/imp/basic.php +++ b/imp/basic.php @@ -33,8 +33,12 @@ try { $ob = new $class($vars); } catch (Exception $e) { - $notification->push($e); - $ob = new IMP_Basic_Error($vars); + if ($registry->getView() == $registry::VIEW_BASIC) { + $notification->push($e); + $ob = new IMP_Basic_Error($vars); + } else { + throw $e; + } } $status = $ob->status(); diff --git a/imp/config/hooks.php.dist b/imp/config/hooks.php.dist index 9aa183e62f2..97666d56f32 100644 --- a/imp/config/hooks.php.dist +++ b/imp/config/hooks.php.dist @@ -161,6 +161,28 @@ class IMP_Hooks } + /** + * Check compose e-mail recipient before sending. + * + * @param Horde_Mail_Rfc822_Object $addr The address object. + * + * @return mixed If an error, an array with the following possible keys: + * - msg: (string) The error text. + * - level: (string; OPTIONAL) Either 'bad' (DEFAULT) or 'warn'. + */ +// public function compose_addr(Horde_Mail_Rfc822_Object $addr) +// { +// // Example: Only allow sending to local addresses. +// if (($addr instanceof Horde_Mail_Rfc822_Address) && +// ($addr->host != 'example.com')) { +// return array( +// 'msg' => 'Can only send to addresses at example.com.', +// 'level' => 'bad' +// ); +// } +// } + + /** * Checks the raw text of the outoging compose message for words that * might indicate an attachment is present, and issues a warning if no diff --git a/imp/docs/CHANGES b/imp/docs/CHANGES index 785761609bf..57e85896ba0 100644 --- a/imp/docs/CHANGES +++ b/imp/docs/CHANGES @@ -2,6 +2,8 @@ v6.2.0-git ---------- +[mms] Better reporting of e-mail address errors when composing. +[mms] Add list information display to dynamic view. [jan] Display signature in compose view. [mms] Add keyboard shortcuts to allow a more granular scroll of the dynamic preview pane (Request #12750). diff --git a/imp/docs/UPGRADING b/imp/docs/UPGRADING index 7f8ae4ebb10..9ce17848225 100644 --- a/imp/docs/UPGRADING +++ b/imp/docs/UPGRADING @@ -51,6 +51,14 @@ The following options have been removed:: $conf['compose']['ac_threshold'] +Hooks (hooks.php) +----------------- + +The following hooks have been added:: + + compose_addr + + Preferences (prefs.php) ----------------------- diff --git a/imp/js/dimpbase.js b/imp/js/dimpbase.js index 11a353afb6e..3247ad39af1 100644 --- a/imp/js/dimpbase.js +++ b/imp/js/dimpbase.js @@ -1460,6 +1460,7 @@ var DimpBase = { case 'ctx_preview': [ $('ctx_preview_allparts') ].invoke(this.pp.hide_all ? 'hide' : 'show'); [ $('ctx_preview_thread') ].invoke(this.viewport.getMetaData('nothread') ? 'hide' : 'show'); + [ $('ctx_preview_listinfo') ].invoke(this.viewport.getSelected().get('dataob').first().listmsg ? 'show' : 'hide'); break; case 'ctx_template': @@ -2657,13 +2658,14 @@ var DimpBase = { clickHandler: function(e) { var tmp, - elt = e.element(); + elt = e.element(), + id = elt.readAttribute('id'); if (DimpCore.DMenu.operaCheck(e.memo)) { return; } - switch (elt.readAttribute('id')) { + switch (id) { case 'imp-normalmboxes': case 'imp-specialmboxes': this._handleMboxMouseClick(e.memo); @@ -2772,7 +2774,7 @@ var DimpBase = { case 'msgloglist_toggle': case 'partlist_toggle': - tmp = (elt.readAttribute('id') == 'partlist_toggle') ? 'partlist' : 'msgloglist'; + tmp = (id == 'partlist_toggle') ? 'partlist' : 'msgloglist'; $(tmp + '_col', tmp + '_exp').invoke('toggle'); Effect.toggle(tmp, 'blind', { duration: 0.2, @@ -2809,8 +2811,9 @@ var DimpBase = { }); break; + case 'ctx_preview_listinfo': case 'ctx_preview_thread': - HordeCore.popupWindow(DimpCore.conf.URI_THREAD, { + HordeCore.popupWindow((id == 'ctx_preview_listinfo') ? DimpCore.conf.URI_LISTINFO : DimpCore.conf.URI_THREAD, { buid: this.pp.VP_id, mailbox: this.pp.VP_view }, { @@ -3334,7 +3337,11 @@ var DimpBase = { if (need.size()) { if (mode == 'tog') { - base.down('A').update(DimpCore.text.loading); + base.down('A').update( + new Element('SPAN') + .addClassName('imp-sidebar-mbox-loading') + .update('[' + DimpCore.text.loading + ']') + ); } this._listMboxes({ all: Number(mode == 'expall'), diff --git a/imp/lib/Ajax/Application/Handler/Common.php b/imp/lib/Ajax/Application/Handler/Common.php index 63c548683af..64e46111a15 100644 --- a/imp/lib/Ajax/Application/Handler/Common.php +++ b/imp/lib/Ajax/Application/Handler/Common.php @@ -703,14 +703,16 @@ protected function _handleBadComposeAddr(IMP_Compose_Exception_Address $e) ? json_decode($this->vars->addr_ac, true) : array(); - foreach ($e->addresses as $key => $val) { - $notification->push(sprintf(_("Invalid e-mail address (%s)."), $key), 'horde.warning'); + foreach ($e as $val) { + $addr = strval($val->address); + $notification->push($val->error, 'horde.warning'); + foreach ($addr_ac as $val2) { - if ($key == $val2['addr']) { + if ($addr == $val2['addr']) { $this->_base->queue->compose_addr( $val2['id'], $val2['itemid'], - 'impACListItemBad' + ($val->level == $e::BAD) ? 'impACListItemBad' : 'impACListItemWarn' ); } } diff --git a/imp/lib/Api.php b/imp/lib/Api.php index bf0adaac04b..0b8576e16f9 100644 --- a/imp/lib/Api.php +++ b/imp/lib/Api.php @@ -94,7 +94,8 @@ public function mailboxList() { $iterator = new IMP_Ftree_IteratorFilter_Nocontainers( IMP_Ftree_IteratorFilter::create( - IMP_Ftree_IteratorFilter::NO_REMOTE + IMP_Ftree_IteratorFilter::NO_REMOTE | + IMP_Ftree_IteratorFilter::UNSUB_PREF ) ); $mboxes = array(); diff --git a/imp/lib/Basic/Listinfo.php b/imp/lib/Basic/Listinfo.php new file mode 100644 index 00000000000..227b64bd0c2 --- /dev/null +++ b/imp/lib/Basic/Listinfo.php @@ -0,0 +1,136 @@ + + * @category Horde + * @copyright 2013 Horde LLC + * @license http://www.horde.org/licenses/gpl GPL + * @package IMP + */ +class IMP_Basic_Listinfo extends IMP_Basic_Base +{ + /** + */ + protected function _init() + { + global $injector, $page_output; + + $imp_mailbox = $this->indices->mailbox->list_ob; + list($m, $u) = $this->indices->getSingle(); + $imp_indices = $imp_mailbox->getFullThread($u, $m); + + if (!count($imp_indices)) { + throw new IMP_Exception(_("Could not load message.")); + } + + /* Parse the message. */ + try { + $imp_contents = $injector->getInstance('IMP_Factory_Contents')->create(new IMP_Indices($imp_mailbox)); + } catch (IMP_Exception $e) { + throw new IMP_Exception(_("Could not load message.")); + } + + $view = new Horde_View(array( + 'templatePath' => IMP_TEMPLATES . '/listinfo' + )); + + $listheaders = $injector->getInstance('Horde_ListHeaders'); + $mime_headers = $imp_contents->getHeader(); + + $view->headers = array(); + foreach ($listheaders->headers() as $key => $val) { + if ($data = $mime_headers->getValue($key)) { + $view->headers[$val] = $this->_parseListHeaders($val, $data); + } + } + + $this->output = $view->render('listinfo'); + $this->title = _("Mailing List Information"); + + $page_output->topbar = $page_output->sidebar = false; + } + + /** + */ + public function status() + { + } + + /** + * @param array $opts Options: + *
+     *   - buid: (string) BUID of message.
+     *   - full: (boolean) Full URL?
+     *   - mailbox: (string) Mailbox of message.
+     * 
+ */ + static public function url(array $opts = array()) + { + $url = Horde::url('basic.php') + ->add('page', 'listinfo') + ->unique() + ->setRaw(!empty($opts['full'])); + + if (!empty($opts['mailbox'])) { + $url->add(array( + 'buid' => $opts['buid'], + 'mailbox' => IMP_Mailbox::get($opts['mailbox'])->form_to + )); + } + + return $url; + } + + /** + * Parse the information in mailing list headers. + * + * @param string $id The header ID. + * @param string $data The header text to process. + * + * @return string The HTML-escaped header value. + */ + protected function _parseListHeaders($id, $data) + { + global $injector; + + $parser = $injector->getInstance('Horde_ListHeaders'); + $text_filter = $injector->getInstance('Horde_Core_Factory_TextFilter'); + + foreach ($parser->parse($id, $data) as $val) { + /* RFC 2369 [2] states that we should only show the *FIRST* URL + * that appears in a header that we can adequately handle. */ + if (stripos($val->url, 'mailto:') === 0) { + $url = substr($val->url, 7); + $clink = new IMP_Compose_Link($url); + $out = Horde::link($clink->link()) . $url . ''; + foreach ($val->comments as $val2) { + $out .= htmlspecialchars('(' . $val2 . ')'); + } + return $out; + } elseif ($url = $text_filter->filter($val->url, 'Linkurls')) { + $out = $url; + foreach ($val->comments as $val2) { + $out .= htmlspecialchars('(' . $val2 . ')'); + } + return $out; + } + } + + return htmlspecialchars($data); + } + +} diff --git a/imp/lib/Basic/Message.php b/imp/lib/Basic/Message.php index 8ab1d48e1e8..334fd8ff9da 100644 --- a/imp/lib/Basic/Message.php +++ b/imp/lib/Basic/Message.php @@ -332,21 +332,11 @@ protected function _init() /* Determine if all/list/user-requested headers needed. */ $all_headers = $this->vars->show_all_headers; - $list_headers = $this->vars->show_list_headers; $user_hdrs = $imp_ui->getUserHeaders(); /* Check for the presence of mailing list information. */ $list_info = $imp_ui->getListInformation($mime_headers); - /* See if the mailing list information has been requested to be - * displayed. */ - if ($list_info['exists'] && ($list_headers || $all_headers)) { - $all_list_headers = $this->_parseAllListHeaders($mime_headers); - $list_headers_lookup = $mime_headers->listHeaders(); - } else { - $all_list_headers = array(); - } - /* Display all headers or, optionally, the user-specified headers for * the current identity. */ $full_headers = array(); @@ -357,7 +347,6 @@ protected function _init() /* Skip the header if we have already dealt with it. */ if (!isset($display_headers[$lc_head]) && - !isset($all_list_headers[$lc_head]) && (!in_array($lc_head, array('importance', 'x-priority')) || !isset($display_headers['priority']))) { $full_headers[$lc_head] = $val; @@ -378,7 +367,7 @@ protected function _init() * need other stuff in the query string, so we need to do an * add/remove of uid info. */ $selfURL = $mailbox->url(Horde::selfUrlParams()->remove(array('actionID')), $buid)->add('message_token', $message_token); - $headersURL = $selfURL->copy()->remove(array('show_all_headers', 'show_list_headers')); + $headersURL = $selfURL->copy()->remove(array('show_all_headers')); /* Generate previous/next links. */ $prev_msg = $imp_mailbox[$imp_mailbox->getIndex() - 1]; @@ -730,7 +719,7 @@ protected function _init() 'title' => _("Headers"), 'nocheck' => true )); - if ($all_headers || $list_headers) { + if ($all_headers) { $a_view->common_headers = Horde::widget(array( 'url' => $headersURL, 'title' => _("Show Common Headers"), @@ -744,9 +733,14 @@ protected function _init() 'nocheck' => true )); } - if ($list_info['exists'] && !$list_headers) { + if ($list_info['exists']) { $a_view->list_headers = Horde::widget(array( - 'url' => $headersURL->copy()->add('show_list_headers', 1), + 'onclick' => Horde::popupJs(IMP_Basic_Listinfo::url(array( + 'buid' => $buid, + 'mailbox' => $mailbox + )), array( + 'urlencode' => true + )), 'title' => _("Show Mailing List Information"), 'nocheck' => true )); @@ -776,12 +770,6 @@ protected function _init() ); } } - foreach ($all_list_headers as $head => $val) { - $hdrs[] = array( - 'name' => $list_headers_lookup[$head], - 'val' => $val - ); - } /* Determine the fields that will appear in the MIME info entries. */ $part_info = $part_info_display = array('icon', 'description', 'size'); @@ -967,64 +955,4 @@ protected function _returnToMailbox($start = null, $actID = null) $this->output = $ob->output; } - /** - * Parses all of the available mailing list headers. - * - * @param Horde_Mime_Headers $headers A Horde_Mime_Headers object. - * - * @return array Keys are the list header names, values are the - * parsed list header values. - */ - protected function _parseAllListHeaders($headers) - { - $ret = array(); - - foreach (array_keys($headers->listHeaders()) as $val) { - if ($data = $headers->getValue($val)) { - $ret[$val] = $this->_parseListHeaders($val, $data); - } - } - - return $ret; - } - - /** - * Parse the information in mailing list headers. - * - * @param string $id The header ID. - * @param string $data The header text to process. - * - * @return string The header value. - */ - protected function _parseListHeaders($id, $data) - { - $output = ''; - $parser = $GLOBALS['injector']->getInstance('Horde_ListHeaders'); - $text_filter = $GLOBALS['injector']->getInstance('Horde_Core_Factory_TextFilter'); - - foreach ($parser->parse($id, $data) as $val) { - /* RFC 2369 [2] states that we should only show the *FIRST* URL - * that appears in a header that we can adequately handle. */ - if (stripos($val->url, 'mailto:') === 0) { - $url = substr($val->url, 7); - $clink = new IMP_Compose_Link($url); - $output = Horde::link($clink->link()) . $url . ''; - foreach ($val->comments as $val2) { - $output .= ' (' . $val2 . ')'; - } - break; - } elseif ($url = $text_filter->filter($val->url, 'linkurls')) { - $output = $url; - foreach ($val->comments as $val2) { - $output .= ' (' . $val2 . ')'; - } - break; - } - } - - return strlen($output) - ? $output - : htmlspecialchars($data); - } - } diff --git a/imp/lib/Compose.php b/imp/lib/Compose.php index 6a75676def3..d4f0182f3f0 100644 --- a/imp/lib/Compose.php +++ b/imp/lib/Compose.php @@ -1165,7 +1165,8 @@ protected function _prepSendMessageAssert(Horde_Mail_Rfc822_List $email, protected function _prepSendMessageEncode(Horde_Mail_Rfc822_List $email, $charset) { - $exception = null; + $exception = new IMP_Compose_Exception_Address(); + $hook = true; $out = array(); foreach ($email as $val) { @@ -1183,16 +1184,48 @@ protected function _prepSendMessageEncode(Horde_Mail_Rfc822_List $email, IMP::parseAddressList($tmp, array( 'validate' => true )); - $out[] = $tmp; + + $error = null; + + if ($hook) { + try { + $error = Horde::callHook('compose_addr', array($tmp), 'imp'); + } catch (Horde_Exception_HookNotSet $e) { + $hook = false; + } + } } catch (Horde_Mail_Exception $e) { - if (is_null($exception)) { - $exception = new IMP_Compose_Exception_Address(); + $error = array( + 'msg' => sprintf(_("Invalid e-mail address (%s)."), $val) + ); + } + + if (is_array($error)) { + switch (isset($error['level']) ? $error['level'] : $exception::BAD) { + case $exception::WARN: + case 'warn': + if (!empty($this->_metadata['warn_addr']) && + in_array(strval($val), $this->_metadata['warn_addr'])) { + $out[] = $tmp; + continue 2; + } + $this->_metadata['warn_addr'][] = strval($val); + $this->changed = 'changed'; + $level = $exception::WARN; + break; + + default: + $level = $exception::BAD; + break; } - $exception->addresses[$val->writeAddress()] = $e; + + $exception->addAddress($val, $error['msg'], $level); + } else { + $out[] = $tmp; } } - if ($exception) { + if (count($exception)) { throw $exception; } diff --git a/imp/lib/Compose/Exception/Address.php b/imp/lib/Compose/Exception/Address.php index 1cde28727cb..593ec00993e 100644 --- a/imp/lib/Compose/Exception/Address.php +++ b/imp/lib/Compose/Exception/Address.php @@ -22,13 +22,61 @@ * @license http://www.horde.org/licenses/gpl GPL * @package IMP */ -class IMP_Compose_Exception_Address extends IMP_Compose_Exception +class IMP_Compose_Exception_Address +extends IMP_Compose_Exception +implements Countable, IteratorAggregate { + /* Severity level. */ + const BAD = 1; + const WARN = 2; + /** - * The list of addresses (keys) and Horde_Mail_Exception objects (values). + * The list of error addresses. * * @var array */ - public $addresses = array(); + protected $_addresses = array(); + + /** + * Add an address to the bad list. + * + * @param Horde_Mail_Rfc822_Object $address Bad address. + * @param Exception|string $msg Error message. + * @param integer $level Severity level. + */ + public function addAddress( + Horde_Mail_Rfc822_Object $address, $msg, $level = self::BAD + ) + { + $ob = new stdClass; + $ob->address = $address; + $ob->error = ($msg instanceof Exception) + ? $msg->getMessage() + : strval($msg); + $ob->level = $level; + + $this->_addresses[] = $ob; + } + + /* Countable method. */ + + /** + * Returns the number of error addresses. + * + * @return integer The number of error addresses. + */ + public function count() + { + return count($this->_addresses); + } + + /* IteratorAggregate method. */ + + /** + */ + public function getIterator() + { + return new ArrayIterator($this->_addresses); + } } diff --git a/imp/lib/Dynamic/Mailbox.php b/imp/lib/Dynamic/Mailbox.php index 7de6866e281..ad4ff136062 100644 --- a/imp/lib/Dynamic/Mailbox.php +++ b/imp/lib/Dynamic/Mailbox.php @@ -134,6 +134,7 @@ protected function _addMailboxVars() $this->js_conf += array_filter(array( // URLs + 'URI_LISTINFO' => strval(IMP_Basic_Listinfo::url(array('full' => true))), 'URI_MESSAGE' => strval(IMP_Dynamic_Message::url()->setRaw(true)), 'URI_PORTAL' => strval($registry->getServiceLink('portal')->setRaw(true)), 'URI_PREFS_IMP' => strval($registry->getServiceLink('prefs', 'imp')->setRaw(true)), @@ -428,7 +429,8 @@ protected function _addMailboxVars() 'save' => _("Save"), 'viewsource' => _("View Source"), 'allparts' => _("All Parts"), - 'thread' => _("View Thread") + 'thread' => _("View Thread"), + 'listinfo' => _("List Info") ); if (empty($conf['user']['allow_view_source'])) { diff --git a/imp/lib/Dynamic/Message.php b/imp/lib/Dynamic/Message.php index 83f72049d51..af084351ea4 100644 --- a/imp/lib/Dynamic/Message.php +++ b/imp/lib/Dynamic/Message.php @@ -75,6 +75,8 @@ protected function _init() $ajax_queue = $injector->getInstance('IMP_Ajax_Queue'); $ajax_queue->poll($this->indices->mailbox); + list(,$buid) = $this->indices->buids->getSingle(); + foreach (array('from', 'to', 'cc', 'bcc', 'replyTo', 'log') as $val) { if (!empty($msg_res[$val])) { $js_vars['DimpMessage.' . $val] = $msg_res[$val]; @@ -82,8 +84,16 @@ protected function _init() } if (!empty($msg_res['list_info']['exists'])) { $js_vars['DimpMessage.reply_list'] = true; + $this->view->listinfo = Horde::popupJs( + IMP_Basic_Listinfo::url(array( + 'buid' => $buid, + 'mailbox' => $this->indices->mailbox + )), array( + 'urlencode' => true + ) + ); } - list(,$js_vars['DimpMessage.buid']) = $this->indices->buids->getSingle(); + $js_vars['DimpMessage.buid'] = $buid; $js_vars['DimpMessage.mbox'] = $this->indices->mailbox->form_to; $js_vars['DimpMessage.tasks'] = $injector->getInstance('Horde_Core_Factory_Ajax')->create('imp', $this->vars)->getTasks(); diff --git a/imp/package.xml b/imp/package.xml index dda8587a80c..9c3f34a3505 100644 --- a/imp/package.xml +++ b/imp/package.xml @@ -33,6 +33,8 @@ GPL-2.0 +* [mms] Better reporting of e-mail address errors when composing. +* [mms] Add list information display to dynamic view. * [jan] Display signature in compose view. * [mms] Add keyboard shortcuts to allow a more granular scroll of the dynamic preview pane (Request #12750). * [mms] Add country flag graphic to contact image information in dynamic view. @@ -1283,7 +1285,7 @@ Horde_ListHeaders pear.horde.org - 1.0.0 + 1.1.0 2.0.0alpha1 2.0.0alpha1 diff --git a/imp/templates/dynamic/message.html.php b/imp/templates/dynamic/message.html.php index f7be35a9da2..41ac145e241 100644 --- a/imp/templates/dynamic/message.html.php +++ b/imp/templates/dynamic/message.html.php @@ -57,6 +57,14 @@ + +listinfo): ?> +
+ + + + +
diff --git a/imp/templates/listinfo/listinfo.html.php b/imp/templates/listinfo/listinfo.html.php new file mode 100644 index 00000000000..e0216106f30 --- /dev/null +++ b/imp/templates/listinfo/listinfo.html.php @@ -0,0 +1,14 @@ +

+ +

+ + + +headers as $k => $v): ?> + + + + + + +
diff --git a/imp/themes/default/dynamic/screen.css b/imp/themes/default/dynamic/screen.css index 29426f9d7a1..3a36286e7b4 100644 --- a/imp/themes/default/dynamic/screen.css +++ b/imp/themes/default/dynamic/screen.css @@ -337,7 +337,8 @@ div.vpRowVert div.msgSubject span.flagUser { .imp-sidebar-container:hover { background: none; } -.imp-sidebar-container a { +.imp-sidebar-container a, +.imp-sidebar-mbox-loading { color: #555 !important; } .imp-sidebar-container a:hover { @@ -456,13 +457,8 @@ div.dimpActionsMsg #windowclose { .msgHeaders table { margin-top: -2px; } -.msgHeaders table thead td { - padding: 0 0 1px 0; -} -.msgHeaders table thead tr { - vertical-align: top; -} .msgHeaders table thead td.label { + display: block; font-weight: bold; padding-right: 4px; text-align: right; @@ -1021,6 +1017,10 @@ span.logoutIcon { { background-image: url("../graphics/filters.png"); } +#ctx_preview_listinfo span.iconImg, +#msg_listinfo span.iconImg { + background-image: url("../graphics/flags/group.png"); +} #ctx_contacts img.contactimg, #ctx_contacts div.flagimg { display: block; diff --git a/imp/themes/default/screen.css b/imp/themes/default/screen.css index 15e1a91ed16..d9d1442fec9 100644 --- a/imp/themes/default/screen.css +++ b/imp/themes/default/screen.css @@ -16,8 +16,8 @@ } /* Attachment tree styling. */ -div.partsTreeDiv span span:last-child { - vertical-align: bottom; +div.partsTreeDiv { + min-height: 0; } /* Message body styling. */ @@ -431,6 +431,13 @@ table.remotemanagement td.noneconfigured { float: right; } +/* Mailing list info page */ +table.mailinglistinfo { + border: 1px solid #d0d0d0; + border-bottom: 0; + margin: 8px; +} + /* Inline display (Horde_Mime_Viewer) styles. */ .mimeStatusMessageTable { margin-bottom: 3px;