520, 'file' => __FILE__, 'line' => __LINE__, 'message' => "php_zip extension is required for the zipdownload plugin"), true, false); return; } $rcmail = rcmail::get_instance(); $this->load_config(); $this->charset = $rcmail->config->get('zipdownload_charset', RCUBE_CHARSET); $this->add_texts('localization'); if ($rcmail->config->get('zipdownload_attachments', 1) > -1 && ($rcmail->action == 'show' || $rcmail->action == 'preview')) { $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')); 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'); } } } /** * Place a link/button after attachments listing to trigger download */ public function attachment_ziplink($p) { $rcmail = rcmail::get_instance(); // 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', '_mbox' => $rcmail->output->env['mailbox'], '_uid' => $rcmail->output->env['uid'], )); $link = html::a(array('href' => $href, 'class' => 'button zipdownload'), rcube::Q($this->gettext('downloadall')) ); // append link to attachments list, slightly different in some skins switch (rcmail::get_instance()->config->get('skin')) { case 'classic': $p['content'] = str_replace('', html::tag('li', array('class' => 'zipdownload'), $link) . '', $p['content']); break; default: $p['content'] .= $link; break; } $this->include_stylesheet($this->local_skin_path() . '/zipdownload.css'); } return $p; } /** * Handler for attachment download action */ public function download_attachments() { $rcmail = rcmail::get_instance(); $imap = $rcmail->get_storage(); $temp_dir = $rcmail->config->get('temp_dir'); $tmpfname = tempnam($temp_dir, 'zipdownload'); $tempfiles = array($tmpfname); $message = new rcube_message(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET)); // open zip file $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); foreach ($message->attachments as $part) { $pid = $part->mime_id; $part = $message->mime_parts[$pid]; $filename = $part->filename; if ($filename === null || $filename === '') { $ext = (array) rcube_mime::get_mime_extensions($part->mimetype); $ext = array_shift($ext); $filename = $rcmail->gettext('messagepart') . ' ' . $pid; if ($ext) { $filename .= '.' . $ext; } } $disp_name = $this->_convert_filename($filename); if ($part->body) { $orig_message_raw = $part->body; $zip->addFromString($disp_name, $orig_message_raw); } else { $tmpfn = tempnam($temp_dir, 'zipattach'); $tmpfp = fopen($tmpfn, 'w'); $imap->get_message_part($message->uid, $part->mime_id, $part, null, $tmpfp, true); $tempfiles[] = $tmpfn; fclose($tmpfp); $zip->addFile($tmpfn, $disp_name); } } $zip->close(); $filename = ($message->subject ? $message->subject : 'roundcube') . '.zip'; $this->_deliver_zipfile($tmpfname, $filename); // delete temporary files from disk foreach ($tempfiles as $tmpfn) { unlink($tmpfn); } exit; } /** * Handler for message download action */ public function download_selection() { if (isset($_REQUEST['_uid'])) { $uids = explode(",", rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GPC)); if (sizeof($uids) > 0) { $this->_download_messages($uids); } } } /** * Handler for folder download action */ public function download_folder() { $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($uids); } /** * Helper method to packs all the given messages into a zip archive * * @param array List of message UIDs to download */ private function _download_messages($uids) { $rcmail = rcmail::get_instance(); $imap = $rcmail->get_storage(); $temp_dir = $rcmail->config->get('temp_dir'); $tmpfname = tempnam($temp_dir, 'zipdownload'); $tempfiles = array($tmpfname); // open zip file $zip = new ZipArchive(); $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE); 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 = $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); } $zip->close(); $this->_deliver_zipfile($tmpfname, $imap->get_folder() . '.zip'); // delete temporary files from disk foreach ($tempfiles as $tmpfn) { unlink($tmpfn); } exit; } /** * Helper method to send the zip archive to the browser */ private function _deliver_zipfile($tmpfname, $filename) { $browser = new rcube_browser; $rcmail = rcmail::get_instance(); $rcmail->output->nocacheing_headers(); if ($browser->ie && $browser->ver < 7) $filename = rawurlencode(abbreviate_string($filename, 55)); else if ($browser->ie) $filename = rawurlencode($filename); else $filename = addcslashes($filename, '"'); // send download headers header("Content-Type: application/octet-stream"); if ($browser->ie) { header("Content-Type: application/force-download"); } // don't kill the connection if download takes more than 30 sec. @set_time_limit(0); header("Content-Disposition: attachment; filename=\"". $filename ."\""); header("Content-length: " . filesize($tmpfname)); readfile($tmpfname); } /** * Helper function to convert filenames to the configured charset */ private function _convert_filename($str) { $str = rcube_charset::convert($str, RCUBE_CHARSET, $this->charset); return strtr($str, array(':'=>'', '/'=>'-')); } }