|
|
|
@ -1,6 +1,6 @@
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
/**
|
|
|
|
|
+-----------------------------------------------------------------------+
|
|
|
|
|
| program/include/rcube_imap_generic.php |
|
|
|
|
|
| |
|
|
|
|
@ -1469,15 +1469,19 @@ class rcube_imap_generic
|
|
|
|
|
$parts_count = count($a);
|
|
|
|
|
if ($parts_count>=6) {
|
|
|
|
|
for ($i=0; $i<$parts_count; $i=$i+2) {
|
|
|
|
|
if ($a[$i] == 'UID')
|
|
|
|
|
if ($a[$i] == 'UID') {
|
|
|
|
|
$result[$id]->uid = intval($a[$i+1]);
|
|
|
|
|
else if ($a[$i] == 'RFC822.SIZE')
|
|
|
|
|
}
|
|
|
|
|
else if ($a[$i] == 'RFC822.SIZE') {
|
|
|
|
|
$result[$id]->size = intval($a[$i+1]);
|
|
|
|
|
else if ($a[$i] == 'INTERNALDATE')
|
|
|
|
|
}
|
|
|
|
|
else if ($a[$i] == 'INTERNALDATE') {
|
|
|
|
|
$time_str = $a[$i+1];
|
|
|
|
|
else if ($a[$i] == 'FLAGS')
|
|
|
|
|
}
|
|
|
|
|
else if ($a[$i] == 'FLAGS') {
|
|
|
|
|
$flags_str = $a[$i+1];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$time_str = str_replace('"', '', $time_str);
|
|
|
|
|
|
|
|
|
@ -1499,7 +1503,7 @@ class rcube_imap_generic
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// the rest of the result
|
|
|
|
|
preg_match('/ BODY\[HEADER.FIELDS \(.*?\)\]\s*(.*)$/s', $line, $m);
|
|
|
|
|
if (preg_match('/ BODY\[HEADER.FIELDS \(.*?\)\]\s*(.*)$/s', $line, $m)) {
|
|
|
|
|
$reslines = explode("\n", trim($m[1], '"'));
|
|
|
|
|
// re-parse (see below)
|
|
|
|
|
foreach ($reslines as $resln) {
|
|
|
|
@ -1510,6 +1514,7 @@ class rcube_imap_generic
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Start parsing headers. The problem is, some header "lines" take up multiple lines.
|
|
|
|
|
// So, we'll read ahead, and if the one we're reading now is a valid header, we'll
|
|
|
|
@ -1610,12 +1615,14 @@ class rcube_imap_generic
|
|
|
|
|
$result[$id]->messageID = $string;
|
|
|
|
|
break;
|
|
|
|
|
case 'x-priority':
|
|
|
|
|
if (preg_match('/^(\d+)/', $string, $matches))
|
|
|
|
|
if (preg_match('/^(\d+)/', $string, $matches)) {
|
|
|
|
|
$result[$id]->priority = intval($matches[1]);
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
if (strlen($field) > 2)
|
|
|
|
|
if (strlen($field) > 2) {
|
|
|
|
|
$result[$id]->others[$field] = $string;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
} // end switch ()
|
|
|
|
|
} // end while ()
|
|
|
|
@ -1840,7 +1847,7 @@ class rcube_imap_generic
|
|
|
|
|
while ($n > 0) {
|
|
|
|
|
$p = strpos($str, ')', $off);
|
|
|
|
|
if ($p === false) {
|
|
|
|
|
error_log('Mismatched brackets parsing IMAP THREAD response:');
|
|
|
|
|
error_log("Mismatched brackets parsing IMAP THREAD response:");
|
|
|
|
|
error_log(substr($str, ($begin < 10) ? 0 : ($begin - 10), $end - $begin + 20));
|
|
|
|
|
error_log(str_repeat(' ', $off - (($begin < 10) ? 0 : ($begin - 10))));
|
|
|
|
|
return $node;
|
|
|
|
@ -1967,14 +1974,18 @@ class rcube_imap_generic
|
|
|
|
|
|
|
|
|
|
if (!empty($items)) {
|
|
|
|
|
$result = array();
|
|
|
|
|
if (in_array('COUNT', $items))
|
|
|
|
|
if (in_array('COUNT', $items)) {
|
|
|
|
|
$result['COUNT'] = count($response);
|
|
|
|
|
if (in_array('MIN', $items))
|
|
|
|
|
}
|
|
|
|
|
if (in_array('MIN', $items)) {
|
|
|
|
|
$result['MIN'] = !empty($response) ? min($response) : 0;
|
|
|
|
|
if (in_array('MAX', $items))
|
|
|
|
|
}
|
|
|
|
|
if (in_array('MAX', $items)) {
|
|
|
|
|
$result['MAX'] = !empty($response) ? max($response) : 0;
|
|
|
|
|
if (in_array('ALL', $items))
|
|
|
|
|
}
|
|
|
|
|
if (in_array('ALL', $items)) {
|
|
|
|
|
$result['ALL'] = $this->compressMessageSet($response, true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
@ -2118,8 +2129,9 @@ class rcube_imap_generic
|
|
|
|
|
$type = $mime ? 'MIME' : 'HEADER';
|
|
|
|
|
|
|
|
|
|
// format request
|
|
|
|
|
foreach($parts as $part)
|
|
|
|
|
foreach($parts as $part) {
|
|
|
|
|
$peeks[] = "BODY.PEEK[$part.$type]";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$request = "$key FETCH $id (" . implode(' ', $peeks) . ')';
|
|
|
|
|
|
|
|
|
@ -2207,12 +2219,15 @@ class rcube_imap_generic
|
|
|
|
|
$result = substr($line, $from, $len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($mode == 1)
|
|
|
|
|
if ($mode == 1) {
|
|
|
|
|
$result = base64_decode($result);
|
|
|
|
|
else if ($mode == 2)
|
|
|
|
|
}
|
|
|
|
|
else if ($mode == 2) {
|
|
|
|
|
$result = quoted_printable_decode($result);
|
|
|
|
|
else if ($mode == 3)
|
|
|
|
|
}
|
|
|
|
|
else if ($mode == 3) {
|
|
|
|
|
$result = convert_uudecode($result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else if ($line[$len-1] == '}') {
|
|
|
|
|
// multi-line request, find sizes of content and receive that many bytes
|
|
|
|
@ -2226,8 +2241,9 @@ class rcube_imap_generic
|
|
|
|
|
while ($bytes > 0) {
|
|
|
|
|
$line = $this->readLine(4096);
|
|
|
|
|
|
|
|
|
|
if ($line === NULL)
|
|
|
|
|
if ($line === NULL) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$len = strlen($line);
|
|
|
|
|
|
|
|
|
@ -2333,7 +2349,7 @@ class rcube_imap_generic
|
|
|
|
|
if ($this->putLine($request)) {
|
|
|
|
|
// Don't wait when LITERAL+ is supported
|
|
|
|
|
if (!$this->prefs['literal+']) {
|
|
|
|
|
$line = $this->readLine(512);
|
|
|
|
|
$line = $this->readReply();
|
|
|
|
|
|
|
|
|
|
if ($line[0] != '+') {
|
|
|
|
|
$this->parseResult($line, 'APPEND: ');
|
|
|
|
@ -2397,7 +2413,7 @@ class rcube_imap_generic
|
|
|
|
|
if ($this->putLine($request)) {
|
|
|
|
|
// Don't wait when LITERAL+ is supported
|
|
|
|
|
if (!$this->prefs['literal+']) {
|
|
|
|
|
$line = $this->readLine(512);
|
|
|
|
|
$line = $this->readReply();
|
|
|
|
|
|
|
|
|
|
if ($line[0] != '+') {
|
|
|
|
|
$this->parseResult($line, 'APPEND: ');
|
|
|
|
@ -2498,8 +2514,9 @@ class rcube_imap_generic
|
|
|
|
|
$parts = explode(' ', $quota_line);
|
|
|
|
|
$storage_part = array_search('STORAGE', $parts);
|
|
|
|
|
|
|
|
|
|
if (!$storage_part)
|
|
|
|
|
if (!$storage_part) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$used = intval($parts[$storage_part+1]);
|
|
|
|
|
$total = intval($parts[$storage_part+2]);
|
|
|
|
@ -2680,11 +2697,12 @@ class rcube_imap_generic
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($entries as $name => $value) {
|
|
|
|
|
if ($value === null)
|
|
|
|
|
if ($value === null) {
|
|
|
|
|
$value = 'NIL';
|
|
|
|
|
else
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$value = sprintf("{%d}\r\n%s", strlen($value), $value);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
$entries[$name] = $this->escape($name) . ' ' . $value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2709,16 +2727,18 @@ class rcube_imap_generic
|
|
|
|
|
*/
|
|
|
|
|
function deleteMetadata($mailbox, $entries)
|
|
|
|
|
{
|
|
|
|
|
if (!is_array($entries) && !empty($entries))
|
|
|
|
|
if (!is_array($entries) && !empty($entries)) {
|
|
|
|
|
$entries = explode(' ', $entries);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (empty($entries)) {
|
|
|
|
|
$this->setError(self::ERROR_COMMAND, "Wrong argument for SETMETADATA command");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($entries as $entry)
|
|
|
|
|
foreach ($entries as $entry) {
|
|
|
|
|
$data[$entry] = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $this->setMetadata($mailbox, $data);
|
|
|
|
|
}
|
|
|
|
@ -2754,14 +2774,17 @@ class rcube_imap_generic
|
|
|
|
|
$options = array_change_key_case($options, CASE_UPPER);
|
|
|
|
|
$opts = array();
|
|
|
|
|
|
|
|
|
|
if (!empty($options['MAXSIZE']))
|
|
|
|
|
if (!empty($options['MAXSIZE'])) {
|
|
|
|
|
$opts[] = 'MAXSIZE '.intval($options['MAXSIZE']);
|
|
|
|
|
if (!empty($options['DEPTH']))
|
|
|
|
|
}
|
|
|
|
|
if (!empty($options['DEPTH'])) {
|
|
|
|
|
$opts[] = 'DEPTH '.intval($options['DEPTH']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($opts)
|
|
|
|
|
if ($opts) {
|
|
|
|
|
$optlist = '(' . implode(' ', $opts) . ')';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$optlist .= ($optlist ? ' ' : '') . $entlist;
|
|
|
|
|
|
|
|
|
@ -2827,10 +2850,12 @@ class rcube_imap_generic
|
|
|
|
|
$attr = $entry[1];
|
|
|
|
|
$value = $entry[2];
|
|
|
|
|
|
|
|
|
|
if ($value === null)
|
|
|
|
|
if ($value === null) {
|
|
|
|
|
$value = 'NIL';
|
|
|
|
|
else
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$value = sprintf("{%d}\r\n%s", strlen($value), $value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$entries[] = sprintf('%s (%s %s)',
|
|
|
|
|
$this->escape($name), $this->escape($attr), $value);
|
|
|
|
@ -2922,12 +2947,14 @@ class rcube_imap_generic
|
|
|
|
|
for ($x=0, $len=count($attribs); $x<$len;) {
|
|
|
|
|
$attr = $attribs[$x++];
|
|
|
|
|
$value = $attribs[$x++];
|
|
|
|
|
if ($attr == 'value.priv')
|
|
|
|
|
if ($attr == 'value.priv') {
|
|
|
|
|
$res['/private' . $entry] = $value;
|
|
|
|
|
else if ($attr == 'value.shared')
|
|
|
|
|
}
|
|
|
|
|
else if ($attr == 'value.shared') {
|
|
|
|
|
$res['/shared' . $entry] = $value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$last_entry = $entry;
|
|
|
|
|
unset($data[$i-1]);
|
|
|
|
|
unset($data[$i-2]);
|
|
|
|
@ -2973,8 +3000,9 @@ class rcube_imap_generic
|
|
|
|
|
$noresp = ($options & self::COMMAND_NORESPONSE);
|
|
|
|
|
$response = $noresp ? null : '';
|
|
|
|
|
|
|
|
|
|
if (!empty($arguments))
|
|
|
|
|
if (!empty($arguments)) {
|
|
|
|
|
$query .= ' ' . implode(' ', $arguments);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send command
|
|
|
|
|
if (!$this->putLineC($query)) {
|
|
|
|
@ -2985,8 +3013,9 @@ class rcube_imap_generic
|
|
|
|
|
// Parse response
|
|
|
|
|
do {
|
|
|
|
|
$line = $this->readLine(4096);
|
|
|
|
|
if ($response !== null)
|
|
|
|
|
if ($response !== null) {
|
|
|
|
|
$response .= $line;
|
|
|
|
|
}
|
|
|
|
|
} while (!$this->startsWith($line, $tag . ' ', true, true));
|
|
|
|
|
|
|
|
|
|
$code = $this->parseResult($line, $command . ': ');
|
|
|
|
@ -3105,9 +3134,11 @@ class rcube_imap_generic
|
|
|
|
|
{
|
|
|
|
|
$result = '';
|
|
|
|
|
$size = strlen($string);
|
|
|
|
|
|
|
|
|
|
for ($i=0; $i<$size; $i++) {
|
|
|
|
|
$result .= chr(ord($string[$i]) ^ ord($string2[$i]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3127,7 +3158,9 @@ class rcube_imap_generic
|
|
|
|
|
while ((($ts = @strtotime($date))===false) || ($ts < 0)) {
|
|
|
|
|
$d = explode(' ', $date);
|
|
|
|
|
array_pop($d);
|
|
|
|
|
if (!$d) break;
|
|
|
|
|
if (!$d) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
$date = implode(' ', $d);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -3172,16 +3205,14 @@ class rcube_imap_generic
|
|
|
|
|
*/
|
|
|
|
|
static function escape($string)
|
|
|
|
|
{
|
|
|
|
|
// NIL
|
|
|
|
|
if ($string === null) {
|
|
|
|
|
return 'NIL';
|
|
|
|
|
}
|
|
|
|
|
// empty string
|
|
|
|
|
else if ($string === '') {
|
|
|
|
|
return '""';
|
|
|
|
|
}
|
|
|
|
|
// string: special chars: SP, CTL, (, ), {, %, *, ", \, ]
|
|
|
|
|
else if (preg_match('/([\x00-\x20\x28-\x29\x7B\x25\x2A\x22\x5C\x5D\x7F]+)/', $string)) {
|
|
|
|
|
// string: special chars: SP, CTL, (, ), {, %, *, ", \, ]
|
|
|
|
|
return '"' . strtr($string, array('"'=>'\\"', '\\' => '\\\\')) . '"';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|