summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Machniak <alec@alec.pl>2014-04-18 10:13:51 +0200
committerAleksander Machniak <alec@alec.pl>2014-04-18 10:13:51 +0200
commited1ceea87829093ddd62bf214e56213bf4d91c2f (patch)
treea59617f4bcf108b40beb08779f9af3941b238819
parente5a77d2634cd165da7bc6f86bb08fe21d9e357ea (diff)
Add possibility to download messages in mbox format (#1486069)
Removed "download folder" option, the same can be done by selecting all messages in a folder Code refactoring
-rw-r--r--plugins/zipdownload/README3
-rw-r--r--plugins/zipdownload/composer.json9
-rw-r--r--plugins/zipdownload/config.inc.php.dist3
-rw-r--r--plugins/zipdownload/localization/en_US.inc9
-rw-r--r--plugins/zipdownload/package.xml17
-rw-r--r--plugins/zipdownload/zipdownload.js116
-rw-r--r--plugins/zipdownload/zipdownload.php183
7 files changed, 227 insertions, 113 deletions
diff --git a/plugins/zipdownload/README b/plugins/zipdownload/README
index f253d63ee..e343398c3 100644
--- a/plugins/zipdownload/README
+++ b/plugins/zipdownload/README
@@ -2,8 +2,7 @@ Roundcube Webmail ZipDownload
=============================
This plugin adds an option to download all attachments to a message in one zip
file, when a message has multiple attachments. The plugin also allows the
-download of a selection of messages in 1 zip file and the download of entire
-folders.
+download of a selection of messages in 1 zip file.
Requirements
============
diff --git a/plugins/zipdownload/composer.json b/plugins/zipdownload/composer.json
index 7f6e30935..cdfbf9923 100644
--- a/plugins/zipdownload/composer.json
+++ b/plugins/zipdownload/composer.json
@@ -1,14 +1,19 @@
{
"name": "roundcube/zipdownload",
"type": "roundcube-plugin",
- "description": "Adds an option to download all attachments to a message in one zip file, when a message has multiple attachments. Also allows the download of a selection of messages in one zip file and the download of entire folders.",
+ "description": "Adds an option to download all attachments to a message in one zip file, when a message has multiple attachments. Also allows the download of a selection of messages in one zip file. Supports mbox and maildir format.",
"license": "GNU GPLv3+",
- "version": "2.1",
+ "version": "3.0",
"authors": [
{
"name": "Thomas Bruederli",
"email": "roundcube@gmail.com",
"role": "Lead"
+ },
+ {
+ "name": "Aleksander Machniak",
+ "email": "alec@alec.pl",
+ "role": "Lead"
}
],
"repositories": [
diff --git a/plugins/zipdownload/config.inc.php.dist b/plugins/zipdownload/config.inc.php.dist
index 0b2d14b60..171b4aea5 100644
--- a/plugins/zipdownload/config.inc.php.dist
+++ b/plugins/zipdownload/config.inc.php.dist
@@ -9,9 +9,6 @@
// -1 to prevent downloading of attachments as zip
$config['zipdownload_attachments'] = 1;
-// Zip entire folders
-$config['zipdownload_folder'] = false;
-
// Zip selection of messages
$config['zipdownload_selection'] = false;
diff --git a/plugins/zipdownload/localization/en_US.inc b/plugins/zipdownload/localization/en_US.inc
index aee8a5e15..91145205e 100644
--- a/plugins/zipdownload/localization/en_US.inc
+++ b/plugins/zipdownload/localization/en_US.inc
@@ -5,7 +5,7 @@
| plugins/zipdownload/localization/<lang>.inc |
| |
| Localization file of the Roundcube Webmail Zipdownload plugin |
- | Copyright (C) 2012-2013, The Roundcube Dev Team |
+ | Copyright (C) 2012-2014, The Roundcube Dev Team |
| |
| Licensed under the GNU General Public License version 3 or |
| any later version with exceptions for skins & plugins. |
@@ -18,6 +18,7 @@
$labels = array();
$labels['downloadall'] = 'Download all attachments';
-$labels['downloadfolder'] = 'Download folder';
-
-?> \ No newline at end of file
+$labels['download'] = 'Download...';
+$labels['downloadmbox'] = 'Mbox format (.zip)';
+$labels['downloadmaildir'] = 'Maildir format (.zip)';
+$labels['downloademl'] = 'Source (.eml)';
diff --git a/plugins/zipdownload/package.xml b/plugins/zipdownload/package.xml
index 3e5722045..7485c5870 100644
--- a/plugins/zipdownload/package.xml
+++ b/plugins/zipdownload/package.xml
@@ -6,7 +6,8 @@
<name>zipdownload</name>
<channel>pear.roundcube.net</channel>
<summary>Download multiple attachments or messages in one zip file</summary>
- <description>Adds an option to download all attachments to a message in one zip file, when a message has multiple attachments. Also allows the download of a selection of messages in one zip file and the download of entire folders.</description>
+ <description>Adds an option to download all attachments to a message in one zip file, when a message has multiple attachments.
+ Also allows the download of a selection of messages in one zip file. Supports mbox and maildir formats.</description>
<lead>
<name>Philip Weir</name>
<user>JohnDoh</user>
@@ -19,11 +20,17 @@
<email>roundcube@gmail.com</email>
<active>yes</active>
</lead>
- <date>2014-04-07</date>
- <time>17:28:00</time>
+ <lead>
+ <name>Aleksander Machniak</name>
+ <user>alec</user>
+ <email>alec@alec.pl</email>
+ <active>yes</active>
+ </lead>
+ <date>2014-04-18</date>
+ <time>09:00:00</time>
<version>
- <release>2.1</release>
- <api>2.0</api>
+ <release>3.0</release>
+ <api>3.0</api>
</version>
<stability>
<release>stable</release>
diff --git a/plugins/zipdownload/zipdownload.js b/plugins/zipdownload/zipdownload.js
index 080dcd9e3..0e0249dd3 100644
--- a/plugins/zipdownload/zipdownload.js
+++ b/plugins/zipdownload/zipdownload.js
@@ -2,32 +2,94 @@
* ZipDownload plugin script
*/
-function rcmail_zipmessages() {
- if (rcmail.message_list && rcmail.message_list.get_selection().length > 1) {
- rcmail.goto_url('plugin.zipdownload.zip_messages', '_mbox=' + urlencode(rcmail.env.mailbox) + '&_uid=' + rcmail.message_list.get_selection().join(','));
- }
+window.rcmail && rcmail.addEventListener('init', function(evt) {
+ // register additional actions
+ rcmail.register_command('download-eml', function() { rcmail_zipdownload('eml'); });
+ rcmail.register_command('download-mbox', function() { rcmail_zipdownload('mbox'); });
+ rcmail.register_command('download-maildir', function() { rcmail_zipdownload('maildir'); });
+
+ // commands status
+ rcmail.message_list.addEventListener('select', function(list) {
+ var selected = list.get_selection().length;
+
+ rcmail.enable_command('download', selected > 0);
+ rcmail.enable_command('download-eml', selected == 1);
+ rcmail.enable_command('download-mbox', 'download-maildir', selected > 1);
+ });
+
+ // hook before default download action
+ rcmail.addEventListener('beforedownload', rcmail_zipdownload_menu);
+
+ // find and modify default download link/button
+ $.each(rcmail.buttons['download'] || [], function() {
+ var link = $('#' + this.id),
+ span = $('span', link);
+
+ if (!span.length) {
+ span = $('<span>');
+ link.html('').append(span);
+ }
+
+ span.addClass('folder-selector-link').text(rcmail.gettext('zipdownload.download'));
+
+ rcmail.env.download_link = link;
+ });
+
+ // hide menu on click out of menu element
+ var fn = function(e) {
+ var menu = $('#zipdownload-menu');
+ if (e.target != menu.get(0))
+ menu.hide();
+ };
+ $(document.body).on('mouseup', fn);
+ $('iframe').contents().on('mouseup', fn)
+ .load(function(e) { try { $(this).contents().on('mouseup', fn); } catch(e) {}; });
+});
+
+
+function rcmail_zipdownload(mode)
+{
+ // default .eml download of single message
+ if (mode == 'eml') {
+ var uid = rcmail.get_single_uid();
+ rcmail.goto_url('viewsource', {_uid: uid, _mbox: rcmail.get_message_mailbox(uid), _save: 1});
+ return;
+ }
+
+ // multi-message download, use hidden form to POST selection
+ if (rcmail.message_list && rcmail.message_list.get_selection().length > 1) {
+ var inputs = [], form = $('#zipdownload-form'),
+ post = rcmail.selection_post_data();
+
+ post._mode = mode;
+ post._token = rcmail.env.request_token;
+
+ $.each(post, function(k, v) {
+ inputs.push($('<input>').attr({type: 'hidden', name: k, value: v}));
+ });
+
+ if (!form.length)
+ form = $('<form>').attr({
+ style: 'display: none',
+ method: 'POST',
+ action: '?_task=mail&_action=plugin.zipdownload.messages'
+ })
+ .appendTo('body');
+
+ form.html('').append(inputs).submit();
+ }
}
-$(document).ready(function() {
- if (window.rcmail) {
- rcmail.addEventListener('init', function(evt) {
- // register command (directly enable in message view mode)
- rcmail.register_command('plugin.zipdownload.zip_folder', function() {
- rcmail.goto_url('plugin.zipdownload.zip_folder', '_mbox=' + urlencode(rcmail.env.mailbox));
- }, rcmail.env.messagecount > 0);
-
- if (rcmail.message_list && rcmail.env.zipdownload_selection) {
- rcmail.message_list.addEventListener('select', function(list) {
- rcmail.enable_command('download', list.get_selection().length > 0);
- });
-
- // check in contextmenu plugin exists and if so allow multiple message download
- if (rcmail.contextmenu_disable_multi)
- rcmail.contextmenu_disable_multi.splice($.inArray('#download', rcmail.contextmenu_disable_multi), 1);
- }
- });
-
- rcmail.addEventListener('listupdate', function(props) { rcmail.enable_command('plugin.zipdownload.zip_folder', rcmail.env.messagecount > 0); } );
- rcmail.addEventListener('beforedownload', function(props) { rcmail_zipmessages(); } );
- }
-}); \ No newline at end of file
+// display download options menu
+function rcmail_zipdownload_menu()
+{
+ // fix menu style and display menu
+ var z_index = rcmail.env.download_link.parents('.popupmenu').css('z-index'),
+ menu = $('#zipdownload-menu').css({'max-height': 'none', 'z-index': z_index + 1}).show();
+
+ // position menu on the screen
+ rcmail.element_position(menu, rcmail.env.download_link);
+
+ // abort default download action
+ return false;
+}
diff --git a/plugins/zipdownload/zipdownload.php b/plugins/zipdownload/zipdownload.php
index 029eecfb8..90a314437 100644
--- a/plugins/zipdownload/zipdownload.php
+++ b/plugins/zipdownload/zipdownload.php
@@ -4,11 +4,13 @@
* ZipDownload
*
* Plugin to allow the download of all message attachments in one zip file
+ * and downloading of many messages in one go.
*
- * @version 2.1
+ * @version 3.0
* @requires php_zip extension (including ZipArchive class)
* @author Philip Weir
* @author Thomas Bruderli
+ * @author Aleksander Machniak
*/
class zipdownload extends rcube_plugin
{
@@ -40,18 +42,11 @@ class zipdownload extends rcube_plugin
$this->add_hook('template_object_messageattachments', array($this, 'attachment_ziplink'));
}
- $this->register_action('plugin.zipdownload.zip_attachments', array($this, 'download_attachments'));
- $this->register_action('plugin.zipdownload.zip_messages', array($this, 'download_selection'));
- $this->register_action('plugin.zipdownload.zip_folder', array($this, 'download_folder'));
+ $this->register_action('plugin.zipdownload.attachments', array($this, 'download_attachments'));
+ $this->register_action('plugin.zipdownload.messages', array($this, 'download_messages'));
- if (($selection = $rcmail->config->get('zipdownload_selection')) || $rcmail->config->get('zipdownload_folder')) {
- $this->include_script('zipdownload.js');
- $this->api->output->set_env('zipdownload_selection', $selection);
-
- if ($rcmail->config->get('zipdownload_folder', false) && ($rcmail->action == '' || $rcmail->action == 'show')) {
- $zipdownload = $this->api->output->button(array('command' => 'plugin.zipdownload.zip_folder', 'type' => 'link', 'classact' => 'active', 'content' => $this->gettext('downloadfolder')));
- $this->api->add_content(html::tag('li', array('class' => 'separator_above'), $zipdownload), 'mailboxoptions');
- }
+ if (!$rcmail->action && $rcmail->config->get('zipdownload_selection')) {
+ $this->download_menu();
}
}
@@ -65,7 +60,7 @@ class zipdownload extends rcube_plugin
// only show the link if there is more than the configured number of attachments
if (substr_count($p['content'], '<li') > $rcmail->config->get('zipdownload_attachments', 1)) {
$href = $rcmail->url(array(
- '_action' => 'plugin.zipdownload.zip_attachments',
+ '_action' => 'plugin.zipdownload.attachments',
'_mbox' => $rcmail->output->env['mailbox'],
'_uid' => $rcmail->output->env['uid'],
));
@@ -92,6 +87,30 @@ class zipdownload extends rcube_plugin
}
/**
+ * Adds download options menu to the page
+ */
+ public function download_menu()
+ {
+ $this->include_script('zipdownload.js');
+ $this->add_label('download');
+
+ $rcmail = rcmail::get_instance();
+ $menu = array();
+ $ul_attr = $rcmail->config->get('skin') == 'classic' ? null : array('class' => 'toolbarmenu');
+
+ foreach (array('eml', 'mbox', 'maildir') as $type) {
+ $menu[] = html::tag('li', null, $rcmail->output->button(array(
+ 'command' => "download-$type",
+ 'label' => "zipdownload.download$type",
+ 'classact' => 'active',
+ )));
+ }
+
+ $rcmail->output->add_footer(html::div(array('id' => 'zipdownload-menu', 'class' => 'popupmenu'),
+ html::tag('ul', $ul_attr, implode('', $menu))));
+ }
+
+ /**
* Handler for attachment download action
*/
public function download_attachments()
@@ -153,52 +172,19 @@ class zipdownload extends rcube_plugin
/**
* Handler for message download action
*/
- public function download_selection()
+ public function download_messages()
{
- if (isset($_REQUEST['_uid'])) {
- $messageset = rcmail::get_uids();
+ $rcmail = rcmail::get_instance();
- if (sizeof($messageset) > 0) {
+ if ($rcmail->config->get('zipdownload_selection') && !empty($_POST['_uid'])) {
+ $messageset = rcmail::get_uids();
+ if (sizeof($messageset)) {
$this->_download_messages($messageset);
}
}
}
/**
- * Handler for folder download action
- */
- public function download_folder()
- {
- @set_time_limit(0);
-
- $imap = rcmail::get_instance()->get_storage();
- $mbox_name = $imap->get_folder();
-
- // initialize searching result if search_filter is used
- if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') {
- $imap->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET);
- }
-
- // fetch message headers for all pages
- $uids = array();
- if ($count = $imap->count($mbox_name, $imap->get_threading() ? 'THREADS' : 'ALL', FALSE)) {
- for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) {
- $a_headers = $imap->list_messages($mbox_name, ($i + 1));
-
- foreach ($a_headers as $header) {
- if (empty($header))
- continue;
-
- array_push($uids, $header->uid);
- }
- }
- }
-
- if (sizeof($uids) > 0)
- $this->_download_messages(array($mbox_name => $uids));
- }
-
- /**
* Helper method to packs all the given messages into a zip archive
*
* @param array List of message UIDs to download
@@ -207,40 +193,80 @@ class zipdownload extends rcube_plugin
{
$rcmail = rcmail::get_instance();
$imap = $rcmail->get_storage();
+ $mode = rcube_utils::get_input_value('_mode', rcube_utils::INPUT_POST);
$temp_dir = $rcmail->config->get('temp_dir');
$tmpfname = tempnam($temp_dir, 'zipdownload');
$tempfiles = array($tmpfname);
$folders = count($messageset) > 1;
+ // @TODO: file size limit
+
// open zip file
$zip = new ZipArchive();
$zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
- foreach ($messageset as $mbox => $uids){
+ if ($mode == 'mbox') {
+ $tmpfp = fopen($tmpfname . '.mbox', 'w');
+ }
+
+ foreach ($messageset as $mbox => $uids) {
$imap->set_folder($mbox);
$path = $folders ? str_replace($imap->get_hierarchy_delimiter(), '/', $mbox) . '/' : '';
- foreach ($uids as $uid){
+ foreach ($uids as $uid) {
$headers = $imap->get_message_headers($uid);
- $subject = rcube_mime::decode_mime_string((string)$headers->subject);
- $subject = $this->_convert_filename($subject);
- $subject = substr($subject, 0, 16);
-
- $disp_name = ($subject ? $subject : 'message_rfc822') . ".eml";
- $disp_name = $path . $uid . "_" . $disp_name;
- $tmpfn = tempnam($temp_dir, 'zipmessage');
- $tmpfp = fopen($tmpfn, 'w');
- $imap->get_raw_body($uid, $tmpfp);
- $tempfiles[] = $tmpfn;
- fclose($tmpfp);
- $zip->addFile($tmpfn, $disp_name);
+ if ($mode == 'mbox') {
+ $from = rcube_mime::decode_address_list($headers->from, null, true, $headers->charset, true);
+ $from = array_shift($from);
+
+ // Mbox format header
+ // @FIXME: \r\n or \n
+ // @FIXME: date format
+ $header = sprintf("From %s %s\r\n",
+ // replace spaces with hyphens
+ $from ? preg_replace('/\s/', '-', $from) : 'MAILER-DAEMON',
+ // internaldate
+ $headers->internaldate
+ );
+
+ fwrite($tmpfp, $header);
+
+ // Use stream filter to quote "From " in the message body
+ stream_filter_register('mbox_filter', 'zipdownload_mbox_filter');
+ $filter = stream_filter_append($tmpfp, 'mbox_filter');
+ $imap->get_raw_body($uid, $tmpfp);
+ stream_filter_remove($filter);
+ fwrite($tmpfp, "\r\n");
+ }
+ else { // maildir
+ $subject = rcube_mime::decode_mime_string((string)$headers->subject);
+ $subject = $this->_convert_filename($subject);
+ $subject = substr($subject, 0, 16);
+
+ $disp_name = ($subject ? $subject : 'message_rfc822') . ".eml";
+ $disp_name = $path . $uid . "_" . $disp_name;
+
+ $tmpfn = tempnam($temp_dir, 'zipmessage');
+ $tmpfp = fopen($tmpfn, 'w');
+ $imap->get_raw_body($uid, $tmpfp);
+ $tempfiles[] = $tmpfn;
+ fclose($tmpfp);
+ $zip->addFile($tmpfn, $disp_name);
+ }
}
}
+ $filename = $folders ? 'messages' : $imap->get_folder();
+
+ if ($mode == 'mbox') {
+ $tempfiles[] = $tmpfname . '.mbox';
+ fclose($tmpfp);
+ $zip->addFile($tmpfname . '.mbox', $filename . '.mbox');
+ }
+
$zip->close();
- $filename = $folders ? 'messages' : $imap->get_folder();
$this->_deliver_zipfile($tmpfname, $filename . '.zip');
// delete temporary files from disk
@@ -261,9 +287,7 @@ class zipdownload extends rcube_plugin
$rcmail->output->nocacheing_headers();
- if ($browser->ie && $browser->ver < 7)
- $filename = rawurlencode(abbreviate_string($filename, 55));
- else if ($browser->ie)
+ if ($browser->ie)
$filename = rawurlencode($filename);
else
$filename = addcslashes($filename, '"');
@@ -288,6 +312,25 @@ class zipdownload extends rcube_plugin
{
$str = rcube_charset::convert($str, RCUBE_CHARSET, $this->charset);
- return strtr($str, array(':'=>'', '/'=>'-'));
+ return strtr($str, array(':' => '', '/' => '-'));
+ }
+}
+
+class zipdownload_mbox_filter extends php_user_filter
+{
+ function filter($in, $out, &$consumed, $closing)
+ {
+ while ($bucket = stream_bucket_make_writeable($in)) {
+ // messages are read line by line
+ if (preg_match('/^>*From /', $bucket->data)) {
+ $bucket->data = '>' . $bucket->data;
+ $bucket->datalen += 1;
+ }
+
+ $consumed += $bucket->datalen;
+ stream_bucket_append($out, $bucket);
+ }
+
+ return PSFS_PASS_ON;
}
}