summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2006-12-29 21:06:39 +0000
committerthomascube <thomas@roundcube.net>2006-12-29 21:06:39 +0000
commit86df1529feb4b7eb1a9721baa194518bacbfd8ff (patch)
tree380827ed01c3e3e3a3253d0b00c350b467186a25
parent3b12aeeeca89bbc3d8cc5342beb07643067e3760 (diff)
Error handling for attachment uploads; multibyte-safe string functions; XSS improvements
-rw-r--r--CHANGELOG7
-rw-r--r--program/include/main.inc5
-rw-r--r--program/include/rcube_shared.inc114
-rw-r--r--program/localization/de_CH/labels.inc6
-rw-r--r--program/localization/de_CH/messages.inc6
-rw-r--r--program/localization/en_US/messages.inc4
-rw-r--r--program/steps/mail/compose.inc12
-rw-r--r--program/steps/mail/func.inc2
-rw-r--r--program/steps/mail/upload.inc10
9 files changed, 139 insertions, 27 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 80afee48a..2c04a3bae 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,13 @@
CHANGELOG RoundCube Webmail
---------------------------
+2006/12/29 (thomasb)
+----------
+- Added error handling for attachment uploads
+- Use multibyte safe string functions where necessary (closes #1483988)
+- Updated Swiss German localization (de_CH)
+
+
2006/12/22 (thomasb)
----------
- Applied security patch to validate the submitted host value (by Kees Cook)
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), '</head>'))
+ if($hpos = rc_strpos(rc_strtolower($output), '</head>'))
$__page_header .= "\n";
else
{
if (!is_numeric($hpos))
- $hpos = strpos(strtolower($output), '<body');
- if (!is_numeric($hpos) && ($hpos = strpos(strtolower($output), '<html')))
+ $hpos = rc_strpos(rc_strtolower($output), '<body');
+ if (!is_numeric($hpos) && ($hpos = rc_strpos(rc_strtolower($output), '<html')))
{
while($output[$hpos]!='>')
$hpos++;
@@ -194,30 +194,30 @@ class rcube_html_page
// add page hader
if($hpos)
- $output = substr($output,0,$hpos) . $__page_header . substr($output,$hpos,strlen($output));
+ $output = rc_substr($output,0,$hpos) . $__page_header . rc_substr($output,$hpos,rc_strlen($output));
else
$output = $__page_header . $output;
// find page body
- if($bpos = strpos(strtolower($output), '<body'))
+ if($bpos = rc_strpos(rc_strtolower($output), '<body'))
{
while($output[$bpos]!='>') $bpos++;
$bpos++;
}
else
- $bpos = strpos(strtolower($output), '</head>')+7;
+ $bpos = rc_strpos(rc_strtolower($output), '</head>')+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, '</body>')) ||
($fpos = strrstr($output_lc, '</html>')))
- $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</%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));
+ }
}