PageRenderTime 60ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/src/application/libraries/Zend/Mail/Storage/Imap.php

https://bitbucket.org/masnug/grc276-blog-laravel
PHP | 644 lines | 272 code | 59 blank | 313 comment | 43 complexity | 34bed69abe6b8c01e2e6fad303112483 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: Imap.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_Protocol_Imap
  28. */
  29. require_once 'Zend/Mail/Protocol/Imap.php';
  30. /**
  31. * @see Zend_Mail_Storage_Writable_Interface
  32. */
  33. require_once 'Zend/Mail/Storage/Writable/Interface.php';
  34. /**
  35. * @see Zend_Mail_Storage_Folder_Interface
  36. */
  37. require_once 'Zend/Mail/Storage/Folder/Interface.php';
  38. /**
  39. * @see Zend_Mail_Storage_Folder
  40. */
  41. require_once 'Zend/Mail/Storage/Folder.php';
  42. /**
  43. * @see Zend_Mail_Message
  44. */
  45. require_once 'Zend/Mail/Message.php';
  46. /**
  47. * @see Zend_Mail_Storage
  48. */
  49. require_once 'Zend/Mail/Storage.php';
  50. /**
  51. * @category Zend
  52. * @package Zend_Mail
  53. * @subpackage Storage
  54. * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
  55. * @license http://framework.zend.com/license/new-bsd New BSD License
  56. */
  57. class Zend_Mail_Storage_Imap extends Zend_Mail_Storage_Abstract
  58. implements Zend_Mail_Storage_Folder_Interface, Zend_Mail_Storage_Writable_Interface
  59. {
  60. // TODO: with an internal cache we could optimize this class, or create an extra class with
  61. // such optimizations. Especially the various fetch calls could be combined to one cache call
  62. /**
  63. * protocol handler
  64. * @var null|Zend_Mail_Protocol_Imap
  65. */
  66. protected $_protocol;
  67. /**
  68. * name of current folder
  69. * @var string
  70. */
  71. protected $_currentFolder = '';
  72. /**
  73. * imap flags to constants translation
  74. * @var array
  75. */
  76. protected static $_knownFlags = array('\Passed' => Zend_Mail_Storage::FLAG_PASSED,
  77. '\Answered' => Zend_Mail_Storage::FLAG_ANSWERED,
  78. '\Seen' => Zend_Mail_Storage::FLAG_SEEN,
  79. '\Deleted' => Zend_Mail_Storage::FLAG_DELETED,
  80. '\Draft' => Zend_Mail_Storage::FLAG_DRAFT,
  81. '\Flagged' => Zend_Mail_Storage::FLAG_FLAGGED);
  82. /**
  83. * map flags to search criterias
  84. * @var array
  85. */
  86. protected static $_searchFlags = array('\Recent' => 'RECENT',
  87. '\Answered' => 'ANSWERED',
  88. '\Seen' => 'SEEN',
  89. '\Deleted' => 'DELETED',
  90. '\Draft' => 'DRAFT',
  91. '\Flagged' => 'FLAGGED');
  92. /**
  93. * Count messages all messages in current box
  94. *
  95. * @return int number of messages
  96. * @throws Zend_Mail_Storage_Exception
  97. * @throws Zend_Mail_Protocol_Exception
  98. */
  99. public function countMessages($flags = null)
  100. {
  101. if (!$this->_currentFolder) {
  102. /**
  103. * @see Zend_Mail_Storage_Exception
  104. */
  105. require_once 'Zend/Mail/Storage/Exception.php';
  106. throw new Zend_Mail_Storage_Exception('No selected folder to count');
  107. }
  108. if ($flags === null) {
  109. return count($this->_protocol->search(array('ALL')));
  110. }
  111. $params = array();
  112. foreach ((array)$flags as $flag) {
  113. if (isset(self::$_searchFlags[$flag])) {
  114. $params[] = self::$_searchFlags[$flag];
  115. } else {
  116. $params[] = 'KEYWORD';
  117. $params[] = $this->_protocol->escapeString($flag);
  118. }
  119. }
  120. return count($this->_protocol->search($params));
  121. }
  122. /**
  123. * get a list of messages with number and size
  124. *
  125. * @param int $id number of message
  126. * @return int|array size of given message of list with all messages as array(num => size)
  127. * @throws Zend_Mail_Protocol_Exception
  128. */
  129. public function getSize($id = 0)
  130. {
  131. if ($id) {
  132. return $this->_protocol->fetch('RFC822.SIZE', $id);
  133. }
  134. return $this->_protocol->fetch('RFC822.SIZE', 1, INF);
  135. }
  136. /**
  137. * Fetch a message
  138. *
  139. * @param int $id number of message
  140. * @return Zend_Mail_Message
  141. * @throws Zend_Mail_Protocol_Exception
  142. */
  143. public function getMessage($id)
  144. {
  145. $data = $this->_protocol->fetch(array('FLAGS', 'RFC822.HEADER'), $id);
  146. $header = $data['RFC822.HEADER'];
  147. $flags = array();
  148. foreach ($data['FLAGS'] as $flag) {
  149. $flags[] = isset(self::$_knownFlags[$flag]) ? self::$_knownFlags[$flag] : $flag;
  150. }
  151. return new $this->_messageClass(array('handler' => $this, 'id' => $id, 'headers' => $header, 'flags' => $flags));
  152. }
  153. /*
  154. * Get raw header of message or part
  155. *
  156. * @param int $id number of message
  157. * @param null|array|string $part path to part or null for messsage header
  158. * @param int $topLines include this many lines with header (after an empty line)
  159. * @param int $topLines include this many lines with header (after an empty line)
  160. * @return string raw header
  161. * @throws Zend_Mail_Protocol_Exception
  162. * @throws Zend_Mail_Storage_Exception
  163. */
  164. public function getRawHeader($id, $part = null, $topLines = 0)
  165. {
  166. if ($part !== null) {
  167. // TODO: implement
  168. /**
  169. * @see Zend_Mail_Storage_Exception
  170. */
  171. require_once 'Zend/Mail/Storage/Exception.php';
  172. throw new Zend_Mail_Storage_Exception('not implemented');
  173. }
  174. // TODO: toplines
  175. return $this->_protocol->fetch('RFC822.HEADER', $id);
  176. }
  177. /*
  178. * Get raw content of message or part
  179. *
  180. * @param int $id number of message
  181. * @param null|array|string $part path to part or null for messsage content
  182. * @return string raw content
  183. * @throws Zend_Mail_Protocol_Exception
  184. * @throws Zend_Mail_Storage_Exception
  185. */
  186. public function getRawContent($id, $part = null)
  187. {
  188. if ($part !== null) {
  189. // TODO: implement
  190. /**
  191. * @see Zend_Mail_Storage_Exception
  192. */
  193. require_once 'Zend/Mail/Storage/Exception.php';
  194. throw new Zend_Mail_Storage_Exception('not implemented');
  195. }
  196. return $this->_protocol->fetch('RFC822.TEXT', $id);
  197. }
  198. /**
  199. * create instance with parameters
  200. * Supported paramters are
  201. * - user username
  202. * - host hostname or ip address of IMAP server [optional, default = 'localhost']
  203. * - password password for user 'username' [optional, default = '']
  204. * - port port for IMAP server [optional, default = 110]
  205. * - ssl 'SSL' or 'TLS' for secure sockets
  206. * - folder select this folder [optional, default = 'INBOX']
  207. *
  208. * @param array $params mail reader specific parameters
  209. * @throws Zend_Mail_Storage_Exception
  210. * @throws Zend_Mail_Protocol_Exception
  211. */
  212. public function __construct($params)
  213. {
  214. if (is_array($params)) {
  215. $params = (object)$params;
  216. }
  217. $this->_has['flags'] = true;
  218. if ($params instanceof Zend_Mail_Protocol_Imap) {
  219. $this->_protocol = $params;
  220. try {
  221. $this->selectFolder('INBOX');
  222. } catch(Zend_Mail_Storage_Exception $e) {
  223. /**
  224. * @see Zend_Mail_Storage_Exception
  225. */
  226. require_once 'Zend/Mail/Storage/Exception.php';
  227. throw new Zend_Mail_Storage_Exception('cannot select INBOX, is this a valid transport?', 0, $e);
  228. }
  229. return;
  230. }
  231. if (!isset($params->user)) {
  232. /**
  233. * @see Zend_Mail_Storage_Exception
  234. */
  235. require_once 'Zend/Mail/Storage/Exception.php';
  236. throw new Zend_Mail_Storage_Exception('need at least user in params');
  237. }
  238. $host = isset($params->host) ? $params->host : 'localhost';
  239. $password = isset($params->password) ? $params->password : '';
  240. $port = isset($params->port) ? $params->port : null;
  241. $ssl = isset($params->ssl) ? $params->ssl : false;
  242. $this->_protocol = new Zend_Mail_Protocol_Imap();
  243. $this->_protocol->connect($host, $port, $ssl);
  244. if (!$this->_protocol->login($params->user, $password)) {
  245. /**
  246. * @see Zend_Mail_Storage_Exception
  247. */
  248. require_once 'Zend/Mail/Storage/Exception.php';
  249. throw new Zend_Mail_Storage_Exception('cannot login, user or password wrong');
  250. }
  251. $this->selectFolder(isset($params->folder) ? $params->folder : 'INBOX');
  252. }
  253. /**
  254. * Close resource for mail lib. If you need to control, when the resource
  255. * is closed. Otherwise the destructor would call this.
  256. *
  257. * @return null
  258. */
  259. public function close()
  260. {
  261. $this->_currentFolder = '';
  262. $this->_protocol->logout();
  263. }
  264. /**
  265. * Keep the server busy.
  266. *
  267. * @return null
  268. * @throws Zend_Mail_Storage_Exception
  269. */
  270. public function noop()
  271. {
  272. if (!$this->_protocol->noop()) {
  273. /**
  274. * @see Zend_Mail_Storage_Exception
  275. */
  276. require_once 'Zend/Mail/Storage/Exception.php';
  277. throw new Zend_Mail_Storage_Exception('could not do nothing');
  278. }
  279. }
  280. /**
  281. * Remove a message from server. If you're doing that from a web enviroment
  282. * you should be careful and use a uniqueid as parameter if possible to
  283. * identify the message.
  284. *
  285. * @param int $id number of message
  286. * @return null
  287. * @throws Zend_Mail_Storage_Exception
  288. */
  289. public function removeMessage($id)
  290. {
  291. if (!$this->_protocol->store(array(Zend_Mail_Storage::FLAG_DELETED), $id, null, '+')) {
  292. /**
  293. * @see Zend_Mail_Storage_Exception
  294. */
  295. require_once 'Zend/Mail/Storage/Exception.php';
  296. throw new Zend_Mail_Storage_Exception('cannot set deleted flag');
  297. }
  298. // TODO: expunge here or at close? we can handle an error here better and are more fail safe
  299. if (!$this->_protocol->expunge()) {
  300. /**
  301. * @see Zend_Mail_Storage_Exception
  302. */
  303. require_once 'Zend/Mail/Storage/Exception.php';
  304. throw new Zend_Mail_Storage_Exception('message marked as deleted, but could not expunge');
  305. }
  306. }
  307. /**
  308. * get unique id for one or all messages
  309. *
  310. * if storage does not support unique ids it's the same as the message number
  311. *
  312. * @param int|null $id message number
  313. * @return array|string message number for given message or all messages as array
  314. * @throws Zend_Mail_Storage_Exception
  315. */
  316. public function getUniqueId($id = null)
  317. {
  318. if ($id) {
  319. return $this->_protocol->fetch('UID', $id);
  320. }
  321. return $this->_protocol->fetch('UID', 1, INF);
  322. }
  323. /**
  324. * get a message number from a unique id
  325. *
  326. * I.e. if you have a webmailer that supports deleting messages you should use unique ids
  327. * as parameter and use this method to translate it to message number right before calling removeMessage()
  328. *
  329. * @param string $id unique id
  330. * @return int message number
  331. * @throws Zend_Mail_Storage_Exception
  332. */
  333. public function getNumberByUniqueId($id)
  334. {
  335. // TODO: use search to find number directly
  336. $ids = $this->getUniqueId();
  337. foreach ($ids as $k => $v) {
  338. if ($v == $id) {
  339. return $k;
  340. }
  341. }
  342. /**
  343. * @see Zend_Mail_Storage_Exception
  344. */
  345. require_once 'Zend/Mail/Storage/Exception.php';
  346. throw new Zend_Mail_Storage_Exception('unique id not found');
  347. }
  348. /**
  349. * get root folder or given folder
  350. *
  351. * @param string $rootFolder get folder structure for given folder, else root
  352. * @return Zend_Mail_Storage_Folder root or wanted folder
  353. * @throws Zend_Mail_Storage_Exception
  354. * @throws Zend_Mail_Protocol_Exception
  355. */
  356. public function getFolders($rootFolder = null)
  357. {
  358. $folders = $this->_protocol->listMailbox((string)$rootFolder);
  359. if (!$folders) {
  360. /**
  361. * @see Zend_Mail_Storage_Exception
  362. */
  363. require_once 'Zend/Mail/Storage/Exception.php';
  364. throw new Zend_Mail_Storage_Exception('folder not found');
  365. }
  366. ksort($folders, SORT_STRING);
  367. $root = new Zend_Mail_Storage_Folder('/', '/', false);
  368. $stack = array(null);
  369. $folderStack = array(null);
  370. $parentFolder = $root;
  371. $parent = '';
  372. foreach ($folders as $globalName => $data) {
  373. do {
  374. if (!$parent || strpos($globalName, $parent) === 0) {
  375. $pos = strrpos($globalName, $data['delim']);
  376. if ($pos === false) {
  377. $localName = $globalName;
  378. } else {
  379. $localName = substr($globalName, $pos + 1);
  380. }
  381. $selectable = !$data['flags'] || !in_array('\\Noselect', $data['flags']);
  382. array_push($stack, $parent);
  383. $parent = $globalName . $data['delim'];
  384. $folder = new Zend_Mail_Storage_Folder($localName, $globalName, $selectable);
  385. $parentFolder->$localName = $folder;
  386. array_push($folderStack, $parentFolder);
  387. $parentFolder = $folder;
  388. break;
  389. } else if ($stack) {
  390. $parent = array_pop($stack);
  391. $parentFolder = array_pop($folderStack);
  392. }
  393. } while ($stack);
  394. if (!$stack) {
  395. /**
  396. * @see Zend_Mail_Storage_Exception
  397. */
  398. require_once 'Zend/Mail/Storage/Exception.php';
  399. throw new Zend_Mail_Storage_Exception('error while constructing folder tree');
  400. }
  401. }
  402. return $root;
  403. }
  404. /**
  405. * select given folder
  406. *
  407. * folder must be selectable!
  408. *
  409. * @param Zend_Mail_Storage_Folder|string $globalName global name of folder or instance for subfolder
  410. * @return null
  411. * @throws Zend_Mail_Storage_Exception
  412. * @throws Zend_Mail_Protocol_Exception
  413. */
  414. public function selectFolder($globalName)
  415. {
  416. $this->_currentFolder = $globalName;
  417. if (!$this->_protocol->select($this->_currentFolder)) {
  418. $this->_currentFolder = '';
  419. /**
  420. * @see Zend_Mail_Storage_Exception
  421. */
  422. require_once 'Zend/Mail/Storage/Exception.php';
  423. throw new Zend_Mail_Storage_Exception('cannot change folder, maybe it does not exist');
  424. }
  425. }
  426. /**
  427. * get Zend_Mail_Storage_Folder instance for current folder
  428. *
  429. * @return Zend_Mail_Storage_Folder instance of current folder
  430. * @throws Zend_Mail_Storage_Exception
  431. */
  432. public function getCurrentFolder()
  433. {
  434. return $this->_currentFolder;
  435. }
  436. /**
  437. * create a new folder
  438. *
  439. * This method also creates parent folders if necessary. Some mail storages may restrict, which folder
  440. * may be used as parent or which chars may be used in the folder name
  441. *
  442. * @param string $name global name of folder, local name if $parentFolder is set
  443. * @param string|Zend_Mail_Storage_Folder $parentFolder parent folder for new folder, else root folder is parent
  444. * @return null
  445. * @throws Zend_Mail_Storage_Exception
  446. */
  447. public function createFolder($name, $parentFolder = null)
  448. {
  449. // TODO: we assume / as the hierarchy delim - need to get that from the folder class!
  450. if ($parentFolder instanceof Zend_Mail_Storage_Folder) {
  451. $folder = $parentFolder->getGlobalName() . '/' . $name;
  452. } else if ($parentFolder != null) {
  453. $folder = $parentFolder . '/' . $name;
  454. } else {
  455. $folder = $name;
  456. }
  457. if (!$this->_protocol->create($folder)) {
  458. /**
  459. * @see Zend_Mail_Storage_Exception
  460. */
  461. require_once 'Zend/Mail/Storage/Exception.php';
  462. throw new Zend_Mail_Storage_Exception('cannot create folder');
  463. }
  464. }
  465. /**
  466. * remove a folder
  467. *
  468. * @param string|Zend_Mail_Storage_Folder $name name or instance of folder
  469. * @return null
  470. * @throws Zend_Mail_Storage_Exception
  471. */
  472. public function removeFolder($name)
  473. {
  474. if ($name instanceof Zend_Mail_Storage_Folder) {
  475. $name = $name->getGlobalName();
  476. }
  477. if (!$this->_protocol->delete($name)) {
  478. /**
  479. * @see Zend_Mail_Storage_Exception
  480. */
  481. require_once 'Zend/Mail/Storage/Exception.php';
  482. throw new Zend_Mail_Storage_Exception('cannot delete folder');
  483. }
  484. }
  485. /**
  486. * rename and/or move folder
  487. *
  488. * The new name has the same restrictions as in createFolder()
  489. *
  490. * @param string|Zend_Mail_Storage_Folder $oldName name or instance of folder
  491. * @param string $newName new global name of folder
  492. * @return null
  493. * @throws Zend_Mail_Storage_Exception
  494. */
  495. public function renameFolder($oldName, $newName)
  496. {
  497. if ($oldName instanceof Zend_Mail_Storage_Folder) {
  498. $oldName = $oldName->getGlobalName();
  499. }
  500. if (!$this->_protocol->rename($oldName, $newName)) {
  501. /**
  502. * @see Zend_Mail_Storage_Exception
  503. */
  504. require_once 'Zend/Mail/Storage/Exception.php';
  505. throw new Zend_Mail_Storage_Exception('cannot rename folder');
  506. }
  507. }
  508. /**
  509. * append a new message to mail storage
  510. *
  511. * @param string $message message as string or instance of message class
  512. * @param null|string|Zend_Mail_Storage_Folder $folder folder for new message, else current folder is taken
  513. * @param null|array $flags set flags for new message, else a default set is used
  514. * @throws Zend_Mail_Storage_Exception
  515. */
  516. // not yet * @param string|Zend_Mail_Message|Zend_Mime_Message $message message as string or instance of message class
  517. public function appendMessage($message, $folder = null, $flags = null)
  518. {
  519. if ($folder === null) {
  520. $folder = $this->_currentFolder;
  521. }
  522. if ($flags === null) {
  523. $flags = array(Zend_Mail_Storage::FLAG_SEEN);
  524. }
  525. // TODO: handle class instances for $message
  526. if (!$this->_protocol->append($folder, $message, $flags)) {
  527. /**
  528. * @see Zend_Mail_Storage_Exception
  529. */
  530. require_once 'Zend/Mail/Storage/Exception.php';
  531. throw new Zend_Mail_Storage_Exception('cannot create message, please check if the folder exists and your flags');
  532. }
  533. }
  534. /**
  535. * copy an existing message
  536. *
  537. * @param int $id number of message
  538. * @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
  539. * @return null
  540. * @throws Zend_Mail_Storage_Exception
  541. */
  542. public function copyMessage($id, $folder)
  543. {
  544. if (!$this->_protocol->copy($folder, $id)) {
  545. /**
  546. * @see Zend_Mail_Storage_Exception
  547. */
  548. require_once 'Zend/Mail/Storage/Exception.php';
  549. throw new Zend_Mail_Storage_Exception('cannot copy message, does the folder exist?');
  550. }
  551. }
  552. /**
  553. * move an existing message
  554. *
  555. * NOTE: imap has no native move command, thus it's emulated with copy and delete
  556. *
  557. * @param int $id number of message
  558. * @param string|Zend_Mail_Storage_Folder $folder name or instance of targer folder
  559. * @return null
  560. * @throws Zend_Mail_Storage_Exception
  561. */
  562. public function moveMessage($id, $folder) {
  563. $this->copyMessage($id, $folder);
  564. $this->removeMessage($id);
  565. }
  566. /**
  567. * set flags for message
  568. *
  569. * NOTE: this method can't set the recent flag.
  570. *
  571. * @param int $id number of message
  572. * @param array $flags new flags for message
  573. * @throws Zend_Mail_Storage_Exception
  574. */
  575. public function setFlags($id, $flags)
  576. {
  577. if (!$this->_protocol->store($flags, $id)) {
  578. /**
  579. * @see Zend_Mail_Storage_Exception
  580. */
  581. require_once 'Zend/Mail/Storage/Exception.php';
  582. throw new Zend_Mail_Storage_Exception('cannot set flags, have you tried to set the recent flag or special chars?');
  583. }
  584. }
  585. }