From: Jérémy Bobbio Date: Sat, 18 Jun 2011 18:27:22 +0000 (+0200) Subject: Merge commit 'debian/0.3.1-1' into debian X-Git-Url: https://git.donarmstrong.com/?a=commitdiff_plain;h=83f95d05351f9d32bd5033a99ac2831ec676c6ca;hp=076088e93843ddabc525e5c1db3b6f56a1e22121;p=roundcube.git Merge commit 'debian/0.3.1-1' into debian --- diff --git a/.htaccess b/.htaccess index 19064fd..00e1bf2 100644 --- a/.htaccess +++ b/.htaccess @@ -10,10 +10,11 @@ php_value upload_max_filesize 5M php_value post_max_size 6M php_value memory_limit 64M -php_value zlib.output_compression Off -php_value magic_quotes_gpc 0 -php_value zend.ze1_compatibility_mode 0 -php_value suhosin.session.encrypt Off +php_flag zlib.output_compression Off +php_flag magic_quotes_gpc Off +php_flag magic_quotes_runtime Off +php_flag zend.ze1_compatibility_mode Off +php_flag suhosin.session.encrypt Off php_value session.auto_start 0 php_value session.gc_maxlifetime 21600 @@ -35,7 +36,7 @@ SetOutputFilter DEFLATE # replace 'append' with 'merge' for Apache version 2.2.9 and later -Header append Cache-Control public env=!NO_CACHE +#Header append Cache-Control public env=!NO_CACHE diff --git a/CHANGELOG b/CHANGELOG index b5d57b4..6f92798 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,36 +1,49 @@ -CHANGELOG Roundcube Webmail (release 0.3-stable) +CHANGELOG RoundCube Webmail =========================== -- Fix gn and givenName should be synonymous in LDAP addressbook (#1485892) -- Add mail_domain to LDAP email entries without @ sign (#1485201) -- Fix saving empty values in LDAP contact data (#1485781) -- Fix LDAP contact update when RDN field is changed (#1485788) -- Fix LDAP attributes case senitivity problems (#1485830) -- Fix LDAP addressbook browsing when only one directory is used (#1486022) -- Fix endless loop on error response for APPEND command (#1486060) -- Don't require date.timezone setting in installer (#1485989) -- Fix date sorting problem with Courier IMAP server (#1486065) -- Unselect pressed buttons on mouse up (#1485987) -- Don't set php_value error_log in .htaccess but mention in INSTALL (#1485924) -- Fix too small status/flag/attachment columns in Safari 4 (#1486063) -- Fix selection disabling while dragging splitter in webkit browsers (#1486056) -- Added 'new_messages' plugin hook (#1486005) -- Added 'logout_after' plugin hook (#1486042) -- Added 'message_compose' hook -- Added 'imap_connect' hook (#1485956) -- Fix vcard_attachments plugin (#1486035) -- Updated PEAR::Auth_SASL to 1.0.3 version -- Use sequence names only with PostgreSQL (#1486018) -- Re-designed User Preferences interface -- Fix MS SQL DDL (#1486020) -- Fix rcube_mdb2.php: call to setCharset not implemented in mssql driver (#1486019) -- Added 'display_next' option -- Fix rcube_mdb2::unixtimestamp for MS SQL (#1486015) -- Fix HTML washing to respect character encoding -- Fix endless loop in iil_C_Login() with Courier IMAP (#1486010) -- Fix #messagemenu display on IE (#1486006) -- Speedup UI by using sprites for (toolbar) buttons -- Fix charset names with X- prefix handling -- Fix displaying of HTML messages with unknown/malformed tags (#1486003) - +- Specify toolbar container in compose template (#1486247) +- Fix $_SERVER['HTTPS'] check for SSL forcing on IIS (#1486243) +- Avoid unnecessary page loads for selected tab (#1486032) +- Fix quota indicator issues by content generation on client-size (#1486197, #1486220) +- Don't display disabled sections in Settings (#1486099) +- Added server-side e-mail address validation with 'email_dns_check' option (#1485857) +- Fix login page loading into an iframe when session expires (#1485952) +- Allow setting port number in 'force_https' option (#1486091) +- Option 'force_https' replaced by 'force_https' plugin +- Fix IE issue with non-UTF-8 characters in AJAX response (#1486159) +- Partially fixed "empty body" issue by showing raw body of malformed message (#1486166) +- Fix importing/sending to email address with whitespace (#1486214) +- Added XIMSS (CommuniGate) driver for Password plugin +- Fix newly attached files are not saved in drafts w/o editing any text (#1486202) +- Added attachment upload indicator with parallel upload (#1486058) +- Use default_charset for bodies of messages without charset definition (#1486187) +- Password: added cPanel driver +- Fix return to first page from e-mail screen (#1486105) +- Fix handling HTML comments in HTML messages (#1486189) +- Fix folder/messagelist controls alignment - icons used (#1486072) +- Fix LDAP addressbook shows 'Contact not found' error sometimes (#1486178) +- Fix cache status checking + improve cache operations performance (#1486104) +- Prevent from setting INBOX as any of special folders (#1486114) +- Fix regular expression for e-mail address (#1486152) +- Fix Received header format +- Implemented sorting by message index - added 'index_sort' option (#1485936) +- Fix dl() use in installer (#1486150) +- Added 'ldap_debug' option +- Fix "Empty startup greeting" bug (#1486085) +- Fix setting user name in 'new_user_identity' plugin (#1486137) +- Fix incorrect count of new messages in folder list when using multiple IMAP clients (#1485995) +- Fix all folders checking for new messages with disabled caching (#1486128) +- Support skins in 'archive' and 'markasjunk' plugins +- Added 'html_editor' hook (#1486068) +- Fix DB constraint violation when populating messages cache (#1486052) +- Password: added password strength options (#1486062) +- Fix LDAP partial result warning (#1485536) +- Fix delete in message view deletes permanently with flag_for_deletion=true (#1486101) +- Use faster/secure mt_rand() (#1486094) +- Fix roundcube hangs on empty inbox with bincimapd (#1486093) +- Fix wrong headers for IE on servers without $_SERVER['HTTPS'] (#1485926) +- Force IE style headers for attachments in non-HTTPS session, 'use_https' option (#1485655) +- Check 'post_max_size' for upload max filesize (#1486089) +- Password Plugin: Fix %d inserts username instead of domain (#1486088) +- Fix rcube_mdb2::affected_rows() (#1486082) diff --git a/INSTALL b/INSTALL index ff905bd..d2b9145 100644 --- a/INSTALL +++ b/INSTALL @@ -25,9 +25,9 @@ REQUIREMENTS - session.auto_start disabled - zend.ze1_compatibility_mode disabled * The PEAR framework with the following packages installed - - MDB2 (2.4.1) + - MDB2 (2.5.0b2) - Mail_Mime (1.5.2) - - Net_SMTP (1.2.11) + - Net_SMTP (1.3.3) * PHP compiled with OpenSSL to connect to IMAPS and to use the spell checker * A MySQL or PostgreSQL database engine or the SQLite extension for PHP * One of the above databases with permission to create tables diff --git a/README b/README index ff975de..d7a13f7 100644 --- a/README +++ b/README @@ -1,9 +1,9 @@ -Roundcube Webmail (http://roundcube.net) +RoundCube Webmail (http://roundcube.net) Introduction: ------------- -Roundcube Webmail is a browser-based multilingual IMAP client with an +RoundCube Webmail is a browser-based multilingual IMAP client with an application-like user interface. It provides full functionality you expect from an e-mail client, including MIME support, address book, folder management, message searching and spell checking. RoundCube Webmail is written in PHP and @@ -35,7 +35,7 @@ LICENSE for more information about our license. Contribution: ------------- -Want to help make Roundcube the best webmail solution ever? +Want to help make RoundCube the best webmail solution ever? RoundCube is open source software. Our developers and contributors all are volunteers and we're always looking for new additions and resources. For more information visit http://roundcube.net/contribute diff --git a/SQL/mysql.initial.sql b/SQL/mysql.initial.sql index 9464dd7..f814547 100644 --- a/SQL/mysql.initial.sql +++ b/SQL/mysql.initial.sql @@ -10,7 +10,7 @@ CREATE TABLE `session` ( `created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `changed` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `ip` varchar(40) NOT NULL, - `vars` text NOT NULL, + `vars` mediumtext NOT NULL, PRIMARY KEY(`sess_id`), INDEX `changed_index` (`changed`) ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; @@ -53,6 +53,7 @@ CREATE TABLE `messages` ( `structure` text, PRIMARY KEY(`message_id`), INDEX `created_index` (`created`), + INDEX `index_index` (`user_id`, `cache_key`, `idx`), UNIQUE `uniqueness` (`user_id`, `cache_key`, `uid`), CONSTRAINT `user_id_fk_messages` FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`) @@ -94,6 +95,7 @@ CREATE TABLE `contacts` ( `vcard` text NULL, `user_id` int(10) UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY(`contact_id`), + INDEX `user_contacts_index` (`user_id`,`email`), CONSTRAINT `user_id_fk_contacts` FOREIGN KEY (`user_id`) REFERENCES `users`(`user_id`) /*!40008 diff --git a/SQL/mysql.update.sql b/SQL/mysql.update.sql index 5590099..77bf317 100644 --- a/SQL/mysql.update.sql +++ b/SQL/mysql.update.sql @@ -1,5 +1,5 @@ -- RoundCube Webmail update script for MySQL databases --- Updates from version 0.1-stable to 0.1.1 +-- Updates from version 0.1-stable to 0.3.1 TRUNCATE TABLE `messages`; @@ -44,3 +44,16 @@ ALTER TABLE `cache` ALTER TABLE `users` CHANGE `language` `language` varchar(5); + +-- Updates from version 0.3-stable + +ALTER TABLE `messages` + ADD INDEX `index_index` (`user_id`, `cache_key`, `idx`); + +TRUNCATE `messages`; + +ALTER TABLE `session` + CHANGE `vars` `vars` MEDIUMTEXT NOT NULL; + +ALTER TABLE `contacts` + ADD INDEX `user_contacts_index` (`user_id`,`email`); diff --git a/SQL/postgres.initial.sql b/SQL/postgres.initial.sql index 1a21ee2..a52a01f 100644 --- a/SQL/postgres.initial.sql +++ b/SQL/postgres.initial.sql @@ -110,7 +110,7 @@ CREATE TABLE contacts ( vcard text ); -CREATE INDEX contacts_user_id_idx ON contacts (user_id); +CREATE INDEX contacts_user_id_idx ON contacts (user_id, email); -- -- Sequence "cache_ids" @@ -174,4 +174,5 @@ CREATE TABLE messages ( ); ALTER TABLE messages ADD UNIQUE (user_id, cache_key, uid); +CREATE INDEX messages_index_idx ON messages (user_id, cache_key, idx); CREATE INDEX messages_created_idx ON messages (created); diff --git a/SQL/postgres.update.sql b/SQL/postgres.update.sql index a29558e..e343dd4 100644 --- a/SQL/postgres.update.sql +++ b/SQL/postgres.update.sql @@ -36,3 +36,10 @@ ALTER TABLE identities ALTER del TYPE smallint; ALTER TABLE identities ALTER standard TYPE smallint; ALTER TABLE contacts ALTER del TYPE smallint; ALTER TABLE messages ALTER del TYPE smallint; + +-- Updates from version 0.3-stable + +CREATE INDEX messages_index_idx ON messages (user_id, cache_key, idx); +TRUNCATE messages; +DROP INDEX contacts_user_id_idx; +CREATE INDEX contacts_user_id_idx ON contacts (user_id, email); diff --git a/SQL/sqlite.initial.sql b/SQL/sqlite.initial.sql index ef7cb43..cccad7a 100644 --- a/SQL/sqlite.initial.sql +++ b/SQL/sqlite.initial.sql @@ -34,7 +34,7 @@ CREATE TABLE contacts ( vcard text NOT NULL default '' ); -CREATE INDEX ix_contacts_user_id ON contacts(user_id); +CREATE INDEX ix_contacts_user_id ON contacts(user_id, email); -- -------------------------------------------------------- @@ -119,5 +119,6 @@ CREATE TABLE messages ( structure text ); -CREATE INDEX ix_messages_user_cache_uid ON messages(user_id,cache_key,uid); +CREATE UNIQUE INDEX ix_messages_user_cache_uid ON messages (user_id,cache_key,uid); +CREATE INDEX ix_messages_index ON messages (user_id,cache_key,idx); CREATE INDEX ix_messages_created ON messages (created); diff --git a/SQL/sqlite.update.sql b/SQL/sqlite.update.sql index 627074e..09af76f 100644 --- a/SQL/sqlite.update.sql +++ b/SQL/sqlite.update.sql @@ -34,3 +34,12 @@ CREATE INDEX ix_messages_created ON messages (created); CREATE INDEX ix_session_changed ON session (changed); CREATE INDEX ix_cache_created ON cache (created); + +-- Updates from version 0.3-stable + +DROP INDEX ix_messages_user_cache_uid; +CREATE UNIQUE INDEX ix_messages_user_cache_uid ON messages (user_id,cache_key,uid); +CREATE INDEX ix_messages_index ON messages (user_id,cache_key,idx); +TRUNCATE messages; +DROP INDEX ix_contacts_user_id; +CREATE INDEX ix_contacts_user_id ON contacts(user_id, email); diff --git a/bin/quotaimg.php b/bin/quotaimg.php deleted file mode 100644 index 7111b89..0000000 --- a/bin/quotaimg.php +++ /dev/null @@ -1,204 +0,0 @@ - | - +-----------------------------------------------------------------------+ - - $Id: quotaimg.php 2453 2009-05-04 08:31:55Z alec $ - -*/ - -define('INSTALL_PATH', realpath(dirname(__FILE__).'/..') . '/'); -require INSTALL_PATH . 'program/include/iniset.php'; - -$RCMAIL = rcmail::get_instance(); - -$used = isset($_GET['u']) ? intval($_GET['u']) : '??'; -$quota = isset($_GET['q']) ? intval($_GET['q']) : '??'; -$width = empty($_GET['w']) ? 100 : min(300, intval($_GET['w'])); -$height = empty($_GET['h']) ? 14 : min(50, intval($_GET['h'])); - -/** - * Quota display - * - * Modify the following few elements to change the display of the image. - * Modifiable attributes are: - * bool border :: Defines whether you want to show a border around it? - * bool unknown :: Leave default; Defines whether quota is "unknown" - * - * int height :: Defines height of the image - * int width :: Defines width of the image - * int font :: Changes the font size & font used in the GD library. - * Available values are from 1 to 5. - * int padding :: Changes the offset (in pixels) from the top of the image - * to where the top of the text will be aligned. User - * greater than 0 to ensure text is off the border. - * array limit :: Holds the integer values of in an associative array as - * to what defines the upper and lower levels for quota - * display. - * High - Quota is nearing capacity. - * Mid - Quota is around the middle - * Low - Currently not used. - * array color :: An associative array of strings of comma separated - * values (R,G,B) for use in color creation. Define the - * RGB values you'd like to use. A list of colors (and - * their RGB values) can be found here: - * http://www.december.com/html/spec/colorcodes.html - * - * @return void - * - * @param mixed $used The amount used, or ?? if unknown. - * @param mixed $total The total available, or ?? if unknown. - * @param int $width Width of the image. - * @param int $height Height of the image. - * - * @see rcube_imap::get_quota() - * @see iil_C_GetQuota() - * - * @todo Make colors a config option. - */ -function genQuota($used, $total, $width, $height) -{ - $unknown = false; - $border = 0; - - $font = 2; - $padding = 0; - - $limit['high'] = 80; - $limit['mid'] = 55; - $limit['low'] = 0; - - // Fill Colors - $color['fill']['high'] = '243, 49, 49'; // Near quota fill color - $color['fill']['mid'] = '245, 173, 60'; // Mid-area of quota fill color - $color['fill']['low'] = '145, 225, 100'; // Far from quota fill color - - // Background colors - $color['bg']['OL'] = '215, 13, 13'; // Over limit bbackground - $color['bg']['Unknown'] = '238, 99, 99'; // Unknown background - $color['bg']['quota'] = '255, 255, 255'; // Normal quota background - - // Misc. Colors - $color['border'] = '0, 0, 0'; - $color['text']['high'] = '255, 255, 255'; // white text for red background - $color['text']['mid'] = '102, 102, 102'; - $color['text']['low'] = '102, 102, 102'; - $color['text']['normal'] = '102, 102, 102'; - - - /************************************ - ***** DO NOT EDIT BELOW HERE ***** - ***********************************/ - - // @todo: Set to "??" instead? - if (preg_match('/^[^0-9?]*$/', $used) || preg_match('/^[^0-9?]*$/', $total)) { - return false; - } - - if (strpos($used, '?') !== false || strpos($total, '?') !== false && $used != 0) { - $unknown = true; - } - - $im = imagecreate($width, $height); - - if ($border) { - list($r, $g, $b) = explode(',', $color['border']); - - $borderc = imagecolorallocate($im, $r, $g, $b); - - imageline($im, 0, 0, $width, 0, $borderc); - imageline($im, 0, $height-$border, 0, 0, $borderc); - imageline($im, $width-1, 0, $width-$border, $height, $borderc); - imageline($im, $width, $height-$border, 0, $height-$border, $borderc); - } - - if ($unknown) { - list($r, $g, $b) = explode(',', $color['text']['normal']); - $text = imagecolorallocate($im, $r, $g, $b); - list($r, $g, $b) = explode(',', $color['bg']['Unknown']); - $background = imagecolorallocate($im, $r, $g, $b); - - imagefilledrectangle($im, 0, 0, $width, $height, $background); - - $string = 'Unknown'; - $mid = floor(($width-(strlen($string)*imagefontwidth($font)))/2)+1; - imagestring($im, $font, $mid, $padding, $string, $text); - } else if ($used > $total) { - list($r, $g, $b) = explode(',', $color['text']['normal']); - $text = imagecolorallocate($im, $r, $g, $b); - list($r, $g, $b) = explode(',', $color['bg']['OL']); - $background = imagecolorallocate($im, $r, $g, $b); - - imagefilledrectangle($im, 0, 0, $width, $height, $background); - - $string = 'Over Limit'; - $mid = floor(($width-(strlen($string)*imagefontwidth($font)))/2)+1; - imagestring($im, $font, $mid, $padding, $string, $text); - } else { - list($r, $g, $b) = explode(',', $color['bg']['quota']); - $background = imagecolorallocate($im, $r, $b, $g); - - imagefilledrectangle($im, 0, 0, $width, $height, $background); - - $quota = ($used==0)?0:(round($used/$total, 2)*100); - - if ($quota >= $limit['high']) { - list($r, $g, $b) = explode(',', $color['text']['high']); - $text = imagecolorallocate($im, $r, $g, $b); - list($r, $g, $b) = explode(',', $color['fill']['high']); - $fill = imagecolorallocate($im, $r, $g, $b); - } elseif($quota >= $limit['mid']) { - list($r, $g, $b) = explode(',', $color['text']['mid']); - $text = imagecolorallocate($im, $r, $g, $b); - list($r, $g, $b) = explode(',', $color['fill']['mid']); - $fill = imagecolorallocate($im, $r, $g, $b); - } else { - // if($quota >= $limit['low']) - list($r, $g, $b) = explode(',', $color['text']['low']); - $text = imagecolorallocate($im, $r, $g, $b); - list($r, $g, $b) = explode(',', $color['fill']['low']); - $fill = imagecolorallocate($im, $r, $g, $b); - } - - $quota_width = $quota / 100 * $width; - if ($quota_width) - imagefilledrectangle($im, $border, 0, $quota_width, $height-2*$border, $fill); - - $string = $quota . '%'; - $mid = floor(($width-(strlen($string)*imagefontwidth($font)))/2)+1; - // Print percent in black - imagestring($im, $font, $mid, $padding, $string, $text); - } - - header('Content-Type: image/gif'); - - // cache for 1 hour - $maxage = 3600; - header('Expires: ' . gmdate('D, d M Y H:i:s', time()+$maxage). ' GMT'); - header('Cache-Control: max-age=' . $maxage); - - imagegif($im); - imagedestroy($im); -} - -if (!empty($RCMAIL->user->ID) && $width > 1 && $height > 1) { - genQuota($used, $quota, $width, $height); -} -else { - header("HTTP/1.0 403 Forbidden"); - echo "Requires a valid user session and positive values"; -} - -exit; -?> diff --git a/config/db.inc.php.dist b/config/db.inc.php.dist index 4020b26..a9ffe52 100644 --- a/config/db.inc.php.dist +++ b/config/db.inc.php.dist @@ -16,11 +16,13 @@ $rcmail_config = array(); // PEAR database DSN for read/write operations // format is db_provider://user:password@host/database +// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php // currently supported db_providers: mysql, mysqli, pgsql, sqlite, mssql $rcmail_config['db_dsnw'] = 'mysql://roundcube:pass@localhost/roundcubemail'; // postgres example: 'pgsql://roundcube:pass@localhost/roundcubemail'; -// sqlite example: 'sqlite://./sqlite.db?mode=0646'; +// Warning: for SQLite use absolute path in DSN: +// sqlite example: 'sqlite:////full/path/to/sqlite.db?mode=0646'; // PEAR database DSN for read only operations (if empty write database will be used) // useful for database replication diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist index 42881df..efa4595 100644 --- a/config/main.inc.php.dist +++ b/config/main.inc.php.dist @@ -43,14 +43,15 @@ $rcmail_config['plugins'] = array(); // enable caching of messages and mailbox data in the local database. // this is recommended if the IMAP server does not run on the same machine -$rcmail_config['enable_caching'] = TRUE; +$rcmail_config['enable_caching'] = FALSE; // lifetime of message cache // possible units: s, m, h, d, w $rcmail_config['message_cache_lifetime'] = '10d'; // enforce connections over https -// with this option enabled, all non-secure connections will be redirected +// with this option enabled, all non-secure connections will be redirected. +// set the port for the ssl connection as value of this option if it differs from the default 443 $rcmail_config['force_https'] = FALSE; // automatically create a new RoundCube user when log-in the first time. @@ -130,6 +131,9 @@ $rcmail_config['sql_debug'] = false; // Log IMAP conversation to /imap or to syslog $rcmail_config['imap_debug'] = false; +// Log LDAP conversation to /ldap or to syslog +$rcmail_config['ldap_debug'] = false; + // Log SMTP conversation to /smtp or to syslog $rcmail_config['smtp_debug'] = false; @@ -365,6 +369,9 @@ $rcmail_config['delete_always'] = false; // Must be less than 'session_lifetime' $rcmail_config['min_keep_alive'] = 60; +// Enable DNS checking for e-mail address validation +$rcmail_config['email_dns_check'] = false; + /***** these settings can be overwritten by user's preferences *****/ // skin name: folder from skins/ @@ -440,5 +447,8 @@ $rcmail_config['check_all_folders'] = FALSE; // If true, after message delete/move, the next message will be displayed $rcmail_config['display_next'] = FALSE; +// If true, messages list will be sorted by message index instead of message date +$rcmail_config['index_sort'] = TRUE; + // end of config file ?> diff --git a/index.php b/index.php index 624d898..2360d7f 100644 --- a/index.php +++ b/index.php @@ -2,7 +2,7 @@ /* +-------------------------------------------------------------------------+ | RoundCube Webmail IMAP Client | - | Version 0.3-stable | + | Version 0.3.1-20091031 | | | | Copyright (C) 2005-2009, RoundCube Dev. - Switzerland | | | @@ -23,7 +23,7 @@ | Author: Thomas Bruederli | +-------------------------------------------------------------------------+ - $Id: index.php 2916 2009-09-04 10:58:29Z thomasb $ + $Id: index.php 3081 2009-10-31 13:20:02Z thomasb $ */ @@ -64,9 +64,12 @@ if ($RCMAIL->action=='error' && !empty($_GET['_code'])) { } // check if https is required (for login) and redirect if necessary -if ($RCMAIL->config->get('force_https', false) && empty($_SESSION['user_id']) && !(isset($_SERVER['HTTPS']) || $_SERVER['SERVER_PORT'] == 443)) { - header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']); - exit; +if (empty($_SESSION['user_id']) && ($force_https = $RCMAIL->config->get('force_https', false))) { + $https_port = is_bool($force_https) ? 443 : $force_https; + if (!rcube_https_check($https_port)) { + header('Location: https://' . $_SERVER['HTTP_HOST'] . ($https_port != 443 ? ':' . $https_port : '') . $_SERVER['REQUEST_URI']); + exit; + } } // trigger startup plugin hook @@ -74,7 +77,6 @@ $startup = $RCMAIL->plugins->exec_hook('startup', array('task' => $RCMAIL->task, $RCMAIL->set_task($startup['task']); $RCMAIL->action = $startup['action']; - // try to log in if ($RCMAIL->action=='login' && $RCMAIL->task=='mail') { // purge the session in case of new login when a session already exists @@ -149,7 +151,7 @@ $request_check_whitelist = array('login'=>1, 'spell'=>1); // check client X-header to verify request origin if ($OUTPUT->ajax_call) { - if (!$RCMAIL->config->get('devel_mode') && rc_request_header('X-RoundCube-Request') != $RCMAIL->get_request_token()) { + if (!$RCMAIL->config->get('devel_mode') && rc_request_header('X-RoundCube-Request') != $RCMAIL->get_request_token() && !empty($RCMAIL->user->ID)) { header('HTTP/1.1 404 Not Found'); die("Invalid Request"); } @@ -160,13 +162,14 @@ else if (!empty($_POST) && !$request_check_whitelist[$RCMAIL->action] && !$RCMAI $OUTPUT->send($RCMAIL->task); } - // not logged in -> show login page if (empty($RCMAIL->user->ID)) { - if ($OUTPUT->ajax_call) $OUTPUT->redirect(array(), 2000); + if (!empty($_REQUEST['_framed'])) + $OUTPUT->command('redirect', '?'); + // check if installer is still active if ($RCMAIL->config->get('enable_installer') && is_readable('./installer/index.php')) { $OUTPUT->add_footer(html::div(array('style' => "background:#ef9398; border:2px solid #dc5757; padding:0.5em; margin:2em auto; width:50em"), diff --git a/installer/check.php b/installer/check.php index 9bdb41b..4593051 100644 --- a/installer/check.php +++ b/installer/check.php @@ -55,14 +55,17 @@ if (version_compare(PHP_VERSION, MIN_PHP_VERSION, '>=')) {

Checking PHP extensions

The following modules/extensions are required to run RoundCube:

$ext) { if (extension_loaded($ext)) { $RCI->pass($name); } else { - $_ext = $prefix . $ext . '.' . PHP_SHLIB_SUFFIX; - $msg = @dl($_ext) ? 'Could be loaded. Please add in php.ini' : ''; + $_ext = $ext_dir . '/' . $prefix . $ext . '.' . PHP_SHLIB_SUFFIX; + $msg = @is_readable($_ext) ? 'Could be loaded. Please add in php.ini' : ''; $RCI->fail($name, $msg, $source_urls[$name]); } echo '
'; @@ -78,8 +81,8 @@ foreach ($optional_php_exts AS $name => $ext) { $RCI->pass($name); } else { - $_ext = $prefix . $ext . '.' . PHP_SHLIB_SUFFIX; - $msg = @dl($_ext) ? 'Could be loaded. Please add in php.ini' : ''; + $_ext = $ext_dir . '/' . $prefix . $ext . '.' . PHP_SHLIB_SUFFIX; + $msg = @is_readable($_ext) ? 'Could be loaded. Please add in php.ini' : ''; $RCI->na($name, $msg, $source_urls[$name]); } echo '
'; @@ -99,8 +102,8 @@ foreach ($supported_dbs AS $database => $ext) { $RCI->pass($database); } else { - $_ext = $prefix . $ext . '.' . PHP_SHLIB_SUFFIX; - $msg = @dl($_ext) ? 'Could be loaded. Please add in php.ini' : 'Not installed'; + $_ext = $ext_dir . '/' . $prefix . $ext . '.' . PHP_SHLIB_SUFFIX; + $msg = @is_readable($_ext) ? 'Could be loaded. Please add in php.ini' : 'Not installed'; $RCI->na($database, $msg, $source_urls[$database]); } echo '
'; diff --git a/installer/config.php b/installer/config.php index e51b4bf..02deb9b 100644 --- a/installer/config.php +++ b/installer/config.php @@ -124,7 +124,7 @@ echo $check_spell->show(intval($RCI->getprop('enable_spellcheck')), array('value $select_spell = new html_select(array('name' => '_spellcheck_engine', 'id' => "cfgspellcheckengine")); if (extension_loaded('pspell')) $select_spell->add('pspell', 'pspell'); -$select_spell->add('Googlie', 'googlie'); +$select_spell->add('Googie', 'googie'); echo $select_spell->show($RCI->is_post ? $_POST['_spellcheck_engine'] : 'pspell'); @@ -269,7 +269,7 @@ echo '
'; echo $input_dbhost->show($RCI->is_post ? $_POST['_dbhost'] : $dsnw['hostspec']); echo '
'; echo $input_dbname->show($RCI->is_post ? $_POST['_dbname'] : $dsnw['database']); -echo '
'; +echo '
'; echo $input_dbuser->show($RCI->is_post ? $_POST['_dbuser'] : $dsnw['username']); echo '
'; echo $input_dbpass->show($RCI->is_post ? $_POST['_dbpass'] : $dsnw['password']); diff --git a/plugins/archive/archive.js b/plugins/archive/archive.js index d771fb6..954fd15 100644 --- a/plugins/archive/archive.js +++ b/plugins/archive/archive.js @@ -29,8 +29,8 @@ if (window.rcmail) { // set css style for archive folder var li; - if (rcmail.env.archive_folder && (li = rcmail.get_folder_li(rcmail.env.archive_folder))) - $(li).css('background-image', 'url(plugins/archive/foldericon.png)'); + if (rcmail.env.archive_folder && rcmail.env.archive_folder_icon && (li = rcmail.get_folder_li(rcmail.env.archive_folder))) + $(li).css('background-image', 'url(' + rcmail.env.archive_folder_icon + ')'); }) } diff --git a/plugins/archive/archive.php b/plugins/archive/archive.php index 9df7f8b..27887ce 100644 --- a/plugins/archive/archive.php +++ b/plugins/archive/archive.php @@ -17,18 +17,22 @@ class archive extends rcube_plugin { $this->register_action('plugin.archive', array($this, 'request_action')); - # There is no "Archived flags" - # $GLOBALS['IMAP_FLAGS']['ARCHIVED'] = 'Archive'; + // There is no "Archived flags" + // $GLOBALS['IMAP_FLAGS']['ARCHIVED'] = 'Archive'; $rcmail = rcmail::get_instance(); - if ($rcmail->task == 'mail' && ($rcmail->action == '' || $rcmail->action == 'show') && ($archive_folder = $rcmail->config->get('archive_mbox'))) { + if ($rcmail->task == 'mail' && ($rcmail->action == '' || $rcmail->action == 'show') + && ($archive_folder = $rcmail->config->get('archive_mbox'))) { + + $skin_path = $this->local_skin_path(); + $this->include_script('archive.js'); $this->add_texts('localization', true); $this->add_button( array( 'command' => 'plugin.archive', - 'imagepas' => 'archive_pas.png', - 'imageact' => 'archive_act.png', + 'imagepas' => $skin_path.'/archive_pas.png', + 'imageact' => $skin_path.'/archive_act.png', 'title' => 'buttontitle', 'domain' => $this->ID, ), @@ -39,13 +43,13 @@ class archive extends rcube_plugin // set env variable for client $rcmail->output->set_env('archive_folder', $archive_folder); + $rcmail->output->set_env('archive_folder_icon', $this->url($skin_path.'/foldericon.png')); // add archive folder to the list of default mailboxes if (($default_folders = $rcmail->config->get('default_imap_folders')) && !in_array($archive_folder, $default_folders)) { $default_folders[] = $archive_folder; $rcmail->config->set('default_imap_folders', $default_folders); - } - + } } else if ($rcmail->task == 'settings') { $dont_override = $rcmail->config->get('dont_override', array()); @@ -111,7 +115,8 @@ class archive extends rcube_plugin $this->add_texts('localization'); $rcmail = rcmail::get_instance(); - $select = rcmail_mailbox_select(array('noselection' => '---', 'realnames' => true, 'maxlength' => 30)); + $select = rcmail_mailbox_select(array('noselection' => '---', 'realnames' => true, + 'maxlength' => 30, 'exceptions' => array('INBOX'))); $args['blocks']['main']['options']['archive_mbox'] = array( 'title' => $this->gettext('archivefolder'), diff --git a/plugins/archive/archive_act.png b/plugins/archive/archive_act.png deleted file mode 100644 index 2a17358..0000000 Binary files a/plugins/archive/archive_act.png and /dev/null differ diff --git a/plugins/archive/archive_pas.png b/plugins/archive/archive_pas.png deleted file mode 100644 index 8de2085..0000000 Binary files a/plugins/archive/archive_pas.png and /dev/null differ diff --git a/plugins/archive/foldericon.png b/plugins/archive/foldericon.png deleted file mode 100644 index ec0853c..0000000 Binary files a/plugins/archive/foldericon.png and /dev/null differ diff --git a/plugins/archive/localization/cs_CZ.inc b/plugins/archive/localization/cs_CZ.inc new file mode 100644 index 0000000..04c8fcf --- /dev/null +++ b/plugins/archive/localization/cs_CZ.inc @@ -0,0 +1,25 @@ + | ++-----------------------------------------------------------------------+ + +@version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ + +*/ + +$labels = array(); +$labels['buttontitle'] = 'Archivovat zprávu'; +$labels['archived'] = 'Úspěšně vloženo do archivu'; +$labels['archivefolder'] = 'Archiv'; + +?> diff --git a/plugins/archive/localization/et_EE.inc b/plugins/archive/localization/et_EE.inc new file mode 100644 index 0000000..e3968d7 --- /dev/null +++ b/plugins/archive/localization/et_EE.inc @@ -0,0 +1,8 @@ + diff --git a/plugins/archive/localization/fr_FR.inc b/plugins/archive/localization/fr_FR.inc index 422d45d..f44f30f 100644 --- a/plugins/archive/localization/fr_FR.inc +++ b/plugins/archive/localization/fr_FR.inc @@ -6,4 +6,3 @@ $labels['archived'] = 'Message archiv $labels['archivefolder'] = 'Archive'; ?> - diff --git a/plugins/archive/localization/ru_RU.inc b/plugins/archive/localization/ru_RU.inc new file mode 100644 index 0000000..e377ad0 --- /dev/null +++ b/plugins/archive/localization/ru_RU.inc @@ -0,0 +1,8 @@ + diff --git a/plugins/archive/skins/default/archive_act.png b/plugins/archive/skins/default/archive_act.png new file mode 100644 index 0000000..2a17358 Binary files /dev/null and b/plugins/archive/skins/default/archive_act.png differ diff --git a/plugins/archive/skins/default/archive_pas.png b/plugins/archive/skins/default/archive_pas.png new file mode 100644 index 0000000..8de2085 Binary files /dev/null and b/plugins/archive/skins/default/archive_pas.png differ diff --git a/plugins/archive/skins/default/foldericon.png b/plugins/archive/skins/default/foldericon.png new file mode 100644 index 0000000..ec0853c Binary files /dev/null and b/plugins/archive/skins/default/foldericon.png differ diff --git a/plugins/filesystem_attachments/filesystem_attachments.php b/plugins/filesystem_attachments/filesystem_attachments.php index fcdcea7..dce2de2 100644 --- a/plugins/filesystem_attachments/filesystem_attachments.php +++ b/plugins/filesystem_attachments/filesystem_attachments.php @@ -57,7 +57,7 @@ class filesystem_attachments extends rcube_plugin $tmpfname = tempnam($temp_dir, 'rcmAttmnt'); if (move_uploaded_file($args['path'], $tmpfname) && file_exists($tmpfname)) { - $args['id'] = count($_SESSION['plugins']['filesystem_attachments']['tmp_files'])+1; + $args['id'] = $this->file_id(); $args['path'] = $tmpfname; $args['status'] = true; @@ -88,7 +88,7 @@ class filesystem_attachments extends rcube_plugin return $args; } - $args['id'] = count($_SESSION['plugins']['filesystem_attachments']['tmp_files'])+1; + $args['id'] = $this->file_id(); $args['status'] = true; // Note the file for later cleanup @@ -146,4 +146,11 @@ class filesystem_attachments extends rcube_plugin } return $args; } + + function file_id() + { + $userid = rcmail::get_instance()->user->ID; + list($usec, $sec) = explode(' ', microtime()); + return preg_replace('/[^0-9]/', '', $userid . $sec . $usec); + } } diff --git a/plugins/help/content/about.html b/plugins/help/content/about.html index afaded6..69ac080 100644 --- a/plugins/help/content/about.html +++ b/plugins/help/content/about.html @@ -1,5 +1,5 @@
-

Copyright © 2005-2009, RoundCube Dev. - Switzerland

+

Copyright © 2005-2009, 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 version 2 @@ -33,5 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Tomasz Pajor (tomekp)
Fourat Zouari (fourat.zouari)
Aleksander Machniak (alec) + +


Website: roundcube.net

diff --git a/plugins/help/localization/cs_CZ.inc b/plugins/help/localization/cs_CZ.inc new file mode 100644 index 0000000..638b355 --- /dev/null +++ b/plugins/help/localization/cs_CZ.inc @@ -0,0 +1,25 @@ + | ++-----------------------------------------------------------------------+ + +@version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ + +*/ + +$labels = array(); +$labels['help'] = 'Nápověda'; +$labels['about'] = 'O aplikaci'; +$labels['license'] = 'Licence'; + +?> diff --git a/plugins/help/localization/hu_HU.inc b/plugins/help/localization/hu_HU.inc new file mode 100644 index 0000000..6ff4f24 --- /dev/null +++ b/plugins/help/localization/hu_HU.inc @@ -0,0 +1,8 @@ + diff --git a/plugins/help/skins/default/help.css b/plugins/help/skins/default/help.css index 7ccc671..e0b01bb 100644 --- a/plugins/help/skins/default/help.css +++ b/plugins/help/skins/default/help.css @@ -22,5 +22,17 @@ #helplicense, #helpabout { - padding: 20px; + width: 46em; + padding: 1em 2em; } + +#helplicense a, #helpabout a +{ + color: #900; +} + +#helpabout +{ + margin: 0 auto; +} + diff --git a/plugins/help/skins/default/help.gif b/plugins/help/skins/default/help.gif index 1ae9032..fe41e43 100644 Binary files a/plugins/help/skins/default/help.gif and b/plugins/help/skins/default/help.gif differ diff --git a/plugins/managesieve/Changelog b/plugins/managesieve/Changelog index 358836f..d5abbb2 100644 --- a/plugins/managesieve/Changelog +++ b/plugins/managesieve/Changelog @@ -1,3 +1,19 @@ +* version 1.7 [2009-09-20] +----------------------------------------------------------- +- Support multiple managesieve hosts using %h variable + in managesieve_host option +- Fix first rule deleting (#1486140) + +* version 1.6 [2009-09-08] +----------------------------------------------------------- +- Fix warning when importing squirrelmail rules +- Fix handling of "true" as "anyof (true)" test + +* version 1.5 [2009-09-04] +----------------------------------------------------------- +- Added es_ES, ua_UA localizations +- Added 'managesieve_mbox_encoding' option + * version 1.4 [2009-07-29] ----------------------------------------------------------- - Updated PEAR::Net_Sieve to 1.1.7 diff --git a/plugins/managesieve/config.inc.php.dist b/plugins/managesieve/config.inc.php.dist index d8e949a..c9ea44e 100644 --- a/plugins/managesieve/config.inc.php.dist +++ b/plugins/managesieve/config.inc.php.dist @@ -3,7 +3,8 @@ // managesieve server port $rcmail_config['managesieve_port'] = 2000; -// managesieve server address +// managesieve server address, default is localhost. +// Use %h variable as replacement for user's IMAP hostname $rcmail_config['managesieve_host'] = 'localhost'; // use or not TLS for managesieve server connection @@ -14,6 +15,11 @@ $rcmail_config['managesieve_usetls'] = false; // default contents of filters script (eg. default spam filter) $rcmail_config['managesieve_default'] = '/etc/dovecot/sieve/global'; +// Sieve RFC says that we should use UTF-8 endcoding for mailbox names, +// but some implementations does not covert UTF-8 to modified UTF-7. +// Defaults to UTF7-IMAP for backward compatybility +$rcmail_config['managesieve_mbox_encoding'] = 'UTF7-IMAP'; + // I need this because my dovecot (with listescape plugin) uses // ':' delimiter, but creates folders with dot delimiter $rcmail_config['managesieve_replace_delimiter'] = ''; diff --git a/plugins/managesieve/lib/rcube_sieve.php b/plugins/managesieve/lib/rcube_sieve.php index 3bb150e..2490aca 100644 --- a/plugins/managesieve/lib/rcube_sieve.php +++ b/plugins/managesieve/lib/rcube_sieve.php @@ -117,7 +117,7 @@ class rcube_sieve $script = $this->_convert_from_squirrel_rules($script); - $this->script = new rcube_sieve_script($script); + $this->script = new rcube_sieve_script($script, $this->disabled); $this->save(); @@ -184,7 +184,7 @@ class rcube_sieve_script * @param string Script's text content * @param array Disabled extensions */ - public function __construct($script, $disabled) + public function __construct($script, $disabled=NULL) { if (!empty($disabled)) foreach ($disabled as $ext) @@ -264,9 +264,10 @@ class rcube_sieve_script { $script = ''; $exts = array(); + $idx = 0; // rules - foreach ($this->content as $idx => $rule) + foreach ($this->content as $rule) { $extension = ''; $tests = array(); @@ -367,7 +368,8 @@ class rcube_sieve_script } $script .= "}\n"; - + $idx++; + if ($extension && !isset($exts[$extension])) $exts[$extension] = $extension; } @@ -442,7 +444,7 @@ class rcube_sieve_script { $result = NULL; - if (preg_match('/^(if|elsif|else)\s+((allof|anyof|exists|header|not|size)\s+(.*))\s+\{(.*)\}$/sm', trim($content), $matches)) + if (preg_match('/^(if|elsif|else)\s+((true|not\s+true|allof|anyof|exists|header|not|size)(.*))\s+\{(.*)\}$/sm', trim($content), $matches)) { list($tests, $join) = $this->_parse_tests(trim($matches[2])); $actions = $this->_parse_actions(trim($matches[5])); @@ -454,7 +456,7 @@ class rcube_sieve_script 'join' => $join, ); } - + return $result; } diff --git a/plugins/managesieve/localization/cs_CZ.inc b/plugins/managesieve/localization/cs_CZ.inc new file mode 100644 index 0000000..62f0fdf --- /dev/null +++ b/plugins/managesieve/localization/cs_CZ.inc @@ -0,0 +1,61 @@ + + * + */ + +$labels['filters'] = 'Filtry'; +$labels['managefilters'] = 'Nastavení filtrů'; +$labels['filtername'] = 'Název filtru'; +$labels['newfilter'] = 'Nový filtr'; +$labels['filteradd'] = 'Přidej filtr'; +$labels['filterdel'] = 'Smaž filtr'; +$labels['moveup'] = 'Posunout nahoru'; +$labels['movedown'] = 'Posunout dolů'; +$labels['filterallof'] = 'Odpovídají všechny pravidla'; +$labels['filteranyof'] = 'Odpovídá kterékoliv pravidlo'; +$labels['filterany'] = 'Všechny zprávy'; +$labels['filtercontains'] = 'obsahuje'; +$labels['filternotcontains'] = 'neobsahuje'; +$labels['filteris'] = 'odpovídá'; +$labels['filterisnot'] = 'neodpovídá'; +$labels['filterexists'] = 'existuje'; +$labels['filternotexists'] = 'neexistuje'; +$labels['filterunder'] = 'pod'; +$labels['filterover'] = 'nad'; +$labels['addrule'] = 'Přidej pravidlo'; +$labels['delrule'] = 'Smaž pravidlo'; +$labels['messagemoveto'] = 'Přesuň zprávu do'; +$labels['messageredirect'] = 'Přeposlat zprávu na'; +$labels['messagereply'] = 'Odpovědět se zprávou'; +$labels['messagedelete'] = 'Smazat zprávu'; +$labels['messagediscard'] = 'Smazat se zprávou'; +$labels['messagesrules'] = 'Pravidla pro příchozí zprávu:'; +$labels['messagesactions'] = '...vykonej následující akce:'; +$labels['add'] = 'Přidej'; +$labels['del'] = 'Smaž'; +$labels['sender'] = 'Odesílatel'; +$labels['recipient'] = 'Příjemce'; +$labels['vacationaddresses'] = 'Seznam příjemců, kterým nebude zpráva odeslána (oddělené čárkou):'; +$labels['vacationdays'] = 'Počet dnů mezi automatickými odpověďmi:'; +$labels['vacationreason'] = 'Zpráva (Důvod nepřítomnosti):'; +$labels['rulestop'] = 'Zastavit pravidla'; + +$messages = array(); +$messages['filterunknownerror'] = 'Neznámá chyba serveru'; +$messages['filterconnerror'] = 'Nebylo možné se připojit k sieve serveru'; +$messages['filterdeleteerror'] = 'Nebylo možné smazat filtr. Server nahlásil chybu'; +$messages['filterdeleted'] = 'Filtr byl smazán'; +$messages['filterconfirmdelete'] = 'Opravdu chcete smazat vybraný filtr?'; +$messages['filtersaved'] = 'Filtr byl uložen'; +$messages['filtersaveerror'] = 'Nebylo možné uložit filtr. Server nahlásil chybu.'; +$messages['ruledeleteconfirm'] = 'Jste si jisti, že chcete smazat vybrané pravidlo?'; +$messages['actiondeleteconfirm'] = 'Jste si jisti, že chcete smazat vybranou akci?'; +$messages['forbiddenchars'] = 'Zakázané znaky v poli'; +$messages['cannotbeempty'] = 'Pole nemůže být prázdné'; + +?> diff --git a/plugins/managesieve/localization/de_DE.inc b/plugins/managesieve/localization/de_DE.inc index c3a2feb..e2caf77 100644 --- a/plugins/managesieve/localization/de_DE.inc +++ b/plugins/managesieve/localization/de_DE.inc @@ -25,7 +25,7 @@ $labels['messagemoveto'] = 'Verschiebe Nachricht nach'; $labels['messageredirect'] = 'Leite Nachricht um nach'; $labels['messagereply'] = 'Antworte mit Nachricht'; $labels['messagedelete'] = 'Nachricht löschen'; -$labels['messagediscard'] = 'Discard with message'; +$labels['messagediscard'] = 'Weise ab mit Nachricht'; $labels['messagesrules'] = 'Für eingehende Nachrichten:'; $labels['messagesactions'] = '...führe folgende Aktionen aus:'; $labels['add'] = 'Hinzufügen'; @@ -40,13 +40,13 @@ $labels['rulestop'] = 'Regelauswertung anhalten'; $messages = array(); $messages['filterunknownerror'] = 'Unbekannter Serverfehler'; $messages['filterconnerror'] = 'Kann nicht zum Sieve-Server verbinden'; -$messages['filterdeleteerror'] = 'Fehler beim des löschen Filters. Serverfehler'; +$messages['filterdeleteerror'] = 'Fehler beim Löschen des Filters. Serverfehler'; $messages['filterdeleted'] = 'Filter erfolgreich gelöscht'; -$messages['filterconfirmdelete'] = 'Möchten Sie den Filter löschen ?'; +$messages['filterconfirmdelete'] = 'Möchten Sie den Filter löschen?'; $messages['filtersaved'] = 'Filter gespeichert'; $messages['filtersaveerror'] = 'Serverfehler, konnte den Filter nicht speichern.'; $messages['ruledeleteconfirm'] = 'Sicher, dass Sie die Regel löschen wollen?'; -$messages['actiondeleteconfirm'] = 'Sicher, dass Sie die ausgewaehlte Aktion löschen wollen?'; +$messages['actiondeleteconfirm'] = 'Sicher, dass Sie die ausgewählte Aktion löschen wollen?'; $messages['forbiddenchars'] = 'Unerlaubte Zeichen im Feld'; $messages['cannotbeempty'] = 'Feld darf nicht leer sein'; diff --git a/plugins/managesieve/localization/el_GR.inc b/plugins/managesieve/localization/el_GR.inc new file mode 100644 index 0000000..a1a5eec --- /dev/null +++ b/plugins/managesieve/localization/el_GR.inc @@ -0,0 +1,56 @@ + diff --git a/plugins/managesieve/localization/en_GB.inc b/plugins/managesieve/localization/en_GB.inc new file mode 100644 index 0000000..c671b83 --- /dev/null +++ b/plugins/managesieve/localization/en_GB.inc @@ -0,0 +1,53 @@ + diff --git a/plugins/managesieve/localization/gb_GB.inc b/plugins/managesieve/localization/gb_GB.inc deleted file mode 100644 index c671b83..0000000 --- a/plugins/managesieve/localization/gb_GB.inc +++ /dev/null @@ -1,53 +0,0 @@ - diff --git a/plugins/managesieve/localization/ru_RU.inc b/plugins/managesieve/localization/ru_RU.inc index ad459a0..b402943 100644 --- a/plugins/managesieve/localization/ru_RU.inc +++ b/plugins/managesieve/localization/ru_RU.inc @@ -32,6 +32,10 @@ $labels['add'] = 'Добавить'; $labels['del'] = 'Удалить'; $labels['sender'] = 'Отправитель'; $labels['recipient'] = 'Получатель'; +$labels['vacationaddresses'] = 'Список дополнительных адресов почты (разделённый запятыми):'; +$labels['vacationdays'] = 'Как часто отправлять сообщение (раз в сколько дней):'; +$labels['vacationreason'] = 'Текст сообщения (причины отсутствия):'; +$labels['rulestop'] = 'Не обрабатывать последующие правила'; $messages = array(); $messages['filterunknownerror'] = 'Неизвестная ошибка сервера'; diff --git a/plugins/managesieve/managesieve.php b/plugins/managesieve/managesieve.php index 21d974d..0c8c492 100644 --- a/plugins/managesieve/managesieve.php +++ b/plugins/managesieve/managesieve.php @@ -7,7 +7,7 @@ * It's clickable interface which operates on text scripts and communicates * with server using managesieve protocol. Adds Filters tab in Settings. * - * @version 1.3 + * @version 1.7 * @author Aleksander 'A.L.E.C' Machniak * * Configuration (see config.inc.php.dist): @@ -62,7 +62,7 @@ class managesieve extends rcube_plugin // try to connect to managesieve server and to fetch the script $this->sieve = new rcube_sieve($_SESSION['username'], $this->rc->decrypt($_SESSION['password']), - $this->rc->config->get('managesieve_host', 'localhost'), + str_replace('%h', $_SESSION['imap_host'], $this->rc->config->get('managesieve_host', 'localhost')), $this->rc->config->get('managesieve_port', 2000), $this->rc->config->get('managesieve_usetls', false), $this->rc->config->get('managesieve_disabled_extensions')); @@ -744,6 +744,9 @@ class managesieve extends rcube_plugin $a_folders = $this->rc->imap->list_mailboxes(); $delimiter = $this->rc->imap->get_hierarchy_delimiter(); + // set mbox encoding + $mbox_encoding = $this->rc->config->get('managesieve_mbox_encoding', 'UTF7-IMAP'); + if ($action['type'] == 'fileinto') $mailbox = $action['target']; else @@ -758,6 +761,9 @@ class managesieve extends rcube_plugin if ($replace_delimiter = $this->rc->config->get('managesieve_replace_delimiter')) $utf7folder = str_replace($delimiter, $replace_delimiter, $utf7folder); + // convert to Sieve implementation encoding + $utf7folder = $this->mbox_encode($utf7folder, $mbox_encoding); + if ($folder_class = rcmail_folder_classname($name)) $foldername = $this->gettext($folder_class); else @@ -812,6 +818,9 @@ class managesieve extends rcube_plugin private function check_email($email) { + if (function_exists('check_email')); + return check_email($email); + // Check for invalid characters if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) return false; @@ -849,6 +858,10 @@ class managesieve extends rcube_plugin return false; } + private function mbox_encode($text, $encoding) + { + return rcube_charset_convert($text, 'UTF7-IMAP', $encoding); + } } ?> diff --git a/plugins/markasjunk/junk_act.png b/plugins/markasjunk/junk_act.png deleted file mode 100644 index b5a84f6..0000000 Binary files a/plugins/markasjunk/junk_act.png and /dev/null differ diff --git a/plugins/markasjunk/junk_pas.png b/plugins/markasjunk/junk_pas.png deleted file mode 100644 index b88a561..0000000 Binary files a/plugins/markasjunk/junk_pas.png and /dev/null differ diff --git a/plugins/markasjunk/localization/cs_CZ.inc b/plugins/markasjunk/localization/cs_CZ.inc new file mode 100644 index 0000000..06ab2e9 --- /dev/null +++ b/plugins/markasjunk/localization/cs_CZ.inc @@ -0,0 +1,24 @@ + | ++-----------------------------------------------------------------------+ + +@version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ + +*/ + +$labels = array(); +$labels['buttontitle'] = 'Označit jako Spam'; +$labels['reportedasjunk'] = 'Úspěšně nahlášeno jako Spam'; + +?> \ No newline at end of file diff --git a/plugins/markasjunk/localization/ru_RU.inc b/plugins/markasjunk/localization/ru_RU.inc new file mode 100644 index 0000000..32d00c2 --- /dev/null +++ b/plugins/markasjunk/localization/ru_RU.inc @@ -0,0 +1,7 @@ + diff --git a/plugins/markasjunk/markasjunk.php b/plugins/markasjunk/markasjunk.php index 959111d..cf81883 100644 --- a/plugins/markasjunk/markasjunk.php +++ b/plugins/markasjunk/markasjunk.php @@ -16,24 +16,32 @@ class markasjunk extends rcube_plugin function init() { $this->register_action('plugin.markasjunk', array($this, 'request_action')); - $GLOBALS['IMAP_FLAGS']['JUNK'] = 'Junk'; $rcmail = rcmail::get_instance(); if ($rcmail->action == '' || $rcmail->action == 'show') { + $skin_path = $this->local_skin_path(); $this->include_script('markasjunk.js'); $this->add_texts('localization', true); - $this->add_button(array('command' => 'plugin.markasjunk', 'imagepas' => 'junk_pas.png', 'imageact' => 'junk_act.png'), 'toolbar'); + $this->add_button(array( + 'command' => 'plugin.markasjunk', + 'imagepas' => $skin_path.'/junk_pas.png', + 'imageact' => $skin_path.'/junk_act.png', + 'title' => 'markasjunk.buttontitle'), 'toolbar'); } } function request_action() { $this->add_texts('localization'); + + $GLOBALS['IMAP_FLAGS']['JUNK'] = 'Junk'; + $GLOBALS['IMAP_FLAGS']['NONJUNK'] = 'NonJunk'; $uids = get_input_value('_uid', RCUBE_INPUT_POST); $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); $rcmail = rcmail::get_instance(); + $rcmail->imap->unset_flag($uids, 'NONJUNK'); $rcmail->imap->set_flag($uids, 'JUNK'); if (($junk_mbox = $rcmail->config->get('junk_mbox')) && $mbox != $junk_mbox) { @@ -44,4 +52,4 @@ class markasjunk extends rcube_plugin $rcmail->output->send(); } -} \ No newline at end of file +} diff --git a/plugins/markasjunk/skins/default/junk_act.png b/plugins/markasjunk/skins/default/junk_act.png new file mode 100644 index 0000000..b5a84f6 Binary files /dev/null and b/plugins/markasjunk/skins/default/junk_act.png differ diff --git a/plugins/markasjunk/skins/default/junk_pas.png b/plugins/markasjunk/skins/default/junk_pas.png new file mode 100644 index 0000000..b88a561 Binary files /dev/null and b/plugins/markasjunk/skins/default/junk_pas.png differ diff --git a/plugins/new_user_dialog/localization/ru_RU.inc b/plugins/new_user_dialog/localization/ru_RU.inc new file mode 100644 index 0000000..d1eb28e --- /dev/null +++ b/plugins/new_user_dialog/localization/ru_RU.inc @@ -0,0 +1,7 @@ + diff --git a/plugins/new_user_dialog/new_user_dialog.php b/plugins/new_user_dialog/new_user_dialog.php index 4f6250f..965a405 100644 --- a/plugins/new_user_dialog/new_user_dialog.php +++ b/plugins/new_user_dialog/new_user_dialog.php @@ -96,7 +96,7 @@ class new_user_dialog extends rcube_plugin $save_data['email'] = $identity['email']; // save data if not empty - if (!empty($save_data['name']) && !empty($save_data['name'])) { + if (!empty($save_data['name']) && !empty($save_data['email'])) { $rcmail->user->update_identity($identity['identity_id'], $save_data); rcube_sess_unset('plugin.newuserdialog'); } diff --git a/plugins/new_user_identity/new_user_identity.php b/plugins/new_user_identity/new_user_identity.php index 7559569..78c9952 100644 --- a/plugins/new_user_identity/new_user_identity.php +++ b/plugins/new_user_identity/new_user_identity.php @@ -19,10 +19,6 @@ * // When automatically setting a new users's full name in their * // new identity, match the user's login name against this field. * $rcmail_config['new_user_identity_match'] = 'uid'; - * - * // Use the value in this field to automatically set a new users's - * // full name in their new identity. - * $rcmail_config['new_user_identity_field'] = 'name'; */ class new_user_identity extends rcube_plugin { @@ -40,7 +36,7 @@ class new_user_identity extends rcube_plugin $ldap->prop['search_fields'] = array($match); $results = $ldap->search($match, $args['user'], TRUE); if (count($results->records) == 1) { - $args['user_name'] = $results->records[0][$rcmail->config->get('new_user_identity_field')]; + $args['user_name'] = $results->records[0]['name']; } } return $args; diff --git a/plugins/password/README b/plugins/password/README index 033af5f..c7e8203 100644 --- a/plugins/password/README +++ b/plugins/password/README @@ -31,6 +31,8 @@ 2.3. Poppassd/Courierpassd (poppassd) 2.4. LDAP (ldap) 2.5. DirectAdmin Control Panel + 2.6. cPanel + 2.7. XIMSS (Communigate) 3. Driver API @@ -156,8 +158,8 @@ 2.3. Poppassd/Courierpassd (poppassd) ------------------------------------- - You can specify which host to connect to via `password_pop_host` and - what port via `password_pop_port`. See config.inc.php file for more info. + You can specify which host to connect to via 'password_pop_host' and + what port via 'password_pop_port'. See config.inc.php file for more info. 2.4. LDAP (ldap) @@ -169,11 +171,25 @@ 2.5. DirectAdmin Control Panel ------------------------------------- - You can specify which host to connect to via `password_directadmin_host` - and what port via `password_direactadmin_port`. See config.inc.php file + You can specify which host to connect to via 'password_directadmin_host' + and what port via 'password_direactadmin_port'. See config.inc.php file for more info. + 2.6. cPanel + ----------- + + You can specify parameters for HTTP connection to cPanel's admin + interface. See config.inc.php file for more info. + + + 2.7. XIMSS (Communigate) + ------------------------------------- + + You can specify which host and port to connect to via 'password_ximss_host' + and 'password_ximss_port'. See config.inc.php file for more info. + + 3. Driver API ------------- diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist index 076cfd6..b9e3b91 100644 --- a/plugins/password/config.inc.php.dist +++ b/plugins/password/config.inc.php.dist @@ -3,12 +3,21 @@ // Password Plugin options // ----------------------- // A driver to use for password change. Default: "sql". +// Current possibilities: 'directadmin', 'ldap', 'poppassd', 'sasl', 'sql', 'vpopmaild', 'cpanel' $rcmail_config['password_driver'] = 'sql'; // Determine whether current password is required to change password. // Default: false. $rcmail_config['password_confirm_current'] = true; +// Require the new password to be a certain length. +// set to blank to allow passwords of any length +$rcmail_config['password_minimum_length'] = 0; + +// Require the new password to contain a letter and punctuation character +// Change to false to remove this check. +$rcmail_config['password_require_nonalpha'] = false; + // SQL Driver options // ------------------ @@ -134,9 +143,49 @@ $rcmail_config['password_ldap_force_replace'] = true; // DirectAdmin Driver options // -------------------------- // The host which changes the password -$rcmail_config['password_directadmin_host'] = 'localhost'; +// Use 'ssl://serverip' instead of 'tcp://serverip' when running DirectAdmin over SSL. +$rcmail_config['password_directadmin_host'] = 'tcp://localhost'; // TCP port used for DirectAdmin connections $rcmail_config['password_directadmin_port'] = 2222; + +// vpopmaild Driver options +// ----------------------- +// The host which changes the password +$rcmail_config['password_vpopmaild_host'] = 'localhost'; + +// TCP port used for vpopmaild connections +$rcmail_config['password_vpopmaild_port'] = 89; + + +// cPanel Driver options +// -------------------------- +// The cPanel Host name +$rcmail_config['password_cpanel_host'] = 'host.domain.com'; + +// The cPanel admin username +$rcmail_config['password_cpanel_username'] = 'username'; + +// The cPanel admin password +$rcmail_config['password_cpanel_password'] = 'password'; + +// The cPanel port to use +$rcmail_config['password_cpanel_port'] = 2082; + +// Using ssl for cPanel connections? +$rcmail_config['password_cpanel_ssl'] = true; + +// The cPanel theme in use +$rcmail_config['password_cpanel_theme'] = 'x'; + + +// XIMSS (Communigate server) Driver options +// ----------------------------------------- +// Host name of the Communigate server +$rcmail_config['password_ximss_host'] = 'mail.example.com'; + +// XIMSS port on Communigate server +$rcmail_config['password_ximss_port'] = 11024; + ?> diff --git a/plugins/password/drivers/cpanel.php b/plugins/password/drivers/cpanel.php new file mode 100644 index 0000000..82bfe74 --- /dev/null +++ b/plugins/password/drivers/cpanel.php @@ -0,0 +1,121 @@ + + */ + +class HTTP +{ + function HTTP($host, $username, $password, $port, $ssl, $theme) + { + $this->ssl = $ssl ? 'ssl://' : ''; + $this->username = $username; + $this->password = $password; + $this->theme = $theme; + $this->auth = base64_encode($username . ':' . $password); + $this->port = $port; + $this->host = $host; + $this->path = '/frontend/' . $theme . '/'; + } + + function getData($url, $data = '') + { + $url = $this->path . $url; + if(is_array($data)) + { + $url = $url . '?'; + foreach($data as $key=>$value) + { + $url .= urlencode($key) . '=' . urlencode($value) . '&'; + } + $url = substr($url, 0, -1); + } + $response = ''; + $fp = fsockopen($this->ssl . $this->host, $this->port); + if(!$fp) + { + return false; + } + $out = 'GET ' . $url . ' HTTP/1.0' . "\r\n"; + $out .= 'Authorization: Basic ' . $this->auth . "\r\n"; + $out .= 'Connection: Close' . "\r\n\r\n"; + fwrite($fp, $out); + while (!feof($fp)) + { + $response .= @fgets($fp); + } + fclose($fp); + return $response; + } +} + + +class emailAccount +{ + function emailAccount($host, $username, $password, $port, $ssl, $theme, $address) + { + $this->HTTP = new HTTP($host, $username, $password, $port, $ssl, $theme); + if(strpos($address, '@')) + { + list($this->email, $this->domain) = explode('@', $address); + } + else + { + list($this->email, $this->domain) = array($address, ''); + } + } + + /* + * Change email account password + * + * Returns true on success or false on failure. + * @param string $password email account password + * @return bool + */ + function setPassword($password) + { + $data['email'] = $this->email; + $data['domain'] = $this->domain; + $data['password'] = $password; + $response = $this->HTTP->getData('mail/dopasswdpop.html', $data); + if(strpos($response, 'success') && !strpos($response, 'failure')) + { + return true; + } + return false; + } +} + + +function password_save($curpas, $newpass) +{ + $rcmail = rcmail::get_instance(); + + // Create a cPanel email object + $cPanel = new emailAccount($rcmail->config->get('password_cpanel_host'), + $rcmail->config->get('password_cpanel_username'), + $rcmail->config->get('password_cpanel_password'), + $rcmail->config->get('password_cpanel_port'), + $rcmail->config->get('password_cpanel_ssl'), + $rcmail->config->get('password_cpanel_theme'), + $_SESSION['username'] ); + + if ($cPanel->setPassword($newpass)){ + return PASSWORD_SUCCESS; + } + else + { + return PASSWORD_ERROR; + } +} + +?> diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php index 9afaa65..1e737f2 100644 --- a/plugins/password/drivers/sql.php +++ b/plugins/password/drivers/sql.php @@ -5,7 +5,7 @@ * * Driver for passwords stored in SQL database * - * @version 1.2 + * @version 1.3 * @author Aleksander 'A.L.E.C' Machniak * */ @@ -81,7 +81,7 @@ function password_save($curpass, $passwd) $user_info = explode('@', $_SESSION['username']); if (count($user_info) >= 2) { $sql = str_replace('%l', $db->quote($user_info[0], 'text'), $sql); - $sql = str_replace('%d', $db->quote($user_info[0], 'text'), $sql); + $sql = str_replace('%d', $db->quote($user_info[1], 'text'), $sql); } $sql = str_replace('%u', $db->quote($_SESSION['username'],'text'), $sql); diff --git a/plugins/password/drivers/vpopmaild.php b/plugins/password/drivers/vpopmaild.php new file mode 100644 index 0000000..db57eaf --- /dev/null +++ b/plugins/password/drivers/vpopmaild.php @@ -0,0 +1,60 @@ +connect($rcmail->config->get('password_vpopmaild_host'), $rcmail->config->get('password_vpopmaild_port'), null))) { + return PASSWORD_CONNECT_ERROR; + } + else { + $result = $vpopmaild->readLine(); + if(!preg_match('/^\+OK/', $result)) { + $vpopmaild->disconnect(); + return PASSWORD_CONNECT_ERROR; + } + else { + $vpopmaild->writeLine("slogin ". $_SESSION['username'] . " " . $curpass); + $result = $vpopmaild->readLine(); + if(!preg_match('/^\+OK/', $result) ) { + $vpopmaild->writeLine("quit"); + $vpopmaild->disconnect(); + return PASSWORD_ERROR; + } + else { + $vpopmaild->writeLine("mod_user ". $_SESSION['username']); + $result = $vpopmaild->readLine(); + if(!preg_match('/^\+OK/', $result) ) { + $vpopmaild->writeLine("quit"); + $vpopmaild->disconnect(); + return PASSWORD_ERROR; + } + else { + $vpopmaild->writeLine("clear_text_password ". $passwd); + $vpopmaild->writeLine("."); + $result = $vpopmaild->readLine(); + $vpopmaild->writeLine("quit"); + $vpopmaild->disconnect(); + if (!preg_match('/^\+OK/', $result)) + return PASSWORD_ERROR; + else + return PASSWORD_SUCCESS; + } + } + } + } +} + +?> diff --git a/plugins/password/drivers/ximss.php b/plugins/password/drivers/ximss.php new file mode 100644 index 0000000..94aba18 --- /dev/null +++ b/plugins/password/drivers/ximss.php @@ -0,0 +1,81 @@ + + */ + +function password_save($pass, $newpass) +{ + + $rcmail = rcmail::get_instance(); + + $sock = stream_socket_client("tcp://".$rcmail->config->get('password_ximss_host').":".$rcmail->config->get('password_ximss_port'), $errno, $errstr, 30) ; + if( $sock === FALSE ) + { + return PASSWORD_CONNECT_ERROR; + } + + // send all requests at once(pipelined) + fwrite( $sock, ''."\0"); + fwrite( $sock, ''."\0"); + fwrite( $sock, ''."\0"); + + //example responses + // \0 + // \0 + // \0 + // \0 + // or an error: + // \0 + + $responseblob = ''; + while (!feof($sock)) { + $responseblob .= fgets($sock, 1024); + } + + fclose($sock); + + foreach( explode( "\0",$responseblob) as $response ) + { + $resp = simplexml_load_string("".$response.""); + + if( $resp->response[0]['id'] == 'A001' ) + { + if( isset( $resp->response[0]['errorNum'] ) ) + { + return PASSWORD_CONNECT_ERROR; + } + } + else if( $resp->response[0]['id'] == 'A002' ) + { + if( isset( $resp->response[0]['errorNum'] )) + { + return PASSWORD_ERROR; + } + } + else if( $resp->response[0]['id'] == 'A003' ) + { + if( isset($resp->response[0]['errorNum'] )) + { + //There was a problem during logout(This is probably harmless) + } + } + } //foreach + + return PASSWORD_SUCCESS; + +} + +?> \ No newline at end of file diff --git a/plugins/password/localization/bg_BG.inc b/plugins/password/localization/bg_BG.inc new file mode 100644 index 0000000..b4576a0 --- /dev/null +++ b/plugins/password/localization/bg_BG.inc @@ -0,0 +1,18 @@ + diff --git a/plugins/password/localization/cs_CZ.inc b/plugins/password/localization/cs_CZ.inc new file mode 100644 index 0000000..18270db --- /dev/null +++ b/plugins/password/localization/cs_CZ.inc @@ -0,0 +1,26 @@ + + * + */ + +$labels = array(); +$labels['changepasswd'] = 'Změna hesla'; +$labels['curpasswd'] = 'Aktuální heslo:'; +$labels['newpasswd'] = 'Nové heslo:'; +$labels['confpasswd'] = 'Nové heslo (pro kontrolu):'; + +$messages = array(); +$messages['nopassword'] = 'Prosím zadejte nové heslo.'; +$messages['nocurpassword'] = 'Prosím zadejte aktuální heslo.'; +$messages['passwordincorrect'] = 'Zadané aktuální heslo není správné.'; +$messages['passwordinconsistency'] = 'Zadaná hesla se neshodují. Prosím zkuste to znovu.'; +$messages['crypterror'] = 'Heslo se nepodařilo uložit. Chybí šifrovací funkce.'; +$messages['connecterror'] = 'Heslo se nepodařilo uložit. Problém s připojením.'; +$messages['internalerror'] = 'Heslo se nepodařilo uložit.'; + +?> diff --git a/plugins/password/localization/da_DK.inc b/plugins/password/localization/da_DK.inc new file mode 100644 index 0000000..5d1d0c9 --- /dev/null +++ b/plugins/password/localization/da_DK.inc @@ -0,0 +1,18 @@ + diff --git a/plugins/password/localization/en_US.inc b/plugins/password/localization/en_US.inc index 6c64cc0..75fe861 100644 --- a/plugins/password/localization/en_US.inc +++ b/plugins/password/localization/en_US.inc @@ -14,5 +14,7 @@ $messages['passwordinconsistency'] = 'Passwords do not match, please try again.' $messages['crypterror'] = 'Could not save new password. Encrypt function missing.'; $messages['connecterror'] = 'Could not save new password. Connection error.'; $messages['internalerror'] = 'Could not save new password.'; +$messages['passwordshort'] = 'Your password must be at least $length characters long.'; +$messages['passwordweak'] = 'Your new password must include at least one number and one punctuation character.'; ?> diff --git a/plugins/password/localization/pl_PL.inc b/plugins/password/localization/pl_PL.inc index 4520d79..774437a 100644 --- a/plugins/password/localization/pl_PL.inc +++ b/plugins/password/localization/pl_PL.inc @@ -14,5 +14,7 @@ $messages['passwordinconsistency'] = 'Hasła nie pasują, spróbuj ponownie.'; $messages['crypterror'] = 'Nie udało się zapisać nowego hasła. Brak funkcji kodującej.'; $messages['connecterror'] = 'Nie udało się zapisać nowego hasła. Błąd połączenia.'; $messages['internalerror'] = 'Nie udało się zapisać nowego hasła.'; +$messages['passwordshort'] = 'Hasło musi posiadać co najmniej $length znaków.'; +$messages['passwordweak'] = 'Hasło musi zawierać co najmniej jedną cyfrę i znak interpunkcyjny.'; ?> diff --git a/plugins/password/localization/pt_PT.inc b/plugins/password/localization/pt_PT.inc index 80ddf58..5307ad6 100644 --- a/plugins/password/localization/pt_PT.inc +++ b/plugins/password/localization/pt_PT.inc @@ -1,4 +1,4 @@ -output->set_pagetitle($this->gettext('changepasswd')); $confirm = $rcmail->config->get('password_confirm_current'); + $required_length = intval($rcmail->config->get('password_minimum_length')); + $check_strength = $rcmail->config->get('password_require_nonalpha'); if (($confirm && !isset($_POST['_curpasswd'])) || !isset($_POST['_newpasswd'])) { $rcmail->output->command('display_message', $this->gettext('nopassword'), 'error'); } else { + $curpwd = get_input_value('_curpasswd', RCUBE_INPUT_POST); $newpwd = get_input_value('_newpasswd', RCUBE_INPUT_POST); + $conpwd = get_input_value('_confpasswd', RCUBE_INPUT_POST); - if ($confirm && $rcmail->decrypt($_SESSION['password']) != $curpwd) + if ($conpwd != $newpwd) { + $rcmail->output->command('display_message', $this->gettext('passwordinconsistency'), 'error'); + } + else if ($confirm && $rcmail->decrypt($_SESSION['password']) != $curpwd) { $rcmail->output->command('display_message', $this->gettext('passwordincorrect'), 'error'); + } + else if ($required_length && strlen($newpwd) < $required_length) { + $rcmail->output->command('display_message', $this->gettext( + array('name' => 'passwordshort', 'vars' => array('length' => $required_length))), 'error'); + } + else if ($check_strength && (!preg_match("/[0-9]/", $newpwd) || !preg_match("/[^A-Za-z0-9]/", $newpwd))) { + $rcmail->output->command('display_message', $this->gettext('passwordweak'), 'error'); + } else if (!($res = $this->_save($curpwd,$newpwd))) { $rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation'); $_SESSION['password'] = $rcmail->encrypt($newpwd); - } else + } + else $rcmail->output->command('display_message', $res, 'error'); } @@ -142,9 +158,9 @@ class password extends rcube_plugin $table->add('title', html::label($field_id, Q($this->gettext('confpasswd')))); $table->add(null, $input_confpasswd->show()); - $out = html::div(array('class' => "settingsbox", 'style' => "margin:0"), - html::div(array('id' => "prefs-title"), $this->gettext('changepasswd')) . - html::div(array('style' => "padding:15px"), $table->show() . + $out = html::div(array('class' => 'settingsbox', 'style' => 'margin:0'), + html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd')) . + html::div(array('class' => 'boxcontent'), $table->show() . html::p(null, $rcmail->output->button(array( 'command' => 'plugin.password-save', diff --git a/plugins/subscriptions_option/localization/cs_CZ.inc b/plugins/subscriptions_option/localization/cs_CZ.inc new file mode 100644 index 0000000..ca637fc --- /dev/null +++ b/plugins/subscriptions_option/localization/cs_CZ.inc @@ -0,0 +1,23 @@ + | ++-----------------------------------------------------------------------+ + +@version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ + +*/ + +$labels = array(); +$labels['useimapsubscriptions'] = 'Používat odebírání IMAP složek'; + +?> diff --git a/plugins/subscriptions_option/localization/de_CH.inc b/plugins/subscriptions_option/localization/de_CH.inc new file mode 100644 index 0000000..b4affe0 --- /dev/null +++ b/plugins/subscriptions_option/localization/de_CH.inc @@ -0,0 +1,6 @@ + diff --git a/plugins/subscriptions_option/localization/de_DE.inc b/plugins/subscriptions_option/localization/de_DE.inc new file mode 100644 index 0000000..b4affe0 --- /dev/null +++ b/plugins/subscriptions_option/localization/de_DE.inc @@ -0,0 +1,6 @@ + diff --git a/plugins/subscriptions_option/localization/ru_RU.inc b/plugins/subscriptions_option/localization/ru_RU.inc new file mode 100644 index 0000000..5deb84e --- /dev/null +++ b/plugins/subscriptions_option/localization/ru_RU.inc @@ -0,0 +1,6 @@ + diff --git a/plugins/subscriptions_option/subscriptions_option.php b/plugins/subscriptions_option/subscriptions_option.php index 09ee6e3..ecbc4e2 100644 --- a/plugins/subscriptions_option/subscriptions_option.php +++ b/plugins/subscriptions_option/subscriptions_option.php @@ -46,9 +46,9 @@ class subscriptions_option extends rcube_plugin $checkbox = new html_checkbox(array('name' => '_use_subscriptions', 'id' => $field_id, 'value' => 1)); $args['blocks']['main']['options']['use_subscriptions'] = array( - 'title' => html::label($field_id, Q($this->gettext('useimapsubscriptions'))), + 'title' => html::label($field_id, Q($this->gettext('useimapsubscriptions'))), 'content' => $checkbox->show($use_subscriptions?1:0), - ); + ); } return $args; @@ -57,18 +57,18 @@ class subscriptions_option extends rcube_plugin function save_prefs($args) { if ($args['section'] == 'server') { - $rcmail = rcmail::get_instance(); + $rcmail = rcmail::get_instance(); $use_subscriptions = $rcmail->config->get('use_subscriptions'); - $args['prefs']['use_subscriptions'] = isset($_POST['_use_subscriptions']) ? true : false; + $args['prefs']['use_subscriptions'] = isset($_POST['_use_subscriptions']) ? true : false; - // if the use_subscriptions preference changes, flush the folder cache - if (($use_subscriptions && !isset($_POST['_use_subscriptions'])) || - (!$use_subscriptions && isset($_POST['_use_subscriptions']))) { - $rcmail->imap_init(true); - $rcmail->imap->clear_cache('mailboxes'); - } - } + // if the use_subscriptions preference changes, flush the folder cache + if (($use_subscriptions && !isset($_POST['_use_subscriptions'])) || + (!$use_subscriptions && isset($_POST['_use_subscriptions']))) { + $rcmail->imap_init(true); + $rcmail->imap->clear_cache('mailboxes'); + } + } return $args; } diff --git a/plugins/userinfo/localization/cs_CZ.inc b/plugins/userinfo/localization/cs_CZ.inc new file mode 100644 index 0000000..812ca7b --- /dev/null +++ b/plugins/userinfo/localization/cs_CZ.inc @@ -0,0 +1,27 @@ + | ++-----------------------------------------------------------------------+ + +@version $Id: labels.inc 2993 2009-09-26 18:32:07Z alec $ + +*/ + +$labels = array(); +$labels['infosfor'] = 'Informace pro'; +$labels['userinfo'] = 'Uživatel'; +$labels['created'] = 'Vytvořen'; +$labels['lastlogin'] = 'Naspoledy přihlášen'; +$labels['defaultidentity'] = 'Výchozí identita'; + +?> \ No newline at end of file diff --git a/plugins/userinfo/localization/pt_PT.inc b/plugins/userinfo/localization/pt_PT.inc index e36d678..45009f9 100644 --- a/plugins/userinfo/localization/pt_PT.inc +++ b/plugins/userinfo/localization/pt_PT.inc @@ -1,4 +1,4 @@ - \ No newline at end of file diff --git a/plugins/vcard_attachments/localization/de_DE.inc b/plugins/vcard_attachments/localization/de_DE.inc new file mode 100644 index 0000000..dcc8ce7 --- /dev/null +++ b/plugins/vcard_attachments/localization/de_DE.inc @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/plugins/vcard_attachments/localization/en_US.inc b/plugins/vcard_attachments/localization/en_US.inc new file mode 100644 index 0000000..59a36e9 --- /dev/null +++ b/plugins/vcard_attachments/localization/en_US.inc @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/plugins/vcard_attachments/localization/ru_RU.inc b/plugins/vcard_attachments/localization/ru_RU.inc new file mode 100644 index 0000000..e127b58 --- /dev/null +++ b/plugins/vcard_attachments/localization/ru_RU.inc @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/plugins/vcard_attachments/vcard_attachments.php b/plugins/vcard_attachments/vcard_attachments.php index 532311e..d23cf37 100644 --- a/plugins/vcard_attachments/vcard_attachments.php +++ b/plugins/vcard_attachments/vcard_attachments.php @@ -35,6 +35,9 @@ class vcard_attachments extends rcube_plugin if (in_array($attachment->mimetype, array('text/vcard', 'text/x-vcard'))) $this->vcard_part = $attachment->mime_id; } + + if ($this->vcard_part) + $this->add_texts('localization'); } /** @@ -57,7 +60,7 @@ class vcard_attachments extends rcube_plugin html::a(array( 'href' => "#", 'onclick' => "return plugin_vcard_save_contact('".JQ($this->vcard_part)."')", - 'title' => "Save contact in local address book"), // TODO: localize this title + 'title' => $this->gettext('addvardmsg')), html::img(array('src' => $this->url('vcard_add_contact.png'), 'align' => "middle"))) . ' ' . html::span(null, Q($display))); @@ -73,6 +76,8 @@ class vcard_attachments extends rcube_plugin */ function save_vcard() { + $this->add_texts('localization', true); + $uid = get_input_value('_uid', RCUBE_INPUT_POST); $mbox = get_input_value('_mbox', RCUBE_INPUT_POST); $mime_id = get_input_value('_part', RCUBE_INPUT_POST); @@ -80,7 +85,7 @@ class vcard_attachments extends rcube_plugin $rcmail = rcmail::get_instance(); $part = $uid && $mime_id ? $rcmail->imap->get_message_part($uid, $mime_id) : null; - $error_msg = 'Failed to saved vcard'; // TODO: localize this text + $error_msg = $this->gettext('vcardsavefailed'); if ($part && ($vcard = new rcube_vcard($part)) && $vcard->displayname && $vcard->email) { $contacts = $rcmail->get_address_book(null, true); @@ -111,5 +116,4 @@ class vcard_attachments extends rcube_plugin $rcmail->output->send(); } - -} \ No newline at end of file +} diff --git a/program/include/iniset.php b/program/include/iniset.php index 5d83686..df2f3f3 100755 --- a/program/include/iniset.php +++ b/program/include/iniset.php @@ -16,13 +16,13 @@ | Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: iniset.php 2916 2009-09-04 10:58:29Z thomasb $ + $Id: iniset.php 3081 2009-10-31 13:20:02Z thomasb $ */ // application constants -define('RCMAIL_VERSION', '0.3-stable'); +define('RCMAIL_VERSION', '0.3.1'); define('RCMAIL_CHARSET', 'UTF-8'); define('JS_OBJECT_NAME', 'rcmail'); @@ -59,15 +59,10 @@ if (isset($_SERVER['HTTPS'])) { ini_set('session.name', 'roundcube_sessid'); ini_set('session.use_cookies', 1); ini_set('session.use_only_cookies', 1); -if (function_exists('set_magic_quotes_runtime')) { - set_magic_quotes_runtime(0); -} // increase maximum execution time for php scripts // (does not work in safe mode) -if (!ini_get('safe_mode')) { - set_time_limit(120); -} +@set_time_limit(120); // set internal encoding for mbstring extension if(extension_loaded('mbstring')) diff --git a/program/include/main.inc b/program/include/main.inc index f25f4cb..423b46e 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: main.inc 2852 2009-08-10 21:32:44Z thomasb $ + $Id: main.inc 3063 2009-10-27 09:43:39Z alec $ */ @@ -942,7 +942,7 @@ function format_date($date, $format=NULL) /** - * Compose a valid representaion of name and e-mail address + * Compose a valid representation of name and e-mail address * * @param string E-mail address * @param string Person name @@ -953,10 +953,10 @@ function format_email_recipient($email, $name='') if ($name && $name != $email) { // Special chars as defined by RFC 822 need to in quoted string (or escaped). - return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, $email); + return sprintf('%s <%s>', preg_match('/[\(\)\<\>\\\.\[\]@,;:"]/', $name) ? '"'.addcslashes($name, '"').'"' : $name, trim($email)); } else - return $email; + return trim($email); } @@ -1022,7 +1022,7 @@ function write_log($name, $line) $line = $log['line']; $date = $log['date']; if ($log['abort']) - return; + return true; } $log_entry = sprintf("[%s]: %s\n", $date, $line); @@ -1038,12 +1038,15 @@ function write_log($name, $line) $CONFIG['log_dir'] = INSTALL_PATH.'logs'; // try to open specific log file for writing - if ($fp = @fopen($CONFIG['log_dir'].'/'.$name, 'a')) { + $logfile = $CONFIG['log_dir'].'/'.$name; + if ($fp = @fopen($logfile, 'a')) { fwrite($fp, $log_entry); fflush($fp); fclose($fp); return true; } + else + trigger_error("Error writing to log file $logfile; Please check permissions", E_USER_WARNING); } return false; } @@ -1148,11 +1151,12 @@ function rcmail_mailbox_select($p = array()) { global $RCMAIL; - $p += array('maxlength' => 100, 'relanames' => false); + $p += array('maxlength' => 100, 'realnames' => false); $a_mailboxes = array(); foreach ($RCMAIL->imap->list_mailboxes() as $folder) - rcmail_build_folder_tree($a_mailboxes, $folder, $RCMAIL->imap->get_hierarchy_delimiter()); + if (empty($p['exceptions']) || !in_array($folder, $p['exceptions'])) + rcmail_build_folder_tree($a_mailboxes, $folder, $RCMAIL->imap->get_hierarchy_delimiter()); $select = new html_select($p); @@ -1374,18 +1378,96 @@ function rcmail_localize_foldername($name) */ function rcube_html_editor($mode='') { - global $OUTPUT, $CONFIG; + global $RCMAIL, $CONFIG; + + $hook = $RCMAIL->plugins->exec_hook('hmtl_editor', array('mode' => $mode)); + + if ($hook['abort']) + return; - $lang = $tinylang = strtolower(substr($_SESSION['language'], 0, 2)); - if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$tinylang.'.js')) - $tinylang = 'en'; + $lang = strtolower(substr($_SESSION['language'], 0, 2)); + if (!file_exists(INSTALL_PATH . 'program/js/tiny_mce/langs/'.$lang.'.js')) + $lang = 'en'; - $OUTPUT->include_script('tiny_mce/tiny_mce.js'); - $OUTPUT->include_script('editor.js'); - $OUTPUT->add_script('rcmail_editor_init("$__skin_path", "'.JQ($tinylang).'", '.intval($CONFIG['enable_spellcheck']).', "'.$mode.'");'); + $RCMAIL->output->include_script('tiny_mce/tiny_mce.js'); + $RCMAIL->output->include_script('editor.js'); + $RCMAIL->output->add_script('rcmail_editor_init("$__skin_path", + "'.JQ($lang).'", '.intval($CONFIG['enable_spellcheck']).', "'.$mode.'");'); +} + + +/** + * Check if working in SSL mode + * + * @param integer HTTPS port number + * @param boolean Enables 'use_https' option checking + */ +function rcube_https_check($port=null, $use_https=true) +{ + global $RCMAIL; + + if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off') + return true; + if ($port && $_SERVER['SERVER_PORT'] == $port) + return true; + if ($use_https && $RCMAIL->config->get('use_https')) + return true; + + return false; } +/** + * E-mail address validation + */ +function check_email($email) +{ + // Check for invalid characters + if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $email)) + return false; + + // Check that there's one @ symbol, and that the lengths are right + if (!preg_match('/^([^@]{1,64})@([^@]{1,255})$/', $email, $email_array)) + return false; + + // Check local part + $local_array = explode('.', $email_array[1]); + foreach ($local_array as $local_part) + if (!preg_match('/^(([A-Za-z0-9!#$%&\'*+\/=?^_`{|}~-]+)|("[^"]+"))$/', $local_part)) + return false; + + // Check domain part + if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/', $email_array[2]) + || preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/', $email_array[2])) + return true; // If an IP address + else { + // If not an IP address + $domain_array = explode('.', $email_array[2]); + if (sizeof($domain_array) < 2) + return false; // Not enough parts to be a valid domain + + foreach ($domain_array as $domain_part) + if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]))$/', $domain_part)) + return false; + + if (!rcmail::get_instance()->config->get('email_dns_check')) + return true; + + if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN' && version_compare(PHP_VERSION, '5.3.0', '<')) + return true; + + // find MX record(s) + if (getmxrr($email_array[2], $mx_records)) + return true; + + // find any DNS record + if (checkdnsrr($email_array[2], 'ANY')) + return true; + } + + return false; +} + /** * Helper class to turn relative urls into absolute ones diff --git a/program/include/rcmail.php b/program/include/rcmail.php index 4624ee1..763c708 100644 --- a/program/include/rcmail.php +++ b/program/include/rcmail.php @@ -266,7 +266,7 @@ class rcmail $contacts = $plugin['instance']; } else if ($id && $ldap_config[$id]) { - $contacts = new rcube_ldap($ldap_config[$id]); + $contacts = new rcube_ldap($ldap_config[$id], $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host'])); } else if ($id === '0') { $contacts = new rcube_contacts($this->db, $this->user->ID); @@ -275,7 +275,7 @@ class rcmail // Use the first writable LDAP address book. foreach ($ldap_config as $id => $prop) { if (!$writeable || $prop['writable']) { - $contacts = new rcube_ldap($prop); + $contacts = new rcube_ldap($prop, $this->config->get('ldap_debug'), $this->config->mail_domain($_SESSION['imap_host'])); break; } } @@ -366,6 +366,7 @@ class rcmail $this->imap = new rcube_imap($this->db); $this->imap->debug_level = $this->config->get('debug_level'); $this->imap->skip_deleted = $this->config->get('skip_deleted'); + $this->imap->index_sort = $this->config->get('index_sort', true); // enable caching of imap data if ($this->config->get('enable_caching')) { @@ -378,7 +379,7 @@ class rcmail // Setting root and delimiter before iil_Connect can save time detecting them // using NAMESPACE and LIST $options = array( - 'imap' => $this->config->get('imap_auth_type', 'check'), + 'auth_method' => $this->config->get('imap_auth_type', 'check'), 'delimiter' => isset($_SESSION['imap_delimiter']) ? $_SESSION['imap_delimiter'] : $this->config->get('imap_delimiter'), 'rootdir' => isset($_SESSION['imap_root']) ? $_SESSION['imap_root'] : $this->config->get('imap_root'), 'debug_mode' => (bool) $this->config->get('imap_debug', 0), @@ -761,7 +762,7 @@ class rcmail continue; if ($label = $rcube_languages[$name]) - $sa_languages[$name] = $label ? $label : $name; + $sa_languages[$name] = $label; } closedir($dh); } @@ -879,7 +880,7 @@ class rcmail $key = $this->task; if (!$_SESSION['request_tokens'][$key]) - $_SESSION['request_tokens'][$key] = md5(uniqid($key . rand(), true)); + $_SESSION['request_tokens'][$key] = md5(uniqid($key . mt_rand(), true)); return $_SESSION['request_tokens'][$key]; } diff --git a/program/include/rcube_browser.php b/program/include/rcube_browser.php index 4010dbc..9f37aaa 100644 --- a/program/include/rcube_browser.php +++ b/program/include/rcube_browser.php @@ -43,24 +43,21 @@ class rcube_browser $this->ns = ($this->ns4 || stristr($HTTP_USER_AGENT, 'netscape')); $this->ie = stristr($HTTP_USER_AGENT, 'compatible; msie') && !$this->opera; $this->mz = stristr($HTTP_USER_AGENT, 'mozilla/5'); + $this->chrome = stristr($HTTP_USER_AGENT, 'chrome'); $this->khtml = stristr($HTTP_USER_AGENT, 'khtml'); $this->safari = ($this->khtml || stristr($HTTP_USER_AGENT, 'safari')); - if ($this->ns) { - $test = preg_match('/mozilla\/([0-9.]+)/i', $HTTP_USER_AGENT, $regs); - $this->ver = $test ? (float)$regs[1] : 0; + if ($this->ns || $this->chrome) { + $test = preg_match('/(mozilla|chrome)\/([0-9.]+)/i', $HTTP_USER_AGENT, $regs); + $this->ver = $test ? (float)$regs[2] : 0; } - if ($this->mz) { + else if ($this->mz) { $test = preg_match('/rv:([0-9.]+)/', $HTTP_USER_AGENT, $regs); $this->ver = $test ? (float)$regs[1] : 0; } - if($this->ie) { - $test = preg_match('/msie ([0-9.]+)/i', $HTTP_USER_AGENT, $regs); - $this->ver = $test ? (float)$regs[1] : 0; - } - if ($this->opera) { - $test = preg_match('/opera ([0-9.]+)/i', $HTTP_USER_AGENT, $regs); - $this->ver = $test ? (float)$regs[1] : 0; + else if ($this->ie || $this->opera) { + $test = preg_match('/(msie|opera) ([0-9.]+)/i', $HTTP_USER_AGENT, $regs); + $this->ver = $test ? (float)$regs[2] : 0; } if (preg_match('/ ([a-z]{2})-([a-z]{2})/i', $HTTP_USER_AGENT, $regs)) diff --git a/program/include/rcube_imap.php b/program/include/rcube_imap.php index bc6d40a..2a64c5d 100644 --- a/program/include/rcube_imap.php +++ b/program/include/rcube_imap.php @@ -16,7 +16,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: rcube_imap.php 2884 2009-08-28 08:31:41Z alec $ + $Id: rcube_imap.php 3048 2009-10-19 07:47:10Z alec $ */ @@ -50,6 +50,7 @@ class rcube_imap var $page_size = 10; var $sort_field = 'date'; var $sort_order = 'DESC'; + var $index_sort = true; var $delimiter = NULL; var $caching_enabled = FALSE; var $default_charset = 'ISO-8859-1'; @@ -69,7 +70,7 @@ class rcube_imap var $search_sort_field = ''; var $debug_level = 1; var $error_code = 0; - var $options = array('imap' => 'check'); + var $options = array('auth_method' => 'check'); private $host, $user, $pass, $port, $ssl; @@ -111,7 +112,7 @@ class rcube_imap $ICL_PORT = $port; $IMAP_USE_INTERNAL_DATE = false; - + $attempt = 0; do { $data = rcmail::get_instance()->plugins->exec_hook('imap_connect', array('host' => $host, 'user' => $user, 'attempt' => ++$attempt)); @@ -143,13 +144,13 @@ class rcube_imap // get server properties if ($this->conn) { - if (!empty($this->conn->delimiter)) - $this->delimiter = $this->conn->delimiter; if (!empty($this->conn->rootdir)) { $this->set_rootdir($this->conn->rootdir); $this->root_ns = preg_replace('/[.\/]$/', '', $this->conn->rootdir); } + if (empty($this->delimiter)) + $this->get_hierarchy_delimiter(); } return $this->conn ? TRUE : FALSE; @@ -484,7 +485,6 @@ class rcube_imap */ private function _messagecount($mailbox='', $mode='ALL', $force=FALSE) { - $a_mailbox_cache = FALSE; $mode = strtoupper($mode); if (empty($mailbox)) @@ -598,7 +598,31 @@ class rcube_imap // retrieve headers from IMAP $a_msg_headers = array(); - if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) + // use message index sort for sorting by Date (for better performance) + if ($this->index_sort && $this->sort_field == 'date') + { + if ($this->skip_deleted) { + // @TODO: this could be cached + if ($msg_index = $this->_search_index($mailbox, 'ALL UNDELETED')) { + $max = max($msg_index); + list($begin, $end) = $this->_get_message_range(count($msg_index), $page); + $msg_index = array_slice($msg_index, $begin, $end-$begin); + } + } else if ($max = iil_C_CountMessages($this->conn, $mailbox)) { + list($begin, $end) = $this->_get_message_range($max, $page); + $msg_index = range($begin+1, $end); + } else + $msg_index = array(); + + if ($slice) + $msg_index = array_slice($msg_index, ($this->sort_order == 'DESC' ? 0 : -$slice), $slice); + + // fetch reqested headers from server + if ($msg_index) + $this->_fetch_headers($mailbox, join(",", $msg_index), $a_msg_headers, $cache_key); + } + // use SORT command + else if ($this->get_capability('sort') && ($msg_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) { list($begin, $end) = $this->_get_message_range(count($msg_index), $page); $max = max($msg_index); @@ -610,13 +634,9 @@ class rcube_imap // fetch reqested headers from server $this->_fetch_headers($mailbox, join(',', $msg_index), $a_msg_headers, $cache_key); } - else + // fetch specified header for all messages and sort + else if ($a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:*", $this->sort_field, $this->skip_deleted)) { - $a_index = iil_C_FetchHeaderIndex($this->conn, $mailbox, "1:*", $this->sort_field, $this->skip_deleted); - - if (empty($a_index)) - return array(); - asort($a_index); // ASC $msg_index = array_keys($a_index); $max = max($msg_index); @@ -677,14 +697,34 @@ class rcube_imap $this->_set_sort_order($sort_field, $sort_order); + // quickest method + if ($this->index_sort && $this->search_sort_field == 'date' && $this->sort_field == 'date') + { + if ($sort_order == 'DESC') + $msgs = array_reverse($msgs); + + // get messages uids for one page + $msgs = array_slice(array_values($msgs), $start_msg, min(count($msgs)-$start_msg, $this->page_size)); + + if ($slice) + $msgs = array_slice($msgs, -$slice, $slice); + + // fetch headers + $this->_fetch_headers($mailbox, join(',',$msgs), $a_msg_headers, NULL); + + // I didn't found in RFC that FETCH always returns messages sorted by index + $sorter = new rcube_header_sorter(); + $sorter->set_sequence_numbers($msgs); + $sorter->sort_headers($a_msg_headers); + + return array_values($a_msg_headers); + } // sorted messages, so we can first slice array and then fetch only wanted headers - if ($this->get_capability('sort')) // SORT searching result + if ($this->get_capability('sort') && (!$this->index_sort || $this->sort_field != 'date')) // SORT searching result { // reset search set if sorting field has been changed if ($this->sort_field && $this->search_sort_field != $this->sort_field) - { $msgs = $this->search('', $this->search_string, $this->search_charset, $this->sort_field); - } // return empty array if no messages found if (empty($msgs)) @@ -710,7 +750,8 @@ class rcube_imap } else { // SEARCH searching result, need sorting $cnt = count($msgs); - if ($cnt > 300 && $cnt > $this->page_size) { // experimantal value for best result + // 300: experimantal value for best result + if (($cnt > 300 && $cnt > $this->page_size) || ($this->index_sort && $this->sort_field == 'date')) { // use memory less expensive (and quick) method for big result set $a_index = $this->message_index('', $this->sort_field, $this->sort_order); // get messages uids for one page... @@ -808,23 +849,18 @@ class rcube_imap { // cache is incomplete $cache_index = $this->get_message_cache_index($cache_key); - - foreach ($a_header_index as $i => $headers) - { -/* - if ($headers->deleted && $this->skip_deleted) - { - // delete from cache - if ($cache_index[$headers->id] && $cache_index[$headers->id] == $headers->uid) - $this->remove_message_cache($cache_key, $headers->uid); - continue; - } -*/ - // add message to cache - if ($this->caching_enabled && $cache_index[$headers->id] != $headers->uid) - $this->add_message_cache($cache_key, $headers->id, $headers, NULL, - !in_array((string)$headers->uid, $cache_index, true)); + foreach ($a_header_index as $i => $headers) { + if ($this->caching_enabled && $cache_index[$headers->id] != $headers->uid) { + // prevent index duplicates + if ($cache_index[$headers->id]) { + $this->remove_message_cache($cache_key, $headers->id, true); + unset($cache_index[$headers->id]); + } + // add message to cache + $this->add_message_cache($cache_key, $headers->id, $headers, NULL, + !in_array($headers->uid, $cache_index)); + } $a_msg_headers[$headers->uid] = $headers; } @@ -849,12 +885,26 @@ class rcube_imap $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; $key = "{$mailbox}:{$this->sort_field}:{$this->sort_order}:{$this->search_string}.msgi"; - // we have a saved search result. get index from there + // we have a saved search result, get index from there if (!isset($this->cache[$key]) && $this->search_string && $mailbox == $this->mailbox) { $this->cache[$key] = array(); - if ($this->get_capability('sort')) + // use message index sort for sorting by Date + if ($this->index_sort && $this->sort_field == 'date') + { + $msgs = $this->search_set; + + if ($this->search_sort_field != 'date') + sort($msgs); + + if ($this->sort_order == 'DESC') + $this->cache[$key] = array_reverse($msgs); + else + $this->cache[$key] = $msgs; + } + // sort with SORT command + else if ($this->get_capability('sort')) { if ($this->sort_field && $this->search_sort_field != $this->sort_field) $this->search('', $this->search_string, $this->search_charset, $this->sort_field); @@ -892,8 +942,22 @@ class rcube_imap return array_keys($a_index); } + // use message index sort for sorting by Date + if ($this->index_sort && $this->sort_field == 'date') + { + if ($this->skip_deleted) { + $a_index = $this->_search_index($mailbox, 'ALL'); + } else if ($max = $this->_messagecount($mailbox)) { + $a_index = range(1, $max); + } + + if ($this->sort_order == 'DESC') + $a_index = array_reverse($a_index); + + $this->cache[$key] = $a_index; + } // fetch complete message index - if ($this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) + else if ($this->get_capability('sort') && ($a_index = iil_C_Sort($this->conn, $mailbox, $this->sort_field, $this->skip_deleted ? 'UNDELETED' : ''))) { if ($this->sort_order == 'DESC') $a_index = array_reverse($a_index); @@ -967,7 +1031,7 @@ class rcube_imap if ($headers = iil_C_FetchHeader($this->conn, $mailbox, join(',', $for_update), false, $this->fetch_add_headers)) foreach ($headers as $header) $this->add_message_cache($cache_key, $header->id, $header, NULL, - in_array((string)$header->uid, (array)$for_remove, true)); + in_array($header->uid, (array)$for_remove)); } } @@ -1037,14 +1101,23 @@ class rcube_imap if ($this->skip_deleted && !preg_match('/UNDELETED/', $criteria)) $criteria = 'UNDELETED '.$criteria; - if ($sort_field && $this->get_capability('sort')) - { + if ($sort_field && $this->get_capability('sort') && (!$this->index_sort || $sort_field != 'date')) { $charset = $charset ? $charset : $this->default_charset; $a_messages = iil_C_Sort($this->conn, $mailbox, $sort_field, $criteria, FALSE, $charset); } - else - $a_messages = iil_C_Search($this->conn, $mailbox, ($charset ? "CHARSET $charset " : '') . $criteria); + else { + if ($orig_criteria == 'ALL') { + $max = $this->_messagecount($mailbox); + $a_messages = $max ? range(1, $max) : array(); + } + else { + $a_messages = iil_C_Search($this->conn, $mailbox, ($charset ? "CHARSET $charset " : '') . $criteria); + // I didn't found that SEARCH always returns sorted IDs + if ($this->index_sort && $this->sort_field == 'date') + sort($a_messages); + } + } // update messagecount cache ? // $a_mailbox_cache = get_cache('messagecount'); // $a_mailbox_cache[$mailbox][$criteria] = sizeof($a_messages); @@ -1150,6 +1223,16 @@ class rcube_imap else $this->struct_charset = $this->_structure_charset($structure); + // Here we can recognize malformed BODYSTRUCTURE and + // 1. [@TODO] parse the message in other way to create our own message structure + // 2. or just show the raw message body. + // Example of structure for malformed MIME message: + // ("text" "plain" ("charset" "us-ascii") NIL NIL "7bit" 2154 70 NIL NIL NIL) + if ($headers->ctype && $headers->ctype != 'text/plain' + && $structure[0] == 'text' && $structure[1] == 'plain') { + return false; + } + $struct = &$this->_structure_part($structure); $struct->headers = get_object_vars($headers); @@ -1467,7 +1550,7 @@ class rcube_imap // convert charset (if text or message part) if ($o_part->ctype_primary=='text' || $o_part->ctype_primary=='message') { // assume default if no charset specified - if (empty($o_part->charset)) + if (empty($o_part->charset) || strtolower($o_part->charset) == 'us-ascii') $o_part->charset = $this->default_charset; $body = rcube_charset_convert($body, $o_part->charset); @@ -1533,9 +1616,10 @@ class rcube_imap * @param mixed Message UIDs as array or as comma-separated string * @param string Flag to set: SEEN, UNDELETED, DELETED, RECENT, ANSWERED, DRAFT, MDNSENT * @param string Folder name + * @param boolean True to skip message cache clean up * @return boolean True on success, False on failure */ - function set_flag($uids, $flag, $mbox_name=NULL) + function set_flag($uids, $flag, $mbox_name=NULL, $skip_cache=false) { $mailbox = $mbox_name ? $this->mod_mailbox($mbox_name) : $this->mailbox; @@ -1549,14 +1633,9 @@ class rcube_imap $result = iil_C_Flag($this->conn, $mailbox, join(',', $uids), $flag); // reload message headers if cached - if ($this->caching_enabled) - { + if ($this->caching_enabled && !$skip_cache) { $cache_key = $mailbox.'.msg'; $this->remove_message_cache($cache_key, $uids); - - // close and re-open connection - // this prevents connection problems with Courier - $this->reconnect(); } // set nr of messages that were flaged @@ -1624,6 +1703,8 @@ class rcube_imap */ function move_message($uids, $to_mbox, $from_mbox='') { + $fbox = $from_mbox; + $tbox = $to_mbox; $to_mbox = $this->mod_mailbox($to_mbox); $from_mbox = $from_mbox ? $this->mod_mailbox($from_mbox) : $this->mailbox; @@ -1638,11 +1719,19 @@ class rcube_imap // convert the list of uids to array $a_uids = is_string($uids) ? explode(',', $uids) : (is_array($uids) ? $uids : NULL); - + // exit if no message uids are specified if (!is_array($a_uids) || empty($a_uids)) return false; + // flag messages as read before moving them + $config = rcmail::get_instance()->config; + if ($config->get('read_when_deleted') && $tbox == $config->get('trash_mbox')) { + // don't flush cache (4th argument) + $this->set_flag($uids, 'SEEN', $fbox, true); + } + + // move messages $iil_move = iil_C_Move($this->conn, join(',', $a_uids), $from_mbox, $to_mbox); $moved = !($iil_move === false || $iil_move < 0); @@ -1657,13 +1746,14 @@ class rcube_imap else if (rcmail::get_instance()->config->get('delete_always', false)) { return iil_C_Delete($this->conn, $from_mbox, join(',', $a_uids)); } - + // remove message ids from search set if ($moved && $this->search_set && $from_mbox == $this->mailbox) { foreach ($a_uids as $uid) $a_mids[] = $this->_uid2id($uid, $from_mbox); $this->search_set = array_diff($this->search_set, $a_mids); } + // update cached message headers $cache_key = $from_mbox.'.msg'; if ($moved && $start_index = $this->get_message_cache_index_min($cache_key, $a_uids)) { @@ -1694,7 +1784,7 @@ class rcube_imap return false; $deleted = iil_C_Delete($this->conn, $mailbox, join(',', $a_uids)); - + // send expunge command in order to have the deleted message // really deleted from the mailbox if ($deleted) @@ -1710,7 +1800,7 @@ class rcube_imap $a_mids[] = $this->_uid2id($uid, $mailbox); $this->search_set = array_diff($this->search_set, $a_mids); } - + // remove deleted messages from cache $cache_key = $mailbox.'.msg'; if ($deleted && $start_index = $this->get_message_cache_index_min($cache_key, $a_uids)) { @@ -2057,8 +2147,8 @@ class rcube_imap */ function get_cache($key) { - // read cache - if (!isset($this->cache[$key]) && $this->caching_enabled) + // read cache (if it was not read before) + if (!count($this->cache) && $this->caching_enabled) { return $this->_read_cache_record($key); } @@ -2135,7 +2225,8 @@ class rcube_imap { $sql_key = preg_replace('/^IMAP\./', '', $sql_arr['cache_key']); $this->cache_keys[$sql_key] = $sql_arr['cache_id']; - $this->cache[$sql_key] = $sql_arr['data'] ? unserialize($sql_arr['data']) : FALSE; + if (!isset($this->cache[$sql_key])) + $this->cache[$sql_key] = $sql_arr['data'] ? unserialize($sql_arr['data']) : FALSE; } } @@ -2150,23 +2241,6 @@ class rcube_imap if (!$this->db) return FALSE; - // check if we already have a cache entry for this key - if (!isset($this->cache_keys[$key])) - { - $sql_result = $this->db->query( - "SELECT cache_id - FROM ".get_table_name('cache')." - WHERE user_id=? - AND cache_key=?", - $_SESSION['user_id'], - 'IMAP.'.$key); - - if ($sql_arr = $this->db->fetch_assoc($sql_result)) - $this->cache_keys[$key] = $sql_arr['cache_id']; - else - $this->cache_keys[$key] = FALSE; - } - // update existing cache record if ($this->cache_keys[$key]) { @@ -2189,6 +2263,18 @@ class rcube_imap $_SESSION['user_id'], 'IMAP.'.$key, $data); + + // get cache entry ID for this key + $sql_result = $this->db->query( + "SELECT cache_id + FROM ".get_table_name('cache')." + WHERE user_id=? + AND cache_key=?", + $_SESSION['user_id'], + 'IMAP.'.$key); + + if ($sql_arr = $this->db->fetch_assoc($sql_result)) + $this->cache_keys[$key] = $sql_arr['cache_id']; } } @@ -2203,6 +2289,8 @@ class rcube_imap AND cache_key=?", $_SESSION['user_id'], 'IMAP.'.$key); + + unset($this->cache_keys[$key]); } @@ -2217,18 +2305,26 @@ class rcube_imap * * @param string Mailbox name * @param string Internal cache key - * @return int -3 = off, -2 = incomplete, -1 = dirty + * @return int Cache status: -3 = off, -2 = incomplete, -1 = dirty */ private function check_cache_status($mailbox, $cache_key) { if (!$this->caching_enabled) return -3; - $cache_index = $this->get_message_cache_index($cache_key, TRUE); + $cache_index = $this->get_message_cache_index($cache_key); $msg_count = $this->_messagecount($mailbox); $cache_count = count($cache_index); - // console("Cache check: $msg_count !== ".count($cache_index)); + // empty mailbox + if (!$msg_count) + return $cache_count ? -2 : 1; + + // @TODO: We've got one big performance problem in cache status checking method + // E.g. mailbox contains 1000 messages, in cache table we've got first 100 + // of them. Now if we want to display only that 100 (which we've got) + // check_cache_status returns 'incomplete' and messages are fetched + // from IMAP instead of DB. if ($cache_count==$msg_count) { if ($this->skip_deleted) { @@ -2244,12 +2340,12 @@ class rcube_imap } return -2; } else { - // get highest index - $header = iil_C_FetchHeader($this->conn, $mailbox, "$msg_count"); + // get UID of message with highest index + $uid = iil_C_ID2UID($this->conn, $mailbox, $msg_count); $cache_uid = array_pop($cache_index); // uids of highest message matches -> cache seems OK - if ($cache_uid == $header->uid) + if ($cache_uid == $uid) return 1; } // cache is dirty @@ -2270,8 +2366,13 @@ class rcube_imap $cache_key = "$key:$from:$to:$sort_field:$sort_order"; $db_header_fields = array('idx', 'uid', 'subject', 'from', 'to', 'cc', 'date', 'size'); - if (!in_array($sort_field, $db_header_fields)) + $config = rcmail::get_instance()->config; + + // use idx sort for sorting by Date with index_sort=true or for unknown field + if (($sort_field == 'date' && $this->index_sort) + || !in_array($sort_field, $db_header_fields)) { $sort_field = 'idx'; + } if ($this->caching_enabled && !isset($this->cache[$cache_key])) { @@ -2345,6 +2446,10 @@ class rcube_imap if (!empty($sa_message_index[$key]) && !$force) return $sa_message_index[$key]; + + // use idx sort for sorting by Date with index_sort=true + if ($sort_field == 'date' && $this->index_sort) + $sort_field = 'idx'; $sa_message_index[$key] = array(); $sql_result = $this->db->query( @@ -2385,8 +2490,7 @@ class rcube_imap FROM ".get_table_name('messages')." WHERE user_id=? AND cache_key=? - AND uid=? - AND del<>1", + AND uid=?", $_SESSION['user_id'], $key, $headers->uid); @@ -2431,16 +2535,16 @@ class rcube_imap /** * @access private */ - private function remove_message_cache($key, $uids) + private function remove_message_cache($key, $ids, $idx=false) { if (!$this->caching_enabled) return; $this->db->query( "DELETE FROM ".get_table_name('messages')." - WHERE user_id=? - AND cache_key=? - AND uid IN (".$this->db->array2list($uids, 'integer').")", + WHERE user_id=? + AND cache_key=? + AND ".($idx ? "idx" : "uid")." IN (".$this->db->array2list($ids, 'integer').")", $_SESSION['user_id'], $key); } @@ -2455,12 +2559,10 @@ class rcube_imap $this->db->query( "DELETE FROM ".get_table_name('messages')." - WHERE user_id=? - AND cache_key=? - AND idx>=?", - $_SESSION['user_id'], - $key, - $start_index); + WHERE user_id=? + AND cache_key=? + AND idx>=?", + $_SESSION['user_id'], $key, $start_index); } /** diff --git a/program/include/rcube_ldap.php b/program/include/rcube_ldap.php index e071ed0..a8e35a3 100644 --- a/program/include/rcube_ldap.php +++ b/program/include/rcube_ldap.php @@ -14,7 +14,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: rcube_ldap.php 2894 2009-08-29 20:56:00Z alec $ + $Id: rcube_ldap.php 2976 2009-09-21 11:50:53Z alec $ */ @@ -34,6 +34,8 @@ class rcube_ldap extends rcube_addressbook var $result = null; var $ldap_result = null; var $sort_col = ''; + var $mail_domain = ''; + var $debug = false; /** public properties */ var $primary_key = 'ID'; @@ -46,10 +48,12 @@ class rcube_ldap extends rcube_addressbook /** * Object constructor * - * @param array LDAP connection properties + * @param array LDAP connection properties + * @param boolean Enables debug mode + * @param string Current user mail domain name * @param integer User-ID */ - function __construct($p) + function __construct($p, $debug=false, $mail_domain=NULL) { $this->prop = $p; @@ -57,10 +61,16 @@ class rcube_ldap extends rcube_addressbook if (preg_match('/^(.+)_field$/', $prop, $matches)) $this->fieldmap[$matches[1]] = $this->_attr_name(strtolower($value)); + // make sure 'required_fields' is an array + if (!is_array($this->prop['required_fields'])) + $this->prop['required_fields'] = (array) $this->prop['required_fields']; + foreach ($this->prop['required_fields'] as $key => $val) $this->prop['required_fields'][$key] = $this->_attr_name(strtolower($val)); $this->sort_col = $p['sort']; + $this->debug = $debug; + $this->mail_domain = $mail_domain; $this->connect(); } @@ -87,17 +97,22 @@ class rcube_ldap extends rcube_addressbook foreach ($this->prop['hosts'] as $host) { + $this->_debug("C: Connect [$host".($this->prop['port'] ? ':'.$this->prop['port'] : '')."]"); + if ($lc = @ldap_connect($host, $this->prop['port'])) { if ($this->prop['use_tls']===true) if (!ldap_start_tls($lc)) continue; + $this->_debug("S: OK"); + ldap_set_option($lc, LDAP_OPT_PROTOCOL_VERSION, $this->prop['ldap_version']); $this->prop['host'] = $host; $this->conn = $lc; break; } + $this->_debug("S: NOT OK"); } if (is_resource($this->conn)) @@ -148,10 +163,15 @@ class rcube_ldap extends rcube_addressbook return false; } + $this->_debug("C: Bind [dn: $dn] [pass: $pass]"); + if (@ldap_bind($this->conn, $dn, $pass)) { + $this->_debug("S: OK"); return true; } + $this->_debug("S: ".ldap_error($this->conn)); + raise_error(array( 'code' => ldap_errno($this->conn), 'type' => 'ldap', @@ -169,6 +189,7 @@ class rcube_ldap extends rcube_addressbook { if ($this->conn) { + $this->_debug("C: Close"); ldap_unbind($this->conn); $this->conn = null; } @@ -384,11 +405,17 @@ class rcube_ldap extends rcube_addressbook $res = null; if ($this->conn && $dn) { - $this->ldap_result = ldap_read($this->conn, base64_decode($dn), '(objectclass=*)', array_values($this->fieldmap)); - $entry = @ldap_first_entry($this->conn, $this->ldap_result); + $this->_debug("C: Read [dn: ".base64_decode($dn)."] [(objectclass=*)]"); + + if ($this->ldap_result = @ldap_read($this->conn, base64_decode($dn), '(objectclass=*)', array_values($this->fieldmap))) + $entry = ldap_first_entry($this->conn, $this->ldap_result); + else + $this->_debug("S: ".ldap_error($this->conn)); if ($entry && ($rec = ldap_get_attributes($this->conn, $entry))) { + $this->_debug("S: OK"); + $rec = array_change_key_case($rec, CASE_LOWER); // Add in the dn for the entry. @@ -433,11 +460,17 @@ class rcube_ldap extends rcube_addressbook // Build the new entries DN. $dn = $this->prop['LDAP_rdn'].'='.$newentry[$this->prop['LDAP_rdn']].','.$this->prop['base_dn']; + + $this->_debug("C: Add [dn: $dn]: ".print_r($newentry, true)); + $res = ldap_add($this->conn, $dn, $newentry); if ($res === FALSE) { + $this->_debug("S: ".ldap_error($this->conn)); return false; } // end if + $this->_debug("S: OK"); + return base64_encode($dn); } @@ -488,8 +521,12 @@ class rcube_ldap extends rcube_addressbook // Update the entry as required. if (!empty($deletedata)) { // Delete the fields. - if (!ldap_mod_del($this->conn, $dn, $deletedata)) + $this->_debug("C: Delete [dn: $dn]: ".print_r($deletedata, true)); + if (!ldap_mod_del($this->conn, $dn, $deletedata)) { + $this->_debug("S: ".ldap_error($this->conn)); return false; + } + $this->_debug("S: OK"); } // end if if (!empty($replacedata)) { @@ -503,21 +540,33 @@ class rcube_ldap extends rcube_addressbook } // Replace the fields. if (!empty($replacedata)) { - if (!ldap_mod_replace($this->conn, $dn, $replacedata)) + $this->_debug("C: Replace [dn: $dn]: ".print_r($replacedata, true)); + if (!ldap_mod_replace($this->conn, $dn, $replacedata)) { + $this->_debug("S: ".ldap_error($this->conn)); return false; + } + $this->_debug("S: OK"); } // end if } // end if if (!empty($newdata)) { // Add the fields. - if (!ldap_mod_add($this->conn, $dn, $newdata)) + $this->_debug("C: Add [dn: $dn]: ".print_r($newdata, true)); + if (!ldap_mod_add($this->conn, $dn, $newdata)) { + $this->_debug("S: ".ldap_error($this->conn)); return false; + } + $this->_debug("S: OK"); } // end if // Handle RDN change if (!empty($newrdn)) { - if (@ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) + $this->_debug("C: Rename [dn: $dn] [dn: $newrdn]"); + if (@ldap_rename($this->conn, $dn, $newrdn, NULL, TRUE)) { + $this->_debug("S: ".ldap_error($this->conn)); return base64_encode($newdn); + } + $this->_debug("S: OK"); } return true; @@ -539,14 +588,17 @@ class rcube_ldap extends rcube_addressbook foreach ($dns as $id) { $dn = base64_decode($id); + $this->_debug("C: Delete [dn: $dn]"); // Delete the record. $res = ldap_delete($this->conn, $dn); if ($res === FALSE) { + $this->_debug("S: ".ldap_error($this->conn)); return false; } // end if + $this->_debug("S: OK"); } // end foreach - return true; + return count($dns); } @@ -561,11 +613,17 @@ class rcube_ldap extends rcube_addressbook { $filter = $this->filter ? $this->filter : '(objectclass=*)'; $function = $this->prop['scope'] == 'sub' ? 'ldap_search' : ($this->prop['scope'] == 'base' ? 'ldap_read' : 'ldap_list'); - $this->ldap_result = $function($this->conn, $this->prop['base_dn'], $filter, array_values($this->fieldmap), 0, 0); - return true; + + $this->_debug("C: Search [".$filter."]"); + + if ($this->ldap_result = @$function($this->conn, $this->prop['base_dn'], $filter, array_values($this->fieldmap), 0, 0)) { + $this->_debug("S: ".ldap_count_entries($this->conn, $this->ldap_result)." record(s)"); + return true; + } else + $this->_debug("S: ".ldap_error($this->conn)); } - else - return false; + + return false; } @@ -584,8 +642,8 @@ class rcube_ldap extends rcube_addressbook foreach ($this->fieldmap as $rf => $lf) { if ($rec[$lf]['count']) { - if ($rf == 'email' && !strpos($rec[$lf][0], '@')) - $out[$rf] = sprintf('%s@%s', $rec[$lf][0] , $RCMAIL->config->mail_domain($_SESSION['imap_host'])); + if ($rf == 'email' && $mail_domain && !strpos($rec[$lf][0], '@')) + $out[$rf] = sprintf('%s@%s', $rec[$lf][0], $this->mail_domain); else $out[$rf] = $rec[$lf][0]; } @@ -621,6 +679,16 @@ class rcube_ldap extends rcube_addressbook } + /** + * @access private + */ + private function _debug($str) + { + if ($this->debug) + write_log('ldap', $str); + } + + /** * @static */ diff --git a/program/include/rcube_mdb2.php b/program/include/rcube_mdb2.php index 51f8be3..f8ed4bb 100644 --- a/program/include/rcube_mdb2.php +++ b/program/include/rcube_mdb2.php @@ -16,7 +16,7 @@ | Author: Lukas Kahwe Smith | +-----------------------------------------------------------------------+ - $Id: rcube_mdb2.php 2834 2009-08-04 08:22:41Z alec $ + $Id: rcube_mdb2.php 2920 2009-09-04 13:07:48Z alec $ */ @@ -256,11 +256,11 @@ class rcube_mdb2 $result = $this->db_handle->setLimit($numrows,$offset); if (empty($params)) - $result = $this->db_handle->query($query); + $result = $mode=='r' ? $this->db_handle->query($query) : $this->db_handle->exec($query); else { $params = (array)$params; - $q = $this->db_handle->prepare($query); + $q = $this->db_handle->prepare($query, null, $mode=='w' ? MDB2_PREPARE_MANIP : null); if ($this->db_handle->isError($q)) { $this->db_error = TRUE; diff --git a/program/include/rcube_message.php b/program/include/rcube_message.php index 7c2457e..1a22427 100644 --- a/program/include/rcube_message.php +++ b/program/include/rcube_message.php @@ -402,7 +402,7 @@ class rcube_message $this->inline_parts[] = $mail_part; } // is a regular attachment - else if (preg_match('!^[a-z]+/[a-z0-9-.]+$!i', $mail_part->mimetype)) { + else if (preg_match('!^[a-z]+/[a-z0-9-.+]+$!i', $mail_part->mimetype)) { if (!$mail_part->filename) $mail_part->filename = 'Part '.$mail_part->mime_id; $this->attachments[] = $mail_part; diff --git a/program/include/rcube_plugin.php b/program/include/rcube_plugin.php index 5e37764..ed30e8f 100644 --- a/program/include/rcube_plugin.php +++ b/program/include/rcube_plugin.php @@ -231,6 +231,20 @@ abstract class rcube_plugin else return $fn; } + + /** + * Provide path to the currently selected skin folder within the plugin directory + * with a fallback to the default skin folder. + * + * @return string Skin path relative to plugins directory + */ + protected function local_skin_path() + { + $skin_path = 'skins/'.$this->api->output->config['skin']; + if (!is_dir(realpath(slashify($this->home) . $skin_path))) + $skin_path = 'skins/default'; + return $skin_path; + } /** * Callback function for array_map diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index e99d324..04885df 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: rcube_shared.inc 2789 2009-07-23 12:14:17Z alec $ + $Id: rcube_shared.inc 3063 2009-10-27 09:43:39Z alec $ */ @@ -41,7 +41,7 @@ function send_nocacheing_headers() header("Pragma: no-cache"); // We need to set the following headers to make downloads work using IE in HTTPS mode. - if (isset($_SERVER['HTTPS'])) { + if (rcube_https_check()) { header('Pragma: '); header('Cache-Control: '); } @@ -554,7 +554,6 @@ function rc_mime_content_type($path, $name, $failover = 'application/octet-strea return $mime_type; } - /** * A method to guess encoding of a string. * @@ -585,6 +584,75 @@ function rc_detect_encoding($string, $failover='') return $result ? $result : $failover; } +/** + * Removes non-unicode characters from input + * + * @param mixed $input String or array. + * @return string + */ +function rc_utf8_clean($input) +{ + // handle input of type array + if (is_array($input)) { + foreach ($input as $idx => $val) + $input[$idx] = rc_utf8_clean($val); + return $input; + } + + if (!is_string($input) || $input == '') + return $input; + + // iconv/mbstring are much faster (especially with long strings) + if (function_exists('mb_convert_encoding') && ($res = mb_convert_encoding($input, 'UTF8', 'UTF8'))) + return $res; + + if (function_exists('iconv') && ($res = iconv('UTF8', 'UTF8//IGNORE', $input))) + return $res; + + $regexp = '/^('. +// '[\x00-\x7F]'. // UTF8-1 + '|[\xC2-\xDF][\x80-\xBF]'. // UTF8-2 + '|\xE0[\xA0-\xBF][\x80-\xBF]'. // UTF8-3 + '|[\xE1-\xEC][\x80-\xBF][\x80-\xBF]'. // UTF8-3 + '|\xED[\x80-\x9F][\x80-\xBF]'. // UTF8-3 + '|[\xEE-\xEF][\x80-\xBF][\x80-\xBF]'. // UTF8-3 + '|\xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF]'. // UTF8-4 + '|[\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]'.// UTF8-4 + '|\xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]'. // UTF8-4 + ')$/'; + + $seq = ''; + $out = ''; + + for ($i = 0, $len = strlen($input)-1; $i < $len; $i++) { + $chr = $input[$i]; + $ord = ord($chr); + // 1-byte character + if ($ord <= 0x7F) { + if ($seq) + $out .= preg_match($regexp, $seq) ? $seq : ''; + $seq = ''; + $out .= $chr; + // first (or second) byte of multibyte sequence + } else if ($ord >= 0xC0) { + if (strlen($seq)>1) { + $out .= preg_match($regexp, $seq) ? $seq : ''; + $seq = ''; + } else if ($seq && ord($seq) < 0xC0) { + $seq = ''; + } + $seq .= $chr; + // next byte of multibyte sequence + } else if ($seq) { + $seq .= $chr; + } + } + + if ($seq) + $out .= preg_match($regexp, $seq) ? $seq : ''; + + return $out; +} /** * Explode quoted string diff --git a/program/include/rcube_string_replacer.php b/program/include/rcube_string_replacer.php index 2625fdf..b1c1fbb 100644 --- a/program/include/rcube_string_replacer.php +++ b/program/include/rcube_string_replacer.php @@ -39,7 +39,7 @@ class rcube_string_replacer $url_chars_within = '\?\.~,!'; $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)([a-z0-9\-\.]+[a-z]{2,4}([$url_chars$url_chars_within]*[$url_chars])?)/i"; - $this->mailto_pattern = "/([a-z0-9][a-z0-9\-\.\+\_]*@[a-z0-9]([a-z0-9\-][.]?)*[a-z0-9]\\.[a-z]{2,5})/i"; + $this->mailto_pattern = "/([a-z0-9][a-z0-9\-\.\+\_]*@([a-z0-9]([-a-z0-9]*[a-z0-9])?\\.)+[a-z]{2,5})/i"; } /** diff --git a/program/include/rcube_template.php b/program/include/rcube_template.php index 3d894b5..5226f8d 100755 --- a/program/include/rcube_template.php +++ b/program/include/rcube_template.php @@ -1005,8 +1005,8 @@ class rcube_template extends rcube_html_page if (empty($url) && !preg_match('/_(task|action)=logout/', $_SERVER['QUERY_STRING'])) $url = $_SERVER['QUERY_STRING']; - $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser', 'size' => 30) + $attrib); - $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd', 'size' => 30) + $attrib); + $input_user = new html_inputfield(array('name' => '_user', 'id' => 'rcmloginuser') + $attrib); + $input_pass = new html_passwordfield(array('name' => '_pass', 'id' => 'rcmloginpwd') + $attrib); $input_action = new html_hiddenfield(array('name' => '_action', 'value' => 'login')); $input_tzone = new html_hiddenfield(array('name' => '_timezone', 'id' => 'rcmlogintz', 'value' => '_default_')); $input_url = new html_hiddenfield(array('name' => '_url', 'id' => 'rcmloginurl', 'value' => $url)); @@ -1026,7 +1026,7 @@ class rcube_template extends rcube_html_page } } else if (empty($default_host)) { - $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost', 'size' => 30)); + $input_host = new html_inputfield(array('name' => '_host', 'id' => 'rcmloginhost') + $attrib); } $form_name = !empty($attrib['form']) ? $attrib['form'] : 'form'; diff --git a/program/include/rcube_user.php b/program/include/rcube_user.php index 54a76c5..c2cad11 100644 --- a/program/include/rcube_user.php +++ b/program/include/rcube_user.php @@ -360,9 +360,8 @@ class rcube_user $rcmail = rcmail::get_instance(); // try to resolve user in virtuser table and file - if (!strpos($user, '@')) { - if ($email_list = self::user2email($user, false, true)) - $user_email = is_array($email_list[0]) ? $email_list[0][0] : $email_list[0]; + if ($email_list = self::user2email($user, false, true)) { + $user_email = is_array($email_list[0]) ? $email_list[0][0] : $email_list[0]; } $data = $rcmail->plugins->exec_hook('create_user', diff --git a/program/include/rcube_vcard.php b/program/include/rcube_vcard.php index 7dbbb3f..f574eed 100644 --- a/program/include/rcube_vcard.php +++ b/program/include/rcube_vcard.php @@ -269,6 +269,7 @@ class rcube_vcard foreach($regs2[1] as $attrid => $attr) { if ((list($key, $value) = explode('=', $attr)) && $value) { + $value = trim($value); if ($key == 'ENCODING') { // add next line(s) to value string if QP line end detected while ($value == 'QUOTED-PRINTABLE' && preg_match('/=$/', $lines[$i])) diff --git a/program/include/session.inc b/program/include/session.inc index 35bd1b8..77d1b1f 100644 --- a/program/include/session.inc +++ b/program/include/session.inc @@ -15,7 +15,7 @@ | Author: Thomas Bruederli | +-----------------------------------------------------------------------+ - $Id: session.inc 2573 2009-05-29 19:10:24Z alec $ + $Id: session.inc 2932 2009-09-07 12:51:21Z alec $ */ @@ -245,7 +245,7 @@ function rcube_sess_regenerate_id() $randval = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; for ($random = "", $i=1; $i <= 32; $i++) { - $random .= substr($randval, rand(0,(strlen($randval) - 1)), 1); + $random .= substr($randval, mt_rand(0,(strlen($randval) - 1)), 1); } // use md5 value for id or remove capitals from string $randval diff --git a/program/js/app.js b/program/js/app.js index 5d1903f..57d1471 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1,4257 +1,3484 @@ -/* - +-----------------------------------------------------------------------+ - | RoundCube Webmail Client Script | - | | - | This file is part of the RoundCube Webmail client | - | Copyright (C) 2005-2009, RoundCube Dev, - Switzerland | - | Licensed under the GNU GPL | - | | - +-----------------------------------------------------------------------+ - | Authors: Thomas Bruederli | - | Charles McNulty | - +-----------------------------------------------------------------------+ - | Requires: jquery.js, common.js, list.js | - +-----------------------------------------------------------------------+ - - $Id: app.js 2889 2009-08-29 18:41:17Z alec $ -*/ - - -function rcube_webmail() -{ - this.env = new Object(); - this.labels = new Object(); - this.buttons = new Object(); - this.buttons_sel = new Object(); - this.gui_objects = new Object(); - this.gui_containers = new Object(); - this.commands = new Object(); - this.command_handlers = new Object(); - this.onloads = new Array(); - - // create protected reference to myself - this.ref = 'rcmail'; - var ref = this; - - // webmail client settings - this.dblclick_time = 500; - this.message_time = 3000; - - this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); - - // mimetypes supported by the browser (default settings) - this.mimetypes = new Array('text/plain', 'text/html', 'text/xml', - 'image/jpeg', 'image/gif', 'image/png', - 'application/x-javascript', 'application/pdf', - 'application/x-shockwave-flash'); - - // default environment vars - this.env.keep_alive = 60; // seconds - this.env.request_timeout = 180; // seconds - this.env.draft_autosave = 0; // seconds - this.env.comm_path = './'; - this.env.bin_path = './bin/'; - this.env.blankpage = 'program/blank.gif'; - - // set jQuery ajax options - jQuery.ajaxSetup({ cache:false, - error:function(request, status, err){ ref.http_error(request, status, err); }, - beforeSend:function(xmlhttp){ xmlhttp.setRequestHeader('X-RoundCube-Request', ref.env.request_token); } - }); - - // set environment variable(s) - this.set_env = function(p, value) - { - if (p != null && typeof(p) == 'object' && !value) - for (var n in p) - this.env[n] = p[n]; - else - this.env[p] = value; - }; - - // add a localized label to the client environment - this.add_label = function(key, value) - { - this.labels[key] = value; - }; - - // add a button to the button list - this.register_button = function(command, id, type, act, sel, over) - { - if (!this.buttons[command]) - this.buttons[command] = new Array(); - - var button_prop = {id:id, type:type}; - if (act) button_prop.act = act; - if (sel) button_prop.sel = sel; - if (over) button_prop.over = over; - - this.buttons[command][this.buttons[command].length] = button_prop; - }; - - // register a specific gui object - this.gui_object = function(name, id) - { - this.gui_objects[name] = id; - }; - - // register a container object - this.gui_container = function(name, id) - { - this.gui_containers[name] = id; - }; - - // add a GUI element (html node) to a specified container - this.add_element = function(elm, container) - { - if (this.gui_containers[container] && this.gui_containers[container].jquery) - this.gui_containers[container].append(elm); - }; - - // register an external handler for a certain command - this.register_command = function(command, callback, enable) - { - this.command_handlers[command] = callback; - - if (enable) - this.enable_command(command, true); - }; - - // execute the given script on load - this.add_onload = function(f) - { - this.onloads[this.onloads.length] = f; - }; - - // initialize webmail client - this.init = function() - { - var p = this; - this.task = this.env.task; - - // check browser - if (!bw.dom || !bw.xmlhttp_test()) - { - this.goto_url('error', '_code=0x199'); - return; - } - - // find all registered gui containers - for (var n in this.gui_containers) - this.gui_containers[n] = $('#'+this.gui_containers[n]); - - // find all registered gui objects - for (var n in this.gui_objects) - this.gui_objects[n] = rcube_find_object(this.gui_objects[n]); - - // init registered buttons - this.init_buttons(); - - // tell parent window that this frame is loaded - if (this.env.framed && parent.rcmail && parent.rcmail.set_busy) - parent.rcmail.set_busy(false); - - // enable general commands - this.enable_command('logout', 'mail', 'addressbook', 'settings', true); - - if (this.env.permaurl) - this.enable_command('permaurl', true); - - switch (this.task) - { - case 'mail': - if (this.gui_objects.messagelist) - { - this.message_list = new rcube_list_widget(this.gui_objects.messagelist, {multiselect:true, draggable:true, keyboard:true, dblclick_time:this.dblclick_time}); - this.message_list.row_init = function(o){ p.init_message_row(o); }; - this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); }); - this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); }); - this.message_list.addEventListener('select', function(o){ p.msglist_select(o); }); - this.message_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); - this.message_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); - this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); }); - document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - - this.message_list.init(); - this.enable_command('toggle_status', 'toggle_flag', true); - - if (this.gui_objects.mailcontframe) - this.gui_objects.mailcontframe.onmousedown = function(e){ return p.click_on_list(e); }; - else - this.message_list.focus(); - } - - if (this.env.coltypes) - this.set_message_coltypes(this.env.coltypes); - - // enable mail commands - this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); - - if (this.env.search_text != null && document.getElementById('quicksearchbox') != null) - document.getElementById('quicksearchbox').value = this.env.search_text; - - if (this.env.action=='show' || this.env.action=='preview') - { - this.enable_command('show', 'reply', 'reply-all', 'forward', 'moveto', 'delete', - 'open', 'mark', 'edit', 'viewsource', 'download', 'print', 'load-attachment', 'load-headers', true); - - if (this.env.next_uid) - { - this.enable_command('nextmessage', true); - this.enable_command('lastmessage', true); - } - if (this.env.prev_uid) - { - this.enable_command('previousmessage', true); - this.enable_command('firstmessage', true); - } - - if (this.env.blockedobjects) - { - if (this.gui_objects.remoteobjectsmsg) - this.gui_objects.remoteobjectsmsg.style.display = 'block'; - this.enable_command('load-images', 'always-load', true); - } - } - - if (this.env.trash_mailbox && this.env.mailbox != this.env.trash_mailbox) - this.set_alttext('delete', 'movemessagetotrash'); - - // make preview/message frame visible - if (this.env.action == 'preview' && this.env.framed && parent.rcmail) - { - this.enable_command('compose', 'add-contact', false); - parent.rcmail.show_contentframe(true); - } - - if (this.env.action=='compose') - { - this.enable_command('add-attachment', 'send-attachment', 'remove-attachment', 'send', true); - if (this.env.spellcheck) - { - this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); }; - this.set_spellcheck_state('ready'); - if ($("input[name='_is_html']").val() == '1') - this.display_spellcheck_controls(false); - } - if (this.env.drafts_mailbox) - this.enable_command('savedraft', true); - - document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - - // init message compose form - this.init_messageform(); - } - - if (this.env.messagecount) - this.enable_command('select-all', 'select-none', 'expunge', true); - - if (this.purge_mailbox_test()) - this.enable_command('purge', true); - - this.set_page_buttons(); - - // show printing dialog - if (this.env.action=='print') - window.print(); - - // get unread count for each mailbox - if (this.gui_objects.mailboxlist) - { - this.env.unread_counts = {}; - this.gui_objects.folderlist = this.gui_objects.mailboxlist; - this.http_request('getunread', ''); - } - - // ask user to send MDN - if (this.env.mdn_request && this.env.uid) - { - var mdnurl = '_uid='+this.env.uid+'&_mbox='+urlencode(this.env.mailbox); - if (confirm(this.get_label('mdnrequest'))) - this.http_post('sendmdn', mdnurl); - else - this.http_post('mark', mdnurl+'&_flag=mdnsent'); - } - - break; - - - case 'addressbook': - if (this.gui_objects.contactslist) - { - this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, {multiselect:true, draggable:true, keyboard:true}); - this.contact_list.row_init = function(row){ p.triggerEvent('insertrow', { cid:row.uid, row:row }); }; - this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); }); - this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); }); - this.contact_list.addEventListener('dragstart', function(o){ p.drag_start(o); }); - this.contact_list.addEventListener('dragmove', function(e){ p.drag_move(e); }); - this.contact_list.addEventListener('dragend', function(e){ p.drag_end(e); }); - this.contact_list.init(); - - if (this.env.cid) - this.contact_list.highlight_row(this.env.cid); - - if (this.gui_objects.contactslist.parentNode) - { - this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; - document.onmouseup = function(e){ return p.doc_mouse_up(e); }; - } - else - this.contact_list.focus(); - - this.gui_objects.folderlist = this.gui_objects.contactslist; - } - - this.set_page_buttons(); - - if (this.env.address_sources && this.env.address_sources[this.env.source] && !this.env.address_sources[this.env.source].readonly) - this.enable_command('add', true); - - if (this.env.cid) - this.enable_command('show', 'edit', true); - - if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform) - this.enable_command('save', true); - else - this.enable_command('search', 'reset-search', 'moveto', 'import', true); - - if (this.contact_list && this.contact_list.rowcount > 0) - this.enable_command('export', true); - - this.enable_command('list', true); - break; - - - case 'settings': - this.enable_command('preferences', 'identities', 'save', 'folders', true); - - if (this.env.action=='identities') { - this.enable_command('add', this.env.identities_level < 2); - } - else if (this.env.action=='edit-identity' || this.env.action=='add-identity') { - this.enable_command('add', this.env.identities_level < 2); - this.enable_command('save', 'delete', 'edit', true); - } - else if (this.env.action=='folders') - this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', 'delete-folder', true); - - if (this.gui_objects.identitieslist) - { - this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false}); - this.identity_list.addEventListener('select', function(o){ p.identity_select(o); }); - this.identity_list.init(); - this.identity_list.focus(); - - if (this.env.iid) - this.identity_list.highlight_row(this.env.iid); - } - else if (this.gui_objects.sectionslist) - { - this.sections_list = new rcube_list_widget(this.gui_objects.sectionslist, {multiselect:false, draggable:false, keyboard:false}); - this.sections_list.addEventListener('select', function(o){ p.section_select(o); }); - this.sections_list.init(); - this.sections_list.focus(); - this.sections_list.select('general'); // open first section by default - } - else if (this.gui_objects.subscriptionlist) - this.init_subscription_list(); - - break; - - case 'login': - var input_user = $('#rcmloginuser'); - input_user.bind('keyup', function(e){ return rcmail.login_user_keyup(e); }); - - if (input_user.val() == '') - input_user.focus(); - else - $('#rcmloginpwd').focus(); - - // detect client timezone - $('#rcmlogintz').val(new Date().getTimezoneOffset() / -60); - - this.enable_command('login', true); - break; - - default: - break; - } - - // flag object as complete - this.loaded = true; - - // show message - if (this.pending_message) - this.display_message(this.pending_message[0], this.pending_message[1]); - - // map implicit containers - if (this.gui_objects.folderlist) - this.gui_containers.foldertray = $(this.gui_objects.folderlist); - - // trigger init event hook - this.triggerEvent('init', { task:this.task, action:this.env.action }); - - // execute all foreign onload scripts - // @deprecated - for (var i=0; i= 0) - this.set_env('flagged_col', found+1); - } - - // set eventhandler to flag icon, if icon found - if (this.env.flagged_col && (row.flagged_icon = row.obj.getElementsByTagName('td')[this.env.flagged_col].getElementsByTagName('img')[0])) - { - var p = this; - row.flagged_icon.id = 'flaggedicn_'+row.uid; - row.flagged_icon._row = row.obj; - row.flagged_icon.onmousedown = function(e) { p.command('toggle_flag', this); }; - } - - this.triggerEvent('insertrow', { uid:uid, row:row }); - }; - - // init message compose form: set focus and eventhandlers - this.init_messageform = function() - { - if (!this.gui_objects.messageform) - return false; - - //this.messageform = this.gui_objects.messageform; - var input_from = $("[name='_from']"); - var input_to = $("[name='_to']"); - var input_subject = $("input[name='_subject']"); - var input_message = $("[name='_message']").get(0); - - // init live search events - this.init_address_input_events(input_to); - this.init_address_input_events($("[name='_cc']")); - this.init_address_input_events($("[name='_bcc']")); - - // add signature according to selected identity - if (input_from.attr('type') == 'select-one' && $("input[name='_draft_saveid']").val() == '' - && $("input[name='_is_html']").val() != '1') { // if we have HTML editor, signature is added in callback - this.change_identity(input_from[0]); - } - - if (input_to.val() == '') - input_to.focus(); - else if (input_subject.val() == '') - input_subject.focus(); - else if (input_message) - input_message.focus(); - - // get summary of all field values - this.compose_field_hash(true); - - // start the auto-save timer - this.auto_save_start(); - }; - - this.init_address_input_events = function(obj) - { - var handler = function(e){ return ref.ksearch_keypress(e,this); }; - obj.bind((bw.safari || bw.ie ? 'keydown' : 'keypress'), handler); - obj.attr('autocomplete', 'off'); - }; - - - /*********************************************************/ - /********* client command interface *********/ - /*********************************************************/ - - // execute a specific command on the web client - this.command = function(command, props, obj) - { - if (obj && obj.blur) - obj.blur(); - - if (this.busy) - return false; - - // command not supported or allowed - if (!this.commands[command]) - { - // pass command to parent window - if (this.env.framed && parent.rcmail && parent.rcmail.command) - parent.rcmail.command(command, props); - - return false; - } - - // check input before leaving compose step - if (this.task=='mail' && this.env.action=='compose' && (command=='list' || command=='mail' || command=='addressbook' || command=='settings')) - { - if (this.cmp_hash != this.compose_field_hash() && !confirm(this.get_label('notsentwarning'))) - return false; - } - - // process external commands - if (typeof this.command_handlers[command] == 'function') - { - var ret = this.command_handlers[command](props, obj); - return ret !== null ? ret : (obj ? false : true); - } - else if (typeof this.command_handlers[command] == 'string') - { - var ret = window[this.command_handlers[command]](props, obj); - return ret !== null ? ret : (obj ? false : true); - } - - // trigger plugin hook - var event_ret = this.triggerEvent('before'+command, props); - if (typeof event_ret != 'undefined') { - // abort if one the handlers returned false - if (event_ret === false) - return false; - else - props = event_ret; - } - - // process internal command - switch (command) - { - case 'login': - if (this.gui_objects.loginform) - this.gui_objects.loginform.submit(); - break; - - // commands to switch task - case 'mail': - case 'addressbook': - case 'settings': - case 'logout': - this.switch_task(command); - break; - - case 'permaurl': - if (obj && obj.href && obj.target) - return true; - else if (this.env.permaurl) - parent.location.href = this.env.permaurl; - break; - - case 'open': - var uid; - if (uid = this.get_single_uid()) - { - obj.href = '?_task='+this.env.task+'&_action=show&_mbox='+urlencode(this.env.mailbox)+'&_uid='+uid; - return true; - } - break; - - // misc list commands - case 'list': - if (this.task=='mail') - { - if (this.env.search_request<0 || (props != '' && (this.env.search_request && props != this.env.mailbox))) - this.reset_qsearch(); - - this.list_mailbox(props); - - if (this.env.trash_mailbox) - this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage'); - } - else if (this.task=='addressbook') - { - if (this.env.search_request<0 || (this.env.search_request && props != this.env.source)) - this.reset_qsearch(); - - this.list_contacts(props); - this.enable_command('add', (this.env.address_sources && !this.env.address_sources[props].readonly)); - } - break; - - - case 'load-headers': - this.load_headers(obj); - break; - - - case 'sort': - var sort_order, sort_col = props; - - if (this.env.sort_col==sort_col) - sort_order = this.env.sort_order=='ASC' ? 'DESC' : 'ASC'; - else - sort_order = 'ASC'; - - // set table header class - $('#rcm'+this.env.sort_col).removeClass('sorted'+(this.env.sort_order.toUpperCase())); - $('#rcm'+sort_col).addClass('sorted'+sort_order); - - // save new sort properties - this.env.sort_col = sort_col; - this.env.sort_order = sort_order; - - // reload message list - this.list_mailbox('', '', sort_col+'_'+sort_order); - break; - - case 'nextpage': - this.list_page('next'); - break; - - case 'lastpage': - this.list_page('last'); - break; - - case 'previouspage': - this.list_page('prev'); - break; - - case 'firstpage': - this.list_page('first'); - break; - - case 'expunge': - if (this.env.messagecount) - this.expunge_mailbox(this.env.mailbox); - break; - - case 'purge': - case 'empty-mailbox': - if (this.env.messagecount) - this.purge_mailbox(this.env.mailbox); - break; - - - // common commands used in multiple tasks - case 'show': - if (this.task=='mail') - { - var uid = this.get_single_uid(); - if (uid && (!this.env.uid || uid != this.env.uid)) - { - if (this.env.mailbox == this.env.drafts_mailbox) - this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true); - else - this.show_message(uid); - } - } - else if (this.task=='addressbook') - { - var cid = props ? props : this.get_single_cid(); - if (cid && !(this.env.action=='show' && cid==this.env.cid)) - this.load_contact(cid, 'show'); - } - break; - - case 'add': - if (this.task=='addressbook') - this.load_contact(0, 'add'); - else if (this.task=='settings') - { - this.identity_list.clear_selection(); - this.load_identity(0, 'add-identity'); - } - break; - - case 'edit': - var cid; - if (this.task=='addressbook' && (cid = this.get_single_cid())) - this.load_contact(cid, 'edit'); - else if (this.task=='settings' && props) - this.load_identity(props, 'edit-identity'); - else if (this.task=='mail' && (cid = this.get_single_uid())) { - var url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid='; - this.goto_url('compose', url+cid+'&_mbox='+urlencode(this.env.mailbox), true); - } - break; - - case 'save-identity': - case 'save': - if (this.gui_objects.editform) - { - var input_pagesize = $("input[name='_pagesize']"); - var input_name = $("input[name='_name']"); - var input_email = $("input[name='_email']"); - - // user prefs - if (input_pagesize.length && isNaN(parseInt(input_pagesize.val()))) - { - alert(this.get_label('nopagesizewarning')); - input_pagesize.focus(); - break; - } - // contacts/identities - else - { - if (input_name.length && input_name.val() == '') - { - alert(this.get_label('nonamewarning')); - input_name.focus(); - break; - } - else if (input_email.length && !rcube_check_email(input_email.val())) - { - alert(this.get_label('noemailwarning')); - input_email.focus(); - break; - } - } - - this.gui_objects.editform.submit(); - } - break; - - case 'delete': - // mail task - if (this.task=='mail') - this.delete_messages(); - // addressbook task - else if (this.task=='addressbook') - this.delete_contacts(); - // user settings task - else if (this.task=='settings') - this.delete_identity(); - break; - - - // mail task commands - case 'move': - case 'moveto': - if (this.task == 'mail') - this.move_messages(props); - else if (this.task == 'addressbook' && this.drag_active) - this.copy_contact(null, props); - break; - - case 'mark': - if (props) - this.mark_message(props); - break; - - case 'toggle_status': - if (props && !props._row) - break; - - var uid; - var flag = 'read'; - - if (props._row.uid) - { - uid = props._row.uid; - - // toggle read/unread - if (this.message_list.rows[uid].deleted) { - flag = 'undelete'; - } else if (!this.message_list.rows[uid].unread) - flag = 'unread'; - } - - this.mark_message(flag, uid); - break; - - case 'toggle_flag': - if (props && !props._row) - break; - - var uid; - var flag = 'flagged'; - - if (props._row.uid) - { - uid = props._row.uid; - // toggle flagged/unflagged - if (this.message_list.rows[uid].flagged) - flag = 'unflagged'; - } - this.mark_message(flag, uid); - break; - - case 'always-load': - if (this.env.uid && this.env.sender) { - this.add_contact(urlencode(this.env.sender)); - window.setTimeout(function(){ ref.command('load-images'); }, 300); - break; - } - - case 'load-images': - if (this.env.uid) - this.show_message(this.env.uid, true, this.env.action=='preview'); - break; - - case 'load-attachment': - var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part; - - // open attachment in frame if it's of a supported mimetype - if (this.env.uid && props.mimetype && find_in_array(props.mimetype, this.mimetypes)>=0) - { - if (props.mimetype == 'text/html') - qstring += '&_safe=1'; - this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment'); - if (this.attachment_win) - { - window.setTimeout(function(){ ref.attachment_win.focus(); }, 10); - break; - } - } - - this.goto_url('get', qstring+'&_download=1', false); - break; - - case 'select-all': - if (props == 'invert') - this.message_list.invert_selection(); - else - this.message_list.select_all(props); - break; - - case 'select-none': - this.message_list.clear_selection(); - break; - - case 'nextmessage': - if (this.env.next_uid) - this.show_message(this.env.next_uid, false, this.env.action=='preview'); - break; - - case 'lastmessage': - if (this.env.last_uid) - this.show_message(this.env.last_uid); - break; - - case 'previousmessage': - if (this.env.prev_uid) - this.show_message(this.env.prev_uid, false, this.env.action=='preview'); - break; - - case 'firstmessage': - if (this.env.first_uid) - this.show_message(this.env.first_uid); - break; - - case 'checkmail': - this.check_for_recent(true); - break; - - case 'compose': - var url = this.env.comm_path+'&_action=compose'; - - if (this.task=='mail') - { - url += '&_mbox='+urlencode(this.env.mailbox); - - if (this.env.mailbox==this.env.drafts_mailbox) - { - var uid; - if (uid = this.get_single_uid()) - url += '&_draft_uid='+uid; - } - else if (props) - url += '&_to='+urlencode(props); - } - // modify url if we're in addressbook - else if (this.task=='addressbook') - { - // switch to mail compose step directly - if (props && props.indexOf('@') > 0) - { - url = this.get_task_url('mail', url); - this.redirect(url + '&_to='+urlencode(props)); - break; - } - - // use contact_id passed as command parameter - var a_cids = new Array(); - if (props) - a_cids[a_cids.length] = props; - // get selected contacts - else if (this.contact_list) - { - var selection = this.contact_list.get_selection(); - for (var n=0; n 0) { - var add_url = (this.env.source ? '_source='+urlencode(this.env.source)+'&' : ''); - if (this.env.search_request) - add_url += '_search='+this.env.search_request; - - this.goto_url('export', add_url); - } - break; - - // collapse/expand folder - case 'collapse-folder': - if (props) - this.collapse_folder(props); - break; - - // user settings commands - case 'preferences': - this.goto_url(''); - break; - - case 'identities': - this.goto_url('identities'); - break; - - case 'delete-identity': - this.delete_identity(); - - case 'folders': - this.goto_url('folders'); - break; - - case 'subscribe': - this.subscribe_folder(props); - break; - - case 'unsubscribe': - this.unsubscribe_folder(props); - break; - - case 'create-folder': - this.create_folder(props); - break; - - case 'rename-folder': - this.rename_folder(props); - break; - - case 'delete-folder': - this.delete_folder(props); - break; - - } - - this.triggerEvent('after'+command, props); - - return obj ? false : true; - }; - - // set command enabled or disabled - this.enable_command = function() - { - var args = arguments; - if(!args.length) return -1; - - var command; - var enable = args[args.length-1]; - - for(var n=0; n= pos.x2 || mouse.y < pos.y1 || mouse.y >= pos.y2) { - if (this.env.last_folder_target) { - $(this.get_folder_li(this.env.last_folder_target)).removeClass('droptarget'); - this.env.folder_coords[this.env.last_folder_target].on = 0; - this.env.last_folder_target = null; - } - return; - } - - // over the folders - for (var k in this.env.folder_coords) { - pos = this.env.folder_coords[k]; - if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2 - && this.check_droptarget(k)) { - - li = this.get_folder_li(k); - div = $(li.getElementsByTagName("div")[0]); - - // if the folder is collapsed, expand it after 1sec and restart the drag & drop process. - if (div.hasClass('collapsed')) { - if (this.folder_auto_timer) - window.clearTimeout(this.folder_auto_timer); - - this.folder_auto_expand = k; - this.folder_auto_timer = window.setTimeout(function() { - rcmail.command("collapse-folder", rcmail.folder_auto_expand); - rcmail.drag_start(null); - }, 1000); - } else if (this.folder_auto_timer) { - window.clearTimeout(this.folder_auto_timer); - this.folder_auto_timer = null; - this.folder_auto_expand = null; - } - - $(li).addClass('droptarget'); - this.env.last_folder_target = k; - this.env.folder_coords[k].on = 1; - } - else if (pos.on) { - $(this.get_folder_li(k)).removeClass('droptarget'); - this.env.folder_coords[k].on = 0; - } - } - } - }; - - this.collapse_folder = function(id) - { - var div; - if ((li = this.get_folder_li(id)) && - (div = $(li.getElementsByTagName("div")[0])) && - (div.hasClass('collapsed') || div.hasClass('expanded'))) - { - var ul = $(li.getElementsByTagName("ul")[0]); - if (div.hasClass('collapsed')) - { - ul.show(); - div.removeClass('collapsed').addClass('expanded'); - var reg = new RegExp('&'+urlencode(id)+'&'); - this.set_env('collapsed_folders', this.env.collapsed_folders.replace(reg, '')); - } - else - { - ul.hide(); - div.removeClass('expanded').addClass('collapsed'); - this.set_env('collapsed_folders', this.env.collapsed_folders+'&'+urlencode(id)+'&'); - - // select parent folder if one of its childs is currently selected - if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0) - this.command('list', id); - } - - // Work around a bug in IE6 and IE7, see #1485309 - if ((bw.ie6 || bw.ie7) && - li.nextSibling && - (li.nextSibling.getElementsByTagName("ul").length>0) && - li.nextSibling.getElementsByTagName("ul")[0].style && - (li.nextSibling.getElementsByTagName("ul")[0].style.display!='none')) - { - li.nextSibling.getElementsByTagName("ul")[0].style.display = 'none'; - li.nextSibling.getElementsByTagName("ul")[0].style.display = ''; - } - - this.http_post('save-pref', '_name=collapsed_folders&_value='+urlencode(this.env.collapsed_folders)); - this.set_unread_count_display(id, false); - } - } - - this.click_on_list = function(e) - { - if (this.gui_objects.qsearchbox) - this.gui_objects.qsearchbox.blur(); - - if (this.message_list) - this.message_list.focus(); - else if (this.contact_list) - this.contact_list.focus(); - - return rcube_event.get_button(e) == 2 ? true : rcube_event.cancel(e); - }; - - this.msglist_select = function(list) - { - if (this.preview_timer) - clearTimeout(this.preview_timer); - - var selected = list.selection.length==1; - - // Hide certain command buttons when Drafts folder is selected - if (this.env.mailbox == this.env.drafts_mailbox) - { - this.enable_command('reply', 'reply-all', 'forward', false); - this.enable_command('show', 'print', 'open', 'edit', 'download', 'viewsource', selected); - this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false)); - } - else - { - this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', 'edit', 'open', 'download', 'viewsource', selected); - this.enable_command('delete', 'moveto', 'mark', (list.selection.length > 0 ? true : false)); - } - - // start timer for message preview (wait for double click) - if (selected && this.env.contentframe && !list.multi_selecting) - this.preview_timer = window.setTimeout(function(){ ref.msglist_get_preview(); }, 200); - else if (this.env.contentframe) - this.show_contentframe(false); - }; - - this.msglist_dbl_click = function(list) - { - if (this.preview_timer) - clearTimeout(this.preview_timer); - - var uid = list.get_single_selection(); - if (uid && this.env.mailbox == this.env.drafts_mailbox) - this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true); - else if (uid) - this.show_message(uid, false, false); - }; - - this.msglist_keypress = function(list) - { - if (list.key_pressed == list.ENTER_KEY) - this.command('show'); - else if (list.key_pressed == list.DELETE_KEY) - this.command('delete'); - else if (list.key_pressed == list.BACKSPACE_KEY) - this.command('delete'); - else - list.shiftkey = false; - }; - - this.msglist_get_preview = function() - { - var uid = this.get_single_uid(); - if (uid && this.env.contentframe && !this.drag_active) - this.show_message(uid, false, true); - else if (this.env.contentframe) - this.show_contentframe(false); - }; - - this.check_droptarget = function(id) - { - if (this.task == 'mail') - return (this.env.mailboxes[id] && this.env.mailboxes[id].id != this.env.mailbox && !this.env.mailboxes[id].virtual); - else if (this.task == 'addressbook') - return (id != this.env.source && this.env.address_sources[id] && !this.env.address_sources[id].readonly); - else if (this.task == 'settings') - return (id != this.env.folder); - }; - - - /*********************************************************/ - /********* (message) list functionality *********/ - /*********************************************************/ - - // when user doble-clicks on a row - this.show_message = function(id, safe, preview) - { - if (!id) return; - - var add_url = ''; - var action = preview ? 'preview': 'show'; - var target = window; - - if (preview && this.env.contentframe && window.frames && window.frames[this.env.contentframe]) - { - target = window.frames[this.env.contentframe]; - add_url = '&_framed=1'; - } - - if (safe) - add_url = '&_safe=1'; - - // also send search request to get the right messages - if (this.env.search_request) - add_url += '&_search='+this.env.search_request; - - var url = '&_action='+action+'&_uid='+id+'&_mbox='+urlencode(this.env.mailbox)+add_url; - if (action == 'preview' && String(target.location.href).indexOf(url) >= 0) - this.show_contentframe(true); - else - { - this.set_busy(true, 'loading'); - target.location.href = this.env.comm_path+url; - - // mark as read and change mbox unread counter - if (action == 'preview' && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread) - { - this.set_message(id, 'unread', false); - if (this.env.unread_counts[this.env.mailbox]) - { - this.env.unread_counts[this.env.mailbox] -= 1; - this.set_unread_count(this.env.mailbox, this.env.unread_counts[this.env.mailbox], this.env.mailbox == 'INBOX'); - } - } - } - }; - - this.show_contentframe = function(show) - { - var frm; - if (this.env.contentframe && (frm = $('#'+this.env.contentframe)) && frm.length) - { - if (!show && window.frames[this.env.contentframe]) - { - if (window.frames[this.env.contentframe].location.href.indexOf(this.env.blankpage)<0) - window.frames[this.env.contentframe].location.href = this.env.blankpage; - } - else if (!bw.safari && !bw.konq) - frm[show ? 'show' : 'hide'](); - } - - if (!show && this.busy) - this.set_busy(false); - }; - - // list a specific page - this.list_page = function(page) - { - if (page=='next') - page = this.env.current_page+1; - if (page=='last') - page = this.env.pagecount; - if (page=='prev' && this.env.current_page>1) - page = this.env.current_page-1; - if (page=='first' && this.env.current_page>1) - page = 1; - - if (page > 0 && page <= this.env.pagecount) - { - this.env.current_page = page; - - if (this.task=='mail') - this.list_mailbox(this.env.mailbox, page); - else if (this.task=='addressbook') - this.list_contacts(this.env.source, page); - } - }; - - // list messages of a specific mailbox using filter - this.filter_mailbox = function(filter) - { - var search; - if (this.gui_objects.qsearchbox) - search = this.gui_objects.qsearchbox.value; - - this.message_list.clear(); - - // reset vars - this.env.current_page = 1; - this.set_busy(true, 'searching'); - this.http_request('search', '_filter='+filter - + (search ? '&_q='+urlencode(search) : '') - + (this.env.mailbox ? '&_mbox='+urlencode(this.env.mailbox) : ''), true); - } - - - // list messages of a specific mailbox - this.list_mailbox = function(mbox, page, sort) - { - var add_url = ''; - var target = window; - - if (!mbox) - mbox = this.env.mailbox; - - // add sort to url if set - if (sort) - add_url += '&_sort=' + sort; - - // also send search request to get the right messages - if (this.env.search_request) - add_url += '&_search='+this.env.search_request; - - // set page=1 if changeing to another mailbox - if (!page) - { - page = 1; - this.env.current_page = page; - this.show_contentframe(false); - } - - if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort)) - add_url += '&_refresh=1'; - - // unselect selected messages - this.last_selected = 0; - if (this.message_list) - this.message_list.clear_selection(); - - this.select_folder(mbox, this.env.mailbox); - this.env.mailbox = mbox; - - // load message list remotely - if (this.gui_objects.messagelist) - { - this.list_mailbox_remote(mbox, page, add_url); - return; - } - - if (this.env.contentframe && window.frames && window.frames[this.env.contentframe]) - { - target = window.frames[this.env.contentframe]; - add_url += '&_framed=1'; - } - - // load message list to target frame/window - if (mbox) - { - this.set_busy(true, 'loading'); - target.location.href = this.env.comm_path+'&_mbox='+urlencode(mbox)+(page ? '&_page='+page : '')+add_url; - } - }; - - // send remote request to load message list - this.list_mailbox_remote = function(mbox, page, add_url) - { - // clear message list first - this.message_list.clear(); - - // send request to server - var url = '_mbox='+urlencode(mbox)+(page ? '&_page='+page : ''); - this.set_busy(true, 'loading'); - this.http_request('list', url+add_url, true); - }; - - this.expunge_mailbox = function(mbox) - { - var lock = false; - var add_url = ''; - - // lock interface if it's the active mailbox - if (mbox == this.env.mailbox) - { - lock = true; - this.set_busy(true, 'loading'); - add_url = '&_reload=1'; - } - - // send request to server - var url = '_mbox='+urlencode(mbox); - this.http_post('expunge', url+add_url, lock); - }; - - this.purge_mailbox = function(mbox) - { - var lock = false; - var add_url = ''; - - if (!confirm(this.get_label('purgefolderconfirm'))) - return false; - - // lock interface if it's the active mailbox - if (mbox == this.env.mailbox) - { - lock = true; - this.set_busy(true, 'loading'); - add_url = '&_reload=1'; - } - - // send request to server - var url = '_mbox='+urlencode(mbox); - this.http_post('purge', url+add_url, lock); - return true; - }; - - // test if purge command is allowed - this.purge_mailbox_test = function() - { - return (this.env.messagecount && (this.env.mailbox == this.env.trash_mailbox || this.env.mailbox == this.env.junk_mailbox - || this.env.mailbox.match('^' + RegExp.escape(this.env.trash_mailbox) + RegExp.escape(this.env.delimiter)) - || this.env.mailbox.match('^' + RegExp.escape(this.env.junk_mailbox) + RegExp.escape(this.env.delimiter)))); - }; - - // set message icon - this.set_message_icon = function(uid) - { - var icn_src; - var rows = this.message_list.rows; - - if (!rows[uid]) - return false; - - if (rows[uid].deleted && this.env.deletedicon) - icn_src = this.env.deletedicon; - else if (rows[uid].replied && this.env.repliedicon) - { - if (rows[uid].forwarded && this.env.forwardedrepliedicon) - icn_src = this.env.forwardedrepliedicon; - else - icn_src = this.env.repliedicon; - } - else if (rows[uid].forwarded && this.env.forwardedicon) - icn_src = this.env.forwardedicon; - else if (rows[uid].unread && this.env.unreadicon) - icn_src = this.env.unreadicon; - else if (this.env.messageicon) - icn_src = this.env.messageicon; - - if (icn_src && rows[uid].icon) - rows[uid].icon.src = icn_src; - - icn_src = ''; - - if (rows[uid].flagged && this.env.flaggedicon) - icn_src = this.env.flaggedicon; - else if (!rows[uid].flagged && this.env.unflaggedicon) - icn_src = this.env.unflaggedicon; - - if (rows[uid].flagged_icon && icn_src) - rows[uid].flagged_icon.src = icn_src; - } - - // set message status - this.set_message_status = function(uid, flag, status) - { - var rows = this.message_list.rows; - - if (!rows[uid]) return false; - - if (flag == 'unread') - rows[uid].unread = status; - else if(flag == 'deleted') - rows[uid].deleted = status; - else if (flag == 'replied') - rows[uid].replied = status; - else if (flag == 'forwarded') - rows[uid].forwarded = status; - else if (flag == 'flagged') - rows[uid].flagged = status; - - this.env.messages[uid] = rows[uid]; - } - - // set message row status, class and icon - this.set_message = function(uid, flag, status) - { - var rows = this.message_list.rows; - - if (!rows[uid]) return false; - - if (flag) - this.set_message_status(uid, flag, status); - - var rowobj = $(rows[uid].obj); - if (rows[uid].unread && rows[uid].classname.indexOf('unread')<0) - { - rows[uid].classname += ' unread'; - rowobj.addClass('unread'); - } - else if (!rows[uid].unread && rows[uid].classname.indexOf('unread')>=0) - { - rows[uid].classname = rows[uid].classname.replace(/\s*unread/, ''); - rowobj.removeClass('unread'); - } - - if (rows[uid].deleted && rows[uid].classname.indexOf('deleted')<0) - { - rows[uid].classname += ' deleted'; - rowobj.addClass('deleted'); - } - else if (!rows[uid].deleted && rows[uid].classname.indexOf('deleted')>=0) - { - rows[uid].classname = rows[uid].classname.replace(/\s*deleted/, ''); - rowobj.removeClass('deleted'); - } - - if (rows[uid].flagged && rows[uid].classname.indexOf('flagged')<0) - { - rows[uid].classname += ' flagged'; - rowobj.addClass('flagged'); - } - else if (!rows[uid].flagged && rows[uid].classname.indexOf('flagged')>=0) - { - rows[uid].classname = rows[uid].classname.replace(/\s*flagged/, ''); - rowobj.removeClass('flagged'); - } - - this.set_message_icon(uid); - } - - // move selected messages to the specified mailbox - this.move_messages = function(mbox) - { - // exit if current or no mailbox specified or if selection is empty - if (!mbox || mbox == this.env.mailbox || (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length))) - return; - - var lock = false; - var add_url = '&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''); - - // show wait message - if (this.env.action=='show') - { - lock = true; - this.set_busy(true, 'movingmessage'); - } - else - this.show_contentframe(false); - - // Hide message command buttons until a message is selected - this.enable_command('reply', 'reply-all', 'forward', 'delete', 'mark', 'print', 'open', 'edit', 'viewsource', 'download', false); - - this._with_selected_messages('moveto', lock, add_url); - }; - - // delete selected messages from the current mailbox - this.delete_messages = function() - { - var selection = this.message_list ? this.message_list.get_selection() : new Array(); - - // exit if no mailbox specified or if selection is empty - if (!this.env.uid && !selection.length) - return; - - // if config is set to flag for deletion - if (this.env.flag_for_deletion) - this.mark_message('delete'); - // if there isn't a defined trash mailbox or we are in it - else if (!this.env.trash_mailbox || String(this.env.mailbox).toLowerCase() == String(this.env.trash_mailbox).toLowerCase()) - this.permanently_remove_messages(); - // if there is a trash mailbox defined and we're not currently in it - else { - // if shift was pressed delete it immediately - if (this.message_list && this.message_list.shiftkey) - { - if (confirm(this.get_label('deletemessagesconfirm'))) - this.permanently_remove_messages(); - } - else - this.move_messages(this.env.trash_mailbox); - } - }; - - // delete the selected messages permanently - this.permanently_remove_messages = function() - { - // exit if no mailbox specified or if selection is empty - if (!this.env.uid && (!this.message_list || !this.message_list.get_selection().length)) - return; - - this.show_contentframe(false); - this._with_selected_messages('delete', false, '&_from='+(this.env.action ? this.env.action : '')); - }; - - // Send a specifc request with UIDs of all selected messages - // @private - this._with_selected_messages = function(action, lock, add_url, remove) - { - var a_uids = new Array(); - - if (this.env.uid) - a_uids[0] = this.env.uid; - else - { - var selection = this.message_list.get_selection(); - var rows = this.message_list.rows; - var id; - for (var n=0; n=0) - message = message.substring(0, p-1) + message.substring(p+sig.length, message.length); - } - - message = message.replace(/[\r\n]+$/, ''); - len = message.length; - - // add the new signature string - if (this.env.signatures && this.env.signatures[id]) - { - sig = this.env.signatures[id]['text']; - if (this.env.signatures[id]['is_html']) - { - sig = this.env.signatures[id]['plain_text']; - } - if (sig.indexOf('-- ')!=0) - sig = '-- \n'+sig; - message += '\n\n'+sig; - if (len) len += 1; - } - } - else - { - var editor = tinyMCE.get(this.env.composebody); - - if (this.env.signatures) - { - // Append the signature as a div within the body - var sigElem = editor.dom.get('_rc_sig'); - var newsig = ''; - var htmlsig = true; - - if (!sigElem) - { - // add empty line before signature on IE - if (bw.ie) - editor.getBody().appendChild(editor.getDoc().createElement('br')); - - sigElem = editor.getDoc().createElement('div'); - sigElem.setAttribute('id', '_rc_sig'); - editor.getBody().appendChild(sigElem); - } - - if (this.env.signatures[id]) - { - newsig = this.env.signatures[id]['text']; - htmlsig = this.env.signatures[id]['is_html']; - - if (newsig) { - if (htmlsig && this.env.signatures[id]['plain_text'].indexOf('-- ')!=0) - newsig = '

--

' + newsig; - else if (!htmlsig && newsig.indexOf('-- ')!=0) - newsig = '-- \n' + newsig; - } - } - - if (htmlsig) - sigElem.innerHTML = newsig; - else - sigElem.innerHTML = '
' + newsig + '
'; - } - } - - input_message.val(message); - - // move cursor before the signature - if (!is_html) - this.set_caret_pos(input_message.get(0), len); - - this.env.identity = id; - return true; - }; - - this.show_attachment_form = function(a) - { - if (!this.gui_objects.uploadbox) - return false; - - var elm, list; - if (elm = this.gui_objects.uploadbox) - { - if (a && (list = this.gui_objects.attachmentlist)) - { - var pos = $(list).offset(); - elm.style.top = (pos.top + list.offsetHeight + 10) + 'px'; - elm.style.left = pos.left + 'px'; - } - - elm.style.visibility = a ? 'visible' : 'hidden'; - } - - // clear upload form - try { - if (!a && this.gui_objects.attachmentform != this.gui_objects.messageform) - this.gui_objects.attachmentform.reset(); - } - catch(e){} // ignore errors - - return true; - }; - - // upload attachment file - this.upload_file = function(form) - { - if (!form) - return false; - - // get file input fields - var send = false; - for (var n=0; n