1<?php 2 3/** 4 * Inline PDF viewer plugin 5 * 6 * Render PDF files directly in the preview window 7 * by using the JavaScript PDF Reader pdf.js by andreasgal (http://mozilla.github.com/pdf.js) 8 * 9 * @version 0.1.2 10 * @author Thomas Bruederli <bruederli@kolabsys.com> 11 * 12 * Copyright (C) 2013, Kolab Systems AG 13 * 14 * This program is free software: you can redistribute it and/or modify 15 * it under the terms of the GNU Affero General Public License as 16 * published by the Free Software Foundation, either version 3 of the 17 * License, or (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU Affero General Public License for more details. 23 * 24 * You should have received a copy of the GNU Affero General Public License 25 * along with this program. If not, see <http://www.gnu.org/licenses/>. 26 */ 27class pdfviewer extends rcube_plugin 28{ 29 public $task = 'mail|calendar|tasks|logout'; 30 31 private $pdf_mimetypes = array( 32 'application/pdf', 33 'application/x-pdf', 34 'application/acrobat', 35 'applications/vnd.pdf', 36 'text/pdf', 37 'text/x-pdf', 38 ); 39 40 /** 41 * Plugin initialization 42 */ 43 function init() 44 { 45 // pdf.js only supports IE9 or higher 46 $ua = new rcube_browser; 47 if ($ua->ie && $ua->ver < 9) 48 return; 49 50 // extend list of mimetypes that should open in preview 51 $rcmail = rcube::get_instance(); 52 if ($rcmail->action == 'preview' || $rcmail->action == 'show' || $rcmail->task == 'calendar' || $rcmail->task == 'tasks') { 53 $mimetypes = (array)$rcmail->config->get('client_mimetypes'); 54 $rcmail->config->set('client_mimetypes', array_merge($mimetypes, $this->pdf_mimetypes)); 55 } 56 57 // only use pdf.js if the browser doesn't support inline PDF rendering 58 if (empty($_SESSION['browser_caps']['pdf']) || $ua->opera) 59 $this->add_hook('message_part_get', array($this, 'get_part')); 60 61 $this->add_hook('message_part_structure', array($this, 'part_structure')); 62 } 63 64 /** 65 * Handler for message attachment download 66 */ 67 public function get_part($args) 68 { 69 // redirect to viewer/viewer.html 70 if (!$args['download'] && $args['mimetype'] && empty($_GET['_load']) && in_array($args['mimetype'], $this->pdf_mimetypes)) { 71 $rcmail = rcube::get_instance(); 72 $file_url = $_SERVER['REQUEST_URI'] . '&_load=1'; 73 $location = $rcmail->output->asset_url($this->urlbase . 'viewer/viewer.html'); 74 75 header('Location: ' . $location . '?file=' . urlencode($file_url)); 76 exit; 77 } 78 79 return $args; 80 } 81 82 /** 83 * Hook for MIME message parsing. 84 * This allows us to fix mimetypes of PDF attachments 85 */ 86 public function part_structure($args) 87 { 88 if (!empty($args['structure']->parts)) { 89 foreach (array_keys($args['structure']->parts) as $i) { 90 $this->fix_mime_part($args['structure']->parts[$i], $args['object']); 91 } 92 } 93 else if ($args['structure']->mimetype != $args['mimetype']) { 94 $args['mimetype'] = $args['structure']; 95 } 96 97 return $args; 98 } 99 100 /** 101 * Helper method to fix potentially invalid mimetypes of PDF attachments 102 */ 103 private function fix_mime_part($part, $message) 104 { 105 // Some versions of Outlook create garbage Content-Type: 106 // application/pdf.A520491B_3BF7_494D_8855_7FAC2C6C0608 107 if (preg_match('/^application\/pdf.+/', $part->mimetype)) { 108 $part->mimetype = 'application/pdf'; 109 } 110 111 // try to fix invalid application/octet-stream mimetypes for PDF attachments 112 if ($part->mimetype == 'application/octet-stream' && preg_match('/\.pdf$/', strval($part->filename))) { 113 $body = $message->get_part_body($part->mime_id, false, 2048); 114 $real_mimetype = rcube_mime::file_content_type($body, $part->filename, $part->mimetype, true, true); 115 if (in_array($real_mimetype, $this->pdf_mimetypes)) { 116 $part->mimetype = $real_mimetype; 117 } 118 } 119 120 list($part->ctype_primary, $part->ctype_secondary) = explode('/', $part->mimetype); 121 } 122} 123