PageRenderTime 65ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/standard/tags/release-0.1.5/incubator/library/Zend/Mail/Transport/Pop3.php

https://github.com/jorgenils/zend-framework
PHP | 400 lines | 198 code | 64 blank | 138 comment | 33 complexity | d8a31f59f4dd14c0e40a32150d86f22f MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to version 1.0 of the Zend Framework
  8. * license, that is bundled with this package in the file LICENSE, and
  9. * is available through the world-wide-web at the following URL:
  10. * http://www.zend.com/license/framework/1_0.txt. If you did not receive
  11. * a copy of the Zend Framework license and are unable to obtain it
  12. * through the world-wide-web, please send a note to license@zend.com
  13. * so we can mail you a copy immediately.
  14. *
  15. * @package Zend_Mail
  16. * @copyright Copyright (c) 2005-2006 Zend Technologies USA Inc. (http://www.zend.com)
  17. * @license http://www.zend.com/license/framework/1_0.txt Zend Framework License version 1.0
  18. */
  19. /**
  20. * Zend_Mail_Transport_Exception
  21. */
  22. require_once 'Zend/Mail/Transport/Exception.php';
  23. /**
  24. * @package Zend_Mail
  25. * @copyright Copyright (c) 2005-2006 Zend Technologies USA Inc. (http://www.zend.com)
  26. * @license http://www.zend.com/license/framework/1_0.txt Zend Framework License version 1.0
  27. */
  28. class Zend_Mail_Transport_Pop3
  29. {
  30. /**
  31. * saves if server supports top
  32. */
  33. public $hasTop = null;
  34. /**
  35. * socket to pop3
  36. */
  37. private $_socket;
  38. /**
  39. * greeting timestamp for apop
  40. */
  41. private $_timestamp;
  42. /**
  43. * Public constructor
  44. *
  45. * @param string $host hostname of IP address of POP3 server, if given connect() is called
  46. * @param int $port port of POP3 server, default is 110 (995 for ssl)
  47. * @param bool $ssl use ssl?
  48. */
  49. public function __construct($host = '', $port = null, $ssl = false)
  50. {
  51. if ($host) {
  52. $this->connect($host, $port);
  53. }
  54. }
  55. /**
  56. * Public destructor
  57. */
  58. public function __destruct()
  59. {
  60. $this->logout();
  61. }
  62. /**
  63. * Open connection to POP3 server
  64. *
  65. * @param string $host hostname of IP address of POP3 server
  66. * @param int $port of POP3 server, default is 110 (995 for ssl)
  67. * @param string $ssl use 'SSL' or 'TLS'
  68. * @throws Zend_Mail_Transport_Exception
  69. * @return string welcome message
  70. */
  71. public function connect($host, $port = null, $ssl = false)
  72. {
  73. if ($ssl == 'SSL') {
  74. $host = 'ssl://' . $host;
  75. }
  76. if (is_null($port)) {
  77. $port = $ssl == 'SSL' ? 995 : 110;
  78. }
  79. $this->_socket = @fsockopen($host, $port);
  80. if (!$this->_socket) {
  81. throw new Zend_Mail_Transport_Exception('cannot connect to host');
  82. }
  83. $welcome = $this->readResponse();
  84. strtok($welcome, '<');
  85. $this->_timestamp = strtok('>');
  86. if (!strpos($this->_timestamp, '@')) {
  87. $this->_timestamp = null;
  88. } else {
  89. $this->_timestamp = '<' . $this->_timestamp . '>';
  90. }
  91. if($ssl === 'TLS') {
  92. $this->request('STLS');
  93. $result = stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
  94. if(!$result) {
  95. throw new Zend_Mail_Transport_Exception('cannot enable TLS');
  96. }
  97. }
  98. return $welcome;
  99. }
  100. /**
  101. * Send a request
  102. *
  103. * @param string $request your request without newline
  104. */
  105. public function sendRequest($request)
  106. {
  107. $result = fputs($this->_socket, $request."\n");
  108. if (!$result) {
  109. throw new Zend_Mail_Transport_Exception('send failed - connection closed?');
  110. }
  111. }
  112. /**
  113. *
  114. * read a response
  115. *
  116. * @param boolean response has multiple lines and should be read until "<nl>.<nl>"
  117. * @throws Zend_Mail_Transport_Exception
  118. * @return string response
  119. */
  120. public function readResponse($multiline = false)
  121. {
  122. $result = fgets($this->_socket);
  123. if (!is_string($result)) {
  124. throw new Zend_Mail_Transport_Exception('read failed - connection closed?');
  125. }
  126. $result = trim($result);
  127. if (strpos($result, ' ')) {
  128. list($status, $message) = explode(' ', $result, 2);
  129. } else {
  130. $status = $result;
  131. $message = '';
  132. }
  133. if ($status != '+OK') {
  134. throw new Zend_Mail_Transport_Exception('last request failed');
  135. }
  136. if ($multiline) {
  137. $message = '';
  138. $line = fgets($this->_socket);
  139. while ($line && trim($line) != '.') {
  140. $message .= $line;
  141. $line = fgets($this->_socket);
  142. };
  143. }
  144. return $message;
  145. }
  146. /**
  147. * Send request and get resposne
  148. * @see sendRequest(), readResponse()
  149. *
  150. * @param string $request request
  151. * @param bool $multiline multiline response?
  152. * @return string result from readResponse()
  153. */
  154. public function request($request, $multiline = false)
  155. {
  156. $this->sendRequest($request);
  157. return $this->readResponse($multiline);
  158. }
  159. /**
  160. * End communication with POP3 server (also closes socket)
  161. */
  162. public function logout()
  163. {
  164. if(!$this->_socket) {
  165. return;
  166. }
  167. try {
  168. $this->request('QUIT');
  169. } catch (Zend_Mail_Transport_Exception $e) {
  170. // ignore error - we're closing the socket anyway
  171. }
  172. fclose($this->_socket);
  173. $this->_socket = null;
  174. }
  175. /**
  176. * Get capabilities from POP3 server
  177. *
  178. * @return array list of capabilities
  179. */
  180. public function capa()
  181. {
  182. $result = $this->request('CAPA', true);
  183. return explode("\n", $result);
  184. }
  185. /**
  186. * Login to POP3 server. Can use APOP
  187. *
  188. * @param string $user username
  189. * @param string $password password
  190. * @param bool $try_apop should APOP be tried?
  191. * @return void
  192. */
  193. public function login($user, $password, $tryApop = true)
  194. {
  195. if ($tryApop && $this->_timestamp) {
  196. try {
  197. $this->request("APOP $user " . md5($this->_timestamp . $password));
  198. return;
  199. } catch (Zend_Mail_Transport_Exception $e) {
  200. // ignore
  201. }
  202. }
  203. $result = $this->request("USER $user");
  204. $result = $this->request("PASS $password");
  205. }
  206. /**
  207. * Make STAT call for message count and size sum
  208. *
  209. * @param int $messages out parameter with count of messages
  210. * @param int $octets out parameter with size in octects of messages
  211. * @return void
  212. */
  213. public function status(&$messages, &$octets)
  214. {
  215. $messages = 0;
  216. $octets = 0;
  217. $result = $this->request('STAT');
  218. list($messages, $octets) = explode(' ', $result);
  219. }
  220. /**
  221. * Make LIST call for size of message(s)
  222. *
  223. * @param int $msgno number of message
  224. * @return int|array size of given message or list with array(num => size)
  225. */
  226. public function getList($msgno = null)
  227. {
  228. if ($msgno !== null) {
  229. $result = $this->request("LIST $msgno");
  230. list(, $result) = explode(' ', $result);
  231. return (int)$result;
  232. }
  233. $result = $this->request('LIST', true);
  234. $messages = array();
  235. $line = strtok($result, "\n");
  236. while($line) {
  237. list($no, $size) = explode(' ', trim($line));
  238. $messages[(int)$no] = (int)$size;
  239. $line = strtok("\n");
  240. }
  241. return $messages;
  242. }
  243. /**
  244. * Make UIDL call for getting a uniqueid
  245. *
  246. * @param int $msgno number of message
  247. * @return string|array uniqueid of message or list with array(num => uniqueid)
  248. */
  249. public function uniqueid($msgno = null)
  250. {
  251. if ($msgno !== null) {
  252. $result = $this->request("UIDL $msgno");
  253. list(, $result) = explode(' ', $result);
  254. return $result;
  255. }
  256. $result = $this->request('UIDL', true);
  257. $result = explode("\n", $result);
  258. $messages = array();
  259. foreach ($result as $line) {
  260. list($no, $id) = explode(' ', $line);
  261. $messages[(int)$no] = $id;
  262. }
  263. return $messages;
  264. }
  265. /**
  266. * Make TOP call for getting headers and maybe some body lines
  267. * This method also sets hasTop - before it it's not known if top is supported
  268. *
  269. * The fallback makes normale RETR call, which retrieves the whole message. Additional
  270. * lines are not removed.
  271. *
  272. * @param int $msgno number of message
  273. * @param int $lines number of wanted body lines (empty line is inserted after header lines)
  274. * @param bool $fallback fallback with full retrieve if top is not supported
  275. * @return string message headers with wanted body lines
  276. */
  277. public function top($msgno, $lines = 0, $fallback = false)
  278. {
  279. if ($this->hasTop === false) {
  280. if ($fallback) {
  281. return $this->retrive($msgno);
  282. } else {
  283. throw new Zend_Mail_Transport_Exception('top not supported and no fallback wanted');
  284. }
  285. }
  286. $this->hasTop = true;
  287. if (!$lines || (int)$lines < 1) {
  288. $request = "TOP $msgno";
  289. } else {
  290. $request = "TOP $msgno $lines";
  291. }
  292. try {
  293. $result = $this->request($request, true);
  294. } catch (Zend_Mail_Transport_Exception $e) {
  295. $this->hasTop = false;
  296. if ($fallback) {
  297. $result = $this->retrive($msgno);
  298. } else {
  299. throw $e;
  300. }
  301. }
  302. return $result;
  303. }
  304. /**
  305. * Make a RETR call for retrieving a full message with headers and body
  306. *
  307. * @param int $msgno message number
  308. * @return string message
  309. */
  310. public function retrive($msgno)
  311. {
  312. $result = $this->request("RETR $msgno", true);
  313. return $result;
  314. }
  315. /**
  316. * Make a NOOP call, maybe needed for keeping the server happy
  317. */
  318. public function noop()
  319. {
  320. $this->request('NOOP');
  321. }
  322. /**
  323. * Make a DELE count to remove a message
  324. */
  325. public function delete($msgno)
  326. {
  327. $this->request("DELE $msgno");
  328. }
  329. /**
  330. * Make RSET call, which rollbacks delete requests
  331. */
  332. public function undelete()
  333. {
  334. $this->request('RSET');
  335. }
  336. }