From 4f53ab347e6ad026f69105b69ce66e21a7654c78 Mon Sep 17 00:00:00 2001 From: Thomas Bruederli Date: Fri, 14 Jun 2013 01:13:13 +0200 Subject: Add feature to import messages to the currently selected folder --- program/js/app.js | 19 ++++-- program/lib/Roundcube/html.php | 4 +- program/localization/en_US/labels.inc | 1 + program/localization/en_US/messages.inc | 2 + program/steps/mail/func.inc | 39 +++++++++++- program/steps/mail/import.inc | 105 ++++++++++++++++++++++++++++++++ 6 files changed, 161 insertions(+), 9 deletions(-) create mode 100644 program/steps/mail/import.inc (limited to 'program') diff --git a/program/js/app.js b/program/js/app.js index 0dea59216..37aee8d88 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -191,7 +191,7 @@ function rcube_webmail() case 'mail': // enable mail commands - this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', true); + this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', 'import-messages', true); if (this.gui_objects.messagelist) { this.message_list = new rcube_list_widget(this.gui_objects.messagelist, { @@ -277,11 +277,12 @@ function rcube_webmail() this.init_messageform(); } // show printing dialog - else if (this.env.action == 'print' && this.env.uid) + else if (this.env.action == 'print' && this.env.uid) { if (bw.safari) setTimeout('window.print()', 10); else window.print(); + } // get unread count for each mailbox if (this.gui_objects.mailboxlist) { @@ -1000,7 +1001,7 @@ function rcube_webmail() // Reset the auto-save timer clearTimeout(this.save_timer); - this.upload_file(props || this.gui_objects.uploadform); + this.upload_file(props || this.gui_objects.uploadform, 'upload'); break; case 'insert-sig': @@ -1101,6 +1102,12 @@ function rcube_webmail() this.list_contacts(props.source, props.id); break; + case 'import-messages': + var form = props || this.gui_objects.importform; + $('input[name="_unlock"]', form).val(this.set_busy(true, 'importwait')); + this.upload_file(form, 'import'); + break; + case 'import': if (this.env.action == 'import' && this.gui_objects.importform) { var file = document.getElementById('rcmimportfile'); @@ -3492,8 +3499,8 @@ function rcube_webmail() return true; }; - // upload attachment file - this.upload_file = function(form) + // upload (attachment) file + this.upload_file = function(form, action) { if (!form) return false; @@ -3520,7 +3527,7 @@ function rcube_webmail() return; } - var frame_name = this.async_upload_form(form, 'upload', function(e) { + var frame_name = this.async_upload_form(form, action || 'upload', function(e) { var d, content = ''; try { if (this.contentDocument) { diff --git a/program/lib/Roundcube/html.php b/program/lib/Roundcube/html.php index eb23c8b2e..3e6e47a56 100644 --- a/program/lib/Roundcube/html.php +++ b/program/lib/Roundcube/html.php @@ -360,8 +360,8 @@ class html_inputfield extends html protected $allowed = array( 'type','name','value','size','tabindex','autocapitalize', 'autocomplete','checked','onchange','onclick','disabled','readonly', - 'spellcheck','results','maxlength','src','multiple','placeholder', - 'autofocus', + 'spellcheck','results','maxlength','src','multiple','accept', + 'placeholder','autofocus', ); /** diff --git a/program/localization/en_US/labels.inc b/program/localization/en_US/labels.inc index d8e517387..c5e6cae4c 100644 --- a/program/localization/en_US/labels.inc +++ b/program/localization/en_US/labels.inc @@ -194,6 +194,7 @@ $labels['listmode'] = 'List view mode'; $labels['folderactions'] = 'Folder actions...'; $labels['compact'] = 'Compact'; $labels['empty'] = 'Empty'; +$labels['importmessages'] = 'Import messages'; $labels['quota'] = 'Disk usage'; $labels['unknown'] = 'unknown'; diff --git a/program/localization/en_US/messages.inc b/program/localization/en_US/messages.inc index f9b5e00a6..16f4c67bf 100644 --- a/program/localization/en_US/messages.inc +++ b/program/localization/en_US/messages.inc @@ -126,6 +126,8 @@ $messages['importwait'] = 'Importing, please wait...'; $messages['importformaterror'] = 'Import failed! The uploaded file is not a valid import data file.'; $messages['importconfirm'] = 'Successfully imported $inserted contacts'; $messages['importconfirmskipped'] = 'Skipped $skipped existing entries'; +$messages['importmessagesuccess'] = 'Successfully imported $nr messages'; +$messages['importmessageerror'] = 'Import failed! The uploaded file is not a valid message or mailbox file'; $messages['opnotpermitted'] = 'Operation not permitted!'; $messages['nofromaddress'] = 'Missing e-mail address in selected identity.'; $messages['editorwarning'] = 'Switching to the plain text editor will cause all text formatting to be lost. Do you wish to continue?'; diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc index 1a687f508..7b6a4829d 100644 --- a/program/steps/mail/func.inc +++ b/program/steps/mail/func.inc @@ -120,7 +120,7 @@ if (empty($RCMAIL->action) || $RCMAIL->action == 'list') { if (!$OUTPUT->ajax_call) $OUTPUT->add_label('checkingmail', 'deletemessage', 'movemessagetotrash', 'movingmessage', 'copyingmessage', 'deletingmessage', 'markingmessage', - 'copy', 'move', 'quota', 'replyall', 'replylist'); + 'copy', 'move', 'quota', 'replyall', 'replylist', 'importwait'); $pagetitle = $RCMAIL->localize_foldername($RCMAIL->storage->mod_folder($mbox_name), true); $pagetitle = str_replace($delimiter, " \xC2\xBB ", $pagetitle); @@ -1922,6 +1922,42 @@ function rcmail_message_error($uid=null) $RCMAIL->output->send('messageerror'); } +function rcmail_message_import_form($attrib = array()) +{ + global $OUTPUT; + + // set defaults + $attrib += array('id' => 'rcmImportform', 'buttons' => 'yes'); + + // Get filesize, enable upload progress bar + $max_filesize = rcube_upload_init(); + + $button = new html_inputfield(array('type' => 'button')); + $fileinput = new html_inputfield(array( + 'type' => 'file', + 'name' => '_file[]', + 'size' => $attrib['attachmentfieldsize'], + 'multiple' => 'multiple', + 'accept' => ".eml, .mbox, message/rfc822, text/*", + )); + + $out = html::div($attrib, + $OUTPUT->form_tag(array('id' => $attrib['id'].'Frm', 'method' => 'post', 'enctype' => 'multipart/form-data'), + html::tag('input', array('type' => 'hidden', 'name' => '_unlock', 'value' => '')) . + html::div(null, $fileinput->show()) . + html::div('hint', rcube_label(array('name' => 'maxuploadsize', 'vars' => array('size' => $max_filesize)))) . + (get_boolean($attrib['buttons']) ? html::div('buttons', + $button->show(rcube_label('close'), array('class' => 'button', 'onclick' => "$('#$attrib[id]').hide()")) . ' ' . + $button->show(rcube_label('upload'), array('class' => 'button mainaction', 'onclick' => JS_OBJECT_NAME . ".command('import-messages', this.form)")) + ) : '') + ) + ); + + $OUTPUT->add_gui_object('importform', $attrib['id'].'Frm'); + return $out; +} + + // register UI objects $OUTPUT->add_handlers(array( 'mailboxlist' => 'rcmail_mailbox_list', @@ -1935,6 +1971,7 @@ $OUTPUT->add_handlers(array( 'messagecontentframe' => 'rcmail_messagecontent_frame', 'messagepartframe' => 'rcmail_message_part_frame', 'messagepartcontrols' => 'rcmail_message_part_controls', + 'messageimportform' => 'rcmail_message_import_form', 'searchfilter' => 'rcmail_search_filter', 'searchform' => array($OUTPUT, 'search_form'), )); diff --git a/program/steps/mail/import.inc b/program/steps/mail/import.inc new file mode 100644 index 000000000..f7e7a3eb8 --- /dev/null +++ b/program/steps/mail/import.inc @@ -0,0 +1,105 @@ + | + +-----------------------------------------------------------------------+ +*/ + +// clear all stored output properties (like scripts and env vars) +$OUTPUT->reset(); + +if (is_array($_FILES['_file'])) { + $imported = 0; + + foreach ((array)$_FILES['_file']['tmp_name'] as $i => $filepath) { + // Process uploaded file if there is no error + $err = $_FILES['_file']['error'][$i]; + + if (!$err) { + // check file content type first + list($mtype_primary,) = explode('/', rc_mime_content_type($filepath, $_FILES['_file']['name'][$i], $_FILES['_file']['type'][$i])); + if (!in_array($mtype_primary, array('text','message'))) { + $OUTPUT->show_message('importmessageerror', 'error'); + continue; + } + + // read the first few lines to detect header-like structure + $fp = fopen($filepath, 'r'); + do { $line = fgets($fp); } + while ($line !== false && trim($line) == ''); + + if (!preg_match('/^From\s+-/', $line) && !preg_match('/^[a-z-_]+:\s+.+/i', $line)) { + $OUTPUT->show_message('importmessageerror', 'error'); + continue; + } + + $message = $lastline = ''; + fseek($fp, 0); + while (($line = fgets($fp)) !== false) { + // importing mbox file, split by From - lines + if (preg_match('/^From\s+-/', $line) && $lastline == '') { + if (!empty($message)) { + if ($RCMAIL->storage->save_message(null, rtrim($message))) { + $imported++; + } + else { + rcube::raise_error("Failed to import message to " . $RCMAIL->storage->get_folder(), false, true); + } + $message = ''; + } + continue; + } + + $message .= $line; + $lastline = rtrim($line); + } + + if (!empty($message) && $RCMAIL->storage->save_message(null, rtrim($message))) { + $imported++; + } + } + + 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 if ($err) { + $OUTPUT->show_message('fileuploaderror', 'error'); + } + } // end foreach + + if ($imported) { + $OUTPUT->show_message(rcube_label(array('name' => 'importmessagesuccess', 'nr' => $imported, 'vars' => array('nr' => $imported))), 'confirmation'); + $OUTPUT->command('command', 'list'); + } + else { + $OUTPUT->show_message('importmessageerror', 'error'); + } +} +else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + // if filesize exceeds post_max_size then $_FILES array is empty, + // show filesizeerror instead of fileuploaderror + if ($maxsize = ini_get('post_max_size')) + $msg = rcube_label(array('name' => 'filesizeerror', 'vars' => array('size' => show_bytes(parse_bytes($maxsize))))); + else + $msg = rcube_label('fileuploaderror'); + + $OUTPUT->command('display_message', $msg, 'error'); +} + +// send html page with JS calls as response +$OUTPUT->send('iframe'); + -- cgit v1.2.3