From ed1ceea87829093ddd62bf214e56213bf4d91c2f Mon Sep 17 00:00:00 2001 From: Aleksander Machniak Date: Fri, 18 Apr 2014 10:13:51 +0200 Subject: 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 --- plugins/zipdownload/zipdownload.php | 183 ++++++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 70 deletions(-) (limited to 'plugins/zipdownload/zipdownload.php') 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'], ' $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'], )); @@ -91,6 +86,30 @@ class zipdownload extends rcube_plugin return $p; } + /** + * 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 */ @@ -153,51 +172,18 @@ 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 * @@ -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; } } -- cgit v1.2.3