web/Zend/Mail/Protocol/Pop3.php
changeset 0 4eba9c11703f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/Zend/Mail/Protocol/Pop3.php	Mon Dec 13 18:29:26 2010 +0100
@@ -0,0 +1,472 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Pop3.php 20096 2010-01-06 02:05:09Z bkarwin $
+ */
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Mail
+ * @subpackage Protocol
+ * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Mail_Protocol_Pop3
+{
+    /**
+     * Default timeout in seconds for initiating session
+     */
+    const TIMEOUT_CONNECTION = 30;
+
+    /**
+     * saves if server supports top
+     * @var null|bool
+     */
+    public $hasTop = null;
+
+    /**
+     * socket to pop3
+     * @var null|resource
+     */
+    protected $_socket;
+
+    /**
+     * greeting timestamp for apop
+     * @var null|string
+     */
+    protected $_timestamp;
+
+
+    /**
+     * Public constructor
+     *
+     * @param  string      $host  hostname or IP address of POP3 server, if given connect() is called
+     * @param  int|null    $port  port of POP3 server, null for default (110 or 995 for ssl)
+     * @param  bool|string $ssl   use ssl? 'SSL', 'TLS' or false
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function __construct($host = '', $port = null, $ssl = false)
+    {
+        if ($host) {
+            $this->connect($host, $port, $ssl);
+        }
+    }
+
+
+    /**
+     * Public destructor
+     */
+    public function __destruct()
+    {
+        $this->logout();
+    }
+
+
+    /**
+     * Open connection to POP3 server
+     *
+     * @param  string      $host  hostname or IP address of POP3 server
+     * @param  int|null    $port  of POP3 server, default is 110 (995 for ssl)
+     * @param  string|bool $ssl   use 'SSL', 'TLS' or false
+     * @return string welcome message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function connect($host, $port = null, $ssl = false)
+    {
+        if ($ssl == 'SSL') {
+            $host = 'ssl://' . $host;
+        }
+
+        if ($port === null) {
+            $port = $ssl == 'SSL' ? 995 : 110;
+        }
+
+        $errno  =  0;
+        $errstr = '';
+        $this->_socket = @fsockopen($host, $port, $errno, $errstr, self::TIMEOUT_CONNECTION);
+        if (!$this->_socket) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('cannot connect to host; error = ' . $errstr .
+                                                   ' (errno = ' . $errno . ' )');
+        }
+
+        $welcome = $this->readResponse();
+
+        strtok($welcome, '<');
+        $this->_timestamp = strtok('>');
+        if (!strpos($this->_timestamp, '@')) {
+            $this->_timestamp = null;
+        } else {
+            $this->_timestamp = '<' . $this->_timestamp . '>';
+        }
+
+        if ($ssl === 'TLS') {
+            $this->request('STLS');
+            $result = stream_socket_enable_crypto($this->_socket, true, STREAM_CRYPTO_METHOD_TLS_CLIENT);
+            if (!$result) {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception('cannot enable TLS');
+            }
+        }
+
+        return $welcome;
+    }
+
+
+    /**
+     * Send a request
+     *
+     * @param string $request your request without newline
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function sendRequest($request)
+    {
+        $result = @fputs($this->_socket, $request . "\r\n");
+        if (!$result) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('send failed - connection closed?');
+        }
+    }
+
+
+    /**
+     * read a response
+     *
+     * @param  boolean $multiline response has multiple lines and should be read until "<nl>.<nl>"
+     * @return string response
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function readResponse($multiline = false)
+    {
+        $result = @fgets($this->_socket);
+        if (!is_string($result)) {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('read failed - connection closed?');
+        }
+
+        $result = trim($result);
+        if (strpos($result, ' ')) {
+            list($status, $message) = explode(' ', $result, 2);
+        } else {
+            $status = $result;
+            $message = '';
+        }
+
+        if ($status != '+OK') {
+            /**
+             * @see Zend_Mail_Protocol_Exception
+             */
+            require_once 'Zend/Mail/Protocol/Exception.php';
+            throw new Zend_Mail_Protocol_Exception('last request failed');
+        }
+
+        if ($multiline) {
+            $message = '';
+            $line = fgets($this->_socket);
+            while ($line && rtrim($line, "\r\n") != '.') {
+                if ($line[0] == '.') {
+                    $line = substr($line, 1);
+                }
+                $message .= $line;
+                $line = fgets($this->_socket);
+            };
+        }
+
+        return $message;
+    }
+
+
+    /**
+     * Send request and get resposne
+     *
+     * @see sendRequest(), readResponse()
+     *
+     * @param  string $request    request
+     * @param  bool   $multiline  multiline response?
+     * @return string             result from readResponse()
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function request($request, $multiline = false)
+    {
+        $this->sendRequest($request);
+        return $this->readResponse($multiline);
+    }
+
+
+    /**
+     * End communication with POP3 server (also closes socket)
+     *
+     * @return null
+     */
+    public function logout()
+    {
+        if (!$this->_socket) {
+            return;
+        }
+
+        try {
+            $this->request('QUIT');
+        } catch (Zend_Mail_Protocol_Exception $e) {
+            // ignore error - we're closing the socket anyway
+        }
+
+        fclose($this->_socket);
+        $this->_socket = null;
+    }
+
+
+    /**
+     * Get capabilities from POP3 server
+     *
+     * @return array list of capabilities
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function capa()
+    {
+        $result = $this->request('CAPA', true);
+        return explode("\n", $result);
+    }
+
+
+    /**
+     * Login to POP3 server. Can use APOP
+     *
+     * @param  string $user      username
+     * @param  string $password  password
+     * @param  bool   $try_apop  should APOP be tried?
+     * @return void
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function login($user, $password, $tryApop = true)
+    {
+        if ($tryApop && $this->_timestamp) {
+            try {
+                $this->request("APOP $user " . md5($this->_timestamp . $password));
+                return;
+            } catch (Zend_Mail_Protocol_Exception $e) {
+                // ignore
+            }
+        }
+
+        $result = $this->request("USER $user");
+        $result = $this->request("PASS $password");
+    }
+
+
+    /**
+     * Make STAT call for message count and size sum
+     *
+     * @param  int $messages  out parameter with count of messages
+     * @param  int $octets    out parameter with size in octects of messages
+     * @return void
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function status(&$messages, &$octets)
+    {
+        $messages = 0;
+        $octets = 0;
+        $result = $this->request('STAT');
+
+        list($messages, $octets) = explode(' ', $result);
+    }
+
+
+    /**
+     * Make LIST call for size of message(s)
+     *
+     * @param  int|null $msgno number of message, null for all
+     * @return int|array size of given message or list with array(num => size)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function getList($msgno = null)
+    {
+        if ($msgno !== null) {
+            $result = $this->request("LIST $msgno");
+
+            list(, $result) = explode(' ', $result);
+            return (int)$result;
+        }
+
+        $result = $this->request('LIST', true);
+        $messages = array();
+        $line = strtok($result, "\n");
+        while ($line) {
+            list($no, $size) = explode(' ', trim($line));
+            $messages[(int)$no] = (int)$size;
+            $line = strtok("\n");
+        }
+
+        return $messages;
+    }
+
+
+    /**
+     * Make UIDL call for getting a uniqueid
+     *
+     * @param  int|null $msgno number of message, null for all
+     * @return string|array uniqueid of message or list with array(num => uniqueid)
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function uniqueid($msgno = null)
+    {
+        if ($msgno !== null) {
+            $result = $this->request("UIDL $msgno");
+
+            list(, $result) = explode(' ', $result);
+            return $result;
+        }
+
+        $result = $this->request('UIDL', true);
+
+        $result = explode("\n", $result);
+        $messages = array();
+        foreach ($result as $line) {
+            if (!$line) {
+                continue;
+            }
+            list($no, $id) = explode(' ', trim($line), 2);
+            $messages[(int)$no] = $id;
+        }
+
+        return $messages;
+
+    }
+
+
+    /**
+     * Make TOP call for getting headers and maybe some body lines
+     * This method also sets hasTop - before it it's not known if top is supported
+     *
+     * The fallback makes normale RETR call, which retrieves the whole message. Additional
+     * lines are not removed.
+     *
+     * @param  int  $msgno    number of message
+     * @param  int  $lines    number of wanted body lines (empty line is inserted after header lines)
+     * @param  bool $fallback fallback with full retrieve if top is not supported
+     * @return string message headers with wanted body lines
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function top($msgno, $lines = 0, $fallback = false)
+    {
+        if ($this->hasTop === false) {
+            if ($fallback) {
+                return $this->retrieve($msgno);
+            } else {
+                /**
+                 * @see Zend_Mail_Protocol_Exception
+                 */
+                require_once 'Zend/Mail/Protocol/Exception.php';
+                throw new Zend_Mail_Protocol_Exception('top not supported and no fallback wanted');
+            }
+        }
+        $this->hasTop = true;
+
+        $lines = (!$lines || $lines < 1) ? 0 : (int)$lines;
+
+        try {
+            $result = $this->request("TOP $msgno $lines", true);
+        } catch (Zend_Mail_Protocol_Exception $e) {
+            $this->hasTop = false;
+            if ($fallback) {
+                $result = $this->retrieve($msgno);
+            } else {
+                throw $e;
+            }
+        }
+
+        return $result;
+    }
+
+
+    /**
+     * Make a RETR call for retrieving a full message with headers and body
+     *
+     * @deprecated since 1.1.0; this method has a typo - please use retrieve()
+     * @param  int $msgno  message number
+     * @return string message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function retrive($msgno)
+    {
+        return $this->retrieve($msgno);
+    }
+
+
+    /**
+     * Make a RETR call for retrieving a full message with headers and body
+     *
+     * @param  int $msgno  message number
+     * @return string message
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function retrieve($msgno)
+    {
+        $result = $this->request("RETR $msgno", true);
+        return $result;
+    }
+
+    /**
+     * Make a NOOP call, maybe needed for keeping the server happy
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function noop()
+    {
+        $this->request('NOOP');
+    }
+
+
+    /**
+     * Make a DELE count to remove a message
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function delete($msgno)
+    {
+        $this->request("DELE $msgno");
+    }
+
+
+    /**
+     * Make RSET call, which rollbacks delete requests
+     *
+     * @return null
+     * @throws Zend_Mail_Protocol_Exception
+     */
+    public function undelete()
+    {
+        $this->request('RSET');
+    }
+}