protected function _fetchCmd(Horde_Imap_Client_Interaction_Pipeline $pipeline, $options)
{
$fetch = new Horde_Imap_Client_Data_Format_List();
$sequence = $options['ids']->sequence;
/* Build an IMAP4rev1 compliant FETCH query. We handle the following
* criteria:
* BINARY[.PEEK][<section #>]<<partial>> (RFC 3516)
* see BODY[] response
* BINARY.SIZE[<section #>] (RFC 3516)
* BODY[.PEEK][<section>]<<partial>>
* <section> = HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME,
* TEXT, empty
* <<partial>> = 0.# (# of bytes)
* BODYSTRUCTURE
* ENVELOPE
* FLAGS
* INTERNALDATE
* MODSEQ (RFC 7162)
* RFC822.SIZE
* UID
*
* No need to support these (can be built from other queries):
* ===========================================================
* ALL macro => (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE)
* BODY => Use BODYSTRUCTURE instead
* FAST macro => (FLAGS INTERNALDATE RFC822.SIZE)
* FULL macro => (FLAGS INTERNALDATE RFC822.SIZE ENVELOPE BODY)
* RFC822 => BODY[]
* RFC822.HEADER => BODY[HEADER]
* RFC822.TEXT => BODY[TEXT]
*/
foreach ($options['_query'] as $type => $c_val) {
switch ($type) {
case Horde_Imap_Client::FETCH_STRUCTURE:
$fetch->add('BODYSTRUCTURE');
break;
case Horde_Imap_Client::FETCH_FULLMSG:
if (empty($c_val['peek'])) {
$this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE);
}
$fetch->add('BODY' . (!empty($c_val['peek']) ? '.PEEK' : '') . '[]' . $this->_partialAtom($c_val));
break;
case Horde_Imap_Client::FETCH_HEADERTEXT:
case Horde_Imap_Client::FETCH_BODYTEXT:
case Horde_Imap_Client::FETCH_MIMEHEADER:
case Horde_Imap_Client::FETCH_BODYPART:
case Horde_Imap_Client::FETCH_HEADERS:
foreach ($c_val as $key => $val) {
$cmd = $key == 0 ? '' : $key . '.';
$main_cmd = 'BODY';
switch ($type) {
case Horde_Imap_Client::FETCH_HEADERTEXT:
$cmd .= 'HEADER';
break;
case Horde_Imap_Client::FETCH_BODYTEXT:
$cmd .= 'TEXT';
break;
case Horde_Imap_Client::FETCH_MIMEHEADER:
$cmd .= 'MIME';
break;
case Horde_Imap_Client::FETCH_BODYPART:
// Remove the last dot from the string.
$cmd = substr($cmd, 0, -1);
if (!empty($val['decode']) && $this->_capability('BINARY')) {
$main_cmd = 'BINARY';
$pipeline->data['binaryquery'][$key] = $val;
}
break;
case Horde_Imap_Client::FETCH_HEADERS:
$cmd .= 'HEADER.FIELDS';
if (!empty($val['notsearch'])) {
$cmd .= '.NOT';
}
$cmd .= ' (' . implode(' ', array_map('Horde_String::upper', $val['headers'])) . ')';
// Maintain a command -> label lookup so we can put
// the results in the proper location.
$pipeline->data['fetch_lookup'][$cmd] = $key;
}
if (empty($val['peek'])) {
$this->openMailbox($this->_selected, Horde_Imap_Client::OPEN_READWRITE);
}
$fetch->add($main_cmd . (!empty($val['peek']) ? '.PEEK' : '') . '[' . $cmd . ']' . $this->_partialAtom($val));
}
break;
case Horde_Imap_Client::FETCH_BODYPARTSIZE:
if ($this->_capability('BINARY')) {
foreach ($c_val as $val) {
$fetch->add('BINARY.SIZE[' . $val . ']');
}
}
break;
case Horde_Imap_Client::FETCH_ENVELOPE:
$fetch->add('ENVELOPE');
break;
case Horde_Imap_Client::FETCH_FLAGS:
$fetch->add('FLAGS');
break;
case Horde_Imap_Client::FETCH_IMAPDATE:
$fetch->add('INTERNALDATE');
break;
case Horde_Imap_Client::FETCH_SIZE:
$fetch->add('RFC822.SIZE');
break;
case Horde_Imap_Client::FETCH_UID:
/* A UID FETCH will always return UID information (RFC 3501
* [6.4.8]). Don't add to query as it just creates a longer
* FETCH command. */
if ($sequence) {
$fetch->add('UID');
}
break;
case Horde_Imap_Client::FETCH_SEQ:
/* Nothing we need to add to fetch request unless sequence is
* the only criteria (see below). */
break;
case Horde_Imap_Client::FETCH_MODSEQ:
/* The 'changedsince' modifier implicitly adds the MODSEQ
* FETCH item (RFC 7162 [3.1.4.1]). Don't add to query as it
* just creates a longer FETCH command. */
if (empty($options['changedsince'])) {
$fetch->add('MODSEQ');
}
break;
}
}
/* If empty fetch, add UID to make command valid. */
if (!count($fetch)) {
$fetch->add('UID');
}
/* Add changedsince parameters. */
if (empty($options['changedsince'])) {
$fetch_cmd = $fetch;
} else {
/* We might just want the list of UIDs changed since a given
* modseq. In that case, we don't have any other FETCH attributes,
* but RFC 3501 requires at least one specified attribute. */
$fetch_cmd = array($fetch, new Horde_Imap_Client_Data_Format_List(array('CHANGEDSINCE', new Horde_Imap_Client_Data_Format_Number($options['changedsince']))));
}
/* The FETCH command should be the only command issued by this library
* that should ever approach the command length limit.
* @todo Move this check to a more centralized location (_command()?).
* For simplification, assume that the UID list is the limiting factor
* and split this list at a sequence comma delimiter if it exceeds
* the character limit. */
foreach ($options['ids']->split($this->_capability()->cmdlength) as $val) {
$cmd = $this->_command($sequence ? 'FETCH' : 'UID FETCH')->add(array($val, $fetch_cmd));
$pipeline->add($cmd);
}
}