From dc336469716000a54865fc59cd2790534e68a848 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Thu, 04 Jul 2013 06:20:00 -0400
Subject: [PATCH] Remove sqlite 2.x requirement
---
program/lib/Roundcube/rcube_imap_generic.php | 337 +++++++++++++++++++++++++++++++++-----------------------
1 files changed, 199 insertions(+), 138 deletions(-)
diff --git a/program/lib/Roundcube/rcube_imap_generic.php b/program/lib/Roundcube/rcube_imap_generic.php
index a0a8f3b..ab2e63d 100644
--- a/program/lib/Roundcube/rcube_imap_generic.php
+++ b/program/lib/Roundcube/rcube_imap_generic.php
@@ -2,8 +2,6 @@
/**
+-----------------------------------------------------------------------+
- | program/include/rcube_imap_generic.php |
- | |
| This file is part of the Roundcube Webmail client |
| Copyright (C) 2005-2012, The Roundcube Dev Team |
| Copyright (C) 2011-2012, Kolab Systems AG |
@@ -19,13 +17,11 @@
| functionality built-in. |
| |
| Based on Iloha IMAP Library. See http://ilohamail.org/ for details |
- | |
+-----------------------------------------------------------------------+
| Author: Aleksander Machniak <alec@alec.pl> |
| Author: Ryo Chijiiwa <Ryo@IlohaMail.org> |
+-----------------------------------------------------------------------+
*/
-
/**
* PHP based wrapper class to connect to an IMAP server
@@ -750,19 +746,23 @@
}
if ($this->prefs['timeout'] <= 0) {
- $this->prefs['timeout'] = ini_get('default_socket_timeout');
+ $this->prefs['timeout'] = max(0, intval(ini_get('default_socket_timeout')));
}
// Connect
$this->fp = @fsockopen($host, $this->prefs['port'], $errno, $errstr, $this->prefs['timeout']);
if (!$this->fp) {
+ if (!$errstr) {
+ $errstr = "Unknown reason (fsockopen() function disabled?)";
+ }
$this->setError(self::ERROR_BAD, sprintf("Could not connect to %s:%d: %s", $host, $this->prefs['port'], $errstr));
return false;
}
- if ($this->prefs['timeout'] > 0)
+ if ($this->prefs['timeout'] > 0) {
stream_set_timeout($this->fp, $this->prefs['timeout']);
+ }
$line = trim(fgets($this->fp, 8192));
@@ -906,7 +906,7 @@
*/
function closeConnection()
{
- if ($this->putLine($this->nextTag() . ' LOGOUT')) {
+ if ($this->logged && $this->putLine($this->nextTag() . ' LOGOUT')) {
$this->readReply();
}
@@ -1077,7 +1077,7 @@
}
if (!$this->data['READ-WRITE']) {
- $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'EXPUNGE');
+ $this->setError(self::ERROR_READONLY, "Mailbox is read-only");
return false;
}
@@ -1310,6 +1310,11 @@
// * LIST (<options>) <delimiter> <mailbox>
if ($cmd == 'LIST' || $cmd == 'LSUB') {
list($opts, $delim, $mailbox) = $this->tokenizeResponse($line, 3);
+
+ // Remove redundant separator at the end of folder name, UW-IMAP bug? (#1488879)
+ if ($delim) {
+ $mailbox = rtrim($mailbox, $delim);
+ }
// Add to result array
if (!$lstatus) {
@@ -1928,7 +1933,7 @@
}
if (!$this->data['READ-WRITE']) {
- $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE');
+ $this->setError(self::ERROR_READONLY, "Mailbox is read-only");
return false;
}
@@ -1990,7 +1995,7 @@
}
if (!$this->data['READ-WRITE']) {
- $this->setError(self::ERROR_READONLY, "Mailbox is read-only", 'STORE');
+ $this->setError(self::ERROR_READONLY, "Mailbox is read-only");
return false;
}
@@ -2125,14 +2130,18 @@
else if ($name == 'RFC822') {
$result[$id]->body = $value;
}
- else if ($name == 'BODY') {
- $body = $this->tokenizeResponse($line, 1);
- if ($value[0] == 'HEADER.FIELDS')
- $headers = $body;
- else if (!empty($value))
- $result[$id]->bodypart[$value[0]] = $body;
+ else if (stripos($name, 'BODY[') === 0) {
+ $name = str_replace(']', '', substr($name, 5));
+
+ if ($name == 'HEADER.FIELDS') {
+ // skip ']' after headers list
+ $this->tokenizeResponse($line, 1);
+ $headers = $this->tokenizeResponse($line, 1);
+ }
+ else if (strlen($name))
+ $result[$id]->bodypart[$name] = $value;
else
- $result[$id]->body = $body;
+ $result[$id]->body = $value;
}
}
@@ -2206,10 +2215,13 @@
}
break;
default:
- if (strlen($field) > 2) {
- $result[$id]->others[$field] = $string;
+ if (strlen($field) < 3) {
+ break;
}
- break;
+ if ($result[$id]->others[$field]) {
+ $string = array_merge((array)$result[$id]->others[$field], (array)$string);
+ }
+ $result[$id]->others[$field] = $string;
}
}
}
@@ -2217,7 +2229,6 @@
// VANISHED response (QRESYNC RFC5162)
// Sample: * VANISHED (EARLIER) 300:310,405,411
-
else if (preg_match('/^\* VANISHED [()EARLIER]*/i', $line, $match)) {
$line = substr($line, strlen($match[0]));
$v_data = $this->tokenizeResponse($line, 1);
@@ -2230,24 +2241,53 @@
return $result;
}
- function fetchHeaders($mailbox, $message_set, $is_uid = false, $bodystr = false, $add = '')
+ /**
+ * Returns message(s) data (flags, headers, etc.)
+ *
+ * @param string $mailbox Mailbox name
+ * @param mixed $message_set Message(s) sequence identifier(s) or UID(s)
+ * @param bool $is_uid True if $message_set contains UIDs
+ * @param bool $bodystr Enable to add BODYSTRUCTURE data to the result
+ * @param array $add_headers List of additional headers
+ *
+ * @return bool|array List of rcube_message_header elements, False on error
+ */
+ function fetchHeaders($mailbox, $message_set, $is_uid = false, $bodystr = false, $add_headers = array())
{
$query_items = array('UID', 'RFC822.SIZE', 'FLAGS', 'INTERNALDATE');
- if ($bodystr)
+ $headers = array('DATE', 'FROM', 'TO', 'SUBJECT', 'CONTENT-TYPE', 'CC', 'REPLY-TO',
+ 'LIST-POST', 'DISPOSITION-NOTIFICATION-TO', 'X-PRIORITY');
+
+ if (!empty($add_headers)) {
+ $add_headers = array_map('strtoupper', $add_headers);
+ $headers = array_unique(array_merge($headers, $add_headers));
+ }
+
+ if ($bodystr) {
$query_items[] = 'BODYSTRUCTURE';
- $query_items[] = 'BODY.PEEK[HEADER.FIELDS ('
- . 'DATE FROM TO SUBJECT CONTENT-TYPE CC REPLY-TO LIST-POST DISPOSITION-NOTIFICATION-TO X-PRIORITY'
- . ($add ? ' ' . trim($add) : '')
- . ')]';
+ }
+
+ $query_items[] = 'BODY.PEEK[HEADER.FIELDS (' . implode(' ', $headers) . ')]';
$result = $this->fetch($mailbox, $message_set, $is_uid, $query_items);
return $result;
}
- function fetchHeader($mailbox, $id, $uidfetch=false, $bodystr=false, $add='')
+ /**
+ * Returns message data (flags, headers, etc.)
+ *
+ * @param string $mailbox Mailbox name
+ * @param int $id Message sequence identifier or UID
+ * @param bool $is_uid True if $id is an UID
+ * @param bool $bodystr Enable to add BODYSTRUCTURE data to the result
+ * @param array $add_headers List of additional headers
+ *
+ * @return bool|rcube_message_header Message data, False on error
+ */
+ function fetchHeader($mailbox, $id, $is_uid = false, $bodystr = false, $add_headers = array())
{
- $a = $this->fetchHeaders($mailbox, $id, $uidfetch, $bodystr, $add);
+ $a = $this->fetchHeaders($mailbox, $id, $is_uid, $bodystr, $add_headers);
if (is_array($a)) {
return array_shift($a);
}
@@ -2379,7 +2419,7 @@
return $this->handlePartBody($mailbox, $id, $is_uid, $part);
}
- function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL, $formatted=false)
+ function handlePartBody($mailbox, $id, $is_uid=false, $part='', $encoding=NULL, $print=NULL, $file=NULL, $formatted=false, $max_bytes=0)
{
if (!$this->select($mailbox)) {
return false;
@@ -2405,10 +2445,13 @@
// Use BINARY extension when possible (and safe)
$binary = $mode && preg_match('/^[0-9.]+$/', $part) && $this->hasCapability('BINARY');
$fetch_mode = $binary ? 'BINARY' : 'BODY';
+ $partial = $max_bytes ? sprintf('<0.%d>', $max_bytes) : '';
// format request
- $key = $this->nextTag();
- $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part])";
+ $key = $this->nextTag();
+ $request = $key . ($is_uid ? ' UID' : '') . " FETCH $id ($fetch_mode.PEEK[$part]$partial)";
+ $result = false;
+ $found = false;
// send request
if (!$this->putLine($request)) {
@@ -2421,116 +2464,125 @@
$mode = -1;
}
- // receive reply line
do {
- $line = rtrim($this->readLine(1024));
- $a = explode(' ', $line);
- } while (!($end = $this->startsWith($line, $key, true)) && $a[2] != 'FETCH');
+ $line = trim($this->readLine(1024));
- $len = strlen($line);
- $result = false;
-
- if ($a[2] != 'FETCH') {
- }
- // handle empty "* X FETCH ()" response
- else if ($line[$len-1] == ')' && $line[$len-2] != '(') {
- // one line response, get everything between first and last quotes
- if (substr($line, -4, 3) == 'NIL') {
- // NIL response
- $result = '';
- } else {
- $from = strpos($line, '"') + 1;
- $to = strrpos($line, '"');
- $len = $to - $from;
- $result = substr($line, $from, $len);
+ if (!$line) {
+ break;
}
- if ($mode == 1) {
- $result = base64_decode($result);
- }
- else if ($mode == 2) {
- $result = quoted_printable_decode($result);
- }
- else if ($mode == 3) {
- $result = convert_uudecode($result);
+ // skip irrelevant untagged responses (we have a result already)
+ if ($found || !preg_match('/^\* ([0-9]+) FETCH (.*)$/', $line, $m)) {
+ continue;
}
- } else if ($line[$len-1] == '}') {
- // multi-line request, find sizes of content and receive that many bytes
- $from = strpos($line, '{') + 1;
- $to = strrpos($line, '}');
- $len = $to - $from;
- $sizeStr = substr($line, $from, $len);
- $bytes = (int)$sizeStr;
- $prev = '';
+ $line = $m[2];
- while ($bytes > 0) {
- $line = $this->readLine(8192);
+ // handle one line response
+ if ($line[0] == '(' && substr($line, -1) == ')') {
+ // tokenize content inside brackets
+ $tokens = $this->tokenizeResponse(preg_replace('/(^\(|\)$)/', '', $line));
- if ($line === NULL) {
- break;
- }
-
- $len = strlen($line);
-
- if ($len > $bytes) {
- $line = substr($line, 0, $bytes);
- $len = strlen($line);
- }
- $bytes -= $len;
-
- // BASE64
- if ($mode == 1) {
- $line = rtrim($line, "\t\r\n\0\x0B");
- // create chunks with proper length for base64 decoding
- $line = $prev.$line;
- $length = strlen($line);
- if ($length % 4) {
- $length = floor($length / 4) * 4;
- $prev = substr($line, $length);
- $line = substr($line, 0, $length);
+ for ($i=0; $i<count($tokens); $i+=2) {
+ if (preg_match('/^(BODY|BINARY)/i', $tokens[$i])) {
+ $result = $tokens[$i+1];
+ $found = true;
+ break;
}
- else
- $prev = '';
- $line = base64_decode($line);
- // QUOTED-PRINTABLE
- } else if ($mode == 2) {
- $line = rtrim($line, "\t\r\0\x0B");
- $line = quoted_printable_decode($line);
- // UUENCODE
- } else if ($mode == 3) {
- $line = rtrim($line, "\t\r\n\0\x0B");
- if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line))
- continue;
- $line = convert_uudecode($line);
- // default
- } else if ($formatted) {
- $line = rtrim($line, "\t\r\n\0\x0B") . "\n";
}
- if ($file)
- fwrite($file, $line);
- else if ($print)
- echo $line;
- else
- $result .= $line;
+ if ($result !== false) {
+ if ($mode == 1) {
+ $result = base64_decode($result);
+ }
+ else if ($mode == 2) {
+ $result = quoted_printable_decode($result);
+ }
+ else if ($mode == 3) {
+ $result = convert_uudecode($result);
+ }
+ }
}
- }
+ // response with string literal
+ else if (preg_match('/\{([0-9]+)\}$/', $line, $m)) {
+ $bytes = (int) $m[1];
+ $prev = '';
+ $found = true;
- // read in anything up until last line
- if (!$end)
- do {
- $line = $this->readLine(1024);
- } while (!$this->startsWith($line, $key, true));
+ while ($bytes > 0) {
+ $line = $this->readLine(8192);
+
+ if ($line === NULL) {
+ break;
+ }
+
+ $len = strlen($line);
+
+ if ($len > $bytes) {
+ $line = substr($line, 0, $bytes);
+ $len = strlen($line);
+ }
+ $bytes -= $len;
+
+ // BASE64
+ if ($mode == 1) {
+ $line = rtrim($line, "\t\r\n\0\x0B");
+ // create chunks with proper length for base64 decoding
+ $line = $prev.$line;
+ $length = strlen($line);
+ if ($length % 4) {
+ $length = floor($length / 4) * 4;
+ $prev = substr($line, $length);
+ $line = substr($line, 0, $length);
+ }
+ else {
+ $prev = '';
+ }
+ $line = base64_decode($line);
+ }
+ // QUOTED-PRINTABLE
+ else if ($mode == 2) {
+ $line = rtrim($line, "\t\r\0\x0B");
+ $line = quoted_printable_decode($line);
+ }
+ // UUENCODE
+ else if ($mode == 3) {
+ $line = rtrim($line, "\t\r\n\0\x0B");
+ if ($line == 'end' || preg_match('/^begin\s+[0-7]+\s+.+$/', $line)) {
+ continue;
+ }
+ $line = convert_uudecode($line);
+ }
+ // default
+ else if ($formatted) {
+ $line = rtrim($line, "\t\r\n\0\x0B") . "\n";
+ }
+
+ if ($file) {
+ if (fwrite($file, $line) === false) {
+ break;
+ }
+ }
+ else if ($print) {
+ echo $line;
+ }
+ else {
+ $result .= $line;
+ }
+ }
+ }
+ } while (!$this->startsWith($line, $key, true));
if ($result !== false) {
if ($file) {
- fwrite($file, $result);
- } else if ($print) {
+ return fwrite($file, $result);
+ }
+ else if ($print) {
echo $result;
- } else
- return $result;
- return true;
+ return true;
+ }
+
+ return $result;
}
return false;
@@ -2543,10 +2595,11 @@
* @param string $message Message content
* @param array $flags Message flags
* @param string $date Message internal date
+ * @param bool $binary Enable BINARY append (RFC3516)
*
* @return string|bool On success APPENDUID response (if available) or True, False on failure
*/
- function append($mailbox, &$message, $flags = array(), $date = null)
+ function append($mailbox, &$message, $flags = array(), $date = null, $binary = false)
{
unset($this->data['APPENDUID']);
@@ -2554,8 +2607,13 @@
return false;
}
- $message = str_replace("\r", '', $message);
- $message = str_replace("\n", "\r\n", $message);
+ $binary = $binary && $this->getCapability('BINARY');
+ $literal_plus = !$binary && $this->prefs['literal+'];
+
+ if (!$binary) {
+ $message = str_replace("\r", '', $message);
+ $message = str_replace("\n", "\r\n", $message);
+ }
$len = strlen($message);
if (!$len) {
@@ -2568,12 +2626,12 @@
if (!empty($date)) {
$request .= ' ' . $this->escape($date);
}
- $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}';
+ $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}';
// send APPEND command
if ($this->putLine($request)) {
// Do not wait when LITERAL+ is supported
- if (!$this->prefs['literal+']) {
+ if (!$literal_plus) {
$line = $this->readReply();
if ($line[0] != '+') {
@@ -2615,10 +2673,11 @@
* @param string $headers Message headers
* @param array $flags Message flags
* @param string $date Message internal date
+ * @param bool $binary Enable BINARY append (RFC3516)
*
* @return string|bool On success APPENDUID response (if available) or True, False on failure
*/
- function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null)
+ function appendFromFile($mailbox, $path, $headers=null, $flags = array(), $date = null, $binary = false)
{
unset($this->data['APPENDUID']);
@@ -2649,18 +2708,21 @@
$len += strlen($headers) + strlen($body_separator);
}
+ $binary = $binary && $this->getCapability('BINARY');
+ $literal_plus = !$binary && $this->prefs['literal+'];
+
// build APPEND command
$key = $this->nextTag();
$request = "$key APPEND " . $this->escape($mailbox) . ' (' . $this->flagsToStr($flags) . ')';
if (!empty($date)) {
$request .= ' ' . $this->escape($date);
}
- $request .= ' {' . $len . ($this->prefs['literal+'] ? '+' : '') . '}';
+ $request .= ' ' . ($binary ? '~' : '') . '{' . $len . ($literal_plus ? '+' : '') . '}';
// send APPEND command
if ($this->putLine($request)) {
// Don't wait when LITERAL+ is supported
- if (!$this->prefs['literal+']) {
+ if (!$literal_plus) {
$line = $this->readReply();
if ($line[0] != '+') {
@@ -3419,25 +3481,24 @@
// Parenthesized list
case '(':
- case '[':
$str = substr($str, 1);
$result[] = self::tokenizeResponse($str);
break;
case ')':
- case ']':
$str = substr($str, 1);
return $result;
break;
- // String atom, number, NIL, *, %
+ // String atom, number, astring, NIL, *, %
default:
// empty string
if ($str === '' || $str === null) {
break 2;
}
- // excluded chars: SP, CTL, ), [, ]
- if (preg_match('/^([^\x00-\x20\x29\x5B\x5D\x7F]+)/', $str, $m)) {
+ // excluded chars: SP, CTL, ), DEL
+ // 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]));
}
--
Gitblit v1.9.1