Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/Horde/Imap/Client/Exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ class Horde_Imap_Client_Exception extends Horde_Exception_Wrapped
* @param string $message Error message (non-translated).
* @param int $code Error code.
*/
public function __construct($message = null, $code = null)
public function __construct($message = '', $code = 0)
{
parent::__construct($message, $code);

Expand Down
6 changes: 3 additions & 3 deletions lib/Horde/Imap/Client/Ids.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ public function add($ids)
} elseif ($add = $this->_resolveIds($ids)) {
if (is_array($this->_ids) && !empty($this->_ids)) {
foreach ($add as $val) {
$this->_ids[] = $val;
$this->_ids[] = (int) $val;
}
} else {
$this->_ids = $add;
Expand Down Expand Up @@ -364,10 +364,10 @@ protected function _fromSequenceString($str)
$range = explode(':', $val);
if (isset($range[1])) {
for ($i = min($range), $j = max($range); $i <= $j; ++$i) {
$ids[] = $i;
$ids[] = (int) $i;
}
} else {
$ids[] = $val;
$ids[] = (int) $val;
}
}

Expand Down
46 changes: 28 additions & 18 deletions lib/Horde/Imap/Client/Socket.php
Original file line number Diff line number Diff line change
Expand Up @@ -3568,21 +3568,29 @@ protected function _parseEnvelope(Horde_Imap_Client_Tokenize $data)
return $ret;
}

/**
*/
protected function _vanished($modseq, Horde_Imap_Client_Ids $ids)
{
$pipeline = $this->_pipeline(
$this->_command('UID FETCH')->add([
strval($ids),
// Unlike _fetchCmd(), sequence IDs are rejected before reaching
// here, so we always issue UID FETCH. Chunk UIDs to avoid
// exceeding the server's command length limit.

$modifiers = new Horde_Imap_Client_Data_Format_List([
'VANISHED',
'CHANGEDSINCE',
new Horde_Imap_Client_Data_Format_Number($modseq),
]);

$pipeline = $this->_pipeline();

foreach ($ids->split($this->_capability()->cmdlength) as $val) {
$cmd = $this->_command('UID FETCH')->add([
$val,
'UID',
new Horde_Imap_Client_Data_Format_List([
'VANISHED',
'CHANGEDSINCE',
new Horde_Imap_Client_Data_Format_Number($modseq),
]),
])
);
$modifiers,
]);
$pipeline->add($cmd);
}

$pipeline->data['vanished'] = $this->getIdsOb();

return $this->_sendCmd($pipeline)->data['vanished'];
Expand Down Expand Up @@ -4339,13 +4347,15 @@ protected function _sendCmdChunk($pipeline, $chunk)
$this->_temp['logout'] = true;
$this->logout();
throw $e;
}

/* For all other issues, catch and store exception; don't
* throw until all input is read since we need to clear
* incoming queue. (For now, only store first exception.) */
if (is_null($exception)) {
$exception = $e;
default:
/* For all other issues, catch and store exception;
* don't throw until all input is read since we need
* to clear incoming queue. (For now, only store first
* exception.) */
if (is_null($exception)) {
$exception = $e;
}
}

if (($e instanceof Horde_Imap_Client_Exception_ServerResponse)
Expand Down
2 changes: 1 addition & 1 deletion lib/Horde/Imap/Client/Socket/Connection/Socket.php
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public function read($size = null)
$read_now = microtime(true);
$t_read = $read_now - $read_start;
if ($t_read > $this->_params['timeout']) {
$this->_params['debug']->info(sprintf('ERROR: read timeout. No data received for %d seconds.', $this->_params['read_timeout']));
$this->_params['debug']->info(sprintf('ERROR: read timeout. No data received for %d seconds.', $this->_params['timeout']));

throw new Horde_Imap_Client_Exception(
Horde_Imap_Client_Translation::r("Read timeout."),
Expand Down
2 changes: 1 addition & 1 deletion lib/Horde/Imap/Client/Socket/Pop3.php
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ protected function _fetchCmd(
case Horde_Imap_Client::FETCH_IMAPDATE:
foreach ($seq_ids as $id) {
$tmp = $this->_pop3Cache('hdrob', $id);
$results->get($lookup[$id])->setImapDate($tmp['Date']);
$results->get($lookup[$id])->setImapDate((string) $tmp['Date']);
}
break;

Expand Down
9 changes: 9 additions & 0 deletions lib/Horde/Imap/Client/Tokenize.php
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,19 @@ public function __construct($data = null)
}
}

public function __destruct()
{
if (isset($this->_stream)) {
$this->_stream->close();
$this->_stream = null;
}
}

/**
*/
public function __clone()
{
$this->_stream = null;
throw new LogicException('Object can not be cloned.');
}

Expand Down
25 changes: 25 additions & 0 deletions test/Stub/Socket.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@

namespace Horde\Imap\Client\Test\Stub;

use Horde_Imap_Client_Data_Capability_Imap;
use Horde_Imap_Client_Data_Thread;
use Horde_Imap_Client_Ids;
use Horde_Imap_Client_Interaction_Pipeline;
use Horde_Imap_Client_Interaction_Server;
use Horde_Imap_Client_Socket;
use Horde_Imap_Client_Tokenize;
Expand All @@ -30,6 +33,19 @@ class Socket extends Horde_Imap_Client_Socket
{
public $fetch_results;

private bool $captureSendCmd = false;

public ?Horde_Imap_Client_Interaction_Pipeline $capturedPipeline = null;

protected function _sendCmd($cmd)
{
if ($this->captureSendCmd) {
$this->capturedPipeline = $cmd;
return $cmd;
}
return parent::_sendCmd($cmd);
}

public function getThreadSort($data)
{
return new Horde_Imap_Client_Data_Thread($this->doServerResponse($this->_pipeline(), $data)->data['threadparse'], 'uid');
Expand Down Expand Up @@ -96,4 +112,13 @@ public function fetch($mailbox, $query, array $options = [])
{
return $this->fetch_results;
}

public function doVanishedPipeline(int $modseq, Horde_Imap_Client_Ids $ids): Horde_Imap_Client_Interaction_Pipeline
{
$this->captureSendCmd = true;
$this->capturedPipeline = null;
$this->_init['capability'] = new Horde_Imap_Client_Data_Capability_Imap();
$this->_vanished($modseq, $ids);
return $this->capturedPipeline;
}
}
41 changes: 41 additions & 0 deletions test/Unit/IdsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,45 @@ public function testSerialize()
);
}

public function testForcedIntForRange()
{
$ids = new Horde_Imap_Client_Ids('1:3');
$this->assertEquals(
[1, 2, 3],
iterator_to_array($ids)
);

foreach (iterator_to_array($ids) as $id) {
$this->assertIsInt($id);
}
}

public function testForcedIntForSequence()
{
$ids = new Horde_Imap_Client_Ids('1,5,7');
$this->assertEquals(
[1, 5, 7],
iterator_to_array($ids)
);

foreach (iterator_to_array($ids) as $id) {
$this->assertIsInt($id);
}
}

public function testAddingWithForcedIntConversion()
{
$ids = new Horde_Imap_Client_Ids('1,5,7');
$ids->add('101:103');

$this->assertEquals(
[1, 5, 7, 101, 102, 103],
iterator_to_array($ids)
);

foreach (iterator_to_array($ids) as $id) {
$this->assertIsInt($id);
}
}

}
26 changes: 23 additions & 3 deletions test/Unit/SocketTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
use PHPUnit\Framework\Attributes\CoversNothing;
use PHPUnit\Framework\TestCase;
use Horde\Imap\Client\Test\Stub\Socket;
use Horde_Imap_Client_Data_Thread;
use Horde_Imap_Client_Fetch_Results;
use Horde_Imap_Client_Ids;

/**
* Tests for the IMAP Socket driver.
Expand Down Expand Up @@ -49,10 +51,10 @@ public function testSimpleThreadParse()
$data = '* THREAD (1)';
$thread = $this->test_ob->getThreadSort($data);

$this->assertFalse($thread instanceof Horde_Imap_Client_Data_Thread);
$this->assertInstanceOf(Horde_Imap_Client_Data_Thread::class, $thread);

$list = $thread->messageList();
$this->assertFalse($list instanceof Horde_Imap_Client_Ids);
$this->assertInstanceOf(Horde_Imap_Client_Ids::class, $list);
$this->assertEquals(
[1],
$list->ids
Expand Down Expand Up @@ -92,7 +94,7 @@ public function testComplexThreadParse()
$thread = $this->test_ob->getThreadSort($data);

$list = $thread->messageList();
$this->assertFalse($list instanceof Horde_Imap_Client_Ids);
$this->assertInstanceOf(Horde_Imap_Client_Ids::class, $list);
$this->assertEquals(
range(1, 17),
$list->ids
Expand Down Expand Up @@ -354,4 +356,22 @@ public function testParseEnvelopeBlankSubject()
$this->assertNotNull($env->to);
}

public function testVanishedCommand()
{
// 200 non-consecutive 4-digit UIDs, fits in one 2000-octet command.
$ids = new Horde_Imap_Client_Ids(range(1001, 1399, 2));
$pipeline = $this->test_ob->doVanishedPipeline(12345, $ids);

$this->assertCount(1, $pipeline);
}

public function testVanishedCommandChunks()
{
// 500 non-consecutive 4-digit UIDs, exceeds the 2000-octet limit.
$ids = new Horde_Imap_Client_Ids(range(1001, 1999, 2));
$pipeline = $this->test_ob->doVanishedPipeline(12345, $ids);

$this->assertGreaterThan(1, count($pipeline));
}

}
Loading