3 * @see https://github.com/zendframework/zend-mail for the canonical source repository
4 * @copyright Copyright (c) 2005-2018 Zend Technologies USA Inc. (https://www.zend.com)
5 * @license https://github.com/zendframework/zend-mail/blob/master/LICENSE.md New BSD License
8 namespace Zend\Mail\Storage\Folder
;
10 use Zend\Mail\Storage
;
11 use Zend\Mail\Storage\Exception
;
12 use Zend\Stdlib\ErrorHandler
;
14 class Maildir
extends Storage\Maildir
implements FolderInterface
17 * root folder for folder structure
20 protected $rootFolder;
23 * rootdir of folder structure
29 * name of current folder
32 protected $currentFolder;
35 * delim char for subfolders
41 * Create instance with parameters
43 * Supported parameters are:
45 * - dirname rootdir of maildir structure
46 * - delim delim char for folder structure, default is '.'
47 * - folder initial selected folder, default is 'INBOX'
49 * @param $params array mail reader specific parameters
50 * @throws Exception\InvalidArgumentException
52 public function __construct($params)
54 if (is_array($params)) {
55 $params = (object) $params;
58 if (! isset($params->dirname
) ||
! is_dir($params->dirname
)) {
59 throw new Exception\
InvalidArgumentException('no valid dirname given in params');
62 $this->rootdir
= rtrim($params->dirname
, DIRECTORY_SEPARATOR
) . DIRECTORY_SEPARATOR
;
64 $this->delim
= isset($params->delim
) ?
$params->delim
: '.';
66 $this->buildFolderTree();
67 $this->selectFolder(! empty($params->folder
) ?
$params->folder
: 'INBOX');
68 $this->has
['top'] = true;
69 $this->has
['flags'] = true;
73 * find all subfolders and mbox files for folder structure
75 * Result is save in Storage\Folder instances with the root in $this->rootFolder.
76 * $parentFolder and $parentGlobalName are only used internally for recursion.
78 * @throws Exception\RuntimeException
80 protected function buildFolderTree()
82 $this->rootFolder
= new Storage\
Folder('/', '/', false);
83 $this->rootFolder
->INBOX
= new Storage\
Folder('INBOX', 'INBOX', true);
85 ErrorHandler
::start(E_WARNING
);
86 $dh = opendir($this->rootdir
);
87 $error = ErrorHandler
::stop();
89 throw new Exception\
RuntimeException("can't read folders in maildir", 0, $error);
93 while (($entry = readdir($dh)) !== false) {
94 // maildir++ defines folders must start with .
95 if ($entry[0] != '.' ||
$entry == '.' ||
$entry == '..') {
99 if ($this->_isMaildir($this->rootdir
. $entry)) {
107 $folderStack = [null];
108 $parentFolder = $this->rootFolder
;
111 foreach ($dirs as $dir) {
113 if (strpos($dir, $parent) === 0) {
114 $local = substr($dir, strlen($parent));
115 if (strpos($local, $this->delim
) !== false) {
116 throw new Exception\
RuntimeException('error while reading maildir');
118 array_push($stack, $parent);
119 $parent = $dir . $this->delim
;
120 $folder = new Storage\
Folder($local, substr($dir, 1), true);
121 $parentFolder->$local = $folder;
122 array_push($folderStack, $parentFolder);
123 $parentFolder = $folder;
126 $parent = array_pop($stack);
127 $parentFolder = array_pop($folderStack);
131 throw new Exception\
RuntimeException('error while reading maildir');
137 * get root folder or given folder
139 * @param string $rootFolder get folder structure for given folder, else root
140 * @throws \Zend\Mail\Storage\Exception\InvalidArgumentException
141 * @return \Zend\Mail\Storage\Folder root or wanted folder
143 public function getFolders($rootFolder = null)
145 if (! $rootFolder ||
$rootFolder == 'INBOX') {
146 return $this->rootFolder
;
149 // rootdir is same as INBOX in maildir
150 if (strpos($rootFolder, 'INBOX' . $this->delim
) === 0) {
151 $rootFolder = substr($rootFolder, 6);
153 $currentFolder = $this->rootFolder
;
154 $subname = trim($rootFolder, $this->delim
);
156 while ($currentFolder) {
157 ErrorHandler
::start(E_NOTICE
);
158 list($entry, $subname) = explode($this->delim
, $subname, 2);
159 ErrorHandler
::stop();
160 $currentFolder = $currentFolder->$entry;
166 if ($currentFolder->getGlobalName() != rtrim($rootFolder, $this->delim
)) {
167 throw new Exception\
InvalidArgumentException("folder $rootFolder not found");
169 return $currentFolder;
173 * select given folder
175 * folder must be selectable!
177 * @param Storage\Folder|string $globalName global name of folder or
178 * instance for subfolder
179 * @throws Exception\RuntimeException
181 public function selectFolder($globalName)
183 $this->currentFolder
= (string) $globalName;
185 // getting folder from folder tree for validation
186 $folder = $this->getFolders($this->currentFolder
);
189 $this->_openMaildir($this->rootdir
. '.' . $folder->getGlobalName());
190 } catch (Exception\ExceptionInterface
$e) {
191 // check what went wrong
192 if (! $folder->isSelectable()) {
193 throw new Exception\
RuntimeException("{$this->currentFolder} is not selectable", 0, $e);
195 // seems like file has vanished; rebuilding folder tree - but it's still an exception
196 $this->buildFolderTree();
197 throw new Exception\
RuntimeException(
198 'seems like the maildir has vanished; I have rebuilt the folder tree; '
199 . 'search for another folder and try again',
207 * get Storage\Folder instance for current folder
209 * @return Storage\Folder instance of current folder
211 public function getCurrentFolder()
213 return $this->currentFolder
;