1<?php 2/** 3 * Zend Framework 4 * 5 * LICENSE 6 * 7 * This source file is subject to the new BSD license that is bundled 8 * with this package in the file LICENSE.txt. 9 * It is also available through the world-wide-web at this URL: 10 * http://framework.zend.com/license/new-bsd 11 * If you did not receive a copy of the license and are unable to 12 * obtain it through the world-wide-web, please send an email 13 * to license@zend.com so we can send you a copy immediately. 14 * 15 * @category Zend 16 * @package Zend_Mail 17 * @subpackage Storage 18 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 19 * @license http://framework.zend.com/license/new-bsd New BSD License 20 * @version $Id$ 21 */ 22 23 24/** 25 * @see Zend_Mail_Storage_Folder 26 */ 27 28/** 29 * @see Zend_Mail_Storage_Folder_Interface 30 */ 31 32/** 33 * @see Zend_Mail_Storage_Maildir 34 */ 35 36 37/** 38 * @category Zend 39 * @package Zend_Mail 40 * @subpackage Storage 41 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 42 * @license http://framework.zend.com/license/new-bsd New BSD License 43 */ 44class Zend_Mail_Storage_Folder_Maildir extends Zend_Mail_Storage_Maildir implements Zend_Mail_Storage_Folder_Interface 45{ 46 /** 47 * Zend_Mail_Storage_Folder root folder for folder structure 48 * @var Zend_Mail_Storage_Folder 49 */ 50 protected $_rootFolder; 51 52 /** 53 * rootdir of folder structure 54 * @var string 55 */ 56 protected $_rootdir; 57 58 /** 59 * name of current folder 60 * @var string 61 */ 62 protected $_currentFolder; 63 64 /** 65 * delim char for subfolders 66 * @var string 67 */ 68 protected $_delim; 69 70 /** 71 * Create instance with parameters 72 * Supported parameters are: 73 * - dirname rootdir of maildir structure 74 * - delim delim char for folder structur, default is '.' 75 * - folder intial selected folder, default is 'INBOX' 76 * 77 * @param array $params mail reader specific parameters 78 * @throws Zend_Mail_Storage_Exception 79 */ 80 public function __construct($params) 81 { 82 if (is_array($params)) { 83 $params = (object)$params; 84 } 85 86 if (!isset($params->dirname) || !is_dir($params->dirname)) { 87 /** 88 * @see Zend_Mail_Storage_Exception 89 */ 90 throw new Zend_Mail_Storage_Exception('no valid dirname given in params'); 91 } 92 93 $this->_rootdir = rtrim($params->dirname, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 94 95 $this->_delim = isset($params->delim) ? $params->delim : '.'; 96 97 $this->_buildFolderTree(); 98 $this->selectFolder(!empty($params->folder) ? $params->folder : 'INBOX'); 99 $this->_has['top'] = true; 100 $this->_has['flags'] = true; 101 } 102 103 /** 104 * find all subfolders and mbox files for folder structure 105 * 106 * Result is save in Zend_Mail_Storage_Folder instances with the root in $this->_rootFolder. 107 * $parentFolder and $parentGlobalName are only used internally for recursion. 108 * 109 * @return null 110 * @throws Zend_Mail_Storage_Exception 111 */ 112 protected function _buildFolderTree() 113 { 114 $this->_rootFolder = new Zend_Mail_Storage_Folder('/', '/', false); 115 $this->_rootFolder->INBOX = new Zend_Mail_Storage_Folder('INBOX', 'INBOX', true); 116 117 $dh = @opendir($this->_rootdir); 118 if (!$dh) { 119 /** 120 * @see Zend_Mail_Storage_Exception 121 */ 122 throw new Zend_Mail_Storage_Exception("can't read folders in maildir"); 123 } 124 $dirs = array(); 125 while (($entry = readdir($dh)) !== false) { 126 // maildir++ defines folders must start with . 127 if ($entry[0] != '.' || $entry == '.' || $entry == '..') { 128 continue; 129 } 130 if ($this->_isMaildir($this->_rootdir . $entry)) { 131 $dirs[] = $entry; 132 } 133 } 134 closedir($dh); 135 136 sort($dirs); 137 $stack = array(null); 138 $folderStack = array(null); 139 $parentFolder = $this->_rootFolder; 140 $parent = '.'; 141 142 foreach ($dirs as $dir) { 143 do { 144 if (strpos($dir, $parent) === 0) { 145 $local = substr($dir, strlen($parent)); 146 if (strpos($local, $this->_delim) !== false) { 147 /** 148 * @see Zend_Mail_Storage_Exception 149 */ 150 throw new Zend_Mail_Storage_Exception('error while reading maildir'); 151 } 152 array_push($stack, $parent); 153 $parent = $dir . $this->_delim; 154 $folder = new Zend_Mail_Storage_Folder($local, substr($dir, 1), true); 155 $parentFolder->$local = $folder; 156 array_push($folderStack, $parentFolder); 157 $parentFolder = $folder; 158 break; 159 } else if ($stack) { 160 $parent = array_pop($stack); 161 $parentFolder = array_pop($folderStack); 162 } 163 } while ($stack); 164 if (!$stack) { 165 /** 166 * @see Zend_Mail_Storage_Exception 167 */ 168 throw new Zend_Mail_Storage_Exception('error while reading maildir'); 169 } 170 } 171 } 172 173 /** 174 * get root folder or given folder 175 * 176 * @param string $rootFolder get folder structure for given folder, else root 177 * @return Zend_Mail_Storage_Folder root or wanted folder 178 * @throws Zend_Mail_Storage_Exception 179 */ 180 public function getFolders($rootFolder = null) 181 { 182 if (!$rootFolder || $rootFolder == 'INBOX') { 183 return $this->_rootFolder; 184 } 185 186 // rootdir is same as INBOX in maildir 187 if (strpos($rootFolder, 'INBOX' . $this->_delim) === 0) { 188 $rootFolder = substr($rootFolder, 6); 189 } 190 $currentFolder = $this->_rootFolder; 191 $subname = trim($rootFolder, $this->_delim); 192 while ($currentFolder) { 193 @list($entry, $subname) = @explode($this->_delim, $subname, 2); 194 $currentFolder = $currentFolder->$entry; 195 if (!$subname) { 196 break; 197 } 198 } 199 200 if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->_delim)) { 201 /** 202 * @see Zend_Mail_Storage_Exception 203 */ 204 throw new Zend_Mail_Storage_Exception("folder $rootFolder not found"); 205 } 206 return $currentFolder; 207 } 208 209 /** 210 * select given folder 211 * 212 * folder must be selectable! 213 * 214 * @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder 215 * @return null 216 * @throws Zend_Mail_Storage_Exception 217 */ 218 public function selectFolder($globalName) 219 { 220 $this->_currentFolder = (string)$globalName; 221 222 // getting folder from folder tree for validation 223 $folder = $this->getFolders($this->_currentFolder); 224 225 try { 226 $this->_openMaildir($this->_rootdir . '.' . $folder->getGlobalName()); 227 } catch(Zend_Mail_Storage_Exception $e) { 228 // check what went wrong 229 if (!$folder->isSelectable()) { 230 /** 231 * @see Zend_Mail_Storage_Exception 232 */ 233 throw new Zend_Mail_Storage_Exception("{$this->_currentFolder} is not selectable", 0, $e); 234 } 235 // seems like file has vanished; rebuilding folder tree - but it's still an exception 236 $this->_buildFolderTree($this->_rootdir); 237 /** 238 * @see Zend_Mail_Storage_Exception 239 */ 240 throw new Zend_Mail_Storage_Exception('seems like the maildir has vanished, I\'ve rebuild the ' . 241 'folder tree, search for an other folder and try again', 0, $e); 242 } 243 } 244 245 /** 246 * get Zend_Mail_Storage_Folder instance for current folder 247 * 248 * @return Zend_Mail_Storage_Folder instance of current folder 249 * @throws Zend_Mail_Storage_Exception 250 */ 251 public function getCurrentFolder() 252 { 253 return $this->_currentFolder; 254 } 255} 256