public function read($size = null)
    {
        $got_data = false;
        $literal_len = null;
        $token = new Horde_Imap_Client_Tokenize();

        do {
            if (feof($this->_stream)) {
                $this->close();
                $this->_params['debug']->info(
                    'ERROR: Server closed the connection.'
                );
                throw new Horde_Imap_Client_Exception(
                    Horde_Imap_Client_Translation::r("Mail server closed the connection unexpectedly."),
                    Horde_Imap_Client_Exception::DISCONNECT
                );
            }

            if (is_null($literal_len)) {
                $buffer = '';

                while (($in = fgets($this->_stream)) !== false) {
                    $got_data = true;

                    if (substr($in, -1) === "\n") {
                        $in = rtrim($in);
                        $this->_params['debug']->server($buffer . $in);
                        $token->add($in);
                        break;
                    }

                    $buffer .= $in;
                    $token->add($in);
                }

                /* Check for literal data. */
                if (is_null($len = $token->getLiteralLength())) {
                    break;
                }

                // Skip 0-length literal data.
                if ($len['length']) {
                    $binary = $len['binary'];
                    $literal_len = $len['length'];
                }

                continue;
            }

            $old_len = $literal_len;

            while (($literal_len > 0) && !feof($this->_stream)) {
                $in = fread($this->_stream, min($literal_len, 8192));
                /* Only store in stream if this is something more than a
                 * nominal number of bytes. */
                if ($old_len > 256) {
                    $token->addLiteralStream($in);
                } else {
                    $token->add($in);
                }

                if (!empty($this->_params['debugliteral'])) {
                    $this->_params['debug']->raw($in);
                }

                $got_data = true;
                $literal_len -= strlen($in);
            }

            $literal_len = null;

            if (empty($this->_params['debugliteral'])) {
                $this->_params['debug']->server('[' . ($binary ? 'BINARY' : 'LITERAL') . ' DATA: ' . $old_len . ' bytes]');
            }
        } while (true);

        if (!$got_data) {
            $this->_params['debug']->info('ERROR: read/timeout error.');
            throw new Horde_Imap_Client_Exception(
                Horde_Imap_Client_Translation::r("Error when communicating with the mail server."),
                Horde_Imap_Client_Exception::SERVER_READERROR
            );
        }

        return $token;
    }