diff options
author | Aleksander Machniak <alec@alec.pl> | 2013-09-20 08:18:54 +0200 |
---|---|---|
committer | Aleksander Machniak <alec@alec.pl> | 2013-09-20 08:18:54 +0200 |
commit | b334a01791689a16c8d6b10955df850b891ff40e (patch) | |
tree | 34173fc260a63a18ec56b75825cdc0925c84f594 | |
parent | 1bfd8ac27aa09421e77b629806dc9f667aa32cb6 (diff) | |
parent | c1ff572e176dc930c52063e53364daa315d34666 (diff) |
Merge branch 'master' of github.com:roundcube/roundcubemail
24 files changed, 379 insertions, 75 deletions
@@ -1,6 +1,9 @@ CHANGELOG Roundcube Webmail =========================== +- Make default font size for HTML messages configurable (request #118) +- Display full attachment name using title attribute when name is too long to display (#1489320) +- Fix XSS issue in addressbook group name field [CVE-2013-5646] (#1489333) - Fix attachment icon issue when rare font/language is used (#1489326) - After message is sent refresh messages list of replied message folder (#1489249) - Add option force specified domain in user login - username_domain_forced (#1489264) @@ -96,8 +99,8 @@ RELEASE 0.9.3 - Fix base URL resolving on attribute values with no quotes (#1489275) - Fix wrong handling of links with '|' character (#1489276) - Fix colorspace issue on image conversion using ImageMagick (#1489270) -- Fix XSS vulnerability when editing a message "as new" or draft (#1489251) -- Fix XSS vulnerability when saving HTML signatures (#1489251) +- Fix XSS vulnerability when editing a message "as new" or draft [CVE-2013-5645] (#1489251) +- Fix XSS vulnerability when saving HTML signatures [CVE-2013-5645] (#1489251) - Fix rewrite rule in .htaccess (#1489240) - Fix detecting Turkish language in ISO-8859-9 encoding (#1489252) - Fix identity-selection using Return-Path headers (#1489241) @@ -317,7 +320,7 @@ RELEASE 0.8.5 - Fix #countcontrols issue in IE<=8 when text is very long (#1488890) - Fix unwanted horizontal scrollbar in message preview header (#1488866) - Add workaround for IE<=8 bug where Content-Disposition:inline was ignored (#1488844) -- Fix XSS vulnerability in vbscript: and data:text links handling (#1488850) +- Fix XSS vulnerability in vbscript: and data:text links handling [CVE-2012-6121] (#1488850) - Fix absolute positioning in HTML messages (#1488819) - Fix cache (in)validation after setting \Deleted flag - Fix keybord events on messages list in opera browser (#1488823) @@ -372,8 +375,8 @@ RELEASE 0.8.1 - Fix bug where domain name was converted to lower-case even with login_lc=false (#1488593) - Fix lower-casing email address on replies (#1488598) - Fix line separator in exported messages (#1488603) -- Fix XSS issue where plain signatures wasn't secured in HTML mode (#1488613) -- Fix XSS issue where href="javascript:" wasn't secured (#1488613) +- Fix XSS issue where plain signatures wasn't secured in HTML mode [CVE-2012-4668] (#1488613) +- Fix XSS issue where href="javascript:" wasn't secured [CVE-2012-3508] (#1488613) - Fix impossible to create message with empty plain text part (#1488610) - Fix stripped apostrophes when replying in plain text to HTML message (#1488606) - Fix inactive Save search option after advanced search (#1488607) @@ -408,7 +411,7 @@ RELEASE 0.8.0 - Fix removing contact photo using LDAP addressbook (#1488420) - Fix storing X-ANNIVERSARY date in vCard format (#1488527) - Update to Mail_Mime-1.8.5 (#1488521) -- Fix XSS vulnerability in message subject handling using Larry skin (#1488519) +- Fix XSS vulnerability in message subject handling using Larry skin [CVE-2012-3507] (#1488519) - Fix handling of links with various URI schemes e.g. "skype:" (#1488106) - Fix handling of links inside PRE elements on html to text conversion - Fix indexing of links on html to text conversion @@ -535,7 +538,7 @@ RELEASE 0.7 - Improved handling of some malformed values encoded with quoted-printable (#1488232) - Add possibility to do LDAP bind before searching for bind DN - Fix handling of empty <U> tags in HTML messages (#1488225) -- Add content filter for embedded attachments to protect from XSS on IE (#1487895) +- Add content filter for embedded attachments to protect from XSS on IE [CVE-2012-1253] (#1487895) - Use strpos() instead of strstr() when possible (#1488211) - Fix handling HTML entities when converting HTML to text (#1488212) - Fix fit_string_to_size() renders browser and ui unresponsive (#1488207) @@ -703,7 +706,7 @@ RELEASE 0.6-beta RELEASE 0.5.4 ------------- -- Fix XSS vulnerability in UI messages (#1488030) +- Fix XSS vulnerability in UI messages [CVE-2011-2937] (#1488030) RELEASE 0.5.3 ------------- @@ -753,8 +756,8 @@ RELEASE 0.5.1 - Security: add optional referer check to prevent CSRF in GET requests - Fix email_dns_check setting not used for identities/contacts (#1487740) - Fix ICANN example addresses doesn't validate (#1487742) -- Security: protect login form submission from CSRF -- Security: prevent from relaying malicious requests through modcss.inc +- Security: protect login form submission from CSRF [CVE-2011-1491] +- Security: prevent from relaying malicious requests through modcss.inc [CVE-2011-1492] - Fix handling of non-image attachments in multipart/related messages (#1487750) - Fix IDNA support when IDN/INTL modules are in use (#1487742) - Fix handling of invalid HTML comments in messages (#1487759) @@ -1197,7 +1200,7 @@ RELEASE 0.3-RC1 --------------- - Fix import of vCard entries with params (#1485453) - Fix HTML messages output with empty block elements (#1485974) -- Use request tokens to protect POST requests from CSRF +- Use request tokens to protect POST requests from CSRF [CVE-2009-4076, CVE-2009-4077] - Added hook when killing a session - Added hook to write_log function (#1485971) - Performance improvements by use UID commands (#1485690) @@ -1324,7 +1327,7 @@ RELEASE 0.2.1 - Fix large search results on server without SORT capability (#1485668) - Get rid of preg_replace() with eval modifier and create_function usage (#1485686) - Bring back <base> and <link> tags in HTML messages -- Fix XSS vulnerability through background attributes as reported by Julien Cayssol +- Fix XSS vulnerability through background attributes [CVE-2009-0413] - Fix problems with backslash as IMAP hierarchy delimiter (#1484467) - Secure vcard export by getting rid of preg's 'e' modifier use (#1485689) - Fix authentication when submitting form with existing session (#1485679) diff --git a/config/defaults.inc.php b/config/defaults.inc.php index bf7c4df2a..97c8f3b25 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -245,6 +245,8 @@ $config['support_url'] = ''; // replace Roundcube logo with this image // specify an URL relative to the document root of this Roundcube installation +// an array can be used to specify different logos for specific template files, '*' for default logo +// for example array("*" => "/images/roundcube_logo.png", "messageprint" => "/images/roundcube_logo_print.png") $config['skin_logo'] = null; // automatically create a new Roundcube user when log-in the first time. @@ -982,5 +984,9 @@ $config['autocomplete_single'] = false; // Georgia, Helvetica, Impact, Tahoma, Terminal, Times New Roman, Trebuchet MS, Verdana $config['default_font'] = 'Verdana'; +// Default font size for composed HTML message. +// Supported sizes: 8pt, 10pt, 12pt, 14pt, 18pt, 24pt, 36pt +$config['default_font_size'] = '10pt'; + // Enables display of email address with name instead of a name (and address in title) $config['message_show_email'] = false; diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist index 82f6617e5..bfea52918 100644 --- a/plugins/password/config.inc.php.dist +++ b/plugins/password/config.inc.php.dist @@ -320,8 +320,7 @@ $config['hmailserver_server'] = array( // 5: domain-username // 6: username_domain // 7: domain_username -// 8: username@domain; mbox.username -$config['password_virtualmin_format'] = 8; +$config['password_virtualmin_format'] = 0; // pw_usermod Driver options diff --git a/plugins/password/drivers/virtualmin.php b/plugins/password/drivers/virtualmin.php index 2c7aee617..2d2f73f97 100644 --- a/plugins/password/drivers/virtualmin.php +++ b/plugins/password/drivers/virtualmin.php @@ -48,10 +48,6 @@ class rcube_virtualmin_password $pieces = explode("_", $username); $domain = $pieces[0]; break; - case 8: // domain taken from alias, username left as it was - $email = $rcmail->user->data['alias']; - $domain = substr(strrchr($email, "@"), 1); - break; default: // username@domain $domain = substr(strrchr($username, "@"), 1); } diff --git a/program/include/rcmail_output_html.php b/program/include/rcmail_output_html.php index a2ec29ca3..6db559358 100644 --- a/program/include/rcmail_output_html.php +++ b/program/include/rcmail_output_html.php @@ -924,8 +924,21 @@ class rcmail_output_html extends rcmail_output } else if ($object == 'logo') { $attrib += array('alt' => $this->xml_command(array('', 'object', 'name="productname"'))); - if ($logo = $this->config->get('skin_logo')) - $attrib['src'] = $logo; + + if ($logo = $this->config->get('skin_logo')) { + if (is_array($logo)) { + if ($template_logo = $logo[$this->template_name]) { + $attrib['src'] = $template_logo; + } + elseif ($template_logo = $logo['*']) { + $attrib['src'] = $template_logo; + } + } + else { + $attrib['src'] = $logo; + } + } + $content = html::img($attrib); } else if ($object == 'productname') { diff --git a/program/include/rcmail_output_json.php b/program/include/rcmail_output_json.php index def6ee42c..d0e1eec64 100644 --- a/program/include/rcmail_output_json.php +++ b/program/include/rcmail_output_json.php @@ -227,6 +227,13 @@ class rcmail_output_json extends rcmail_output if (!empty($this->callbacks)) $response['callbacks'] = $this->callbacks; + // trigger generic hook where plugins can put additional content to the response + $hook = $this->app->plugins->exec_hook("render_response", array('response' => $response)); + + // save some memory + $response = $hook['response']; + unset($hook['response']); + echo self::json_serialize($response); } diff --git a/program/js/app.js b/program/js/app.js index 42c661144..337a12156 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -1881,7 +1881,7 @@ function rcube_webmail() html = expando; else if (c == 'subject') { if (bw.ie) { - col.onmouseover = function() { rcube_webmail.long_subject_title_ie(this, message.depth+1); }; + col.onmouseover = function() { rcube_webmail.long_subject_title_ex(this, message.depth+1); }; if (bw.ie8) tree = '<span></span>' + tree; // #1487821 } @@ -3427,7 +3427,8 @@ function rcube_webmail() message = input_message.val(), is_html = ($("input[name='_is_html']").val() == '1'), sig = this.env.identity, - delim = this.env.recipients_delimiter, + delim = this.env.recipients_separator, + rx_delim = RegExp.escape(delim), headers = ['replyto', 'bcc']; // update reply-to/bcc fields with addresses defined in identities @@ -3444,16 +3445,18 @@ function rcube_webmail() } // cleanup - rx = new RegExp(RegExp.escape(delim) + '\\s*' + RegExp(delim), 'g'); - input_val = input_val.replace(rx, delim) - rx = new RegExp('^\\s*' + RegExp.escape(delim) + '\\s*$'); - input_val = input_val.replace(rx, '') + rx = new RegExp(rx_delim + '\\s*' + rx_delim, 'g'); + input_val = input_val.replace(rx, delim); + rx = new RegExp('^[\\s' + rx_delim + ']+'); + input_val = input_val.replace(rx, ''); // add new address(es) - if (new_val) { - rx = new RegExp(RegExp.escape(delim) + '\\s*$'); - if (input_val && !rx.test(input_val)) - input_val += delim + ' '; + if (new_val && input_val.indexOf(new_val) == -1 && input_val.indexOf(new_val.replace(/"/g, '')) == -1) { + if (input_val) { + rx = new RegExp('[' + rx_delim + '\\s]+$') + input_val = input_val.replace(rx, '') + delim + ' '; + } + input_val += new_val + delim + ' '; } @@ -3639,7 +3642,12 @@ function rcube_webmail() att.html = '<a title="'+this.get_label('cancel')+'" onclick="return rcmail.cancel_attachment_upload(\''+name+'\', \''+att.frame+'\');" href="#cancelupload" class="cancelupload">' + (this.env.cancelicon ? '<img src="'+this.env.cancelicon+'" alt="" />' : this.get_label('cancel')) + '</a>' + att.html; - var indicator, li = $('<li>').attr('id', name).addClass(att.classname).html(att.html); + var indicator, li = $('<li>'); + + li.attr('id', name) + .addClass(att.classname) + .html(att.html) + .on('mouseover', function() { rcube_webmail.long_subject_title_ex(this, 0); }); // replace indicator's li if (upload_id && (indicator = document.getElementById(upload_id))) { @@ -4345,7 +4353,7 @@ function rcube_webmail() boxtitle.append(' » '); } - boxtitle.append($('<span>'+prop.name+'</span>')); + boxtitle.append($('<span>').text(prop.name)); } this.triggerEvent('groupupdate', prop); @@ -6986,11 +6994,11 @@ rcube_webmail.long_subject_title = function(elem, indent) if (!elem.title) { var $elem = $(elem); if ($elem.width() + indent * 15 > $elem.parent().width()) - elem.title = $elem.html(); + elem.title = $elem.text(); } }; -rcube_webmail.long_subject_title_ie = function(elem, indent) +rcube_webmail.long_subject_title_ex = function(elem, indent) { if (!elem.title) { var $elem = $(elem), diff --git a/program/js/editor.js b/program/js/editor.js index e403d1f63..e1ef36835 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -80,6 +80,9 @@ function rcmail_editor_callback() if (rcmail.env.default_font) $(tinyMCE.get(rcmail.env.composebody).getBody()).css('font-family', rcmail.env.default_font); + if (rcmail.env.default_font_size) + $(tinyMCE.get(rcmail.env.composebody).getBody()).css('font-size', rcmail.env.default_font_size); + if (elem && elem.type == 'select-one') { rcmail.change_identity(elem); // Focus previously focused element diff --git a/program/lib/Roundcube/rcube_config.php b/program/lib/Roundcube/rcube_config.php index ac3ea678c..a3741758f 100644 --- a/program/lib/Roundcube/rcube_config.php +++ b/program/lib/Roundcube/rcube_config.php @@ -214,7 +214,7 @@ class rcube_config $success = true; } // deprecated name of config variable - else if (is_array($rcmail_config)) { + if (is_array($rcmail_config)) { $this->merge($rcmail_config); $success = true; } diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc index f83f6892e..85aa9542b 100644 --- a/program/steps/mail/attachments.inc +++ b/program/steps/mail/attachments.inc @@ -118,9 +118,12 @@ if (is_array($_FILES['_attachments']['tmp_name'])) { 'alt' => rcube_label('delete') )); } - else { + else if ($COMPOSE['textbuttons']) { $button = Q(rcube_label('delete')); } + else { + $button = ''; + } $content = html::a(array( 'href' => "#delete", diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index e9f638cb1..30c9f79fb 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -148,6 +148,9 @@ if ($font && !is_array($font)) { $OUTPUT->set_env('default_font', $font); } +// default font size for HTML editor +$OUTPUT->set_env('default_font_size', $RCMAIL->config->get('default_font_size')); + // get reference message and set compose mode if ($msg_uid = $COMPOSE['param']['draft_uid']) { $compose_mode = RCUBE_COMPOSE_DRAFT; @@ -1370,8 +1373,9 @@ function rcmail_compose_attachment_list($attrib) if (!$attrib['id']) $attrib['id'] = 'rcmAttachmentList'; - $out = "\n"; + $out = "\n"; $jslist = array(); + $button = ''; if (is_array($COMPOSE['attachments'])) { if ($attrib['deleteicon']) { @@ -1380,27 +1384,38 @@ function rcmail_compose_attachment_list($attrib) 'alt' => rcube_label('delete') )); } - else + else if (rcube_utils::get_boolean($attrib['textbuttons'])) { $button = Q(rcube_label('delete')); + } foreach ($COMPOSE['attachments'] as $id => $a_prop) { if (empty($a_prop)) continue; - $out .= html::tag('li', array('id' => 'rcmfile'.$id, 'class' => rcmail_filetype2classname($a_prop['mimetype'], $a_prop['name'])), + $out .= html::tag('li', + array( + 'id' => 'rcmfile'.$id, + 'class' => rcmail_filetype2classname($a_prop['mimetype'], $a_prop['name']), + 'onmouseover' => "rcube_webmail.long_subject_title_ex(this, 0)", + ), html::a(array( 'href' => "#delete", 'title' => rcube_label('delete'), 'onclick' => sprintf("return %s.command('remove-attachment','rcmfile%s', this)", JS_OBJECT_NAME, $id), - 'class' => 'delete'), - $button) . Q($a_prop['name'])); + 'class' => 'delete' + ), + $button + ) . Q($a_prop['name']) + ); - $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']); + $jslist['rcmfile'.$id] = array('name' => $a_prop['name'], 'complete' => true, 'mimetype' => $a_prop['mimetype']); } } if ($attrib['deleteicon']) $COMPOSE['deleteicon'] = $CONFIG['skin_path'] . $attrib['deleteicon']; + else if (rcube_utils::get_boolean($attrib['textbuttons'])) + $COMPOSE['textbuttons'] = true; if ($attrib['cancelicon']) $OUTPUT->set_env('cancelicon', $CONFIG['skin_path'] . $attrib['cancelicon']); if ($attrib['loadingicon']) diff --git a/program/steps/mail/sendmail.inc b/program/steps/mail/sendmail.inc index 779fb87cd..3f4475e46 100644 --- a/program/steps/mail/sendmail.inc +++ b/program/steps/mail/sendmail.inc @@ -473,8 +473,9 @@ $isHtml = (bool) get_input_value('_is_html', RCUBE_INPUT_POST); $message_body = get_input_value('_message', RCUBE_INPUT_POST, TRUE, $message_charset); if ($isHtml) { - $font = rcube_fontdefs($RCMAIL->config->get('default_font')); - $bstyle = $font && is_string($font) ? " style='font-family: $font'" : ''; + $font_family = rcube_fontdefs($RCMAIL->config->get('default_font', 'Arial')); + $font_size = $RCMAIL->config->get('default_font_size'); + $bstyle = ' style="font:' . $font_size . ' ' . $font_family . ';"'; // append doctype and html/body wrappers $message_body = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">' . diff --git a/program/steps/mail/show.inc b/program/steps/mail/show.inc index 59f4d55e1..9d85f9c8f 100644 --- a/program/steps/mail/show.inc +++ b/program/steps/mail/show.inc @@ -175,9 +175,9 @@ function rcmail_message_attachments($attrib) $ol .= html::tag('li', null, Q(sprintf("%s (%s)", $filename, $size))); } else { - if (mb_strlen($filename) > 50) { + if ($attrib['maxlength'] && mb_strlen($filename) > $attrib['maxlength']) { $title = $filename; - $filename = abbreviate_string($filename, 50); + $filename = abbreviate_string($filename, $attrib['maxlength']); } else { $title = ''; @@ -190,6 +190,7 @@ function rcmail_message_attachments($attrib) 'href' => $MESSAGE->get_part_url($attach_prop->mime_id, false), 'onclick' => sprintf('return %s.command(\'load-attachment\',\'%s\',this)', JS_OBJECT_NAME, $attach_prop->mime_id), + 'onmouseover' => $title ? '' : 'rcube_webmail.long_subject_title_ex(this, 0)', 'title' => Q($title), ), Q($filename)); $ol .= html::tag('li', array('class' => $class, 'id' => $id), $link); diff --git a/program/steps/settings/edit_prefs.inc b/program/steps/settings/edit_prefs.inc index 468e4994d..adf6b1623 100644 --- a/program/steps/settings/edit_prefs.inc +++ b/program/steps/settings/edit_prefs.inc @@ -40,24 +40,21 @@ function rcmail_user_prefs_form($attrib) $out = $form_start; - foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $block) { + foreach ($SECTIONS[$CURR_SECTION]['blocks'] as $class => $block) { if (!empty($block['options'])) { $table = new html_table(array('cols' => 2)); foreach ($block['options'] as $option) { - if ($option['advanced']) - $table->set_row_attribs('advanced'); - if (isset($option['title'])) { $table->add('title', $option['title']); - $table->add(null, $option['content']); + $table->add(null, $option['content']); } else { $table->add(array('colspan' => 2), $option['content']); } } - $out .= html::tag('fieldset', null, html::tag('legend', null, $block['name']) . $table->show($attrib)); + $out .= html::tag('fieldset', $class, html::tag('legend', null, $block['name']) . $table->show($attrib)); } else if (!empty($block['content'])) { $out .= html::tag('fieldset', null, html::tag('legend', null, $block['name']) . $block['content']); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index fdc07be9e..53c98eddf 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -158,6 +158,7 @@ function rcmail_user_prefs($current = null) 'main' => array('name' => Q(rcube_label('mainoptions'))), 'skin' => array('name' => Q(rcube_label('skin'))), 'browser' => array('name' => Q(rcube_label('browseroptions'))), + 'advanced'=> array('name' => Q(rcube_label('advancedoptions'))), ); // language selection @@ -367,6 +368,7 @@ function rcmail_user_prefs($current = null) $blocks = array( 'main' => array('name' => Q(rcube_label('mainoptions'))), 'new_message' => array('name' => Q(rcube_label('newmessage'))), + 'advanced' => array('name' => Q(rcube_label('advancedoptions'))), ); // show config parameter for preview pane @@ -488,6 +490,7 @@ function rcmail_user_prefs($current = null) case 'mailview': $blocks = array( 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'advanced' => array('name' => Q(rcube_label('advancedoptions'))), ); // show checkbox to open message view in new window @@ -543,7 +546,7 @@ function rcmail_user_prefs($current = null) $field_id = 'rcmfd_default_charset'; - $blocks['main']['options']['default_charset'] = array( + $blocks['advanced']['options']['default_charset'] = array( 'title' => html::label($field_id, Q(rcube_label('defaultcharset'))), 'content' => $RCMAIL->output->charset_selector(array( 'id' => $field_id, 'name' => '_default_charset', 'selected' => $config['default_charset'] @@ -605,6 +608,7 @@ function rcmail_user_prefs($current = null) 'main' => array('name' => Q(rcube_label('mainoptions'))), 'sig' => array('name' => Q(rcube_label('signatureoptions'))), 'spellcheck' => array('name' => Q(rcube_label('spellcheckoptions'))), + 'advanced' => array('name' => Q(rcube_label('advancedoptions'))), ); // show checkbox to compose messages in a new window @@ -673,8 +677,7 @@ function rcmail_user_prefs($current = null) $select->add(rcube_label('miscfolding'), 1); $select->add(rcube_label('2047folding'), 2); - $blocks['main']['options']['mime_param_folding'] = array( - 'advanced' => true, + $blocks['advanced']['options']['mime_param_folding'] = array( 'title' => html::label($field_id, Q(rcube_label('mimeparamfolding'))), 'content' => $select->show($config['mime_param_folding']), ); @@ -688,8 +691,7 @@ function rcmail_user_prefs($current = null) $field_id = 'rcmfd_force_7bit'; $input = new html_checkbox(array('name' => '_force_7bit', 'id' => $field_id, 'value' => 1)); - $blocks['main']['options']['force_7bit'] = array( - 'advanced' => true, + $blocks['advanced']['options']['force_7bit'] = array( 'title' => html::label($field_id, Q(rcube_label('force7bit'))), 'content' => $input->show($config['force_7bit']?1:0), ); @@ -842,23 +844,28 @@ function rcmail_user_prefs($current = null) continue 2; } + // Default font size + $field_id = 'rcmfd_default_font_size'; + $select_default_font_size = new html_select(array('name' => '_default_font_size', 'id' => $field_id)); + + $fontsizes = array('8pt', '10pt', '12pt', '14pt', '18pt', '24pt', '36pt'); + foreach ($fontsizes as $size) { + $select_default_font_size->add($size, $size); + } + + // Default font $field_id = 'rcmfd_default_font'; - $fonts = rcube_fontdefs(); - $selected = $config['default_font']; + $select_default_font = new html_select(array('name' => '_default_font', 'id' => $field_id)); - $select = '<select name="_default_font" id="'.$field_id.'">'; - $select .= '<option value=""' . (!$selected ? ' selected="selected"' : '') . '>---</option>'; + $fonts = rcube_fontdefs(); foreach ($fonts as $fname => $font) { - $select .= '<option value="'.$fname.'"' - . ($fname == $selected ? ' selected="selected"' : '') - . ' style=\'font-family: ' . $font . '\'>' - . Q($fname) . '</option>'; + $select_default_font->add($fname, $fname); } - $select .= '</select>'; $blocks['main']['options']['default_font'] = array( 'title' => html::label($field_id, Q(rcube_label('defaultfont'))), - 'content' => $select + 'content' => $select_default_font->show($RCMAIL->config->get('default_font', 1)) . + $select_default_font_size->show($RCMAIL->config->get('default_font_size', 1)) ); } break; @@ -866,7 +873,8 @@ function rcmail_user_prefs($current = null) // Addressbook config case 'addressbook': $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'advanced' => array('name' => Q(rcube_label('advancedoptions'))), ); if (!isset($no_override['default_addressbook']) @@ -962,7 +970,8 @@ function rcmail_user_prefs($current = null) // Special IMAP folders case 'folders': $blocks = array( - 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'main' => array('name' => Q(rcube_label('mainoptions'))), + 'advanced' => array('name' => Q(rcube_label('advancedoptions'))), ); if (!isset($no_override['show_real_foldernames'])) { @@ -1043,6 +1052,7 @@ function rcmail_user_prefs($current = null) $blocks = array( 'main' => array('name' => Q(rcube_label('mainoptions'))), 'maintenance' => array('name' => Q(rcube_label('maintenance'))), + 'advanced' => array('name' => Q(rcube_label('advancedoptions'))), ); if (!isset($no_override['read_when_deleted'])) { diff --git a/program/steps/settings/save_prefs.inc b/program/steps/settings/save_prefs.inc index 3e8b1d17e..717c7ad8c 100644 --- a/program/steps/settings/save_prefs.inc +++ b/program/steps/settings/save_prefs.inc @@ -89,6 +89,7 @@ switch ($CURR_SECTION) 'reply_mode' => isset($_POST['_reply_mode']) ? intval($_POST['_reply_mode']) : 0, 'strip_existing_sig' => isset($_POST['_strip_existing_sig']), 'default_font' => get_input_value('_default_font', RCUBE_INPUT_POST), + 'default_font_size' => get_input_value('_default_font_size', RCUBE_INPUT_POST), 'forward_attachment' => !empty($_POST['_forward_attachment']), ); diff --git a/skins/classic/mail.css b/skins/classic/mail.css index f712069be..43367749c 100644 --- a/skins/classic/mail.css +++ b/skins/classic/mail.css @@ -1594,9 +1594,7 @@ input.from_address height: 18px; line-height: 16px; font-size: 11px; - padding-left: 2px; - padding-top: 2px; - padding-right: 4px; + padding: 2px 2px 1px 2px; border-bottom: 1px solid #EBEBEB; white-space: nowrap; overflow: hidden; @@ -1609,8 +1607,10 @@ input.from_address text-indent: -5000px; width: 17px; height: 16px; + padding-bottom: 2px; display: inline-block; text-decoration: none; + vertical-align: middle; } #compose-attachments li img diff --git a/skins/classic/templates/message.html b/skins/classic/templates/message.html index 757c0a635..bd4fbf277 100644 --- a/skins/classic/templates/message.html +++ b/skins/classic/templates/message.html @@ -49,7 +49,7 @@ </div> <roundcube:object name="messageHeaders" class="headers-table" cellspacing="0" cellpadding="2" addicon="/images/icons/silhouette.png" summary="Message headers" /> <roundcube:object name="messageFullHeaders" id="full-headers" /> -<roundcube:object name="messageAttachments" id="attachment-list" /> +<roundcube:object name="messageAttachments" id="attachment-list" maxlength="50" /> <roundcube:object name="messageObjects" id="message-objects" /> <roundcube:object name="messageBody" id="messagebody" /> </div> diff --git a/skins/classic/templates/messagepreview.html b/skins/classic/templates/messagepreview.html index b42a06342..82414c420 100644 --- a/skins/classic/templates/messagepreview.html +++ b/skins/classic/templates/messagepreview.html @@ -20,7 +20,7 @@ </div> <roundcube:object name="messageHeaders" class="headers-table" cellspacing="0" cellpadding="2" addicon="/images/icons/silhouette.png" summary="Message headers" /> <roundcube:object name="messageFullHeaders" id="full-headers" /> -<roundcube:object name="messageAttachments" id="attachment-list" /> +<roundcube:object name="messageAttachments" id="attachment-list" maxlength="50" /> </div> <roundcube:object name="messageObjects" id="message-objects" /> diff --git a/skins/larry/addressbook.css b/skins/larry/addressbook.css index 6bf9426c4..39d0cce21 100644 --- a/skins/larry/addressbook.css +++ b/skins/larry/addressbook.css @@ -387,3 +387,8 @@ a.deletebutton { overflow: auto; padding: 10px; } + +#import-box p, +#import-box .propform { + max-width: 50em; +} diff --git a/skins/larry/settings.css b/skins/larry/settings.css index 59037ac76..6afa48c40 100644 --- a/skins/larry/settings.css +++ b/skins/larry/settings.css @@ -48,6 +48,26 @@ border-radius: 4px 4px 0 0; } +#preferences-details fieldset.advanced legend { + position: relative; + display: block; + width: 100%; + cursor: pointer; +} + +#preferences-details fieldset.advanced .propform { + display: none; +} + +#preferences-details fieldset.advanced .advanced-toggle { + position: absolute; + top: 2px; + right: 6px; + text-decoration: none; + color: #666; + font-size: 11px; +} + #sections-table tbody td.section, #settings-sections span.listitem a, #settings-sections span.tablink a { diff --git a/skins/larry/templates/importcontacts.html b/skins/larry/templates/importcontacts.html index d3d0f2b93..69b138b9a 100644 --- a/skins/larry/templates/importcontacts.html +++ b/skins/larry/templates/importcontacts.html @@ -18,7 +18,7 @@ <h2 class="boxtitle"><roundcube:label name="importcontacts" /></h2> <div id="import-box" class="boxcontent"> -<roundcube:object name="importstep" /> +<roundcube:object name="importstep" class="propform" /> <br/> <p class="formbuttons"> <roundcube:object name="importnav" class="button" /> diff --git a/skins/larry/ui.js b/skins/larry/ui.js index ae14d81b2..d558f16a2 100644 --- a/skins/larry/ui.js +++ b/skins/larry/ui.js @@ -195,6 +195,19 @@ function rcube_mail_ui() new rcube_splitter({ id:'prefviewsplitter', p1:'#sectionslist', p2:'#preferences-box', orientation:'v', relative:true, start:266, min:180, size:12 }).init(); } + else if (rcmail.env.action == 'edit-prefs') { + $('<a href="#toggle">▼</a>') + .addClass('advanced-toggle') + .appendTo('#preferences-details fieldset.advanced legend'); + + $('#preferences-details fieldset.advanced legend').click(function(e){ + var collapsed = $(this).hasClass('collapsed'), + toggle = $('.advanced-toggle', this).html(collapsed ? '▲' : '▼'); + $(this) + .toggleClass('collapsed') + .closest('fieldset').children('.propform').toggle() + }).addClass('collapsed') + } } /*** addressbook task ***/ else if (rcmail.env.task == 'addressbook') { diff --git a/tests/Framework/Browser.php b/tests/Framework/Browser.php index c3860d8a3..832d4bf14 100644 --- a/tests/Framework/Browser.php +++ b/tests/Framework/Browser.php @@ -17,4 +17,207 @@ class Framework_Browser extends PHPUnit_Framework_TestCase $this->assertInstanceOf('rcube_browser', $object, "Class constructor"); } + + /** + * @dataProvider browsers + */ + function test_browser($useragent, $opera, $chrome, $ie, $ns, $ns4, $khtml, $safari, $mz) + { + + $object = $this->getBrowser($useragent); + + $this->assertEquals($opera, $object->opera, 'Check for Opera failed'); + $this->assertEquals($chrome, $object->chrome, 'Check for Chrome failed'); + $this->assertEquals($ie, $object->ie, 'Check for IE failed'); + $this->assertEquals($ns, $object->ns, 'Check for NS failed'); + $this->assertEquals($ns4, $object->ns4, 'Check for NS4 failed'); + $this->assertEquals($khtml, $object->khtml, 'Check for khtml failed'); + $this->assertEquals($safari, $object->safari, 'Check for Safari failed'); + $this->assertEquals($mz, $object->mz, 'Check for MZ failed'); + } + + /** + * @dataProvider os + */ + function test_os($useragent, $windows, $linux, $unix, $mac) + { + $object = $this->getBrowser($useragent); + + $this->assertEquals($windows, $object->win, 'Check Result of Windows'); + $this->assertEquals($linux, $object->linux, 'Check Result of Linux'); + $this->assertEquals($mac, $object->mac, 'Check Result of Mac'); + $this->assertEquals($unix, $object->unix, 'Check Result of Unix'); + + } + + /** + * @dataProvider versions + */ + function test_version($useragent, $version) + { + $object = $this->getBrowser($useragent); + $this->assertEquals($version, $object->ver); + } + + /** + * @dataProvider dom + */ + function test_dom($useragent, $dom) + { + $object = $this->getBrowser($useragent); + $this->assertEquals($dom, $object->dom); + + } + + /** + * @dataProvider pngalpha + */ + function test_pngalpha($useragent, $pngalpha) + { + $object = $this->getBrowser($useragent); + $this->assertEquals($pngalpha, $object->pngalpha); + } + + /** + * @dataProvider imgdata + */ + function test_imgdata($useragent, $imgdata) + { + $object = $this->getBrowser($useragent); + $this->assertEquals($imgdata, $object->imgdata); + } + + function versions() + { + return $this->extractDataSet(array('version')); + } + + function pngalpha() + { + return $this->extractDataSet(array('canPNGALPHA')); + } + + function imgdata() + { + return $this->extractDataSet(array('canIMGDATA')); + } + + private function extractDataSet($keys) + { + $keys = array_merge(array('useragent'), $keys); + + $browser = $this->useragents(); + + $extracted = array(); + + foreach ($browser as $label => $data) { + foreach($keys as $key) { + $extracted[$data['useragent']][] = $data[$key]; + } + + } + + return $extracted; + } + + function lang() + { + return $this->extractDataSet(array('lang')); + } + + function dom() + { + return $this->extractDataSet(array('hasDOM')); + } + + function browsers() + { + return $this->extractDataSet(array('isOpera','isChrome','isIE','isNS','isNS4','isKHTML','isSafari','isMZ')); + } + + function useragents() + { + return array( + 'WIN: Mozilla Firefox ' => array( + 'useragent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.1) Gecko/20060111 Firefox/1.5.0.1', + 'version' => '1.8', //Version + 'isWin' => true, //isWindows + 'isLinux' => false, + 'isMac' => false, //isMac + 'isUnix' => false, //isUnix + 'isOpera' => false, //isOpera + 'isChrome' => false, //isChrome + 'isIE' => false, //isIE + 'isNS' => false, //isNS + 'isNS4' => false, //isNS4 + 'isKHTML' => false, //isKHTML + 'isSafari' => false, //isSafari + 'isMZ' => true, //isMZ + 'lang' => 'en-US', //lang + 'hasDOM' => true, //hasDOM + 'canPNGALPHA' => true, //canPNGALPHA + 'canIMGDATA' => true, //canIMGDATA + ), + 'LINUX: Bon Echo ' => array( + 'useragent' => 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.1) Gecko/20070222 BonEcho/2.0.0.1', + 'version' => '1.8', //Version + 'isWin' => false, //isWindows + 'isLinux' => true, + 'isMac' => false, //isMac + 'isUnix' => false, //isUnix + 'isOpera' => false, //isOpera + 'isChrome' => false, //isChrome + 'isIE' => false, //isIE + 'isNS' => false, //isNS + 'isNS4' => false, //isNS4 + 'isKHTML' => false, //isKHTML + 'isSafari' => false, //isSafari + 'isMZ' => true, //isMZ + 'lang' => 'en-US', //lang + 'hasDOM' => true, //hasDOM + 'canPNGALPHA' => true, //canPNGALPHA + 'canIMGDATA' => true, //canIMGDATA + ), + + 'Chrome Mac' => array( + 'useragent' => 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.3 (KHTML, like Gecko) Chrome/6.0.461.0 Safari/534.3', + 'version' => '5', //Version + 'isWin' => false, //isWindows + 'isLinux' => false, + 'isMac' => true, //isMac + 'isUnix' => false, //isUnix + 'isOpera' => false, //isOpera + 'isChrome' => true, //isChrome + 'isIE' => false, //isIE + 'isNS' => false, //isNS + 'isNS4' => false, //isNS4 + 'isKHTML' => true, //isKHTML + 'isSafari' => false, //isSafari + 'isMZ' => false, //isMZ + 'lang' => 'en-US', //lang + 'hasDOM' => false, //hasDOM + 'canPNGALPHA' => false, //canPNGALPHA + 'canIMGDATA' => true, //canIMGDATA + ), + ); + } + + function os() + { + return $this->extractDataSet(array('isWin','isLinux','isUnix','isMac')); + } + + /** + * @param string $useragent + * @return rcube_browser + */ + private function getBrowser($useragent) + { + /** @var $object rcube_browser */ + $_SERVER['HTTP_USER_AGENT'] = $useragent; + + $object = new rcube_browser(); + + return $object; + } } |