PageRenderTime 47ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/plugins/zipdownload/zipdownload.php

https://github.com/netconstructor/roundcubemail
PHP | 267 lines | 173 code | 47 blank | 47 comment | 34 complexity | f1799bf78ed38055dde6edd71f87796e 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->charset = $rcmail->config->get('zipdownload_charset', RCMAIL_CHARSET);
  31. $this->load_config();
  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. $link = html::a(array(
  56. 'href' => rcmail_url('plugin.zipdownload.zip_attachments', array('_mbox' => $rcmail->output->env['mailbox'], '_uid' => $rcmail->output->env['uid'])),
  57. 'class' => 'button zipdownload',
  58. ),
  59. Q($this->gettext('downloadall'))
  60. );
  61. // append link to attachments list, slightly different in some skins
  62. switch (rcmail::get_instance()->config->get('skin')) {
  63. case 'classic':
  64. $p['content'] = str_replace('</ul>', html::tag('li', array('class' => 'zipdownload'), $link) . '</ul>', $p['content']);
  65. break;
  66. default:
  67. $p['content'] .= $link;
  68. break;
  69. }
  70. $this->include_stylesheet($this->local_skin_path() . '/zipdownload.css');
  71. }
  72. return $p;
  73. }
  74. /**
  75. * Handler for attachment download action
  76. */
  77. public function download_attachments()
  78. {
  79. $rcmail = rcmail::get_instance();
  80. $imap = $rcmail->storage;
  81. $temp_dir = $rcmail->config->get('temp_dir');
  82. $tmpfname = tempnam($temp_dir, 'zipdownload');
  83. $tempfiles = array($tmpfname);
  84. $message = new rcube_message(get_input_value('_uid', RCUBE_INPUT_GET));
  85. // open zip file
  86. $zip = new ZipArchive();
  87. $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
  88. foreach ($message->attachments as $part) {
  89. $pid = $part->mime_id;
  90. $part = $message->mime_parts[$pid];
  91. $disp_name = $this->_convert_filename($part->filename, $part->charset);
  92. if ($part->body) {
  93. $orig_message_raw = $part->body;
  94. $zip->addFromString($disp_name, $orig_message_raw);
  95. }
  96. else {
  97. $tmpfn = tempnam($temp_dir, 'zipattach');
  98. $tmpfp = fopen($tmpfn, 'w');
  99. $imap->get_message_part($message->uid, $part->mime_id, $part, null, $tmpfp, true);
  100. $tempfiles[] = $tmpfn;
  101. fclose($tmpfp);
  102. $zip->addFile($tmpfn, $disp_name);
  103. }
  104. }
  105. $zip->close();
  106. $filename = ($message->subject ? $message->subject : 'roundcube') . '.zip';
  107. $this->_deliver_zipfile($tmpfname, $filename);
  108. // delete temporary files from disk
  109. foreach ($tempfiles as $tmpfn)
  110. unlink($tmpfn);
  111. exit;
  112. }
  113. /**
  114. * Handler for message download action
  115. */
  116. public function download_selection()
  117. {
  118. if (isset($_REQUEST['_uid'])) {
  119. $uids = explode(",", get_input_value('_uid', RCUBE_INPUT_GPC));
  120. if (sizeof($uids) > 0)
  121. $this->_download_messages($uids);
  122. }
  123. }
  124. /**
  125. * Handler for folder download action
  126. */
  127. public function download_folder()
  128. {
  129. $imap = rcmail::get_instance()->storage;
  130. $mbox_name = $imap->get_folder();
  131. // initialize searching result if search_filter is used
  132. if ($_SESSION['search_filter'] && $_SESSION['search_filter'] != 'ALL') {
  133. $imap->search($mbox_name, $_SESSION['search_filter'], RCMAIL_CHARSET);
  134. }
  135. // fetch message headers for all pages
  136. $uids = array();
  137. if ($count = $imap->count($mbox_name, $imap->get_threading() ? 'THREADS' : 'ALL', FALSE)) {
  138. for ($i = 0; ($i * $imap->get_pagesize()) <= $count; $i++) {
  139. $a_headers = $imap->list_messages($mbox_name, ($i + 1));
  140. foreach ($a_headers as $n => $header) {
  141. if (empty($header))
  142. continue;
  143. array_push($uids, $header->uid);
  144. }
  145. }
  146. }
  147. if (sizeof($uids) > 0)
  148. $this->_download_messages($uids);
  149. }
  150. /**
  151. * Helper method to packs all the given messages into a zip archive
  152. *
  153. * @param array List of message UIDs to download
  154. */
  155. private function _download_messages($uids)
  156. {
  157. $rcmail = rcmail::get_instance();
  158. $imap = $rcmail->storage;
  159. $temp_dir = $rcmail->config->get('temp_dir');
  160. $tmpfname = tempnam($temp_dir, 'zipdownload');
  161. $tempfiles = array($tmpfname);
  162. // open zip file
  163. $zip = new ZipArchive();
  164. $zip->open($tmpfname, ZIPARCHIVE::OVERWRITE);
  165. foreach ($uids as $key => $uid){
  166. $headers = $imap->get_message_headers($uid);
  167. $subject = rcube_mime::decode_mime_string((string)$headers->subject);
  168. $subject = $this->_convert_filename($subject);
  169. $subject = substr($subject, 0, 16);
  170. if (isset($subject) && $subject !="")
  171. $disp_name = $subject . ".eml";
  172. else
  173. $disp_name = "message_rfc822.eml";
  174. $disp_name = $uid . "_" . $disp_name;
  175. $tmpfn = tempnam($temp_dir, 'zipmessage');
  176. $tmpfp = fopen($tmpfn, 'w');
  177. $imap->get_raw_body($uid, $tmpfp);
  178. $tempfiles[] = $tmpfn;
  179. fclose($tmpfp);
  180. $zip->addFile($tmpfn, $disp_name);
  181. }
  182. $zip->close();
  183. $this->_deliver_zipfile($tmpfname, $imap->get_folder() . '.zip');
  184. // delete temporary files from disk
  185. foreach ($tempfiles as $tmpfn)
  186. unlink($tmpfn);
  187. exit;
  188. }
  189. /**
  190. * Helper method to send the zip archive to the browser
  191. */
  192. private function _deliver_zipfile($tmpfname, $filename)
  193. {
  194. $browser = new rcube_browser;
  195. send_nocacheing_headers();
  196. if ($browser->ie && $browser->ver < 7)
  197. $filename = rawurlencode(abbreviate_string($filename, 55));
  198. else if ($browser->ie)
  199. $filename = rawurlencode($filename);
  200. else
  201. $filename = addcslashes($filename, '"');
  202. // send download headers
  203. header("Content-Type: application/octet-stream");
  204. if ($browser->ie)
  205. header("Content-Type: application/force-download");
  206. // don't kill the connection if download takes more than 30 sec.
  207. @set_time_limit(0);
  208. header("Content-Disposition: attachment; filename=\"". $filename ."\"");
  209. header("Content-length: " . filesize($tmpfname));
  210. readfile($tmpfname);
  211. }
  212. /**
  213. * Helper function to convert filenames to the configured charset
  214. */
  215. private function _convert_filename($str, $from = RCMAIL_CHARSET)
  216. {
  217. return strtr(rcube_charset_convert($str, $from, $this->charset), array(':'=>'', '/'=>'-'));
  218. }
  219. }
  220. ?>