1<?php 2/** 3 * Copyright 2011-2017 Horde LLC (http://www.horde.org/) 4 * 5 * See the enclosed file COPYING for license information (GPL). If you 6 * did not receive this file, see http://www.horde.org/licenses/gpl. 7 * 8 * @category Horde 9 * @copyright 2011-2017 Horde LLC 10 * @license http://www.horde.org/licenses/gpl GPL 11 * @package IMP 12 */ 13 14/** 15 * Method to import MBOX data into a mailbox. 16 * 17 * @author Michael Slusarz <slusarz@horde.org> 18 * @category Horde 19 * @copyright 2011-2017 Horde LLC 20 * @license http://www.horde.org/licenses/gpl GPL 21 * @package IMP 22 */ 23class IMP_Mbox_Import 24{ 25 /** 26 * Temporary data. 27 * 28 * @var array 29 */ 30 protected $_import; 31 32 /** 33 * Import mailbox. 34 * 35 * @var IMP_Mailbox 36 */ 37 protected $_mbox; 38 39 /** 40 * Import a MBOX file into a mailbox. 41 * 42 * @param string $mbox The mailbox name to import into (UTF-8). 43 * @param string $form_name The form field name that contains the MBOX 44 * data. 45 * 46 * @return string Notification message. 47 * @throws Horde_Exception 48 */ 49 public function import($mbox, $form_name) 50 { 51 $GLOBALS['browser']->wasFileUploaded($form_name, _("mailbox file")); 52 $this->_mbox = $mbox; 53 54 $res = $this->_import($_FILES[$form_name]['tmp_name'], $_FILES[$form_name]['type']); 55 $mbox_name = basename(Horde_Util::dispelMagicQuotes($_FILES[$form_name]['name'])); 56 57 if ($res === false) { 58 throw new IMP_Exception(sprintf(_("There was an error importing %s."), $mbox_name)); 59 } 60 61 return sprintf(ngettext('Imported %d message from %s.', 'Imported %d messages from %s', $res), $res, $mbox_name); 62 } 63 64 /** 65 * Imports messages from a mbox (see RFC 4155) -or- a message source 66 * (eml) file. 67 * 68 * @param string $fname Filename containing the message data. 69 * @param string $type The MIME type of the message data. 70 * 71 * @return mixed False (boolean) on fail or the number of messages 72 * imported (integer) on success. 73 * @throws IMP_Exception 74 */ 75 protected function _import($fname, $type) 76 { 77 if (!is_readable($fname)) { 78 return false; 79 } 80 81 $fd = null; 82 83 switch ($type) { 84 case 'application/gzip': 85 case 'application/x-gzip': 86 case 'application/x-gzip-compressed': 87 // No need to default to Horde_Compress because it uses zlib 88 // also. 89 if (in_array('compress.zlib', stream_get_wrappers())) { 90 $fd = 'compress.zlib://' . $fname; 91 } 92 break; 93 94 case 'application/x-bzip2': 95 case 'application/x-bzip': 96 if (in_array('compress.bzip2', stream_get_wrappers())) { 97 $fd = 'compress.bzip2://' . $fname; 98 } 99 break; 100 101 case 'application/zip': 102 case 'application/x-compressed': 103 case 'application/x-zip-compressed': 104 if (in_array('zip', stream_get_wrappers())) { 105 $fd = 'zip://' . $fname; 106 } else { 107 try { 108 $zip = Horde_Compress::factory('Zip'); 109 if ($zip->canDecompress) { 110 $file_data = file_get_contents($fname); 111 112 $zip_info = $zip->decompress($file_data, array( 113 'action' => Horde_Compress_Zip::ZIP_LIST 114 )); 115 116 if (!empty($zip_info)) { 117 $fd = fopen('php://temp', 'r+'); 118 119 foreach (array_keys($zip_info) as $key) { 120 fwrite($fd, $zip->decompress($file_data, array( 121 'action' => Horde_Compress_Zip::ZIP_DATA, 122 'info' => $zip_info, 123 'key' => $key 124 ))); 125 } 126 127 rewind($fd); 128 } 129 } 130 } catch (Horde_Compress_Exception $e) { 131 if ($fd) { 132 fclose($fd); 133 $fd = null; 134 } 135 } 136 } 137 break; 138 139 default: 140 $fd = $fname; 141 break; 142 } 143 144 if (is_null($fd)) { 145 throw new IMP_Exception(_("The uploaded file cannot be opened.")); 146 } 147 148 $parsed = new IMP_Mbox_Parse( 149 $fd, 150 $GLOBALS['injector']->getInstance('IMP_Factory_Imap')->create()->config->import_limit 151 ); 152 153 $this->_import = array( 154 'data' => array(), 155 'msgs' => 0, 156 'size' => 0 157 ); 158 159 if ($pcount = count($parsed)) { 160 foreach ($parsed as $key => $val) { 161 $this->_importHelper($val, ($key + 1) != $pcount); 162 } 163 } else { 164 $this->_importHelper($parsed[0]); 165 } 166 167 return $this->_import['msgs'] 168 ? $this->_import['msgs'] 169 : false; 170 } 171 172 /** 173 * Helper for _import(). 174 * 175 * @param array $msg Message data. 176 * @param integer $buffer Buffer messages before sending? 177 */ 178 protected function _importHelper($msg, $buffer = false) 179 { 180 $this->_import['data'][] = array_filter(array( 181 'data' => $msg['data'], 182 'internaldate' => $msg['date'] 183 )); 184 $this->_import['size'] += $msg['size']; 185 186 /* Buffer 1 MB of messages before sending. */ 187 if ($buffer && ($this->_import['size'] < 1048576)) { 188 return; 189 } 190 191 try { 192 $this->_mbox->imp_imap->append($this->_mbox, $this->_import['data']); 193 $this->_import['msgs'] += count($this->_import['data']); 194 } catch (IMP_Imap_Exception $e) { 195 throw new IMP_Exception(sprintf(_("Error when importing messages; %u messages successfully imported before error."), $this->_import['msgs'])); 196 } 197 198 foreach ($this->_import['data'] as $val) { 199 fclose($val['data']); 200 } 201 202 $this->_import['data'] = array(); 203 $this->_import['size'] = 0; 204 } 205 206} 207