From 4921c21cff15b9ba2a5a05b2145861b01c9e85d6 Mon Sep 17 00:00:00 2001 From: Aleksander Machniak <alec@alec.pl> Date: Thu, 05 May 2016 08:10:55 -0400 Subject: [PATCH] Optimize SELECT response handling --- program/lib/Roundcube/rcube_imap_generic.php | 116 +++++++++++++++++++++++++++++++++++++++------------------ 1 files changed, 79 insertions(+), 37 deletions(-) diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php index caf2ebe..f682b71 100644 --- a/program/lib/Roundcube/rcube_imap_generic.php +++ b/program/lib/Roundcube/rcube_imap_generic.php @@ -107,7 +107,11 @@ $this->debug('C: ' . $log); } - $res = fwrite($this->fp, $string . ($endln ? "\r\n" : '')); + if ($endln) { + $string .= "\r\n"; + } + + $res = fwrite($this->fp, $string); if ($res === false) { @fclose($this->fp); @@ -174,6 +178,7 @@ } } } + return $res; } @@ -997,7 +1002,18 @@ return false; } - if (!stream_socket_enable_crypto($this->fp, true, STREAM_CRYPTO_METHOD_TLS_CLIENT)) { + if (isset($this->prefs['socket_options']['ssl']['crypto_method'])) { + $crypto_method = $this->prefs['socket_options']['ssl']['crypto_method']; + } + else { + // There is no flag to enable all TLS methods. Net_SMTP + // handles enabling TLS similarly. + $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT + | @STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT + | @STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT; + } + + if (!stream_socket_enable_crypto($this->fp, true, $crypto_method)) { $this->setError(self::ERROR_BAD, "Unable to negotiate TLS"); $this->closeConnection(); return false; @@ -1047,7 +1063,7 @@ */ public function connected() { - return ($this->fp && $this->logged) ? true : false; + return $this->fp && $this->logged; } /** @@ -1112,35 +1128,61 @@ $response = explode("\r\n", $response); foreach ($response as $line) { - if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT)$/i', $line, $m)) { - $this->data[strtoupper($m[2])] = (int) $m[1]; - } - else if (preg_match('/^\* OK \[/i', $line, $match)) { - $line = substr($line, 6); - if (preg_match('/^(UIDNEXT|UIDVALIDITY|UNSEEN) ([0-9]+)/i', $line, $match)) { - $this->data[strtoupper($match[1])] = (int) $match[2]; - } - else if (preg_match('/^(HIGHESTMODSEQ) ([0-9]+)/i', $line, $match)) { - $this->data[strtoupper($match[1])] = (string) $match[2]; - } - else if (preg_match('/^(NOMODSEQ)/i', $line, $match)) { - $this->data[strtoupper($match[1])] = true; - } - else if (preg_match('/^PERMANENTFLAGS \(([^\)]+)\)/iU', $line, $match)) { - $this->data['PERMANENTFLAGS'] = explode(' ', $match[1]); + if (preg_match('/^\* OK \[/i', $line)) { + $pos = strcspn($line, ' ]', 6); + $token = strtoupper(substr($line, 6, $pos)); + $pos += 7; + + switch ($token) { + case 'UIDNEXT': + case 'UIDVALIDITY': + case 'UNSEEN': + if ($len = strspn($line, '0123456789', $pos)) { + $this->data[$token] = (int) substr($line, $pos, $len); + } + break; + + case 'HIGHESTMODSEQ': + if ($len = strspn($line, '0123456789', $pos)) { + $this->data[$token] = (string) substr($line, $pos, $len); + } + break; + + case 'NOMODSEQ': + $this->data[$token] = true; + break; + + case 'PERMANENTFLAGS': + $start = strpos($line, '(', $pos); + $end = strrpos($line, ')'); + if ($start && $end) { + $flags = substr($line, $start + 1, $end - $start - 1); + $this->data[$token] = explode(' ', $flags); + } + break; } } - // QRESYNC FETCH response (RFC5162) - else if (preg_match('/^\* ([0-9+]) FETCH/i', $line, $match)) { - $line = substr($line, strlen($match[0])); - $fetch_data = $this->tokenizeResponse($line, 1); - $data = array('id' => $match[1]); + else if (preg_match('/^\* ([0-9]+) (EXISTS|RECENT|FETCH)/i', $line, $match)) { + $token = strtoupper($match[2]); + switch ($token) { + case 'EXISTS': + case 'RECENT': + $this->data[$token] = (int) $match[1]; + break; - for ($i=0, $size=count($fetch_data); $i<$size; $i+=2) { - $data[strtolower($fetch_data[$i])] = $fetch_data[$i+1]; + case 'FETCH': + // QRESYNC FETCH response (RFC5162) + $line = substr($line, strlen($match[0])); + $fetch_data = $this->tokenizeResponse($line, 1); + $data = array('id' => $match[1]); + + for ($i=0, $size=count($fetch_data); $i<$size; $i+=2) { + $data[strtolower($fetch_data[$i])] = $fetch_data[$i+1]; + } + + $this->data['QRESYNC'][$data['uid']] = $data; + break; } - - $this->data['QRESYNC'][$data['uid']] = $data; } // QRESYNC VANISHED response (RFC5162) else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) { @@ -3454,6 +3496,7 @@ if (!is_array($entries)) { $entries = array($entries); } + // create entries string // ANNOTATEMORE drafts before version 08 require quoted parameters foreach ($entries as $idx => $name) { @@ -3464,7 +3507,8 @@ if (!is_array($attribs)) { $attribs = array($attribs); } - // create entries string + + // create attributes string foreach ($attribs as $idx => $name) { $attribs[$idx] = $this->escape($name, true); } @@ -3725,9 +3769,9 @@ if (!is_numeric(($bytes = substr($str, 1, $epos - 1)))) { // error } + $result[] = $bytes ? substr($str, $epos + 3, $bytes) : ''; - // Advance the string - $str = substr($str, $epos + 3 + $bytes); + $str = substr($str, $epos + 3 + $bytes); break; // Quoted string @@ -3744,9 +3788,7 @@ } } } - if ($str[$pos] != '"') { - // error - } + // we need to strip slashes for a quoted string $result[] = stripslashes(substr($str, 1, $pos - 1)); $str = substr($str, $pos + 1); @@ -3754,13 +3796,13 @@ // Parenthesized list case '(': - $str = substr($str, 1); + $str = substr($str, 1); $result[] = self::tokenizeResponse($str); break; + case ')': $str = substr($str, 1); return $result; - break; // String atom, number, astring, NIL, *, % default: @@ -3773,7 +3815,7 @@ // we do not exclude [ and ] (#1489223) if (preg_match('/^([^\x00-\x20\x29\x7F]+)/', $str, $m)) { $result[] = $m[1] == 'NIL' ? null : $m[1]; - $str = substr($str, strlen($m[1])); + $str = substr($str, strlen($m[1])); } break; } -- Gitblit v1.9.1