From 95df255af4562a019b4d1f429a8f5a1bcbb5ef93 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Thu, 1 Sep 2016 10:37:09 +0200 Subject: [PATCH] Added max_message_size option enforced when attaching files to a composed message (#4993) --- CHANGELOG | 1 + config/defaults.inc.php | 9 +++- program/localization/en_US/messages.inc | 1 + program/steps/mail/attachments.inc | 68 ++++++++++++++++++++++--- 4 files changed, 70 insertions(+), 9 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 09e88e8db..fcd52b0a2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Added max_message_size option enforced when attaching files to a composed message (#4993) - Added Search button in quick search menus (#5312) - Implement "one click" attachment/messages/photo upload (#5024) - Squirrelmail_usercopy: Add option to define character set of data files diff --git a/config/defaults.inc.php b/config/defaults.inc.php index b7ebf1fdc..e7d3aa282 100644 --- a/config/defaults.inc.php +++ b/config/defaults.inc.php @@ -504,12 +504,17 @@ $config['password_charset'] = 'ISO-8859-1'; // How many seconds must pass between emails sent by a user $config['sendmail_delay'] = 0; +// Message size limit. Note that SMTP server(s) may use a different value. +// This limit is verified when user attaches files to a composed message. +// Size in bytes (possible unit suffix: K, M, G) +$config['max_message_size'] = '100M'; + // Maximum number of recipients per message. Default: 0 (no limit) -$config['max_recipients'] = 0; +$config['max_recipients'] = 0; // Maximum allowed number of members of an address group. Default: 0 (no limit) // If 'max_recipients' is set this value should be less or equal -$config['max_group_members'] = 0; +$config['max_group_members'] = 0; // Name your service. This is displayed on the login screen and in the window title $config['product_name'] = 'Roundcube Webmail'; diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index 8c2428fc8..ccf931776 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -119,6 +119,7 @@ $messages['messageopenerror'] = 'Could not load message from server.'; $messages['filelinkerror'] = 'Attaching the file failed.'; $messages['fileuploaderror'] = 'File upload failed.'; $messages['filesizeerror'] = 'The uploaded file exceeds the maximum size of $size.'; +$messages['msgsizeerror'] = 'Failed to attach a file. Maximum size of a message ($size) exceeded.'; $messages['copysuccess'] = 'Successfully copied $nr contacts.'; $messages['movesuccess'] = 'Successfully moved $nr contacts.'; $messages['copyerror'] = 'Could not copy any contacts.'; diff --git a/program/steps/mail/attachments.inc b/program/steps/mail/attachments.inc index 4a0beebe6..8c1993e67 100644 --- a/program/steps/mail/attachments.inc +++ b/program/steps/mail/attachments.inc @@ -122,18 +122,32 @@ if ($uri) { // handle file(s) upload if (is_array($_FILES['_attachments']['tmp_name'])) { $multiple = count($_FILES['_attachments']['tmp_name']) > 1; + $errors = array(); foreach ($_FILES['_attachments']['tmp_name'] as $i => $filepath) { // Process uploaded attachment if there is no error $err = $_FILES['_attachments']['error'][$i]; if (!$err) { + $filename = $_FILES['_attachments']['name'][$i]; + $filesize = $_FILES['_attachments']['size'][$i]; + $filetype = rcube_mime::file_content_type($filepath, $filename, $_FILES['_attachments']['type'][$i]); + + if ($err = rcmail_check_message_size($filesize, $filetype)) { + if (!in_array($err, $errors)) { + $OUTPUT->command('display_message', $err, 'error'); + $OUTPUT->command('remove_from_attachment_list', $uploadid); + $errors[] = $err; + } + continue; + } + $attachment = $RCMAIL->plugins->exec_hook('attachment_upload', array( - 'path' => $filepath, - 'size' => $_FILES['_attachments']['size'][$i], - 'name' => $_FILES['_attachments']['name'][$i], - 'mimetype' => rcube_mime::file_content_type($filepath, $_FILES['_attachments']['name'][$i], $_FILES['_attachments']['type'][$i]), - 'group' => $COMPOSE_ID, + 'path' => $filepath, + 'name' => $filename, + 'size' => $filesize, + 'mimetype' => $filetype, + 'group' => $COMPOSE_ID, )); } @@ -157,8 +171,11 @@ if (is_array($_FILES['_attachments']['tmp_name'])) { } if ($attachment['error'] || $err != UPLOAD_ERR_NO_FILE) { - $OUTPUT->command('display_message', $msg, 'error'); - $OUTPUT->command('remove_from_attachment_list', $uploadid); + if (!in_array($msg, $errors)) { + $OUTPUT->command('display_message', $msg, 'error'); + $OUTPUT->command('remove_from_attachment_list', $uploadid); + $errors[] = $msg; + } } } } @@ -230,3 +247,40 @@ function rcmail_attachment_success($attachment, $uploadid) 'classname' => rcube_utils::file2class($attachment['mimetype'], $attachment['name']), 'complete' => true), $uploadid); } + +/** + * Checks if the attached file will fit in message size limit. + * Calculates size of all attachments and compares with the limit. + * + * @param int $filesize File size + * @param string $filetype File mimetype + * + * @return string Error message if the limit is exceeded + */ +function rcmail_check_message_size($filesize, $filetype) +{ + global $RCMAIL, $COMPOSE; + + $limit = parse_bytes($RCMAIL->config->get('max_message_size')); + $size = 10 * 1024; // size of message body + + if (!$limit) { + return; + } + + // add size of already attached files + foreach ((array) $COMPOSE['attachments'] as $att) { + // All attachments are base64-encoded except message/rfc822 (see sendmail.inc) + $multip = $att['mimetype'] == 'message/rfc822' ? 1 : 1.33; + $size += $att['size'] * $multip; + } + + // add size of the new attachment + $multip = $filetype == 'message/rfc822' ? 1 : 1.33; + $size += $filesize * $multip; + + if ($size > $limit) { + $limit = $RCMAIL->show_bytes($limit); + return $RCMAIL->gettext(array('name' => 'msgsizeerror', 'vars' => array('size' => $limit))); + } +}