PageRenderTime 42ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/zipdownload/zipdownload.php

https://github.com/fretelweb/roundcubemail
PHP | 272 lines | 176 code | 49 blank | 47 comment | 34 complexity | 4d3cb9e8c1f5e2c0893fdeb7fff9f408 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. <?php
  2. /**
  3. * ZipDownload
  4. *
  5. * Plugin to allow the download of all message attachments in one zip file
  6. *
  7. * @version @package_version@
  8. * @requires php_zip extension (including ZipArchive class)
  9. * @author Philip Weir
  10. * @author Thomas Bruderli
  11. */
  12. class zipdownload extends rcube_plugin
  13. {
  14. public $task = 'mail';
  15. private $charset = 'ASCII';
  16. /**
  17. * Plugin initialization
  18. */
  19. public function init()
  20. {
  21. // check requirements first
  22. if (!class_exists('ZipArchive', false)) {
  23. rcmail::raise_error(array(
  24. 'code' => 520, 'type' => 'php',
  25. 'file' => __FILE__, 'line' => __LINE__,
  26. 'message' => "php_zip extension is required for the zipdownload plugin"), true, false);
  27. return;
  28. }
  29. $rcmail = rcmail::get_instance();
  30. $this->load_config();
  31. $this->charset = $rcmail->config->get('zipdownload_charset', RCUBE_CHARSET);
  32. $this->add_texts('localization');
  33. if ($rcmail->config->get('zipdownload_attachments', 1) > -1 && ($rcmail->action == 'show' || $rcmail->action == 'preview'))
  34. $this->add_hook('template_object_messageattachments', array($this, 'attachment_ziplink'));
  35. $this->register_action('plugin.zipdownload.zip_attachments', array($this, 'download_attachments'));
  36. $this->register_action('plugin.zipdownload.zip_messages', array($this, 'download_selection'));
  37. $this->register_action('plugin.zipdownload.zip_folder', array($this, 'download_folder'));
  38. if ($rcmail->config->get('zipdownload_folder', false) || $rcmail->config->get('zipdownload_selection', false)) {
  39. $this->include_script('zipdownload.js');
  40. $this->api->output->set_env('zipdownload_selection', $rcmail->config->get('zipdownload_selection', false));
  41. if ($rcmail->config->get('zipdownload_folder', false) && ($rcmail->action == '' || $rcmail->action == 'show')) {
  42. $zipdownload = $this->api->output->button(array('command' => 'plugin.zipdownload.zip_folder', 'type' => 'link', 'classact' => 'active', 'content' => $this->gettext('downloadfolder')));
  43. $this->api->add_content(html::tag('li', array('class' => 'separator_above'), $zipdownload), 'mailboxoptions');
  44. }
  45. }
  46. }
  47. /**
  48. * Place a link/button after attachments listing to trigger download
  49. */
  50. public function attachment_ziplink($p)
  51. {
  52. $rcmail = rcmail::get_instance();
  53. // only show the link if there is more than the configured number of attachments
  54. if (substr_count($p['content'], '<li') > $rcmail->config->get('zipdownload_attachments', 1)) {
  55. $href = $rcmail->url(array(
  56. '_action' => 'plugin.zipdownload.zip_attachments',
  57. '_mbox' => $rcmail->output->env['mailbox'],
  58. '_uid' => $rcmail->output->env['uid'],
  59. ));
  60. $link = html::a(array('href' => $href, 'class' => 'button zipdownload'),
  61. rcube::Q($this->gettext('downloadall'))
  62. );
  63. // append link to attachments list, slightly different in some skins
  64. switch (rcmail::get_instance()->config->get('skin')) {
  65. case 'classic':
  66. $p['content'] = str_replace('</ul>', html::tag('li', array('class' => 'zipdownload'), $link) . '</ul>', $p['content']);
  67. break;
  68. default:
  69. $p['content'] .= $link;
  70. break;
  71. }
  72. $this->include_stylesheet($this->local_skin_path() . '/zipdownload.css');
  73. }
  74. return $p;
  75. }
  76. /**
  77. * Handler for attachment download action
  78. */
  79. public function download_attachments()
  80. {
  81. $rcmail = rcmail::get_instance();
  82. $imap = $rcmail->storage;
  83. $temp_dir = $rcmail->config->get('temp_dir');
  84. $tmpfname = tempnam($temp_dir, 'zipdownload');
  85. $tempfiles = array($tmpfname);
  86. $message = new rcube_message(rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GET));
  87. // open zip file
  88. $zip = new ZipArchive();
  89. $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
  90. foreach ($message->attachments as $part) {
  91. $pid = $part->mime_id;
  92. $part = $message->mime_parts[$pid];
  93. $disp_name = $this->_convert_filename($part->filename);
  94. if ($part->body) {
  95. $orig_message_raw = $part->body;
  96. $zip->addFromString($disp_name, $orig_message_raw);
  97. }
  98. else {
  99. $tmpfn = tempnam($temp_dir, 'zipattach');
  100. $tmpfp = fopen($tmpfn, 'w');
  101. $imap->get_message_part($message->uid, $part->mime_id, $part, null, $tmpfp, true);
  102. $tempfiles[] = $tmpfn;
  103. fclose($tmpfp);
  104. $zip->addFile($tmpfn, $disp_name);
  105. }
  106. }
  107. $zip->close();
  108. $filename = ($message->subject ? $message->subject : 'roundcube') . '.zip';
  109. $this->_deliver_zipfile($tmpfname, $filename);
  110. // delete temporary files from disk
  111. foreach ($tempfiles as $tmpfn)
  112. unlink($tmpfn);
  113. exit;
  114. }
  115. /**
  116. * Handler for message download action
  117. */
  118. public function download_selection()
  119. {
  120. if (isset($_REQUEST['_uid'])) {
  121. $uids = explode(",", rcube_utils::get_input_value('_uid', rcube_utils::INPUT_GPC));
  122. if (sizeof($uids) > 0)
  123. $this->_download_messages($uids);
  124. }
  125. }
  126. /**
  127. * Handler for folder download action
  128. */
  129. public function download_folder()
  130. {
  131. $imap = rcmail::get_instance()->storage;
  132. $mbox_name = $imap->get_folder();
  133. // initialize searching result if search_filter is used
  134. if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') {
  135. $imap->search($mbox_name, $_SESSION['search_filter'], RCUBE_CHARSET);
  136. }
  137. // fetch message headers for all pages
  138. $uids = array();
  139. if ($count = $imap->count($mbox_name, $imap->get_threading() ? 'THREADS' : 'ALL', FALSE)) {
  140. for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) {
  141. $a_headers = $imap->list_messages($mbox_name, ($i + 1));
  142. foreach ($a_headers as $header) {
  143. if (empty($header))
  144. continue;
  145. array_push($uids, $header->uid);
  146. }
  147. }
  148. }
  149. if (sizeof($uids) > 0)
  150. $this->_download_messages($uids);
  151. }
  152. /**
  153. * Helper method to packs all the given messages into a zip archive
  154. *
  155. * @param array List of message UIDs to download
  156. */
  157. private function _download_messages($uids)
  158. {
  159. $rcmail = rcmail::get_instance();
  160. $imap = $rcmail->storage;
  161. $temp_dir = $rcmail->config->get('temp_dir');
  162. $tmpfname = tempnam($temp_dir, 'zipdownload');
  163. $tempfiles = array($tmpfname);
  164. // open zip file
  165. $zip = new ZipArchive();
  166. $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
  167. foreach ($uids as $uid){
  168. $headers = $imap->get_message_headers($uid);
  169. $subject = rcube_mime::decode_mime_string((string)$headers->subject);
  170. $subject = $this->_convert_filename($subject);
  171. $subject = substr($subject, 0, 16);
  172. if (isset($subject) && $subject !="")
  173. $disp_name = $subject . ".eml";
  174. else
  175. $disp_name = "message_rfc822.eml";
  176. $disp_name = $uid . "_" . $disp_name;
  177. $tmpfn = tempnam($temp_dir, 'zipmessage');
  178. $tmpfp = fopen($tmpfn, 'w');
  179. $imap->get_raw_body($uid, $tmpfp);
  180. $tempfiles[] = $tmpfn;
  181. fclose($tmpfp);
  182. $zip->addFile($tmpfn, $disp_name);
  183. }
  184. $zip->close();
  185. $this->_deliver_zipfile($tmpfname, $imap->get_folder() . '.zip');
  186. // delete temporary files from disk
  187. foreach ($tempfiles as $tmpfn)
  188. unlink($tmpfn);
  189. exit;
  190. }
  191. /**
  192. * Helper method to send the zip archive to the browser
  193. */
  194. private function _deliver_zipfile($tmpfname, $filename)
  195. {
  196. $browser = new rcube_browser;
  197. $rcmail = rcmail::get_instance();
  198. $rcmail->output->nocacheing_headers();
  199. if ($browser->ie && $browser->ver < 7)
  200. $filename = rawurlencode(abbreviate_string($filename, 55));
  201. else if ($browser->ie)
  202. $filename = rawurlencode($filename);
  203. else
  204. $filename = addcslashes($filename, '"');
  205. // send download headers
  206. header("Content-Type: application/octet-stream");
  207. if ($browser->ie)
  208. header("Content-Type: application/force-download");
  209. // don't kill the connection if download takes more than 30 sec.
  210. @set_time_limit(0);
  211. header("Content-Disposition: attachment; filename=\"". $filename ."\"");
  212. header("Content-length: " . filesize($tmpfname));
  213. readfile($tmpfname);
  214. }
  215. /**
  216. * Helper function to convert filenames to the configured charset
  217. */
  218. private function _convert_filename($str)
  219. {
  220. $str = rcube_charset::convert($str, RCUBE_CHARSET, $this->charset);
  221. return strtr($str, array(':'=>'', '/'=>'-'));
  222. }
  223. }