public function fetch($uid, $mailbox, $range, $select, &$error, $outputFormat = 'smart')
{
$error = null;
if (!preg_match('/(([1-9]d*|*)(:(?2))?)(,(?1))*/', $range))
{
return false;
}
if (empty($select))
{
$select = '(FLAGS)';
}
else if (is_array($select))
{
$select = sprintf('(%s)', join(' ', $select));
}
if (!$this->select($mailbox, $error))
{
return false;
}
$list = array();
if ($this->sessMailbox['exists'] > 0)
{
$fetchUntaggedRegex = '/^ * x20 ( d+ ) x20 FETCH x20 ( ( .+ ) ) rn $/isx';
$this->getUntagged($fetchUntaggedRegex, true);
$response = $this->executeCommand(
sprintf('%sFETCH %s %s', $uid ? 'UID ' : '', $range, $select),
$error
);
if ($error)
{
$error = $error == Imap::ERR_COMMAND_REJECTED ? null : $error;
$error = $this->errorMessage(array(Imap::ERR_FETCH, $error), $response);
return false;
}
$shiftName = function (&$item)
{
$result = false;
// #120949
$regex = sprintf(
'/^
(
[a-z0-9]+ (?: . [a-z0-9]+ )*
(?: [ (?: [a-z0-9]+ (?: . [a-z0-9]* )* (?: x20 %s )* )? ] )?
(?: < d+ > )?
)
x20
/ix',
self::$astringRegex
);
if (preg_match($regex, $item, $matches))
{
$result = $matches[1];
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
return $result;
};
$shiftValue = function (&$item) use (&$shiftValue)
{
$result = false;
$tail = ' (?= [x20)] | $ ) x20? ';
if (BinaryString::getSubstring($item, 0, 1) === '(')
{
$item = BinaryString::getSubstring($item, 1);
$result = array();
while (BinaryString::getLength($item) > 0 && BinaryString::getSubstring($item, 0, 1) !== ')')
{
$subresult = $shiftValue($item);
if (false !== $subresult)
{
$result[] = $subresult;
}
else
{
return false;
}
}
if (preg_match('/^ ) (?= [x20()] | $ ) x20? /ix', $item, $matches))
{
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
else
{
return false;
}
}
else if (preg_match('/^ { ( d+ ) } rn /ix', $item, $matches))
{
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
if (BinaryString::getLength($item) >= $matches[1])
{
$result = BinaryString::getSubstring($item, 0, $matches[1]);
$item = BinaryString::getSubstring($item, $matches[1]);
if (preg_match(sprintf('/^ %s /ix', $tail), $item, $matches))
{
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
else
{
return false;
}
}
}
else if (preg_match(sprintf('/^ NIL %s /ix', $tail), $item, $matches))
{
$result = null;
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
else if (preg_match(sprintf('/^ " ( (?: %s )* ) " %s /ix', self::$qcharExtRegex, $tail), $item, $matches))
{
$result = self::unescapeQuoted($matches[1]);
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
else if (preg_match(sprintf('/^ ( x5c? %s ) %s /ix', self::$astringRegex, $tail), $item, $matches))
{
$result = $matches[1];
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
else if (preg_match(sprintf('/^ %s /ix', $tail), $item, $matches))
{
$result = '';
$item = BinaryString::getSubstring($item, BinaryString::getLength($matches[0]));
}
return $result;
};
$bodystructure = function (&$value) use (&$bodystructure)
{
if (!is_array($value) || !is_array($value[0]))
{
return $value;
}
$value[0] = $bodystructure($value[0]);
$value[0] = array($value[0]);
while (array_key_exists(1, $value) && is_array($value[1]))
{
$value[0][] = $bodystructure($value[1]);
array_splice($value, 1, 1);
}
while (count($value[0]) == 1 && count($value[0][0]) == 1)
{
$value[0] = $value[0][0];
}
return $value;
};
foreach ($this->getUntagged($fetchUntaggedRegex, true) as $item)
{
$data = array(
'id' => $item[1][1],
);
while (BinaryString::getLength($item[1][2]) > 0)
{
if (($name = $shiftName($item[1][2])) !== false)
{
if (($value = $shiftValue($item[1][2])) !== false)
{
if (in_array(mb_strtoupper($name), array('BODY', 'BODYSTRUCTURE')))
{
$value = $bodystructure($value);
}
$data[$name] = $value;
continue;
}
}
break;
}
$list[$data['id']] = $data;
}
}
ksort($list);
// todo remove the different format of the data output
if ($outputFormat === 'smart' && !preg_match('/[:,]/', $range))
{
$list = reset($list);
}
return $list;
}