PageRenderTime 48ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Zend/Mail/Storage/Maildir.php

https://gitlab.com/devtoannh/cafe
PHP | 475 lines | 227 code | 53 blank | 195 comment | 47 complexity | 0e735a976f5490ae4f73a222df667a2d MD5 | raw file
  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-2011 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. * @version $Id: Maildir.php 23775 2011-03-01 17:25:24Z ralph $
  21. */
  22. /**
  23. * @see Zend_Mail_Storage_Abstract
  24. */
  25. require_once 'Zend/Mail/Storage/Abstract.php';
  26. /**
  27. * @see Zend_Mail_Message_File
  28. */
  29. require_once 'Zend/Mail/Message/File.php';
  30. /**
  31. * @see Zend_Mail_Storage
  32. */
  33. require_once 'Zend/Mail/Storage.php';
  34. /**
  35. * @category Zend
  36. * @package Zend_Mail
  37. * @subpackage Storage
  38. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  39. * @license http://framework.zend.com/license/new-bsd New BSD License
  40. */
  41. class Zend_Mail_Storage_Maildir extends Zend_Mail_Storage_Abstract
  42. {
  43. /**
  44. * used message class, change it in an extened class to extend the returned message class
  45. * @var string
  46. */
  47. protected $_messageClass = 'Zend_Mail_Message_File';
  48. /**
  49. * data of found message files in maildir dir
  50. * @var array
  51. */
  52. protected $_files = array();
  53. /**
  54. * known flag chars in filenames
  55. *
  56. * This list has to be in alphabetical order for setFlags()
  57. *
  58. * @var array
  59. */
  60. protected static $_knownFlags = array('D' => Zend_Mail_Storage::FLAG_DRAFT,
  61. 'F' => Zend_Mail_Storage::FLAG_FLAGGED,
  62. 'P' => Zend_Mail_Storage::FLAG_PASSED,
  63. 'R' => Zend_Mail_Storage::FLAG_ANSWERED,
  64. 'S' => Zend_Mail_Storage::FLAG_SEEN,
  65. 'T' => Zend_Mail_Storage::FLAG_DELETED);
  66. // TODO: getFlags($id) for fast access if headers are not needed (i.e. just setting flags)?
  67. /**
  68. * Count messages all messages in current box
  69. *
  70. * @return int number of messages
  71. * @throws Zend_Mail_Storage_Exception
  72. */
  73. public function countMessages($flags = null)
  74. {
  75. if ($flags === null) {
  76. return count($this->_files);
  77. }
  78. $count = 0;
  79. if (!is_array($flags)) {
  80. foreach ($this->_files as $file) {
  81. if (isset($file['flaglookup'][$flags])) {
  82. ++$count;
  83. }
  84. }
  85. return $count;
  86. }
  87. $flags = array_flip($flags);
  88. foreach ($this->_files as $file) {
  89. foreach ($flags as $flag => $v) {
  90. if (!isset($file['flaglookup'][$flag])) {
  91. continue 2;
  92. }
  93. }
  94. ++$count;
  95. }
  96. return $count;
  97. }
  98. /**
  99. * Get one or all fields from file structure. Also checks if message is valid
  100. *
  101. * @param int $id message number
  102. * @param string|null $field wanted field
  103. * @return string|array wanted field or all fields as array
  104. * @throws Zend_Mail_Storage_Exception
  105. */
  106. protected function _getFileData($id, $field = null)
  107. {
  108. if (!isset($this->_files[$id - 1])) {
  109. /**
  110. * @see Zend_Mail_Storage_Exception
  111. */
  112. require_once 'Zend/Mail/Storage/Exception.php';
  113. throw new Zend_Mail_Storage_Exception('id does not exist');
  114. }
  115. if (!$field) {
  116. return $this->_files[$id - 1];
  117. }
  118. if (!isset($this->_files[$id - 1][$field])) {
  119. /**
  120. * @see Zend_Mail_Storage_Exception
  121. */
  122. require_once 'Zend/Mail/Storage/Exception.php';
  123. throw new Zend_Mail_Storage_Exception('field does not exist');
  124. }
  125. return $this->_files[$id - 1][$field];
  126. }
  127. /**
  128. * Get a list of messages with number and size
  129. *
  130. * @param int|null $id number of message or null for all messages
  131. * @return int|array size of given message of list with all messages as array(num => size)
  132. * @throws Zend_Mail_Storage_Exception
  133. */
  134. public function getSize($id = null)
  135. {
  136. if ($id !== null) {
  137. $filedata = $this->_getFileData($id);
  138. return isset($filedata['size']) ? $filedata['size'] : filesize($filedata['filename']);
  139. }
  140. $result = array();
  141. foreach ($this->_files as $num => $data) {
  142. $result[$num + 1] = isset($data['size']) ? $data['size'] : filesize($data['filename']);
  143. }
  144. return $result;
  145. }
  146. /**
  147. * Fetch a message
  148. *
  149. * @param int $id number of message
  150. * @return Zend_Mail_Message_File
  151. * @throws Zend_Mail_Storage_Exception
  152. */
  153. public function getMessage($id)
  154. {
  155. // TODO that's ugly, would be better to let the message class decide
  156. if (strtolower($this->_messageClass) == 'zend_mail_message_file' || is_subclass_of($this->_messageClass, 'zend_mail_message_file')) {
  157. return new $this->_messageClass(array('file' => $this->_getFileData($id, 'filename'),
  158. 'flags' => $this->_getFileData($id, 'flags')));
  159. }
  160. return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $this->getRawHeader($id),
  161. 'flags' => $this->_getFileData($id, 'flags')));
  162. }
  163. /*
  164. * Get raw header of message or part
  165. *
  166. * @param int $id number of message
  167. * @param null|array|string $part path to part or null for messsage header
  168. * @param int $topLines include this many lines with header (after an empty line)
  169. * @return string raw header
  170. * @throws Zend_Mail_Storage_Exception
  171. */
  172. public function getRawHeader($id, $part = null, $topLines = 0)
  173. {
  174. if ($part !== null) {
  175. // TODO: implement
  176. /**
  177. * @see Zend_Mail_Storage_Exception
  178. */
  179. require_once 'Zend/Mail/Storage/Exception.php';
  180. throw new Zend_Mail_Storage_Exception('not implemented');
  181. }
  182. $fh = fopen($this->_getFileData($id, 'filename'), 'r');
  183. $content = '';
  184. while (!feof($fh)) {
  185. $line = fgets($fh);
  186. if (!trim($line)) {
  187. break;
  188. }
  189. $content .= $line;
  190. }
  191. fclose($fh);
  192. return $content;
  193. }
  194. /*
  195. * Get raw content of message or part
  196. *
  197. * @param int $id number of message
  198. * @param null|array|string $part path to part or null for messsage content
  199. * @return string raw content
  200. * @throws Zend_Mail_Storage_Exception
  201. */
  202. public function getRawContent($id, $part = null)
  203. {
  204. if ($part !== null) {
  205. // TODO: implement
  206. /**
  207. * @see Zend_Mail_Storage_Exception
  208. */
  209. require_once 'Zend/Mail/Storage/Exception.php';
  210. throw new Zend_Mail_Storage_Exception('not implemented');
  211. }
  212. $fh = fopen($this->_getFileData($id, 'filename'), 'r');
  213. while (!feof($fh)) {
  214. $line = fgets($fh);
  215. if (!trim($line)) {
  216. break;
  217. }
  218. }
  219. $content = stream_get_contents($fh);
  220. fclose($fh);
  221. return $content;
  222. }
  223. /**
  224. * Create instance with parameters
  225. * Supported parameters are:
  226. * - dirname dirname of mbox file
  227. *
  228. * @param array $params mail reader specific parameters
  229. * @throws Zend_Mail_Storage_Exception
  230. */
  231. public function __construct($params)
  232. {
  233. if (is_array($params)) {
  234. $params = (object)$params;
  235. }
  236. if (!isset($params->dirname) || !is_dir($params->dirname)) {
  237. /**
  238. * @see Zend_Mail_Storage_Exception
  239. */
  240. require_once 'Zend/Mail/Storage/Exception.php';
  241. throw new Zend_Mail_Storage_Exception('no valid dirname given in params');
  242. }
  243. if (!$this->_isMaildir($params->dirname)) {
  244. /**
  245. * @see Zend_Mail_Storage_Exception
  246. */
  247. require_once 'Zend/Mail/Storage/Exception.php';
  248. throw new Zend_Mail_Storage_Exception('invalid maildir given');
  249. }
  250. $this->_has['top'] = true;
  251. $this->_has['flags'] = true;
  252. $this->_openMaildir($params->dirname);
  253. }
  254. /**
  255. * check if a given dir is a valid maildir
  256. *
  257. * @param string $dirname name of dir
  258. * @return bool dir is valid maildir
  259. */
  260. protected function _isMaildir($dirname)
  261. {
  262. if (file_exists($dirname . '/new') && !is_dir($dirname . '/new')) {
  263. return false;
  264. }
  265. if (file_exists($dirname . '/tmp') && !is_dir($dirname . '/tmp')) {
  266. return false;
  267. }
  268. return is_dir($dirname . '/cur');
  269. }
  270. /**
  271. * open given dir as current maildir
  272. *
  273. * @param string $dirname name of maildir
  274. * @return null
  275. * @throws Zend_Mail_Storage_Exception
  276. */
  277. protected function _openMaildir($dirname)
  278. {
  279. if ($this->_files) {
  280. $this->close();
  281. }
  282. $dh = @opendir($dirname . '/cur/');
  283. if (!$dh) {
  284. /**
  285. * @see Zend_Mail_Storage_Exception
  286. */
  287. require_once 'Zend/Mail/Storage/Exception.php';
  288. throw new Zend_Mail_Storage_Exception('cannot open maildir');
  289. }
  290. $this->_getMaildirFiles($dh, $dirname . '/cur/');
  291. closedir($dh);
  292. $dh = @opendir($dirname . '/new/');
  293. if ($dh) {
  294. $this->_getMaildirFiles($dh, $dirname . '/new/', array(Zend_Mail_Storage::FLAG_RECENT));
  295. closedir($dh);
  296. } else if (file_exists($dirname . '/new/')) {
  297. /**
  298. * @see Zend_Mail_Storage_Exception
  299. */
  300. require_once 'Zend/Mail/Storage/Exception.php';
  301. throw new Zend_Mail_Storage_Exception('cannot read recent mails in maildir');
  302. }
  303. }
  304. /**
  305. * find all files in opened dir handle and add to maildir files
  306. *
  307. * @param resource $dh dir handle used for search
  308. * @param string $dirname dirname of dir in $dh
  309. * @param array $default_flags default flags for given dir
  310. * @return null
  311. */
  312. protected function _getMaildirFiles($dh, $dirname, $default_flags = array())
  313. {
  314. while (($entry = readdir($dh)) !== false) {
  315. if ($entry[0] == '.' || !is_file($dirname . $entry)) {
  316. continue;
  317. }
  318. @list($uniq, $info) = explode(':', $entry, 2);
  319. @list(,$size) = explode(',', $uniq, 2);
  320. if ($size && $size[0] == 'S' && $size[1] == '=') {
  321. $size = substr($size, 2);
  322. }
  323. if (!ctype_digit($size)) {
  324. $size = null;
  325. }
  326. @list($version, $flags) = explode(',', $info, 2);
  327. if ($version != 2) {
  328. $flags = '';
  329. }
  330. $named_flags = $default_flags;
  331. $length = strlen($flags);
  332. for ($i = 0; $i < $length; ++$i) {
  333. $flag = $flags[$i];
  334. $named_flags[$flag] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
  335. }
  336. $data = array('uniq' => $uniq,
  337. 'flags' => $named_flags,
  338. 'flaglookup' => array_flip($named_flags),
  339. 'filename' => $dirname . $entry);
  340. if ($size !== null) {
  341. $data['size'] = (int)$size;
  342. }
  343. $this->_files[] = $data;
  344. }
  345. }
  346. /**
  347. * Close resource for mail lib. If you need to control, when the resource
  348. * is closed. Otherwise the destructor would call this.
  349. *
  350. * @return void
  351. */
  352. public function close()
  353. {
  354. $this->_files = array();
  355. }
  356. /**
  357. * Waste some CPU cycles doing nothing.
  358. *
  359. * @return void
  360. */
  361. public function noop()
  362. {
  363. return true;
  364. }
  365. /**
  366. * stub for not supported message deletion
  367. *
  368. * @return null
  369. * @throws Zend_Mail_Storage_Exception
  370. */
  371. public function removeMessage($id)
  372. {
  373. /**
  374. * @see Zend_Mail_Storage_Exception
  375. */
  376. require_once 'Zend/Mail/Storage/Exception.php';
  377. throw new Zend_Mail_Storage_Exception('maildir is (currently) read-only');
  378. }
  379. /**
  380. * get unique id for one or all messages
  381. *
  382. * if storage does not support unique ids it's the same as the message number
  383. *
  384. * @param int|null $id message number
  385. * @return array|string message number for given message or all messages as array
  386. * @throws Zend_Mail_Storage_Exception
  387. */
  388. public function getUniqueId($id = null)
  389. {
  390. if ($id) {
  391. return $this->_getFileData($id, 'uniq');
  392. }
  393. $ids = array();
  394. foreach ($this->_files as $num => $file) {
  395. $ids[$num + 1] = $file['uniq'];
  396. }
  397. return $ids;
  398. }
  399. /**
  400. * get a message number from a unique id
  401. *
  402. * I.e. if you have a webmailer that supports deleting messages you should use unique ids
  403. * as parameter and use this method to translate it to message number right before calling removeMessage()
  404. *
  405. * @param string $id unique id
  406. * @return int message number
  407. * @throws Zend_Mail_Storage_Exception
  408. */
  409. public function getNumberByUniqueId($id)
  410. {
  411. foreach ($this->_files as $num => $file) {
  412. if ($file['uniq'] == $id) {
  413. return $num + 1;
  414. }
  415. }
  416. /**
  417. * @see Zend_Mail_Storage_Exception
  418. */
  419. require_once 'Zend/Mail/Storage/Exception.php';
  420. throw new Zend_Mail_Storage_Exception('unique id not found');
  421. }
  422. }