protected function _expunge($options)
{
$expunged_ob = $modseq = null;
$ids = $options['ids'];
$list_msgs = !empty($options['list']);
$mailbox = $this->_selected;
$uidplus = $this->_capability('UIDPLUS');
$unflag = array();
$use_cache = $this->_initCache(true);
if ($ids->all) {
if (!$uidplus || $list_msgs || $use_cache) {
$ids = $this->resolveIds($mailbox, $ids, 2);
}
} elseif ($uidplus) {
/* If QRESYNC is not available, and we are returning the list of
* expunged messages (or we are caching), we have to make sure we
* have a mapping of Sequence -> UIDs. If we have QRESYNC, the
* server SHOULD return a VANISHED response with UIDs. However,
* even if the server returns EXPUNGEs instead, we can use
* vanished() to grab the list. */
unset($this->_temp['search_save']);
if ($this->_capability()->isEnabled('QRESYNC')) {
$ids = $this->resolveIds($mailbox, $ids, 1);
if ($list_msgs) {
$modseq = $this->_mailboxOb()->getStatus(Horde_Imap_Client::STATUS_HIGHESTMODSEQ);
}
} else {
$ids = $this->resolveIds($mailbox, $ids, $list_msgs || $use_cache ? 2 : 1);
}
if (!empty($this->_temp['search_save'])) {
$ids = $this->getIdsOb(Horde_Imap_Client_Ids::SEARCH_RES);
}
} else {
/* Without UIDPLUS, need to temporarily unflag all messages marked
* as deleted but not a part of requested IDs to delete. Use NOT
* searches to accomplish this goal. */
$squery = new Horde_Imap_Client_Search_Query();
$squery->flag(Horde_Imap_Client::FLAG_DELETED, true);
$squery->ids($ids, true);
$s_res = $this->search($mailbox, $squery, array('results' => array(Horde_Imap_Client::SEARCH_RESULTS_MATCH, Horde_Imap_Client::SEARCH_RESULTS_SAVE)));
$this->store($mailbox, array('ids' => empty($s_res['save']) ? $s_res['match'] : $this->getIdsOb(Horde_Imap_Client_Ids::SEARCH_RES), 'remove' => array(Horde_Imap_Client::FLAG_DELETED)));
$unflag = $s_res['match'];
}
if ($list_msgs) {
$expunged_ob = $this->getIdsOb();
$this->_temp['expunged'] = $expunged_ob;
}
/* Always use UID EXPUNGE if available. */
if ($uidplus) {
/* We can only pipeline STORE w/ EXPUNGE if using UIDs and UIDPLUS
* is available. */
if (empty($options['delete'])) {
$pipeline = $this->_pipeline();
} else {
$pipeline = $this->_storeCmd(array('add' => array(Horde_Imap_Client::FLAG_DELETED), 'ids' => $ids));
}
foreach ($ids->split(2000) as $val) {
$pipeline->add($this->_command('UID EXPUNGE')->add($val));
}
$resp = $this->_sendCmd($pipeline);
} else {
if (!empty($options['delete'])) {
$this->store($mailbox, array('add' => array(Horde_Imap_Client::FLAG_DELETED), 'ids' => $ids));
}
if ($use_cache || $list_msgs) {
$this->_sendCmd($this->_command('EXPUNGE'));
} else {
/* This is faster than an EXPUNGE because the server will not
* return untagged EXPUNGE responses. We can only do this if
* we are not updating cache information. */
$this->close(array('expunge' => true));
}
}
unset($this->_temp['expunged']);
if (!empty($unflag)) {
$this->store($mailbox, array('add' => array(Horde_Imap_Client::FLAG_DELETED), 'ids' => $unflag));
}
if (!is_null($modseq) && !empty($resp->data['expunge_seen'])) {
/* There's a chance we actually did a full map of sequence -> UID,
* but this code should never be reached in the first place so
* be ultra-safe and just do a full VANISHED search. */
$expunged_ob = $this->vanished($mailbox, $modseq, array('ids' => $ids));
$this->_deleteMsgs($mailbox, $expunged_ob, array('pipeline' => $resp));
}
return $expunged_ob;
}