protected $_search = array();
/**
- * The Horde_Imap_Client_Utils object
- *
- * @var Horde_Imap_Client_Utils
- */
- protected $_utils = null;
-
- /**
- * Constructor
- */
- public function __construct()
- {
- $this->__wakeup();
- }
-
- /**
- * Tasks to perform on a serialize().
- */
- public function __sleep()
- {
- return array_diff(array_keys(get_class_vars(__CLASS__)), array('_utils'));
- }
-
- /**
- * Tasks to perform on an unserialize().
- */
- public function __wakeup()
- {
- $this->_utils = new Horde_Imap_Client_Utils();
- }
-
- /**
* Sets the charset of the search text.
*
* @param string $charset The charset to use for the search.
// This is a 'NOT' search. All system flags but \Recent
// have 'UN' equivalents.
if ($key == 'RECENT') {
- $tmp = 'NOT ';
+ $cmds[] = 'NOT';
// NOT searches were not in IMAP2
$imap4 = true;
} else {
}
}
- $cmds[] = $tmp . ($val['type'] == 'keyword' ? 'KEYWORD ' : '') . $key;
+ if ($val['type'] == 'keyword') {
+ $cmds[] = $tmp . 'KEYWORD';
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_ATOM, 'v' => $key);
+ } else {
+ $cmds[] = $tmp . $key;
+ }
}
}
if (!empty($ptr['header'])) {
foreach ($ptr['header'] as $val) {
- $tmp = '';
if ($val['not']) {
- $tmp = 'NOT ';
+ $cmds[] = 'NOT';
// NOT searches were not in IMAP2
$imap4 = true;
}
- if (!in_array($val['header'], $this->_systemheaders)) {
+ if (in_array($val['header'], $this->_systemheaders)) {
+ $cmds[] = $val['header'];
+ } else {
// HEADER searches were not in IMAP2
- $tmp .= 'HEADER ';
+ $cmds[] = 'HEADER';
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $val['header']);
$imap4 = true;
}
- $cmds[] = $tmp . $val['header'] . ' ' . $this->_utils->escape($val['text']);
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $val['text']);
}
}
if (!empty($ptr['text'])) {
foreach ($ptr['text'] as $val) {
- $tmp = '';
if ($val['not']) {
- $tmp = 'NOT ';
+ $cmds[] = 'NOT';
// NOT searches were not in IMAP2
$imap4 = true;
}
- $cmds[] = $tmp . $val['type'] . ' ' . $this->_utils->escape($val['text']);
+ $cmds[] = $val['type'];
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $val['text']);
}
}
if (!empty($ptr['size'])) {
foreach ($ptr['size'] as $key => $val) {
- $cmds[] = ($val['not'] ? 'NOT ' : '' ) . $key . ' ' . $val['size'];
+ if ($val['not']) {
+ $cmds[] = 'NOT';
+ }
+ $cmds[] = $key;
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $val['size']);
// LARGER/SMALLER searches were not in IMAP2
$imap4 = true;
}
}
if (isset($ptr['sequence'])) {
- $cmds[] = ($ptr['sequence']['not'] ? 'NOT ' : '') . ($ptr['sequence']['sequence'] ? '' : 'UID ') . $ptr['sequence']['ids'];
+ if ($ptr['sequence']['not']) {
+ $cmds[] = 'NOT';
+ }
+ if (!$ptr['sequence']['sequence']) {
+ $cmds[] = 'UID';
+ }
+ $cmds[] = $ptr['sequence']['ids'];
// sequence searches were not in IMAP2
$imap4 = true;
if (!empty($ptr['date'])) {
foreach ($ptr['date'] as $key => $val) {
- $tmp = '';
if ($val['not']) {
- $tmp = 'NOT ';
+ $cmds[] = 'NOT';
// NOT searches were not in IMAP2
$imap4 = true;
}
if ($key == 'header') {
- $tmp .= 'SENT';
+ $cmds[] = 'SENT' . $val['range'];
// 'SENT*' searches were not in IMAP2
$imap4 = true;
+ } else {
+ $cmds[] = $val['range'];
}
- $cmds[] = $tmp . $val['range'] . ' ' . $val['date'];
+ $cmds[] = $val['date'];
}
}
if (!empty($ptr['within'])) {
if (isset($exts['WITHIN'])) {
foreach ($ptr['within'] as $key => $val) {
- $cmds[] = ($val['not'] ? 'NOT ' : '') . $key . ' ' . $val['interval'];
+ if ($val['not']) {
+ $cmds[] = 'NOT';
+ }
+ $cmds[] = $key;
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $val['interval']);
}
$exts_used[] = 'WITHIN';
$imap4 = true;
// This workaround is only accurate to within 1 day, due to
// limitations with the IMAP4rev1 search commands.
foreach ($ptr['within'] as $key => $val) {
- $tmp = '';
if ($val['not']) {
- $tmp = 'NOT ';
+ $cmds[] = 'NOT';
// NOT searches were not in IMAP2
$imap4 = true;
}
$date = new DateTime('now -' . $val['interval'] . ' seconds');
- $cmds[] = $tmp .
- (($key == self::INTERVAL_OLDER) ? self::DATE_BEFORE : self::DATE_SINCE) .
- ' ' . $date->format('d-M-Y');
+ $cmds[] = ($key == self::INTERVAL_OLDER)
+ ? self::DATE_BEFORE
+ : self::DATE_SINCE;
+ $cmds[] = $date->format('d-M-Y');
}
}
}
$exts_used[] = 'CONDSTORE';
$imap4 = true;
- $cmds[] = ($ptr['modseq']['not'] ? 'NOT ' : '') .
- 'MODSEQ ' .
- (is_null($ptr['modseq']['name'])
- ? ''
- : $this->_utils->escape($ptr['modseq']['name']) . ' ' . $ptr['modseq']['type'] . ' ') .
- $ptr['modseq']['value'];
+ if ($ptr['modseq']['not']) {
+ $cmds[] = 'NOT';
+ }
+ $cmds[] = 'MODSEQ';
+ if (!is_null($ptr['modseq']['name'])) {
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_STRING, 'v' => $ptr['modseq']['name']);
+ $cmds[] = $ptr['modseq']['type'];
+ }
+ $cmds[] = array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $ptr['modseq']['value']);
}
if (isset($ptr['prevsearch'])) {
$exts_used[] = 'SEARCHRES';
$imap4 = true;
- $cmds[] = ($ptr['prevsearch'] ? '' : 'NOT ') . '$';
+ if (!$ptr['prevsearch']) {
+ $cmds[] = 'NOT';
+ }
+ $cmds[] = '$';
}
- $query = '';
-
// Add AND'ed queries
if (!empty($ptr['and'])) {
foreach ($ptr['and'] as $val) {
$ret = $val->build();
- $query .= ' ' . $ret['query'];
+ $cmds = array_merge($cmds, $ret['query']);
}
}
$ret = $val->build();
// First OR'd query
- $query = (empty($query) && empty($cmds))
- ? trim($ret['query']) . ' '
- : 'OR (' . trim($ret['query']) . ') ' . $query;
+ if (empty($cmds)) {
+ $cmds = $ret['query'];
+ } else {
+ $cmds = array_merge(array(
+ 'OR',
+ $ret['query']
+ ), $cmds);
+ }
}
}
// Default search is 'ALL'
if (empty($cmds)) {
- $query .= empty($query) ? 'ALL' : '';
- } else {
- $query .= implode(' ', $cmds);
+ $cmds[] = 'ALL';
}
return array(
'charset' => $this->_charset,
'exts' => $exts_used,
'imap4' => $imap4,
- 'query' => trim($query)
+ 'query' => $cmds
);
}
if (empty($ids)) {
$ids = '1:*';
} else {
- $ids = $this->_utils->toSequenceString($ids);
+ $utils = new Horde_Imap_Client_Utils();
+ $ids = $utils->toSequenceString($ids);
}
$this->_search['sequence'] = array(
'ids' => $ids,
switch ($method) {
case 'CRAM-MD5':
case 'DIGEST-MD5':
- $ob = $this->_sendLine('AUTHENTICATE ' . $method, array('noparse' => true));
+ $ob = $this->_sendLine(array(
+ 'AUTHENTICATE',
+ array('t' => Horde_Imap_Client::DATA_ATOM, 'v' => $method)
+ ), array(
+ 'noparse' => true
+ ));
switch ($method) {
case 'CRAM-MD5':
}
$auth_sasl = Auth_SASL::factory('crammd5');
$response = base64_encode($auth_sasl->getResponse($this->_params['username'], $this->_params['password'], base64_decode($ob['line'])));
- $this->_sendLine($response, array('debug' => '[CRAM-MD5 Response]', 'notag' => true));
+ $this->_sendLine($response, array(
+ 'debug' => '[CRAM-MD5 Response]',
+ 'notag' => true
+ ));
break;
case 'DIGEST-MD5':
}
$auth_sasl = Auth_SASL::factory('digestmd5');
$response = base64_encode($auth_sasl->getResponse($this->_params['username'], $this->_params['password'], base64_decode($ob['line']), $this->_params['hostspec'], 'imap'));
- $ob = $this->_sendLine($response, array('debug' => '[DIGEST-MD5 Response]', 'noparse' => true, 'notag' => true));
+ $ob = $this->_sendLine($response, array(
+ 'debug' => '[DIGEST-MD5 Response]',
+ 'noparse' => true,
+ 'notag' => true
+ ));
$response = base64_decode($ob['line']);
if (strpos($response, 'rspauth=') === false) {
throw new Horde_Imap_Client_Exception('Unexpected response from server to Digest-MD5 response.');
}
- $this->_sendLine('', array('notag' => true));
+ $this->_sendLine('', array(
+ 'notag' => true
+ ));
break;
}
break;
case 'LOGIN':
- $this->_sendLine('LOGIN ' . $this->utils->escape($this->_params['username']) . ' ' . $this->utils->escape($this->_params['password']), array('debug' => sprintf('[LOGIN Command - username: %s]', $this->_params['username'])));
+ $this->_sendLine(array(
+ 'LOGIN',
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $this->_params['username']),
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $this->_params['password'])
+ ), array(
+ 'debug' => sprintf('[LOGIN Command - username: %s]', $this->_params['username'])
+ ));
break;
case 'PLAIN':
$auth = base64_encode(implode("\0", array($this->_params['username'], $this->_params['username'], $this->_params['password'])));
if ($this->queryCapability('SASL-IR')) {
// IMAP Extension for SASL Initial Client Response (RFC 4959)
- $this->_sendLine('AUTHENTICATE PLAIN ' . $auth, array('debug' => sprintf('[SASL-IR AUTHENTICATE Command - username: %s]', $this->_params['username'])));
+ $this->_sendLine(array(
+ 'AUTHENTICATE',
+ 'PLAIN',
+ $auth
+ ), array(
+ 'debug' => sprintf('[SASL-IR AUTHENTICATE Command - username: %s]', $this->_params['username'])
+ ));
} else {
- $this->_sendLine('AUTHENTICATE PLAIN', array('noparse' => true));
- $this->_sendLine($auth, array('debug' => sprintf('[AUTHENTICATE Command - username: %s]', $this->_params['username']), 'notag' => true));
+ $this->_sendLine('AUTHENTICATE PLAIN', array(
+ 'noparse' => true
+ ));
+ $this->_sendLine($auth, array(
+ 'debug' => sprintf('[AUTHENTICATE Command - username: %s]', $this->_params['username']),
+ 'notag' => true
+ ));
}
break;
}
*/
protected function _sendID($info)
{
+ $cmd = array('ID');
+
if (empty($info)) {
- $cmd = 'NIL';
+ $cmd[] = array('t' => Horde_Imap_Client::DATA_NSTRING, null);
} else {
- $cmd = '(';
+ $tmp = array();
foreach ($info as $key => $val) {
- $cmd .= $this->utils->escape(strtolower($key)) . ' ' . $this->utils->escape($val);
+ $tmp[] = array('t' => Horde_Imap_Client::DATA_STRING, strtolower($key));
+ $tmp[] = array('t' => Horde_Imap_Client::DATA_NSTRING, $val);
}
- $cmd .= ')';
+ $cmd[] = $tmp;
}
- $this->_sendLine('ID ' . $cmd);
+ $this->_sendLine($cmd);
}
/**
*/
protected function _setLanguage($langs)
{
- $cmd = array();
- foreach ($langs as $val) {
- $cmd[] = $this->utils->escape($val);
+ $cmd = array('LANGUAGE');
+ foreach ($langs as $lang) {
+ $cmd[] = array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $lang);
}
try {
- $this->_sendLine('LANGUAGE ' . implode(' ', $cmd));
+ $this->_sendLine($cmd);
} catch (Horde_Imap_Client_Exception $e) {
$this->_init['lang'] = null;
return null;
// Only enable non-enabled extensions
$exts = array_diff($exts, array_keys($this->_init['enabled']));
if (!empty($exts)) {
- $this->_sendLine('ENABLE ' . implode(' ', array_map('strtoupper', $exts)));
+ $this->_sendLine(array_merge(array('ENABLE'), $exts));
}
}
$this->_temp['qresyncmbox'] = $mailbox;
}
- $cmd = (($mode == Horde_Imap_Client::OPEN_READONLY) ? 'EXAMINE' : 'SELECT') . ' ' . $this->utils->escape($mailbox);
+ $cmd = array(
+ (($mode == Horde_Imap_Client::OPEN_READONLY) ? 'EXAMINE' : 'SELECT'),
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ );
/* If QRESYNC is available, synchronize the mailbox. */
if ($qresync) {
* response handlers.
* TODO: Use 4th parameter (useful if we keep a sequence
* number->UID lookup in the future). */
- $cmd .= ' (QRESYNC (' . $metadata['uidvalid'] . ' ' . $metadata['HICmodseq'] . ' ' . $this->utils->toSequenceString($uids) . '))';
+ $cmd[] = array(
+ 'QRESYNC',
+ array(
+ $metadata['uidvalid'],
+ $metadata['HICmodseq'],
+ $this->utils->toSequenceString($uids)
+ )
+ );
}
}
} elseif (!isset($this->_init['enabled']['CONDSTORE']) &&
$this->_initCache() &&
$this->queryCapability('CONDSTORE')) {
/* Activate CONDSTORE now if ENABLE is not available. */
- $cmd .= ' (CONDSTORE)';
+ $cmd[] = array('CONDSTORE');
$condstore = true;
}
$this->login();
// CREATE returns no untagged information (RFC 3501 [6.3.3])
- $this->_sendLine('CREATE ' . $this->utils->escape($mailbox));
+ $this->_sendLine(array(
+ 'CREATE',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ ));
}
/**
try {
// DELETE returns no untagged information (RFC 3501 [6.3.4])
- $this->_sendLine('DELETE ' . $this->utils->escape($mailbox));
+ $this->_sendLine(array(
+ 'DELETE',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ ));
} catch (Horde_Imap_Client_Exception $e) {
// Some IMAP servers won't allow a mailbox delete unless all
// messages in that mailbox are deleted.
$this->login();
// RENAME returns no untagged information (RFC 3501 [6.3.5])
- $this->_sendLine('RENAME ' . $this->utils->escape($old) . ' ' . $this->utils->escape($new));
+ $this->_sendLine(array(
+ 'RENAME',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $old),
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $new)
+ ));
}
/**
// SUBSCRIBE/UNSUBSCRIBE returns no untagged information (RFC 3501
// [6.3.6 & 6.3.7])
- $this->_sendLine(($subscribe ? '' : 'UN') . 'SUBSCRIBE ' . $this->utils->escape($mailbox));
+ $this->_sendLine(array(
+ ($subscribe ? 'SUBSCRIBE' : 'UNSUBSCRIBE'),
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ ));
}
/**
$t['listresponse'] = array();
if ($this->queryCapability('LIST-EXTENDED')) {
- $cmd = 'LIST';
+ $cmd = array('LIST');
$t['mailboxlist']['ext'] = true;
$return_opts = $select_opts = array();
}
if (!empty($select_opts)) {
- $cmd .= ' (' . implode(' ', $select_opts) . ')';
+ $cmd[] = $select_opts;
}
- $cmd .= ' "" ';
+ $cmd[] = '""';
- if (is_array($pattern)) {
- $cmd .= '(';
- foreach ($pattern as $val) {
- $cmd .= $this->utils->escape($val) . ' ';
- }
- $cmd = rtrim($cmd) . ')';
- } else {
- $cmd .= $this->utils->escape($pattern);
+ if (!is_array($pattern)) {
+ $pattern = array($pattern);
}
+ $tmp = array();
+ foreach ($pattern as $val) {
+ $tmp[] = array('t' => Horde_Imap_Client::DATA_LISTMAILBOX, 'v' => $val);
+ }
+ $cmd[] = $tmp;
if (!empty($options['children'])) {
$return_opts[] = 'CHILDREN';
}
if (!empty($status_opts)) {
- $return_opts[] = 'STATUS (' . implode(' ', $status_opts) . ')';
+ $return_opts[] = 'STATUS';
+ $return_opts[] = $status_opts;
}
}
if (!empty($return_opts)) {
- $cmd .= ' RETURN (' . implode(' ', $return_opts) . ')';
+ $cmd[] = 'RETURN';
+ $cmd[] = $return_opts;
}
} else {
if (is_array($pattern)) {
return $return_array;
}
- $cmd = (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST') . ' "" ' . $this->utils->escape($pattern);
+ $cmd = array(
+ (($mode == Horde_Imap_Client::MBOX_SUBSCRIBED) ? 'LSUB' : 'LIST'),
+ '""',
+ array('t' => Horde_Imap_Client::DATA_LISTMAILBOX, 'v' => $pattern)
+ );
}
$this->_sendLine($cmd);
return $data;
}
- $this->_sendLine('STATUS ' . $this->utils->escape($mailbox) . ' (' . implode(' ', array_map('strtoupper', $query)) . ')');
+ $this->_sendLine(array(
+ 'STATUS',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ array_map('strtoupper', $query)
+ ));
return $this->_temp['status'][$mailbox];
}
reset($data);
while (list(,$m_data) = each($data)) {
if (!$i++ || !$multiappend) {
- $cmd = 'APPEND ' . $this->utils->escape($mailbox);
+ $cmd = array(
+ 'APPEND',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ );
} else {
- $cmd = '';
+ $cmd = array();
$notag = true;
}
if (!empty($m_data['flags'])) {
- $cmd .= ' (' . implode(' ', $m_data['flags']) . ')';
+ $tmp = array();
+ foreach ($m_data['flags'] as $val) {
+ $tmp[] = array('t' => Horde_Imap_Client::DATA_ATOM, 'v' => $val);
+ }
+ $cmd[] = $tmp;
}
if (!empty($m_data['internaldate'])) {
- $cmd .= ' ' . $this->utils->escape($m_data['internaldate']->format('j-M-Y H:i:s O'));
+ $cmd[] = $m_data['internaldate']->format('j-M-Y H:i:s O');
}
/* @todo There is no way I am aware of to determine the length of
}
try {
- $this->_sendLine($cmd, array('binary' => $binary, 'literal' => $datalength, 'notag' => $notag));
+ $this->_sendLine($cmd, array(
+ 'binary' => $binary,
+ 'literal' => $datalength,
+ 'notag' => $notag
+ ));
} catch (Horde_Imap_Client_Exception $e) {
if (!empty($options['create']) && $this->_temp['trycreate']) {
$this->createMailbox($mailbox);
}
// Send data.
- $this->_sendLine($text, array('literaldata' => $literaldata, 'notag' => true));
+ $this->_sendLine($text, array(
+ 'literaldata' => $literaldata,
+ 'notag' => true
+ ));
}
/* If we reach this point and have data in $_temp['appenduid'],
/* Always use UID EXPUNGE if available. */
if ($uidplus) {
- $this->_sendLine('UID EXPUNGE ' . $uid_string);
+ $this->_sendLine(array(
+ 'UID',
+ 'EXPUNGE',
+ $uid_string
+ ));
} elseif ($use_cache || $list_msgs) {
$this->_sendLine('EXPUNGE');
} else {
* doesn't support it will return BAD. Catch that here and thrown
* an exception. */
if (in_array('CONDSTORE', $options['_query']['exts']) &&
- empty($this->_temp['mailbox']['highestmodseq']) &&
- (strpos($options['_query']['query'], 'MODSEQ ') !== false)) {
+ empty($this->_temp['mailbox']['highestmodseq'])) {
throw new Horde_Imap_Client_Exception('Mailbox does not support mod-sequences.', Horde_Imap_Client_Exception::MBOXNOMODSEQ);
}
- $cmd = '';
+ $cmd = array();
if (empty($options['sequence'])) {
- $cmd = 'UID ';
+ $cmd[] = 'UID';
}
$sort_criteria = array(
}
if ($server_sort) {
+ $cmd[] = 'SORT';
// Check for ESORT capability (RFC 5267)
if ($this->queryCapability('ESORT')) {
$results = array();
$results[] = $results_criteria[$val];
}
}
- $cmd .= 'SORT RETURN (' . implode(' ', $results) . ') (';
- } else {
- $cmd .= 'SORT (';
+ $cmd[] = 'RETURN';
+ $cmd[] = $results;
}
+ $tmp = array();
foreach ($options['sort'] as $val) {
if (isset($sort_criteria[$val])) {
- $cmd .= $sort_criteria[$val] . ' ';
+ $tmp[] = $sort_criteria[$val];
}
}
- $cmd = rtrim($cmd) . ') ';
+ $cmd[] = $tmp;
} else {
// Check if the server supports ESEARCH (RFC 4731).
$esearch = $this->queryCapability('ESEARCH');
+ $cmd[] = 'SEARCH';
+
if ($esearch) {
// Always use ESEARCH if available because it returns results
// in a more compact sequence-set list
$results[] = $results_criteria[$val];
}
}
- $cmd .= 'SEARCH RETURN (' . implode(' ', $results) . ') CHARSET ';
- } else {
- $cmd .= 'SEARCH CHARSET ';
+ $cmd[] = 'RETURN';
+ $cmd[] = $results;
}
+ $cmd[] = 'CHARSET';
+
// SEARCHRES requires ESEARCH
unset($this->_temp['searchnotsaved']);
}
$sr = &$this->_temp['searchresp'];
$er = $sr = array();
- $this->_sendLine($cmd . $options['_query']['charset'] . ' ' . $options['_query']['query']);
+ $cmd[] = $options['_query']['charset'];
+ $cmd = array_merge($cmd, $options['_query']['query']);
+
+ $this->_sendLine($cmd);
if ($return_sort && !$server_sort) {
if ($server_seq_sort) {
{
$this->_login();
- $cmd = array();
- foreach (explode(' ', $comparator) as $val) {
- $cmd[] = $this->utils->escape($val);
+ $cmd = array('COMPARATOR');
+ foreach ($comparator as $val) {
+ $cmd[] = array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $val);
}
-
- $this->_sendLine('COMPARATOR ' . implode(' ', $cmd));
+ $this->_sendLine($cmd);
}
/**
$this->_sendLine('COMPARATOR');
- return isset($this->_temp['comparator']) ? $this->_temp['comparator'] : null;
+ return isset($this->_temp['comparator'])
+ ? $this->_temp['comparator']
+ : null;
}
/**
if (empty($options['search'])) {
$charset = 'US-ASCII';
- $search = 'ALL';
+ $search = array('ALL');
} else {
$search_query = $options['search']->build();
$charset = $search_query['charset'];
}
$this->_temp['threadparse'] = array('base' => null, 'resp' => array());
- $this->_sendLine((empty($options['sequence']) ? 'UID ' : '') . 'THREAD ' . $tsort . ' ' . $charset . ' ' . $search);
+
+ $this->_sendLine(array_merge(array(
+ (empty($options['sequence']) ? 'UID' : null),
+ 'THREAD',
+ $tsort,
+ $charset
+ ), $search));
return $this->_temp['threadparse']['resp'];
}
: $this->utils->toSequenceString($options['ids']));
$use_seq = !empty($options['sequence']);
- $cmd = ($use_seq ? '' : 'UID ') . 'FETCH ' . $seq . ' (' . implode(' ', $fetch) . ')';
+ $cmd = array(
+ ($use_seq ? null : 'UID'),
+ 'FETCH',
+ $seq,
+ $fetch
+ );
if (!empty($options['changedsince'])) {
if (empty($this->_temp['mailbox']['highestmodseq'])) {
throw new Horde_Imap_Client_Exception('Mailbox does not support mod-sequences.', Horde_Imap_Client_Exception::MBOXNOMODSEQ);
}
- $cmd .= ' (CHANGEDSINCE ' . intval($options['changedsince']) . ')';
+ $cmd[] = array(
+ 'CHANGEDSINCE',
+ array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $options['changedsince'])
+ );
}
$this->_sendLine($cmd);
? '$'
: $this->utils->toSequenceString($options['ids']));
- $cmd_prefix = (empty($options['sequence']) ? 'UID ' : '') .
- 'STORE ' . $seq . ' ';
+ $cmd = array(
+ (empty($options['sequence']) ? 'UID' : null),
+ 'STORE',
+ $seq
+ );
$condstore = $ucsince = null;
$ucsince = $this->_temp['mailbox']['highestmodseq'];
}
}
- }
- if ($ucsince) {
- $cmd_prefix .= '(UNCHANGEDSINCE ' . $ucsince . ') ';
+ if ($ucsince) {
+ $cmd[] = array(
+ 'UNCHANGEDSINCE',
+ array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $ucsince)
+ );
+ }
}
$this->_temp['modified'] = array();
if (!empty($options['replace'])) {
- $this->_sendLine($cmd_prefix . 'FLAGS' . ($this->_debug ? '' : '.SILENT') . ' (' . implode(' ', $options['replace']) . ')');
+ $cmd[] = 'FLAGS' . ($this->_debug ? '' : '.SILENT');
+ foreach ($options['replace'] as $val) {
+ $cmd[] = array('t' => Horde_Imap_Client::DATA_ATOM, 'v' => $val);
+ }
+
+ $this->_sendLine($cmd);
} else {
foreach (array('add' => '+', 'remove' => '-') as $k => $v) {
if (!empty($options[$k])) {
- $this->_sendLine($cmd_prefix . $v . 'FLAGS' . ($this->_debug ? '' : '.SILENT') . ' (' . implode(' ', $options[$k]) . ')');
+ $cmdtmp = $cmd;
+ $cmdtmp[] = $v . 'FLAGS' . ($this->_debug ? '' : '.SILENT');
+ foreach ($options[$k] as $val) {
+ $cmdtmp[] = array('t' => Horde_Imap_Client::DATA_ATOM, 'v' => $val);
+ }
+
+ $this->_sendLine($cmdtmp);
}
}
}
// COPY returns no untagged information (RFC 3501 [6.4.7])
try {
- $this->_sendLine((empty($options['sequence']) ? 'UID ' : '') . 'COPY ' . $seq . ' ' . $this->utils->escape($dest));
+ $this->_sendLine(array(
+ (empty($options['sequence']) ? 'UID' : null),
+ 'COPY',
+ $seq,
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $dest)
+ ));
} catch (Horde_Imap_Client_Exception $e) {
if (!empty($options['create']) && $this->_temp['trycreate']) {
$this->createMailbox($dest);
$limits = array();
if (isset($options['messages'])) {
- $limits[] = 'MESSAGE ' . $options['messages'];
+ $limits[] = 'MESSAGE';
+ $limits[] = array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $options['messages']);
}
if (isset($options['storage'])) {
- $limits[] = 'STORAGE ' . $options['storage'];
+ $limits[] = 'STORAGE';
+ $limits[] = array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $options['storage']);
}
- $this->_sendLine('SETQUOTA ' . $this->utils->escape($root) . ' (' . implode(' ', $limits) . ')');
+ $this->_sendLine(array(
+ 'SETQUOTA',
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $root),
+ $limits
+ ));
}
/**
$this->login();
$this->_temp['quotaresp'] = array();
- $this->_sendLine('GETQUOTA ' . $this->utils->escape($root));
+ $this->_sendLine(array(
+ 'GETQUOTA',
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $root)
+ ));
return reset($this->_temp['quotaresp']);
}
$this->login();
$this->_temp['quotaresp'] = array();
- $this->_sendLine('GETQUOTAROOT ' . $this->utils->escape($mailbox));
+ $this->_sendLine(array(
+ 'GETQUOTAROOT',
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $mailbox)
+ ));
return $this->_temp['quotaresp'];
}
// SETACL/DELETEACL returns no untagged information (RFC 4314 [3.1 &
// 3.2]).
if (empty($options['rights']) && !empty($options['remove'])) {
- $this->_sendLine('DELETEACL ' . $this->utils->escape($mailbox) . ' ' . $identifier);
+ $this->_sendLine(array(
+ 'DELETEACL',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $identifier)
+ ));
} else {
- $this->_sendLine('SETACL ' . $this->utils->escape($mailbox) . ' ' . $identifier . ' ' . $options['rights']);
+ $this->_sendLine(array(
+ 'SETACL',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $identifier),
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $options['rights'])
+ ));
}
}
$this->login();
$this->_temp['getacl'] = array();
- $this->_sendLine('GETACL ' . $this->utils->escape($mailbox));
+ $this->_sendLine(array(
+ 'GETACL',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ ));
return $this->_temp['getacl'];
}
$this->login();
$this->_temp['listaclrights'] = array();
- $this->_sendLine('LISTRIGHTS ' . $this->utils->escape($mailbox) . ' ' . $identifier);
+ $this->_sendLine(array(
+ 'LISTRIGHTS',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $identifier)
+ ));
return $this->_temp['listaclrights'];
}
$this->login();
$this->_temp['myrights'] = array();
- $this->_sendLine('MYRIGHTS ' . $this->utils->escape($mailbox));
+ $this->_sendLine(array(
+ 'MYRIGHTS',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox)
+ ));
return $this->_temp['myrights'];
}
$this->login();
$this->_temp['metadata'] = array();
-
- $cmd_options = array();
- $option_string = $single_type = '';
- $use_rfc5464 = false;
+ $queries = array();
if ($this->queryCapability('METADATA') ||
((strlen($mailbox) == 0) &&
$this->queryCapability('METADATA-SERVER'))) {
- $use_rfc5464 = true;
- } elseif (!$this->queryCapability('ANNOTATEMORE') &&
- !$this->queryCapability('ANNOTATEMORE2')) {
- throw new Horde_Imap_Client_Exception('Server does not support the METADATA extension.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
- }
-
- if ($use_rfc5464) {
- $cmd = 'GETMETADATA ';
+ $cmd_options = array();
if (!empty($options['maxsize'])) {
- $cmd_options[] = '(MAXSIZE ' . intval($options['maxsize']) . ')';
+ $cmd_options[] = array(
+ 'MAXSIZE',
+ array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $options['maxsize'])
+ );
}
if (!empty($options['depth'])) {
- $cmd_options[] = '(DEPTH ' . $options['depth'] . ')';
+ $cmd_options[] = array(
+ 'DEPTH',
+ array('t' => Horde_Imap_Client::DATA_NUMBER, 'v' => $options['depth'])
+ );
}
- } else {
- $cmd = 'GETANNOTATION ';
- $result = array();
foreach ($entries as $md_entry) {
- list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
- if (empty($single_type)) {
- $single_type = $type;
- } else if ($single_type != $type) {
- // TODO: Recursive calls to _getMetadata()
- throw new Horde_Imap_Client_Exception('Multiple value types may not be retrieved in one call when using ANNOTATEMORE.');
- }
- $result[] = $entry;
+ $queries[] = array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $md_entry);
}
- $entries = $result;
+
+ $this->_sendLine(array(
+ 'GETMETADATA',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ (empty($cmd_options) ? null : $cmd_options),
+ $queries
+ ));
+
+ return $this->_temp['metadata'];
}
- if (count($cmd_options) == 1) {
- $option_string = $cmd_options[0];
- } else {
- $option_string = '(' . join(' ', $cmd_options) . ')';
+ if (!$this->queryCapability('ANNOTATEMORE') &&
+ !$this->queryCapability('ANNOTATEMORE2')) {
+ throw new Horde_Imap_Client_Exception('Server does not support the METADATA extension.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
}
- $entry_string = (count($entries) == 1)
- ? $this->utils->escape($entries[0]) . ' ' . $this->utils->escape($single_type)
- : '(' . join(' ', $entries) . ') ' . $single_type;
+ $queries = array();
+ foreach ($entries as $md_entry) {
+ list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
- $this->_sendLine($cmd . $this->utils->escape($mailbox) . ' ' . $option_string . ' ' . $entry_string);
+ if (!isset($queries[$type])) {
+ $queries[$type] = array();
+ }
+ $queries[$type][] = array('t' => Horde_Imap_Client::DATA_STRING, 'v' => $entry);
+ }
- if (!$use_rfc5464) {
+ $result = array();
+ foreach ($queries as $key => $val) {
// TODO: Honor maxsize and depth options.
+ $this->_sendLine(array(
+ 'GETANNOTATION',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ $val,
+ array('t' => Horde_Imap_Client::DATA_STRING, 'v' => $key)
+ ));
+
+ $result = array_merge($result, $this->_temp['metadata']);
}
- return $this->_temp['metadata'];
+ return $result;
}
/**
protected function _setMetadata($mailbox, $data)
{
$data_elements = array();
- $use_rfc5464 = false;
if ($this->queryCapability('METADATA') ||
((strlen($mailbox) == 0) &&
$this->queryCapability('METADATA-SERVER'))) {
- $use_rfc5464 = true;
- } elseif (!$this->queryCapability('ANNOTATEMORE') &&
- !$this->queryCapability('ANNOTATEMORE2')) {
- throw new Horde_Imap_Client_Exception('Server does not support the METADATA extension.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
- }
-
- if ($use_rfc5464) {
- $cmd = 'SETMETADATA ';
-
foreach ($data as $key => $value) {
- $i_value = is_null($value)
- ? 'NIL'
- : $this->utils->escape($value);
- $data_elements[] = $this->utils->escape($key) . ' ' . $i_value;
- }
- } else {
- $cmd = 'SETANNOTATION ';
-
- foreach ($data as $md_entry => $value) {
- list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
- $i_value = is_null($value)
- ? 'NIL'
- : $this->utils->escape($value);
- $data_elements[] = $this->utils->escape($entry) . ' (' . $this->utils->escape($type) . ' ' . $i_value . ')';
+ $data_elements[] = array(
+ array('t' => Horde_Imap_Client::DATA_ASTRING, 'v' => $key),
+ array('t' => Horde_Imap_Client::DATA_NSTRING, 'v' => $value)
+ );
}
+
+ $this->_sendLine(
+ 'SETMETADATA',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ $data_elements
+ );
+
+ return;
}
- $data_string = (count($data_elements) == 1)
- ? $data_elements[0]
- : '(' . join(' ', $data_elements) . ')';
+ if (!$this->queryCapability('ANNOTATEMORE') &&
+ !$this->queryCapability('ANNOTATEMORE2')) {
+ throw new Horde_Imap_Client_Exception('Server does not support the METADATA extension.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
+ }
- /* Disallow multi-line data for now.
- * @todo: Support this with sending literal data. */
- $data_string = str_replace("\n", '', $data_string);
+ foreach ($data as $md_entry => $value) {
+ list($entry, $type) = $this->_getAnnotateMoreEntry($md_entry);
+ $data_elements[] = array(
+ array('t' => Horde_Imap_Client::DATA_STRING, 'v' => $entry),
+ array(
+ array('t' => Horde_Imap_Client::DATA_STRING, 'v' => $type),
+ array('t' => Horde_Imap_Client::DATA_NSTRING, 'v' => $value)
+ )
+ );
+ }
- $this->_sendLine($cmd . $this->utils->escape($mailbox) . ' ' . $data_string);
+ $this->_sendLine(
+ 'SETANNOTATION',
+ array('t' => Horde_Imap_Client::DATA_MAILBOX, 'v' => $mailbox),
+ $data_elements
+ );
}
/**
* meant for a command while scanning for untagged responses
* unilaterally sent by the server.
*
- * @param string $query The IMAP command to execute.
+ * @param mixed $query The IMAP command to execute. If string TODO. If
+ * array TODO.
* @param array $options Additional options:
* <pre>
* 'binary' - (boolean) Does $query contain binary data? If so, and the
*/
protected function _sendLine($query, $options = array())
{
+ $out = '';
+
if (empty($options['notag'])) {
- $query = ++$this->_tag . ' ' . $query;
+ $out = ++$this->_tag . ' ';
/* Catch all FETCH responses until a tagged response. */
- $this->_temp['fetchresp'] = array('seq' => array(), 'uid' => array());
+ $this->_temp['fetchresp'] = array(
+ 'seq' => array(),
+ 'uid' => array()
+ );
+ }
+
+ if (is_array($query)) {
+ if (!empty($options['debug'])) {
+ $this->_temp['sendnodebug'] = true;
+ }
+ $out = rtrim($this->parseCommandArray($query, $out, array($this, 'parseCommandArrayCallback')));
+ unset($this->_temp['sendnodebug']);
+ } else {
+ $out .= $query;
}
$continuation = $literalplus = false;
}
if (!empty($options['literal'])) {
- $query .= ' ';
+ $out .= ' ';
// RFC 3516 - Send literal8 if we have binary data.
if (!empty($options['binary'])) {
if (!$this->queryCapability('BINARY')) {
throw new Horde_Imap_Client_Exception('Can not send binary data to server that does not support it.', Horde_Imap_Client_Exception::NOSUPPORTIMAPEXT);
}
- $query .= '~';
+ $out .= '~';
}
- $query .= '{' . $options['literal'] . ($literalplus ? '+' : '') . '}';
+ $out .= '{' . $options['literal'] . ($literalplus ? '+' : '') . '}';
}
}
- if ($this->_debug) {
- fwrite($this->_debug, '(' . microtime(true) . ') C: ' . (empty($options['debug']) ? $query : $options['debug']) . "\n");
+ if ($this->_debug && empty($this->_temp['sendnodebug'])) {
+ fwrite($this->_debug, '(' . microtime(true) . ') C: ' . (empty($options['debug']) ? $out : $options['debug']) . "\n");
}
- fwrite($this->_stream, $query . "\r\n");
+ fwrite($this->_stream, $out . "\r\n");
if ($literalplus) {
return;
}
/**
+ * Callback for parseCommandArray() when literal data is found.
+ *
+ * @param string $cmd The unprocessed command string.
+ * @param string $literal The literal data.
+ *
+ * @return string The new unprocessed command string.
+ */
+ public function parseCommandArrayCallback($cmd, $literal)
+ {
+ $this->_sendLine($cmd, array(
+ 'literal' => strlen($literal),
+ 'notag' => true
+ ));
+
+ $this->_sendLine($literal, array(
+ 'literaldata' => true,
+ 'notag' => true
+ ));
+
+ return '';
+ }
+
+ /**
* Gets data from the IMAP stream and parses it.
*
* @return array An array with the following keys: