- Applied fixes from trunk up to r5479

release-0.7
alecpl 13 years ago
parent c994e0e7cd
commit 3ad2b1b4b0

@ -1,7 +1,14 @@
CHANGELOG Roundcube Webmail CHANGELOG Roundcube Webmail
=========================== ===========================
- Fix possible infinite redirect on attachment preview (#1488199)
- Improved clickjacking protection for browsers which don't support X-Frame-Options headers
- Fixed bug where similiar folder names were highlighted wrong (#1487860)
- Fixed bug in handling link with '!' character in it (#1488195)
- Fixed bug where session ID's length was limited to 40 characters (#1488196)
RELEASE 0.7-beta
----------------
- Fix handling of HTML form elements in messages (#1485137) - Fix handling of HTML form elements in messages (#1485137)
- Fix regression in setting recipient to self when replying to a Sent message (#1487074) - Fix regression in setting recipient to self when replying to a Sent message (#1487074)
- Fix listing of folders in hidden namespaces (#1486796) - Fix listing of folders in hidden namespaces (#1486796)

@ -81,7 +81,7 @@ CREATE TABLE [dbo].[identities] (
GO GO
CREATE TABLE [dbo].[session] ( CREATE TABLE [dbo].[session] (
[sess_id] [varchar] (32) COLLATE Latin1_General_CI_AI NOT NULL , [sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL ,
[created] [datetime] NOT NULL , [created] [datetime] NOT NULL ,
[changed] [datetime] NULL , [changed] [datetime] NULL ,
[ip] [varchar] (40) COLLATE Latin1_General_CI_AI NOT NULL , [ip] [varchar] (40) COLLATE Latin1_General_CI_AI NOT NULL ,

@ -239,3 +239,8 @@ ALTER TABLE [dbo].[cache_messages] ADD CONSTRAINT [FK_cache_messages_user_id]
ON DELETE CASCADE ON UPDATE CASCADE ON DELETE CASCADE ON UPDATE CASCADE
GO GO
-- Updates from version 0.7-beta
ALTER TABLE [dbo].[session] ALTER COLUMN [sess_id] [varchar] (128) COLLATE Latin1_General_CI_AI NOT NULL
GO

@ -6,7 +6,7 @@
-- Table structure for table `session` -- Table structure for table `session`
CREATE TABLE `session` ( CREATE TABLE `session` (
`sess_id` varchar(40) NOT NULL, `sess_id` varchar(128) NOT NULL,
`created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00', `created` datetime NOT NULL DEFAULT '1000-01-01 00:00:00',
`changed` 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, `ip` varchar(40) NOT NULL,

@ -208,3 +208,7 @@ CREATE TABLE `cache_messages` (
INDEX `changed_index` (`changed`), INDEX `changed_index` (`changed`),
PRIMARY KEY (`user_id`, `mailbox`, `uid`) PRIMARY KEY (`user_id`, `mailbox`, `uid`)
) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */; ) /*!40000 ENGINE=INNODB */ /*!40101 CHARACTER SET utf8 COLLATE utf8_general_ci */;
-- Updates from version 0.7-beta
ALTER TABLE `session` CHANGE `sess_id` `sess_id` varchar(128) NOT NULL;

@ -37,7 +37,7 @@ CREATE INDEX users_alias_id_idx ON users (alias);
-- --
CREATE TABLE "session" ( CREATE TABLE "session" (
sess_id varchar(40) DEFAULT '' PRIMARY KEY, sess_id varchar(128) DEFAULT '' PRIMARY KEY,
created timestamp with time zone DEFAULT now() NOT NULL, created timestamp with time zone DEFAULT now() NOT NULL,
changed timestamp with time zone DEFAULT now() NOT NULL, changed timestamp with time zone DEFAULT now() NOT NULL,
ip varchar(41) NOT NULL, ip varchar(41) NOT NULL,

@ -165,3 +165,7 @@ CREATE TABLE cache_messages (
); );
CREATE INDEX cache_messages_changed_idx ON cache_messages (changed); CREATE INDEX cache_messages_changed_idx ON cache_messages (changed);
-- Updates from version 0.7-beta
ALTER TABLE "session" ALTER sess_id TYPE varchar(128);

@ -110,7 +110,7 @@ CREATE INDEX ix_users_alias ON users(alias);
-- --
CREATE TABLE session ( CREATE TABLE session (
sess_id varchar(40) NOT NULL PRIMARY KEY, sess_id varchar(128) NOT NULL PRIMARY KEY,
created datetime NOT NULL default '0000-00-00 00:00:00', created datetime NOT NULL default '0000-00-00 00:00:00',
changed datetime NOT NULL default '0000-00-00 00:00:00', changed datetime NOT NULL default '0000-00-00 00:00:00',
ip varchar(40) NOT NULL default '', ip varchar(40) NOT NULL default '',

@ -282,3 +282,16 @@ CREATE TABLE cache_messages (
); );
CREATE INDEX ix_cache_messages_changed ON cache_messages (changed); CREATE INDEX ix_cache_messages_changed ON cache_messages (changed);
-- Updates from version 0.7-beta
DROP TABLE session;
CREATE TABLE session (
sess_id varchar(128) NOT NULL PRIMARY KEY,
created datetime NOT NULL default '0000-00-00 00:00:00',
changed datetime NOT NULL default '0000-00-00 00:00:00',
ip varchar(40) NOT NULL default '',
vars text NOT NULL
);
CREATE INDEX ix_session_changed ON session (changed);

@ -27,7 +27,9 @@ if (window.rcmail) {
// set css style for archive folder // set css style for archive folder
var li; var li;
if (rcmail.env.archive_folder && rcmail.env.archive_folder_icon && (li = rcmail.get_folder_li(rcmail.env.archive_folder))) if (rcmail.env.archive_folder && rcmail.env.archive_folder_icon
&& (li = rcmail.get_folder_li(rcmail.env.archive_folder, '', true))
)
$(li).css('background-image', 'url(' + rcmail.env.archive_folder_icon + ')'); $(li).css('background-image', 'url(' + rcmail.env.archive_folder_icon + ')');
}) })
} }

@ -13,10 +13,9 @@
<email>roundcube@gmail.com</email> <email>roundcube@gmail.com</email>
<active>yes</active> <active>yes</active>
</lead> </lead>
<date>2010-02-06</date> <date>2011-11-23</date>
<time>12:12:00</time>
<version> <version>
<release>1.4</release> <release>1.5</release>
<api>1.4</api> <api>1.4</api>
</version> </version>
<stability> <stability>
@ -35,14 +34,21 @@
<tasks:replace from="@name@" to="name" type="package-info"/> <tasks:replace from="@name@" to="name" type="package-info"/>
<tasks:replace from="@package_version@" to="version" type="package-info"/> <tasks:replace from="@package_version@" to="version" type="package-info"/>
</file> </file>
<file name="localization/en_US.inc" role="data"></file>
<file name="localization/cs_CZ.inc" role="data"></file> <file name="localization/cs_CZ.inc" role="data"></file>
<file name="localization/de_CH.inc" role="data"></file> <file name="localization/de_CH.inc" role="data"></file>
<file name="localization/de_DE.inc" role="data"></file> <file name="localization/de_DE.inc" role="data"></file>
<file name="localization/en_US.inc" role="data"></file>
<file name="localization/es_AR.inc" role="data"></file>
<file name="localization/es_ES.inc" role="data"></file>
<file name="localization/et_EE.inc" role="data"></file> <file name="localization/et_EE.inc" role="data"></file>
<file name="localization/fr_FR.inc" role="data"></file> <file name="localization/fr_FR.inc" role="data"></file>
<file name="localization/gl_ES.inc" role="data"></file>
<file name="localization/ja_JP.inc" role="data"></file>
<file name="localization/nl_NL.inc" role="data"></file>
<file name="localization/pl_PL.inc" role="data"></file> <file name="localization/pl_PL.inc" role="data"></file>
<file name="localization/pt_BR.inc" role="data"></file>
<file name="localization/ru_RU.inc" role="data"></file> <file name="localization/ru_RU.inc" role="data"></file>
<file name="localization/sv_SE.inc" role="data"></file>
<file name="localization/zh_TW.inc" role="data"></file> <file name="localization/zh_TW.inc" role="data"></file>
<file name="skins/default/archive_act.png" role="data"></file> <file name="skins/default/archive_act.png" role="data"></file>
<file name="skins/default/archive_pas.png" role="data"></file> <file name="skins/default/archive_pas.png" role="data"></file>

@ -1,4 +1,5 @@
- Fixed setting test type to :is when none is specified - Fixed setting test type to :is when none is specified
- Fixed javascript error in IE8
* version 5.0-rc1 [2011-11-17] * version 5.0-rc1 [2011-11-17]
----------------------------------------------------------- -----------------------------------------------------------

@ -53,6 +53,31 @@ $labels['none'] = 'ninguno';
$labels['fromset'] = 'de conjunto '; $labels['fromset'] = 'de conjunto ';
$labels['fromfile'] = 'de archivo'; $labels['fromfile'] = 'de archivo';
$labels['filterdisabled'] = 'Filtro desactivado'; $labels['filterdisabled'] = 'Filtro desactivado';
$labels['filtermatches'] = 'coincide con la expresión';
$labels['filternotmatches'] = 'no coincide con la expresión';
$labels['filterregex'] = 'coincide con la expresión regular';
$labels['filternotregex'] = 'no coincide con la expresión regular';
$labels['vacationsubject'] = 'Asunto del Mensaje:';
$labels['countisgreaterthan'] = 'contiene más que';
$labels['countisgreaterthanequal'] = 'contiene más o igual que';
$labels['countislessthan'] = 'contiene menos que';
$labels['countislessthanequal'] = 'contiene menos o igual que';
$labels['countequals'] = 'contiene igual que';
$labels['countnotequals'] = 'contiene distinto que';
$labels['valueisgreaterthan'] = 'el valor es mayor que';
$labels['valueisgreaterthanequal'] = 'el valor es mayor o igual que';
$labels['valueislessthan'] = 'el valor es menor que';
$labels['valueislessthanequal'] = 'el valor es menor o igual que';
$labels['valueequals'] = 'el valor es igual que';
$labels['valuenotequals'] = 'el valor es distinto que';
$labels['setflags'] = 'Etiquetar el mensaje';
$labels['addflags'] = 'Agregar etiqueta al mensaje';
$labels['removeflags'] = 'Eliminar etiquetas al mensaje';
$labels['flagread'] = 'Leido';
$labels['flagdeleted'] = 'Eliminado';
$labels['flaganswered'] = 'Respondido';
$labels['flagflagged'] = 'Marcado';
$labels['flagdraft'] = 'Borrador';
$messages = array(); $messages = array();
$messages['filterunknownerror'] = 'Error desconocido de servidor'; $messages['filterunknownerror'] = 'Error desconocido de servidor';
@ -77,5 +102,6 @@ $messages['setcreateerror'] = 'Imposible crear el conjunto de filtros. Ha ocurri
$messages['setcreated'] = 'Conjunto de filtros creado satisfactoriamente'; $messages['setcreated'] = 'Conjunto de filtros creado satisfactoriamente';
$messages['emptyname'] = 'Imposible crear el conjunto de filtros. Sin nombre'; $messages['emptyname'] = 'Imposible crear el conjunto de filtros. Sin nombre';
$messages['nametoolong'] = 'Imposible crear el conjunto de filtros. Nombre demasiado largo' $messages['nametoolong'] = 'Imposible crear el conjunto de filtros. Nombre demasiado largo'
$messages['setdeactivateerror'] = 'Imposible desactivar el conjunto de filtros seleccionado. Ha ocurrido un error en el servidor';
?> ?>

@ -290,8 +290,8 @@ rcube_webmail.prototype.managesieve_updatelist = function(action, o)
td.innerHTML = el.name; td.innerHTML = el.name;
td.className = 'name'; td.className = 'name';
tr.id = 'rcmrow' + el.id; tr.id = 'rcmrow' + el.id;
if (el.class) if (el['class'])
tr.className = el.class tr.className = el['class'];
tr.appendChild(td); tr.appendChild(td);
list.insert_row(tr); list.insert_row(tr);
@ -721,9 +721,7 @@ rcube_webmail.prototype.managesieve_create = function()
// load form in the iframe // load form in the iframe
var frame = $('<iframe>').attr({src: url, frameborder: 0}) var frame = $('<iframe>').attr({src: url, frameborder: 0})
frame.height(dialog.height()); // temp. dialog.empty().append(frame).dialog('dialog').resize();
dialog.empty().append(frame);
dialog.dialog('dialog').resize();
// Change [Next Step] button with [Save] button // Change [Next Step] button with [Save] button
buttons = {}; buttons = {};
@ -743,7 +741,8 @@ rcube_webmail.prototype.managesieve_create = function()
close: function() { rcmail.managesieve_dialog_close(); }, close: function() { rcmail.managesieve_dialog_close(); },
buttons: buttons, buttons: buttons,
minWidth: 600, minWidth: 600,
minHeight: 300 minHeight: 300,
height: 250
}).show(); }).show();
this.env.managesieve_dialog = dialog; this.env.managesieve_dialog = dialog;

@ -110,6 +110,7 @@ body.iframe
#filter-form #filter-form
{ {
min-width: 550px; min-width: 550px;
width: expression(Math.max(550, document.documentElement.clientWidth)+'px');
white-space: nowrap; white-space: nowrap;
padding: 20px 10px 10px 10px; padding: 20px 10px 10px 10px;
} }
@ -145,8 +146,8 @@ div.rulerow:hover, div.actionrow:hover
div.rulerow table, div.actionrow table div.rulerow table, div.actionrow table
{ {
padding: 0px; padding: 0px;
width: 100%; min-width: 600px;
min-width: 620px; width: expression(Math.max(600, document.documentElement.clientWidth)+'px');
} }
td td
@ -189,6 +190,7 @@ td.rowactions
{ {
white-space: nowrap; white-space: nowrap;
width: 1%; width: 1%;
padding-top: 2px;
} }
td.rowtargets td.rowtargets
@ -196,6 +198,7 @@ td.rowtargets
white-space: nowrap; white-space: nowrap;
width: 98%; width: 98%;
padding-left: 3px; padding-left: 3px;
padding-top: 2px;
} }
td.rowtargets div.adv td.rowtargets div.adv

@ -272,6 +272,7 @@ function hashPassword( $passwordClear, $encodageType )
case 'samba': case 'samba':
if (function_exists('hash')) { if (function_exists('hash')) {
$cryptedPassword = hash('md4', rcube_charset_convert($passwordClear, RCMAIL_CHARSET, 'UTF-16LE')); $cryptedPassword = hash('md4', rcube_charset_convert($passwordClear, RCMAIL_CHARSET, 'UTF-16LE'));
$cryptedPassword = strtoupper($cryptedPassword);
} else { } else {
/* Your PHP install does not have the hash() function */ /* Your PHP install does not have the hash() function */
return false; return false;

@ -238,6 +238,7 @@ function ldap_simple_hash_password($password_clear, $encodage_type)
case 'samba': case 'samba':
if (function_exists('hash')) { if (function_exists('hash')) {
$crypted_password = hash('md4', rcube_charset_convert($password_clear, RCMAIL_CHARSET, 'UTF-16LE')); $crypted_password = hash('md4', rcube_charset_convert($password_clear, RCMAIL_CHARSET, 'UTF-16LE'));
$crypted_password = strtoupper($crypted_password);
} else { } else {
/* Your PHP install does not have the hash() function */ /* Your PHP install does not have the hash() function */
return false; return false;

@ -15,10 +15,9 @@
<email>alec@alec.pl</email> <email>alec@alec.pl</email>
<active>yes</active> <active>yes</active>
</lead> </lead>
<date></date> <date>2011-11-23</date>
<time></time>
<version> <version>
<release></release> <release>2.4</release>
<api>1.6</api> <api>1.6</api>
</version> </version>
<stability> <stability>
@ -28,6 +27,7 @@
<license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license>
<notes> <notes>
- Added option to use punycode or unicode for domain names (#1488103) - Added option to use punycode or unicode for domain names (#1488103)
- Save Samba password hashes in capital letters (#1488197)
</notes> </notes>
<contents> <contents>
<dir baseinstalldir="/" name="/"> <dir baseinstalldir="/" name="/">
@ -51,21 +51,27 @@
<file name="localization/de_CH.inc" role="data"></file> <file name="localization/de_CH.inc" role="data"></file>
<file name="localization/de_DE.inc" role="data"></file> <file name="localization/de_DE.inc" role="data"></file>
<file name="localization/en_US.inc" role="data"></file> <file name="localization/en_US.inc" role="data"></file>
<file name="localization/es_AR.inc" role="data"></file>
<file name="localization/es_ES.inc" role="data"></file> <file name="localization/es_ES.inc" role="data"></file>
<file name="localization/et_EE.inc" role="data"></file> <file name="localization/et_EE.inc" role="data"></file>
<file name="localization/fi_FI.inc" role="data"></file> <file name="localization/fi_FI.inc" role="data"></file>
<file name="localization/fr_FR.inc" role="data"></file> <file name="localization/fr_FR.inc" role="data"></file>
<file name="localization/gl_ES.inc" role="data"></file> <file name="localization/gl_ES.inc" role="data"></file>
<file name="localization/hr_HR.inc" role="data"></file>
<file name="localization/hu_HU.inc" role="data"></file> <file name="localization/hu_HU.inc" role="data"></file>
<file name="localization/it_IT.inc" role="data"></file> <file name="localization/it_IT.inc" role="data"></file>
<file name="localization/ja_JA.inc" role="data"></file>
<file name="localization/lt_LT.inc" role="data"></file> <file name="localization/lt_LT.inc" role="data"></file>
<file name="localization/lv_LV.inc" role="data"></file> <file name="localization/lv_LV.inc" role="data"></file>
<file name="localization/nl_NL.inc" role="data"></file> <file name="localization/nl_NL.inc" role="data"></file>
<file name="localization/pl_PL.inc" role="data"></file> <file name="localization/pl_PL.inc" role="data"></file>
<file name="localization/pt_BR.inc" role="data"></file> <file name="localization/pt_BR.inc" role="data"></file>
<file name="localization/pt_PT.inc" role="data"></file> <file name="localization/pt_PT.inc" role="data"></file>
<file name="localization/ru_RU.inc" role="data"></file>
<file name="localization/sk_SK.inc" role="data"></file>
<file name="localization/sl_SI.inc" role="data"></file> <file name="localization/sl_SI.inc" role="data"></file>
<file name="localization/sv_SE.inc" role="data"></file> <file name="localization/sv_SE.inc" role="data"></file>
<file name="localization/tr_TR.inc" role="data"></file>
<file name="localization/zh_TW.inc" role="data"></file> <file name="localization/zh_TW.inc" role="data"></file>
<file name="drivers/chgsaslpasswd.c" role="data"></file> <file name="drivers/chgsaslpasswd.c" role="data"></file>

@ -730,12 +730,14 @@ function asciiwords($str, $css_id = false, $replace_with = '')
/** /**
* Convert the given string into a valid HTML identifier * Convert the given string into a valid HTML identifier
* Same functionality as done in app.js with this.identifier_expr * Same functionality as done in app.js with rcube_webmail.html_identifier()
*
*/ */
function html_identifier($str) function html_identifier($str, $encode=false)
{ {
return asciiwords($str, true, '_'); if ($encode)
return rtrim(strtr(base64_encode($str), '+/', '-_'), '=');
else
return asciiwords($str, true, '_');
} }
/** /**
@ -1331,7 +1333,7 @@ function rcmail_render_folder_tree_html(&$arrFolders, &$mbox_name, &$jslist, $at
} }
// make folder name safe for ids and class names // make folder name safe for ids and class names
$folder_id = html_identifier($folder['id']); $folder_id = html_identifier($folder['id'], true);
$classes = array('mailbox'); $classes = array('mailbox');
// set special class for Sent, Drafts, Trash and Junk // set special class for Sent, Drafts, Trash and Junk

@ -39,7 +39,7 @@ class rcube_string_replacer
// Support unicode/punycode in top-level domain part // Support unicode/punycode in top-level domain part
$utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})'; $utf_domain = '[^?&@"\'\\/()\s\r\t\n]+\\.([^\\x00-\\x2f\\x3b-\\x40\\x5b-\\x60\\x7b-\\x7f]{2,}|xn--[a-z0-9]{2,})';
$url1 = '.:;,'; $url1 = '.:;,';
$url2 = 'a-z0-9%=#@+?&\\/_~\\[\\]{}-'; $url2 = 'a-z0-9%=#@+?!&\\/_~\\[\\]{}-';
$this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i"; $this->link_pattern = "/([\w]+:\/\/|\Wwww\.)($utf_domain([$url1]?[$url2]+)*)/i";
$this->mailto_pattern = "/(" $this->mailto_pattern = "/("

@ -71,6 +71,7 @@ class rcube_template extends rcube_html_page
//$this->framed = $framed; //$this->framed = $framed;
$this->set_env('task', $task); $this->set_env('task', $task);
$this->set_env('x_frame_options', $this->app->config->get('x_frame_options', 'sameorigin'));
// load the correct skin (in case user-defined) // load the correct skin (in case user-defined)
$this->set_skin($this->config['skin']); $this->set_skin($this->config['skin']);
@ -915,6 +916,7 @@ class rcube_template extends rcube_html_page
// make valid href to specific buttons // make valid href to specific buttons
if (in_array($attrib['command'], rcmail::$main_tasks)) { if (in_array($attrib['command'], rcmail::$main_tasks)) {
$attrib['href'] = rcmail_url(null, null, $attrib['command']); $attrib['href'] = rcmail_url(null, null, $attrib['command']);
$attrib['onclick'] = sprintf("%s.switch_task('%s');return false", JS_OBJECT_NAME, $attrib['command']);
} }
else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) { else if ($attrib['task'] && in_array($attrib['task'], rcmail::$main_tasks)) {
$attrib['href'] = rcmail_url($attrib['command'], null, $attrib['task']); $attrib['href'] = rcmail_url($attrib['command'], null, $attrib['task']);

@ -37,7 +37,7 @@ function rcube_webmail()
// webmail client settings // webmail client settings
this.dblclick_time = 500; this.dblclick_time = 500;
this.message_time = 2000; this.message_time = 4000;
this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi'); this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi');
@ -128,7 +128,7 @@ function rcube_webmail()
// initialize webmail client // initialize webmail client
this.init = function() this.init = function()
{ {
var p = this; var n, p = this;
this.task = this.env.task; this.task = this.env.task;
// check browser // check browser
@ -138,13 +138,29 @@ function rcube_webmail()
} }
// find all registered gui containers // find all registered gui containers
for (var n in this.gui_containers) for (n in this.gui_containers)
this.gui_containers[n] = $('#'+this.gui_containers[n]); this.gui_containers[n] = $('#'+this.gui_containers[n]);
// find all registered gui objects // find all registered gui objects
for (var n in this.gui_objects) for (n in this.gui_objects)
this.gui_objects[n] = rcube_find_object(this.gui_objects[n]); this.gui_objects[n] = rcube_find_object(this.gui_objects[n]);
// clickjacking protection
if (this.env.x_frame_options) {
try {
// bust frame if not allowed
if (this.env.x_frame_options == 'deny' && top.location.href != self.location.href)
top.location.href = self.location.href;
else if (top.location.hostname != self.location.hostname)
throw 1;
} catch (e) {
// possible clickjacking attack: disable all form elements
$('form').each(function(){ ref.lock_form(this, true); });
this.display_message("Blocked: possible clickjacking attack!", 'error');
return;
}
}
// init registered buttons // init registered buttons
this.init_buttons(); this.init_buttons();
@ -380,8 +396,10 @@ function rcube_webmail()
$('#rcmloginpwd').focus(); $('#rcmloginpwd').focus();
// detect client timezone // detect client timezone
var tz = new Date().getTimezoneOffset() / -60; var dt = new Date(),
var stdtz = new Date().getStdTimezoneOffset() / -60; tz = dt.getTimezoneOffset() / -60,
stdtz = dt.getStdTimezoneOffset() / -60;
$('#rcmlogintz').val(stdtz); $('#rcmlogintz').val(stdtz);
$('#rcmlogindst').val(tz > stdtz ? 1 : 0); $('#rcmlogindst').val(tz > stdtz ? 1 : 0);
@ -442,7 +460,7 @@ function rcube_webmail()
// execute a specific command on the web client // execute a specific command on the web client
this.command = function(command, props, obj) this.command = function(command, props, obj)
{ {
var ret; var ret, uid, cid, url, flag;
if (obj && obj.blur) if (obj && obj.blur)
obj.blur(); obj.blur();
@ -517,7 +535,6 @@ function rcube_webmail()
return false; return false;
case 'open': case 'open':
var uid;
if (uid = this.get_single_uid()) { if (uid = this.get_single_uid()) {
obj.href = '?_task='+this.env.task+'&_action=show&_mbox='+urlencode(this.env.mailbox)+'&_uid='+uid; obj.href = '?_task='+this.env.task+'&_action=show&_mbox='+urlencode(this.env.mailbox)+'&_uid='+uid;
return true; return true;
@ -586,7 +603,7 @@ function rcube_webmail()
// common commands used in multiple tasks // common commands used in multiple tasks
case 'show': case 'show':
if (this.task == 'mail') { if (this.task == 'mail') {
var uid = this.get_single_uid(); uid = this.get_single_uid();
if (uid && (!this.env.uid || uid != this.env.uid)) { if (uid && (!this.env.uid || uid != this.env.uid)) {
if (this.env.mailbox == this.env.drafts_mailbox) if (this.env.mailbox == this.env.drafts_mailbox)
this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true); this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
@ -595,7 +612,7 @@ function rcube_webmail()
} }
} }
else if (this.task == 'addressbook') { else if (this.task == 'addressbook') {
var cid = props ? props : this.get_single_cid(); cid = props ? props : this.get_single_cid();
if (cid && !(this.env.action == 'show' && cid == this.env.cid)) if (cid && !(this.env.action == 'show' && cid == this.env.cid))
this.load_contact(cid, 'show'); this.load_contact(cid, 'show');
} }
@ -611,13 +628,12 @@ function rcube_webmail()
break; break;
case 'edit': case 'edit':
var cid;
if (this.task=='addressbook' && (cid = this.get_single_cid())) if (this.task=='addressbook' && (cid = this.get_single_cid()))
this.load_contact(cid, 'edit'); this.load_contact(cid, 'edit');
else if (this.task=='settings' && props) else if (this.task=='settings' && props)
this.load_identity(props, 'edit-identity'); this.load_identity(props, 'edit-identity');
else if (this.task=='mail' && (cid = this.get_single_uid())) { else if (this.task=='mail' && (cid = this.get_single_uid())) {
var url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid='; url = (this.env.mailbox == this.env.drafts_mailbox) ? '_draft_uid=' : '_uid=';
this.goto_url('compose', url+cid+'&_mbox='+urlencode(this.env.mailbox), true); this.goto_url('compose', url+cid+'&_mbox='+urlencode(this.env.mailbox), true);
} }
break; break;
@ -695,7 +711,7 @@ function rcube_webmail()
if (props && !props._row) if (props && !props._row)
break; break;
var uid, flag = 'read'; flag = 'read';
if (props._row.uid) { if (props._row.uid) {
uid = props._row.uid; uid = props._row.uid;
@ -715,7 +731,7 @@ function rcube_webmail()
if (props && !props._row) if (props && !props._row)
break; break;
var uid, flag = 'flagged'; flag = 'flagged';
if (props._row.uid) { if (props._row.uid) {
uid = props._row.uid; uid = props._row.uid;
@ -811,7 +827,7 @@ function rcube_webmail()
break; break;
case 'compose': case 'compose':
var url = this.url('mail/compose'); url = this.url('mail/compose');
if (this.task == 'mail') { if (this.task == 'mail') {
url += '&_mbox='+urlencode(this.env.mailbox); url += '&_mbox='+urlencode(this.env.mailbox);
@ -921,9 +937,8 @@ function rcube_webmail()
case 'reply-all': case 'reply-all':
case 'reply-list': case 'reply-list':
case 'reply': case 'reply':
var uid;
if (uid = this.get_single_uid()) { if (uid = this.get_single_uid()) {
var url = '_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); url = '_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
if (command == 'reply-all') if (command == 'reply-all')
// do reply-list, when list is detected and popup menu wasn't used // do reply-list, when list is detected and popup menu wasn't used
url += '&_all=' + (!props && this.commands['reply-list'] ? 'list' : 'all'); url += '&_all=' + (!props && this.commands['reply-list'] ? 'list' : 'all');
@ -936,7 +951,6 @@ function rcube_webmail()
case 'forward-attachment': case 'forward-attachment':
case 'forward': case 'forward':
var uid, url;
if (uid = this.get_single_uid()) { if (uid = this.get_single_uid()) {
url = '_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox); url = '_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
if (command == 'forward-attachment' || (!props && this.env.forward_attachment)) if (command == 'forward-attachment' || (!props && this.env.forward_attachment))
@ -946,7 +960,6 @@ function rcube_webmail()
break; break;
case 'print': case 'print':
var uid;
if (uid = this.get_single_uid()) { if (uid = this.get_single_uid()) {
ref.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : '')); ref.printwin = window.open(this.env.comm_path+'&_action=print&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(this.env.safemode ? '&_safe=1' : ''));
if (this.printwin) { if (this.printwin) {
@ -958,7 +971,6 @@ function rcube_webmail()
break; break;
case 'viewsource': case 'viewsource':
var uid;
if (uid = this.get_single_uid()) { if (uid = this.get_single_uid()) {
ref.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)); ref.sourcewin = window.open(this.env.comm_path+'&_action=viewsource&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox));
if (this.sourcewin) if (this.sourcewin)
@ -967,7 +979,6 @@ function rcube_webmail()
break; break;
case 'download': case 'download':
var uid;
if (uid = this.get_single_uid()) if (uid = this.get_single_uid())
this.goto_url('viewsource', '&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+'&_save=1'); this.goto_url('viewsource', '&_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+'&_save=1');
break; break;
@ -1064,10 +1075,10 @@ function rcube_webmail()
// set command(s) enabled or disabled // set command(s) enabled or disabled
this.enable_command = function() this.enable_command = function()
{ {
var args = Array.prototype.slice.call(arguments), var i, n, args = Array.prototype.slice.call(arguments),
enable = args.pop(), cmd; enable = args.pop(), cmd;
for (var n=0; n<args.length; n++) { for (n=0; n<args.length; n++) {
cmd = args[n]; cmd = args[n];
// argument of type array // argument of type array
if (typeof cmd === 'string') { if (typeof cmd === 'string') {
@ -1076,7 +1087,7 @@ function rcube_webmail()
} }
// push array elements into commands array // push array elements into commands array
else { else {
for (var i in cmd) for (i in cmd)
args.push(cmd[i]); args.push(cmd[i]);
} }
} }
@ -1203,6 +1214,24 @@ function rcube_webmail()
this.http_post('save-pref', request); this.http_post('save-pref', request);
}; };
this.html_identifier = function(str, encode)
{
str = String(str);
if (encode)
return Base64.encode(str).replace(/=+$/, '').replace(/\+/g, '-').replace(/\//g, '_');
else
return str.replace(this.identifier_expr, '_');
};
this.html_identifier_decode = function(str)
{
str = String(str).replace(/-/g, '+').replace(/_/g, '/');
while (str.length % 4) str += '=';
return Base64.decode(str);
};
/*********************************************************/ /*********************************************************/
/********* event handling methods *********/ /********* event handling methods *********/
@ -1249,13 +1278,14 @@ function rcube_webmail()
this.initialBodyScrollTop = bw.ie ? 0 : window.pageYOffset; this.initialBodyScrollTop = bw.ie ? 0 : window.pageYOffset;
this.initialListScrollTop = this.gui_objects.folderlist.parentNode.scrollTop; this.initialListScrollTop = this.gui_objects.folderlist.parentNode.scrollTop;
var li, pos, list, height; var k, li, height,
list = $(this.gui_objects.folderlist); list = $(this.gui_objects.folderlist);
pos = list.offset(); pos = list.offset();
this.env.folderlist_coords = { x1:pos.left, y1:pos.top, x2:pos.left + list.width(), y2:pos.top + list.height() }; this.env.folderlist_coords = { x1:pos.left, y1:pos.top, x2:pos.left + list.width(), y2:pos.top + list.height() };
this.env.folder_coords = []; this.env.folder_coords = [];
for (var k in model) { for (k in model) {
if (li = this.get_folder_li(k)) { if (li = this.get_folder_li(k)) {
// only visible folders // only visible folders
if (height = li.firstChild.offsetHeight) { if (height = li.firstChild.offsetHeight) {
@ -1291,19 +1321,18 @@ function rcube_webmail()
this.drag_move = function(e) this.drag_move = function(e)
{ {
if (this.gui_objects.folderlist && this.env.folder_coords) { if (this.gui_objects.folderlist && this.env.folder_coords) {
// offsets to compensate for scrolling while dragging a message var k, li, div, check, oldclass,
var boffset = bw.ie ? -document.documentElement.scrollTop : this.initialBodyScrollTop; layerclass = 'draglayernormal',
var moffset = this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop; mouse = rcube_event.get_mouse_pos(e),
var toffset = -moffset-boffset; pos = this.env.folderlist_coords,
var li, div, pos, mouse, check, oldclass, // offsets to compensate for scrolling while dragging a message
layerclass = 'draglayernormal'; boffset = bw.ie ? -document.documentElement.scrollTop : this.initialBodyScrollTop,
moffset = this.initialListScrollTop-this.gui_objects.folderlist.parentNode.scrollTop;
if (this.contact_list && this.contact_list.draglayer) if (this.contact_list && this.contact_list.draglayer)
oldclass = this.contact_list.draglayer.attr('class'); oldclass = this.contact_list.draglayer.attr('class');
mouse = rcube_event.get_mouse_pos(e); mouse.y += -moffset-boffset;
pos = this.env.folderlist_coords;
mouse.y += toffset;
// if mouse pointer is outside of folderlist // if mouse pointer is outside of folderlist
if (mouse.x < pos.x1 || mouse.x >= pos.x2 || mouse.y < pos.y1 || mouse.y >= pos.y2) { if (mouse.x < pos.x1 || mouse.x >= pos.x2 || mouse.y < pos.y1 || mouse.y >= pos.y2) {
@ -1318,10 +1347,10 @@ function rcube_webmail()
} }
// over the folders // over the folders
for (var k in this.env.folder_coords) { for (k in this.env.folder_coords) {
pos = this.env.folder_coords[k]; pos = this.env.folder_coords[k];
if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2){ if (mouse.x >= pos.x1 && mouse.x < pos.x2 && mouse.y >= pos.y1 && mouse.y < pos.y2){
if ((check = this.check_droptarget(k))) { if ((check = this.check_droptarget(k))) {
li = this.get_folder_li(k); li = this.get_folder_li(k);
div = $(li.getElementsByTagName('div')[0]); div = $(li.getElementsByTagName('div')[0]);
@ -1332,9 +1361,9 @@ function rcube_webmail()
this.folder_auto_expand = k; this.folder_auto_expand = k;
this.folder_auto_timer = window.setTimeout(function() { this.folder_auto_timer = window.setTimeout(function() {
rcmail.command('collapse-folder', rcmail.folder_auto_expand); rcmail.command('collapse-folder', rcmail.folder_auto_expand);
rcmail.drag_start(null); rcmail.drag_start(null);
}, 1000); }, 1000);
} else if (this.folder_auto_timer) { } else if (this.folder_auto_timer) {
window.clearTimeout(this.folder_auto_timer); window.clearTimeout(this.folder_auto_timer);
this.folder_auto_timer = null; this.folder_auto_timer = null;
@ -1360,31 +1389,29 @@ function rcube_webmail()
} }
}; };
this.collapse_folder = function(id) this.collapse_folder = function(name)
{ {
var li = this.get_folder_li(id), var li = this.get_folder_li(name, '', true),
div = $(li.getElementsByTagName('div')[0]); div = $('div:first', li),
ul = $('ul:first', li);
if (!div || (!div.hasClass('collapsed') && !div.hasClass('expanded')))
return;
var ul = $(li.getElementsByTagName('ul')[0]);
if (div.hasClass('collapsed')) { if (div.hasClass('collapsed')) {
ul.show(); ul.show();
div.removeClass('collapsed').addClass('expanded'); div.removeClass('collapsed').addClass('expanded');
var reg = new RegExp('&'+urlencode(id)+'&'); var reg = new RegExp('&'+urlencode(name)+'&');
this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, ''); this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, '');
} }
else { else if (div.hasClass('expanded')) {
ul.hide(); ul.hide();
div.removeClass('expanded').addClass('collapsed'); div.removeClass('expanded').addClass('collapsed');
this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(id)+'&'; this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(name)+'&';
// select parent folder if one of its childs is currently selected // select parent folder if one of its childs is currently selected
if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0) if (this.env.mailbox.indexOf(name + this.env.delimiter) == 0)
this.command('list', id); this.command('list', name);
} }
else
return;
// Work around a bug in IE6 and IE7, see #1485309 // Work around a bug in IE6 and IE7, see #1485309
if (bw.ie6 || bw.ie7) { if (bw.ie6 || bw.ie7) {
@ -1396,7 +1423,7 @@ function rcube_webmail()
} }
this.command('save-pref', { name: 'collapsed_folders', value: this.env.collapsed_folders }); this.command('save-pref', { name: 'collapsed_folders', value: this.env.collapsed_folders });
this.set_unread_count_display(id, false); this.set_unread_count_display(name, false);
}; };
this.doc_mouse_up = function(e) this.doc_mouse_up = function(e)
@ -1989,7 +2016,7 @@ function rcube_webmail()
if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort)) if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort))
url += '&_refresh=1'; url += '&_refresh=1';
this.select_folder(mbox); this.select_folder(mbox, '', true);
this.env.mailbox = mbox; this.env.mailbox = mbox;
// load message list remotely // load message list remotely
@ -3349,16 +3376,8 @@ function rcube_webmail()
this.remove_from_attachment_list = function(name) this.remove_from_attachment_list = function(name)
{ {
if (this.env.attachments[name]) delete this.env.attachments[name];
delete this.env.attachments[name]; $('#'+name).remove();
if (!this.gui_objects.attachmentlist)
return false;
var list = this.gui_objects.attachmentlist.getElementsByTagName("li");
for (i=0; i<list.length; i++)
if (list[i].id == name)
this.gui_objects.attachmentlist.removeChild(list[i]);
}; };
this.remove_attachment = function(name) this.remove_attachment = function(name)
@ -3695,7 +3714,7 @@ function rcube_webmail()
return; return;
// display search results // display search results
var ul, li, text, init, var i, len, ul, li, text, init,
value = this.ksearch_value, value = this.ksearch_value,
data = this.ksearch_data, data = this.ksearch_data,
maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15; maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15;
@ -3726,8 +3745,8 @@ function rcube_webmail()
} }
// add each result line to list // add each result line to list
if (results && results.length) { if (results && (len = results.length)) {
for (i=0; i < results.length && maxlen > 0; i++) { for (i=0; i < len && maxlen > 0; i++) {
text = typeof results[i] === 'object' ? results[i].name : results[i]; text = typeof results[i] === 'object' ? results[i].name : results[i];
li = document.createElement('LI'); li = document.createElement('LI');
li.innerHTML = text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>'); li.innerHTML = text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
@ -3748,7 +3767,7 @@ function rcube_webmail()
} }
} }
if (results && results.length) if (len)
this.env.contacts = this.env.contacts.concat(results); this.env.contacts = this.env.contacts.concat(results);
// run next parallel search // run next parallel search
@ -4031,10 +4050,10 @@ function rcube_webmail()
this.delete_contacts = function() this.delete_contacts = function()
{ {
// exit if no mailbox specified or if selection is empty
var selection = this.contact_list.get_selection(), var selection = this.contact_list.get_selection(),
undelete = this.env.address_sources[this.env.source].undelete; undelete = this.env.address_sources[this.env.source].undelete;
// exit if no mailbox specified or if selection is empty
if (!(selection.length || this.env.cid) || (!undelete && !confirm(this.get_label('deletecontactconfirm')))) if (!(selection.length || this.env.cid) || (!undelete && !confirm(this.get_label('deletecontactconfirm'))))
return; return;
@ -4075,7 +4094,7 @@ function rcube_webmail()
{ {
var c, row, list = this.contact_list; var c, row, list = this.contact_list;
cid = String(cid).replace(this.identifier_expr, '_'); cid = this.html_identifier(cid);
// when in searching mode, concat cid with the source name // when in searching mode, concat cid with the source name
if (!list.rows[cid]) { if (!list.rows[cid]) {
@ -4091,7 +4110,7 @@ function rcube_webmail()
// cid change // cid change
if (newcid) { if (newcid) {
newcid = String(newcid).replace(this.identifier_expr, '_'); newcid = this.html_identifier(newcid);
row.id = 'rcmrow' + newcid; row.id = 'rcmrow' + newcid;
list.remove_row(cid); list.remove_row(cid);
list.init_row(row); list.init_row(row);
@ -4110,7 +4129,7 @@ function rcube_webmail()
var c, list = this.contact_list, var c, list = this.contact_list,
row = document.createElement('tr'); row = document.createElement('tr');
row.id = 'rcmrow'+String(cid).replace(this.identifier_expr, '_'); row.id = 'rcmrow'+this.html_identifier(cid);
row.className = 'contact'; row.className = 'contact';
if (list.in_selection(cid)) if (list.in_selection(cid))
@ -4292,7 +4311,7 @@ function rcube_webmail()
.attr('rel', prop.source+':'+prop.id) .attr('rel', prop.source+':'+prop.id)
.click(function() { return rcmail.command('listgroup', prop, this); }) .click(function() { return rcmail.command('listgroup', prop, this); })
.html(prop.name), .html(prop.name),
li = $('<li>').attr({id: 'rcmli'+key.replace(this.identifier_expr, '_'), 'class': 'contactgroup'}) li = $('<li>').attr({id: 'rcmli'+this.html_identifier(key), 'class': 'contactgroup'})
.append(link); .append(link);
this.env.contactfolders[key] = this.env.contactgroups[key] = prop; this.env.contactfolders[key] = this.env.contactgroups[key] = prop;
@ -4315,7 +4334,7 @@ function rcube_webmail()
var newkey = 'G'+prop.source+prop.newid, var newkey = 'G'+prop.source+prop.newid,
newprop = $.extend({}, prop);; newprop = $.extend({}, prop);;
li.id = String('rcmli'+newkey).replace(this.identifier_expr, '_'); li.id = 'rcmli' + this.html_identifier(newkey);
this.env.contactfolders[newkey] = this.env.contactfolders[key]; this.env.contactfolders[newkey] = this.env.contactfolders[key];
this.env.contactfolders[newkey].id = prop.newid; this.env.contactfolders[newkey].id = prop.newid;
this.env.group = prop.newid; this.env.group = prop.newid;
@ -4347,7 +4366,7 @@ function rcube_webmail()
{ {
var row, name = prop.name.toUpperCase(), var row, name = prop.name.toUpperCase(),
sibling = this.get_folder_li(prop.source), sibling = this.get_folder_li(prop.source),
prefix = 'rcmliG'+(prop.source).replace(this.identifier_expr, '_'); prefix = 'rcmliG' + this.html_identifier(prop.source);
// When renaming groups, we need to remove it from DOM and insert it in the proper place // When renaming groups, we need to remove it from DOM and insert it in the proper place
if (reloc) { if (reloc) {
@ -4580,7 +4599,7 @@ function rcube_webmail()
.attr('rel', id) .attr('rel', id)
.click(function() { return rcmail.command('listsearch', id, this); }) .click(function() { return rcmail.command('listsearch', id, this); })
.html(name), .html(name),
li = $('<li>').attr({id: 'rcmli'+key.replace(this.identifier_expr, '_'), 'class': 'contactsearch'}) li = $('<li>').attr({id: 'rcmli' + this.html_identifier(key), 'class': 'contactsearch'})
.append(link), .append(link),
prop = {name:name, id:id, li:li[0]}; prop = {name:name, id:id, li:li[0]};
@ -5151,17 +5170,18 @@ function rcube_webmail()
init_button(cmd, this.buttons[cmd][i]); init_button(cmd, this.buttons[cmd][i]);
} }
} }
// set active task button
this.set_button(this.task, 'sel');
}; };
// set button to a specific state // set button to a specific state
this.set_button = function(command, state) this.set_button = function(command, state)
{ {
var button, obj, a_buttons = this.buttons[command]; var n, button, obj, a_buttons = this.buttons[command],
len = a_buttons ? a_buttons.length : 0;
if (!a_buttons || !a_buttons.length)
return false;
for (var n=0; n<a_buttons.length; n++) { for (n=0; n<len; n++) {
button = a_buttons[n]; button = a_buttons[n];
obj = document.getElementById(button.id); obj = document.getElementById(button.id);
@ -5196,15 +5216,14 @@ function rcube_webmail()
// display a specific alttext // display a specific alttext
this.set_alttext = function(command, label) this.set_alttext = function(command, label)
{ {
if (!this.buttons[command] || !this.buttons[command].length) var n, button, obj, link, a_buttons = this.buttons[command],
return; len = a_buttons ? a_buttons.length : 0;
var button, obj, link; for (n=0; n<len; n++) {
for (var n=0; n<this.buttons[command].length; n++) { button = a_buttons[n];
button = this.buttons[command][n];
obj = document.getElementById(button.id); obj = document.getElementById(button.id);
if (button.type=='image' && obj) { if (button.type == 'image' && obj) {
obj.setAttribute('alt', this.get_label(label)); obj.setAttribute('alt', this.get_label(label));
if ((link = obj.parentNode) && link.tagName.toLowerCase() == 'a') if ((link = obj.parentNode) && link.tagName.toLowerCase() == 'a')
link.setAttribute('title', this.get_label(label)); link.setAttribute('title', this.get_label(label));
@ -5217,20 +5236,18 @@ function rcube_webmail()
// mouse over button // mouse over button
this.button_over = function(command, id) this.button_over = function(command, id)
{ {
var button, elm, a_buttons = this.buttons[command]; var n, button, obj, a_buttons = this.buttons[command],
len = a_buttons ? a_buttons.length : 0;
if (!a_buttons || !a_buttons.length)
return false;
for (var n=0; n<a_buttons.length; n++) { for (n=0; n<len; n++) {
button = a_buttons[n]; button = a_buttons[n];
if (button.id == id && button.status == 'act') { if (button.id == id && button.status == 'act') {
elm = document.getElementById(button.id); obj = document.getElementById(button.id);
if (elm && button.over) { if (obj && button.over) {
if (button.type == 'image') if (button.type == 'image')
elm.src = button.over; obj.src = button.over;
else else
elm.className = button.over; obj.className = button.over;
} }
} }
} }
@ -5239,20 +5256,18 @@ function rcube_webmail()
// mouse down on button // mouse down on button
this.button_sel = function(command, id) this.button_sel = function(command, id)
{ {
var button, elm, a_buttons = this.buttons[command]; var n, button, obj, a_buttons = this.buttons[command],
len = a_buttons ? a_buttons.length : 0;
if (!a_buttons || !a_buttons.length)
return;
for (var n=0; n<a_buttons.length; n++) { for (n=0; n<len; n++) {
button = a_buttons[n]; button = a_buttons[n];
if (button.id == id && button.status == 'act') { if (button.id == id && button.status == 'act') {
elm = document.getElementById(button.id); obj = document.getElementById(button.id);
if (elm && button.sel) { if (obj && button.sel) {
if (button.type == 'image') if (button.type == 'image')
elm.src = button.sel; obj.src = button.sel;
else else
elm.className = button.sel; obj.className = button.sel;
} }
this.buttons_sel[id] = command; this.buttons_sel[id] = command;
} }
@ -5262,26 +5277,23 @@ function rcube_webmail()
// mouse out of button // mouse out of button
this.button_out = function(command, id) this.button_out = function(command, id)
{ {
var button, elm, a_buttons = this.buttons[command]; var n, button, obj, a_buttons = this.buttons[command],
len = a_buttons ? a_buttons.length : 0;
if (!a_buttons || !a_buttons.length)
return;
for (var n=0; n<a_buttons.length; n++) { for (n=0; n<len; n++) {
button = a_buttons[n]; button = a_buttons[n];
if (button.id == id && button.status == 'act') { if (button.id == id && button.status == 'act') {
elm = document.getElementById(button.id); obj = document.getElementById(button.id);
if (elm && button.act) { if (obj && button.act) {
if (button.type == 'image') if (button.type == 'image')
elm.src = button.act; obj.src = button.act;
else else
elm.className = button.act; obj.className = button.act;
} }
} }
} }
}; };
this.focus_textfield = function(elem) this.focus_textfield = function(elem)
{ {
elem._hasfocus = true; elem._hasfocus = true;
@ -5315,14 +5327,14 @@ function rcube_webmail()
if (!this.gui_objects.message) { if (!this.gui_objects.message) {
// save message in order to display after page loaded // save message in order to display after page loaded
if (type != 'loading') if (type != 'loading')
this.pending_message = new Array(msg, type, timeout); this.pending_message = [msg, type, timeout];
return false; return false;
} }
type = type ? type : 'notice'; type = type ? type : 'notice';
var ref = this, var ref = this,
key = String(msg).replace(this.identifier_expr, '_'), key = this.html_identifier(msg),
date = new Date(), date = new Date(),
id = type + date.getTime(); id = type + date.getTime();
@ -5415,7 +5427,7 @@ function rcube_webmail()
}; };
// mark a mailbox as selected and set environment variable // mark a mailbox as selected and set environment variable
this.select_folder = function(name, prefix) this.select_folder = function(name, prefix, encode)
{ {
if (this.gui_objects.folderlist) { if (this.gui_objects.folderlist) {
var current_li, target_li; var current_li, target_li;
@ -5423,7 +5435,7 @@ function rcube_webmail()
if ((current_li = $('li.selected', this.gui_objects.folderlist))) { if ((current_li = $('li.selected', this.gui_objects.folderlist))) {
current_li.removeClass('selected').addClass('unfocused'); current_li.removeClass('selected').addClass('unfocused');
} }
if ((target_li = this.get_folder_li(name, prefix))) { if ((target_li = this.get_folder_li(name, prefix, encode))) {
$(target_li).removeClass('unfocused').addClass('selected'); $(target_li).removeClass('unfocused').addClass('selected');
} }
@ -5433,13 +5445,13 @@ function rcube_webmail()
}; };
// helper method to find a folder list item // helper method to find a folder list item
this.get_folder_li = function(name, prefix) this.get_folder_li = function(name, prefix, encode)
{ {
if (!prefix) if (!prefix)
prefix = 'rcmli'; prefix = 'rcmli';
if (this.gui_objects.folderlist) { if (this.gui_objects.folderlist) {
name = String(name).replace(this.identifier_expr, '_'); name = this.html_identifier(name, encode);
return document.getElementById(prefix+name); return document.getElementById(prefix+name);
} }
@ -5553,7 +5565,7 @@ function rcube_webmail()
{ {
var reg, link, text_obj, item, mycount, childcount, div; var reg, link, text_obj, item, mycount, childcount, div;
if (item = this.get_folder_li(mbox)) { if (item = this.get_folder_li(mbox, '', true)) {
mycount = this.env.unread_counts[mbox] ? this.env.unread_counts[mbox] : 0; mycount = this.env.unread_counts[mbox] ? this.env.unread_counts[mbox] : 0;
link = $(item).children('a').eq(0); link = $(item).children('a').eq(0);
text_obj = link.children('span.unreadcount'); text_obj = link.children('span.unreadcount');
@ -5606,16 +5618,12 @@ function rcube_webmail()
this.toggle_prefer_html = function(checkbox) this.toggle_prefer_html = function(checkbox)
{ {
var elem; $('#rcmfd_show_images').prop('disabled', !checkbox.checked).val(0);
if (elem = document.getElementById('rcmfd_addrbook_show_images'))
elem.disabled = !checkbox.checked;
}; };
this.toggle_preview_pane = function(checkbox) this.toggle_preview_pane = function(checkbox)
{ {
var elem; $('#rcmfd_preview_pane_mark_read').prop('disabled', !checkbox.checked);
if (elem = document.getElementById('rcmfd_preview_pane_mark_read'))
elem.disabled = !checkbox.checked;
}; };
// display fetched raw headers // display fetched raw headers
@ -5731,14 +5739,14 @@ function rcube_webmail()
$.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream', $.ajax({ type: 'POST', url: url, data: htmlText, contentType: 'application/octet-stream',
error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }, error: function(o, status, err) { rcmail.http_error(o, status, err, lock); },
success: function(data) { rcmail.set_busy(false, null, lock); $(document.getElementById(id)).val(data); rcmail.log(data); } success: function(data) { rcmail.set_busy(false, null, lock); $('#'+id).val(data); rcmail.log(data); }
}); });
}; };
this.plain2html = function(plainText, id) this.plain2html = function(plainText, id)
{ {
var lock = this.set_busy(true, 'converting'); var lock = this.set_busy(true, 'converting');
$(document.getElementById(id)).val(plainText ? '<pre>'+plainText+'</pre>' : ''); $('#'+id).val(plainText ? '<pre>'+plainText+'</pre>' : '');
this.set_busy(false, null, lock); this.set_busy(false, null, lock);
}; };

@ -711,3 +711,82 @@ if (bw.ie)
return obj; return obj;
} }
} }
// This code was written by Tyler Akins and has been placed in the
// public domain. It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com
var Base64 = (function () {
var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var obj = {
/**
* Encodes a string in base64
* @param {String} input The string to encode in base64.
*/
encode: function (input) {
if (typeof(window.btoa) === 'function')
return btoa(input);
var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i = 0, output = '', len = input.length;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2))
enc3 = enc4 = 64;
else if (isNaN(chr3))
enc4 = 64;
output = output
+ keyStr.charAt(enc1) + keyStr.charAt(enc2)
+ keyStr.charAt(enc3) + keyStr.charAt(enc4);
} while (i < len);
return output;
},
/**
* Decodes a base64 string.
* @param {String} input The string to decode.
*/
decode: function (input) {
if (typeof(window.atob) === 'function')
return atob(input);
var chr1, chr2, chr3, enc1, enc2, enc3, enc4, len, i = 0, output = '';
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
len = input.length;
do {
enc1 = keyStr.indexOf(input.charAt(i++));
enc2 = keyStr.indexOf(input.charAt(i++));
enc3 = keyStr.indexOf(input.charAt(i++));
enc4 = keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64)
output = output + String.fromCharCode(chr2);
if (enc4 != 64)
output = output + String.fromCharCode(chr3);
} while (i < len);
return output;
}
};
return obj;
})();

@ -22,7 +22,7 @@
// show loading page // show loading page
if (!empty($_GET['_preload'])) { if (!empty($_GET['_preload'])) {
$url = str_replace('&_preload=1', '', $_SERVER['REQUEST_URI']); $url = preg_replace('/[&?]+_preload=1/', '', $_SERVER['REQUEST_URI']);
$message = rcube_label('loadingdata'); $message = rcube_label('loadingdata');
header('Content-Type: text/html; charset=' . RCMAIL_CHARSET); header('Content-Type: text/html; charset=' . RCMAIL_CHARSET);

@ -437,14 +437,15 @@ function rcmail_user_prefs($current=null)
if (!isset($no_override['show_images'])) { if (!isset($no_override['show_images'])) {
$field_id = 'rcmfd_show_images'; $field_id = 'rcmfd_show_images';
$input_show_images = new html_select(array('name' => '_show_images', 'id' => $field_id)); $input_show_images = new html_select(array('name' => '_show_images', 'id' => $field_id,
'disabled' => !$config['prefer_html']));
$input_show_images->add(rcube_label('never'), 0); $input_show_images->add(rcube_label('never'), 0);
$input_show_images->add(rcube_label('fromknownsenders'), 1); $input_show_images->add(rcube_label('fromknownsenders'), 1);
$input_show_images->add(rcube_label('always'), 2); $input_show_images->add(rcube_label('always'), 2);
$blocks['main']['options']['show_images'] = array( $blocks['main']['options']['show_images'] = array(
'title' => html::label($field_id, Q(rcube_label('showremoteimages'))), 'title' => html::label($field_id, Q(rcube_label('showremoteimages'))),
'content' => $input_show_images->show($config['show_images']), 'content' => $input_show_images->show($config['prefer_html'] ? $config['show_images'] : 0),
); );
} }

@ -5,7 +5,8 @@ body
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif; font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif;
margin: 8px; margin: 8px;
background-color: #F6F6F6; background-color: #F6F6F6;
color: #000000; color: #000;
font-size: 12px;
} }
body.iframe body.iframe
@ -19,9 +20,10 @@ body.extwin
margin: 10px; margin: 10px;
} }
body, td, th, div, p, select, input, textarea td, th, div, p, select, input, textarea
{ {
font-size: 12px; font-size: 12px;
font-family: inherit;
} }
th th
@ -36,13 +38,13 @@ h3
a, a:active, a:visited a, a:active, a:visited
{ {
color: #000000; color: #000;
outline: none; outline: none;
} }
a.button, a.button:visited, a.tab, a.tab:visited, a.axislist a.button, a.button:visited, a.tab, a.tab:visited, a.axislist
{ {
color: #000000; color: #000;
text-decoration: none; text-decoration: none;
} }
@ -56,7 +58,7 @@ a.tab
hr hr
{ {
height: 1px; height: 1px;
background-color: #666666; background-color: #666;
border-style: none; border-style: none;
} }
@ -65,9 +67,9 @@ input[type="button"],
input[type="password"], input[type="password"],
textarea textarea
{ {
border: 1px solid #666666; border: 1px solid #666;
color: #333333; color: #333;
background-color: #ffffff; background-color: #FFF;
} }
input, textarea input, textarea

@ -55,7 +55,6 @@ class rcube_test_mailfunc extends UnitTestCase
//$this->assertNoPattern('/<style [^>]+>/', $html, "No style tags allowed"); //$this->assertNoPattern('/<style [^>]+>/', $html, "No style tags allowed");
$this->assertNoPattern('/<form [^>]+>/', $html, "No form tags allowed"); $this->assertNoPattern('/<form [^>]+>/', $html, "No form tags allowed");
$this->assertPattern('/Subscription form/', $html, "Include <form> contents"); $this->assertPattern('/Subscription form/', $html, "Include <form> contents");
$this->assertPattern('/<!-- input ignored -->/', $html, "No input elements allowed");
$this->assertPattern('/<!-- link ignored -->/', $html, "No external links allowed"); $this->assertPattern('/<!-- link ignored -->/', $html, "No external links allowed");
$this->assertPattern('/<a[^>]+ target="_blank">/', $html, "Set target to _blank"); $this->assertPattern('/<a[^>]+ target="_blank">/', $html, "Set target to _blank");
$this->assertTrue($GLOBALS['REMOTE_OBJECTS'], "Remote object detected"); $this->assertTrue($GLOBALS['REMOTE_OBJECTS'], "Remote object detected");

Loading…
Cancel
Save