From 86df1529feb4b7eb1a9721baa194518bacbfd8ff Mon Sep 17 00:00:00 2001 From: thomascube Date: Fri, 29 Dec 2006 21:06:39 +0000 Subject: Error handling for attachment uploads; multibyte-safe string functions; XSS improvements --- program/include/main.inc | 5 +- program/include/rcube_shared.inc | 114 ++++++++++++++++++++++++++------ program/localization/de_CH/labels.inc | 6 ++ program/localization/de_CH/messages.inc | 6 ++ program/localization/en_US/messages.inc | 4 ++ program/steps/mail/compose.inc | 12 ++-- program/steps/mail/func.inc | 2 +- program/steps/mail/upload.inc | 10 +++ 8 files changed, 132 insertions(+), 27 deletions(-) (limited to 'program') diff --git a/program/include/main.inc b/program/include/main.inc index a1c00d340..f04636a4d 100644 --- a/program/include/main.inc +++ b/program/include/main.inc @@ -400,7 +400,7 @@ function load_gui() // set localization charset based on the given language function rcmail_set_locale($lang) { - global $OUTPUT, $MBSTRING; + global $OUTPUT, $CHARSET, $MBSTRING; static $s_mbstring_loaded = NULL; // settings for mbstring module (by Tadashi Jokagi) @@ -408,6 +408,9 @@ function rcmail_set_locale($lang) $MBSTRING = $s_mbstring_loaded = extension_loaded("mbstring"); else $MBSTRING = $s_mbstring_loaded = FALSE; + + if ($MBSTRING) + mb_internal_encoding($CHARSET); $OUTPUT->set_charset(rcube_language_prop($lang, 'charset')); } diff --git a/program/include/rcube_shared.inc b/program/include/rcube_shared.inc index 4200a914a..20c806270 100644 --- a/program/include/rcube_shared.inc +++ b/program/include/rcube_shared.inc @@ -5,7 +5,7 @@ | rcube_shared.inc | | | | This file is part of the RoundCube PHP suite | - | Copyright (C) 2005, RoundCube Dev. - Switzerland | + | Copyright (C) 2005-2006, RoundCube Dev. - Switzerland | | Licensed under the GNU GPL | | | | CONTENTS: | @@ -129,7 +129,7 @@ class rcube_html_page $output = empty($templ) ? $this->default_template : trim($templ); // set default page title - if (!strlen($this->title)) + if (empty($this->title)) $this->title = 'RoundCube Mail'; // replace specialchars in content @@ -158,7 +158,7 @@ class rcube_html_page } } - if (strlen($this->scripts['head'])) + if (!empty($this->scripts['head'])) $__page_header .= sprintf($this->script_tag, $this->scripts['head']); if (is_array($this->script_files['foot'])) @@ -167,7 +167,7 @@ class rcube_html_page $__page_footer .= sprintf($this->script_tag_file, $this->scripts_path, $file); } - if (strlen($this->scripts['foot'])) + if (!empty($this->scripts['foot'])) $__page_footer .= sprintf($this->script_tag, $this->scripts['foot']); if ($this->footer) @@ -176,13 +176,13 @@ class rcube_html_page $__page_header .= $this->css->show(); // find page header - if($hpos = strpos(strtolower($output), '')) + if($hpos = rc_strpos(rc_strtolower($output), '')) $__page_header .= "\n"; else { if (!is_numeric($hpos)) - $hpos = strpos(strtolower($output), '')+7; + $bpos = rc_strpos(rc_strtolower($output), '')+7; // add page body if($bpos && $__page_body) - $output = substr($output,0,$bpos) . "\n$__page_body\n" . substr($output,$bpos,strlen($output)); + $output = rc_substr($output,0,$bpos) . "\n$__page_body\n" . rc_substr($output,$bpos,rc_strlen($output)); // find and add page footer - $output_lc = strtolower($output); + $output_lc = rc_strtolower($output); if(($fpos = strrstr($output_lc, '')) || ($fpos = strrstr($output_lc, ''))) - $output = substr($output,0,$fpos) . "$__page_footer\n" . substr($output,$fpos); + $output = rc_substr($output,0,$fpos) . "$__page_footer\n" . rc_substr($output,$fpos); else $output .= "\n$__page_footer"; @@ -878,7 +878,7 @@ class textarea extends base_form_element if (isset($this->attrib['value'])) unset($this->attrib['value']); - if (strlen($value) && !isset($this->attrib['mce_editable'])) + if (!empty($value) && !isset($this->attrib['mce_editable'])) $value = Q($value, 'strict', FALSE); // return final tag @@ -1012,12 +1012,12 @@ class select extends base_form_element foreach ($this->options as $option) { - $selected = ((strlen($option['value']) && in_array($option['value'], $select, TRUE)) || + $selected = ((!empty($option['value']) && in_array($option['value'], $select, TRUE)) || (in_array($option['text'], $select, TRUE))) ? $this->_conv_case(' selected', 'attrib') : ''; $options_str .= sprintf("<%s%s%s>%s\n", $this->_conv_case('option', 'tag'), - strlen($option['value']) ? sprintf($value_str, $option['value']) : '', + !empty($option['value']) ? sprintf($value_str, $option['value']) : '', $selected, Q($option['text'], 'strict', FALSE), $this->_conv_case('option', 'tag')); @@ -1104,7 +1104,7 @@ function rcube_label($attrib) $nr = is_numeric($attrib['nr']) ? $attrib['nr'] : 1; $vars = isset($attrib['vars']) ? $attrib['vars'] : ''; - $command_name = strlen($attrib['command']) ? $attrib['command'] : NULL; + $command_name = !empty($attrib['command']) ? $attrib['command'] : NULL; $alias = $attrib['name'] ? $attrib['name'] : ($command_name && $command_label_map[$command_name] ? $command_label_map[$command_name] : ''); @@ -1277,7 +1277,7 @@ function array2js($arr, $type='') $is_string = false; $value = $value ? "true" : "false"; } - else if ((($type=='mixed' && is_numeric($value)) || $type=='int') && strlen($value)<16) // js interprets numbers with digits >15 as ...e+... + else if ((($type=='mixed' && is_numeric($value)) || $type=='int') && rc_strlen($value)<16) // js interprets numbers with digits >15 as ...e+... $is_string = FALSE; else $is_string = TRUE; @@ -1334,6 +1334,32 @@ function get_boolean($str) } +// parse a human readable string for a number of bytes +function parse_bytes($str) + { + if (is_numeric($str)) + return intval($str); + + if (preg_match('/([0-9]+)([a-z])/i', $str, $regs)) + { + $bytes = floatval($regs[1]); + switch (strtolower($regs[2])) + { + case 'g': + $bytes *= 1073741824; + break; + case 'm': + $bytes *= 1048576; + break; + case 'k': + $bytes *= 1024; + break; + } + } + + return intval($bytes); + } + // create a human readable string for a number of bytes function show_bytes($bytes) { @@ -1393,17 +1419,63 @@ function make_absolute_url($path, $base_url) } +// wrapper function for strlen +function rc_strlen($str) + { + if (function_exists('mb_strlen')) + return mb_strlen($str); + else + return strlen($str); + } + +// wrapper function for strtolower +function rc_strtolower($str) + { + if (function_exists('mb_strtolower')) + return mb_strtolower($str); + else + return strtolower($str); + } + +// wrapper function for substr +function rc_substr($str, $start, $len) + { + if (function_exists('mb_substr')) + return mb_substr($str, $start, $len); + else + return substr($str, $start, $len); + } + +// wrapper function for strpos +function rc_strpos($haystack, $needle, $offset=0) + { + if (function_exists('mb_strpos')) + return mb_strpos($haystack, $needle, $offset); + else + return strpos($haystack, $needle, $offset); + } + +// wrapper function for strrpos +function rc_strrpos($haystack, $needle, $offset=0) + { + if (function_exists('mb_strrpos')) + return mb_strrpos($haystack, $needle, $offset); + else + return strrpos($haystack, $needle, $offset); + } + + // replace the middle part of a string with ... // if it is longer than the allowed length function abbrevate_string($str, $maxlength, $place_holder='...') { - $length = strlen($str); - $first_part_length = floor($maxlength/2) - strlen($place_holder); + $length = rc_strlen($str); + $first_part_length = floor($maxlength/2) - rc_strlen($place_holder); if ($length > $maxlength) { $second_starting_location = $length - $maxlength + $first_part_length + 1; - $str = substr($str, 0, $first_part_length) . $place_holder . substr($str, $second_starting_location, $length); + $str = rc_substr($str, 0, $first_part_length) . $place_holder . rc_substr($str, $second_starting_location, $length); } return $str; diff --git a/program/localization/de_CH/labels.inc b/program/localization/de_CH/labels.inc index e734b0a33..8c32791b3 100644 --- a/program/localization/de_CH/labels.inc +++ b/program/localization/de_CH/labels.inc @@ -132,6 +132,7 @@ $labels['savemessage'] = 'Nachricht speichern'; $labels['sendmessage'] = 'Nachricht jetzt senden'; $labels['addattachment'] = 'Datei anfügen'; $labels['charset'] = 'Zeichensatz'; +$labels['editortype'] = 'Editor-Typ'; $labels['returnreceipt'] = 'Empfangsbestätigung'; $labels['checkspelling'] = 'Rechtschreibung prüfen'; @@ -151,6 +152,9 @@ $labels['highest'] = 'Höchste'; $labels['nosubject'] = '(kein Betreff)'; $labels['showimages'] = 'Bilder anzeigen'; +$labels['htmltoggle'] = 'HTML'; +$labels['plaintoggle'] = 'Klartext'; + // address book // Adressbuch $labels['name'] = 'Anzeigename'; @@ -174,7 +178,9 @@ $labels['print'] = 'Drucken'; $labels['export'] = 'Exportieren'; $labels['previouspage'] = 'Eine Seite zurück'; +$labels['firstpage'] = 'Erste Seite'; $labels['nextpage'] = 'Nächste Seite'; +$labels['lastpage'] = 'Letzte Seite'; // LDAP search $labels['ldapsearch'] = 'LDAP Verzeichnis-Suche'; diff --git a/program/localization/de_CH/messages.inc b/program/localization/de_CH/messages.inc index 0e6466e65..bb493497a 100644 --- a/program/localization/de_CH/messages.inc +++ b/program/localization/de_CH/messages.inc @@ -66,6 +66,8 @@ $messages['errordeleting'] = 'Nachricht konnte nicht gelöscht werden'; $messages['deletecontactconfirm'] = 'Wollen Sie die ausgewählten Kontakte wirklich löschen'; +$messages['deletemessagesconfirm'] = 'Wollen Sie die ausgewählten Nachrichten wirklich löschen?'; + $messages['deletefolderconfirm'] = 'Wollen Sie diesen Ordner wirklich löschen?'; $messages['purgefolderconfirm'] = 'Wollen Sie diesen Ordner wirklich leeren?'; @@ -110,4 +112,8 @@ $messages['converting'] = 'Entferne Formatierungen...'; $messages['messageopenerror'] = 'Die Nachricht konnte nicht vom Server geladen werden'; +$messages['fileuploaderror'] = 'Der Dateiupload ist fehlgeschlagen'; + +$messages['filesizeerror'] = 'Die Datei überschreitet die maximale Grösse von $size'; + ?> \ No newline at end of file diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index f5e0e8ba9..d9b3896f0 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -114,4 +114,8 @@ $messages['converting'] = 'Removing formatting from message...'; $messages['messageopenerror'] = 'Could not load message from server'; +$messages['fileuploaderror'] = 'File upload failed'; + +$messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size'; + ?> diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index a50b1ecf0..1c2639d9b 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -46,12 +46,16 @@ if ($_action=='remove-attachment' && preg_match('/^rcmfile([0-9]+)$/', $_GET['_f $MESSAGE_FORM = NULL; $MESSAGE = NULL; -// nothing below is called during message composition, only at "new/forward/reply/draft" initialization -// since there are many ways to leave the compose page improperly, it seems necessary to clean-up an old +// Nothing below is called during message composition, only at "new/forward/reply/draft" initialization or +// if a compose-ID is given (i.e. when the compose step is opened in a new window/tab). +// Since there are many ways to leave the compose page improperly, it seems necessary to clean-up an old // compose when a "new/forward/reply/draft" is called - otherwise the old session attachments will appear -rcmail_compose_cleanup(); -$_SESSION['compose'] = array('id' => uniqid(rand())); +if (!is_array($_SESSION['compose']) || $_SESSION['compose']['id'] != get_input_value('_id', RCUBE_INPUT_GET)) + { + rcmail_compose_cleanup(); + $_SESSION['compose'] = array('id' => uniqid(rand())); + } // add some labels to client rcube_add_label('nosubject', 'norecipientwarning', 'nosubjectwarning', 'nobodywarning', 'notsentwarning', 'savingmessage', 'sendingmessage', 'messagesaved', 'converting'); diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index dea6c040e..b8c391aae 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -1214,7 +1214,7 @@ function rcmail_mod_html_body($body, $container_id) while ($body != $prev_body) { $prev_body = $body; - $body = preg_replace('/(<[^!][^>]*?\s)(on\w+?)(=[^>]*?>)/im', '$1__removed=$3', $body); + $body = preg_replace('/(<[^!][^>]*?\s)(on[^=]+)(=[^>]*?>)/im', '$1__removed=$3', $body); $body = preg_replace('/(<[^!][^>]*?\shref=["\']?)(javascript:)([^>]*?>)/im', '$1null:$3', $body); } diff --git a/program/steps/mail/upload.inc b/program/steps/mail/upload.inc index 0d9761e44..06ed26591 100644 --- a/program/steps/mail/upload.inc +++ b/program/steps/mail/upload.inc @@ -65,6 +65,16 @@ foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) $id, $content); } + else // upload failed + { + $err = $_FILES['_attachments']['error'][$i]; + if ($err == UPLOAD_ERR_INI_SIZE || $err == UPLOAD_ERR_FORM_SIZE) + $msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array('size' => show_bytes(parse_bytes(ini_get('upload_max_filesize')))))); + else + $msg = rcube_label('fileuploaderror'); + + $response = sprintf("parent.%s.display_message('%s', 'error');", $JS_OBJECT_NAME, JQ($msg)); + } } -- cgit v1.2.3