/** * Query the validity of a charset. * * @param string $charset The charset to query. * @param boolean $cached If true, only query cached values. * * @return boolean True if the charset is valid for searching. */ public function query($charset, $cached = false) { $charset = Horde_String::upper($charset); if (isset($this->_charsets[$charset])) { return $this->_charsets[$charset]; } elseif ($cached) { return null; } if (!$this->_baseob) { throw new RuntimeException('Base object needs to be defined to query for charset.'); } /* Use a dummy search query and search for BADCHARSET response. */ $query = new Horde_Imap_Client_Search_Query(); $query->charset($charset, false); $query->ids($this->_baseob->getIdsOb(1, true)); $query->text('a'); try { $this->_baseob->search('INBOX', $query, array('nocache' => true, 'sequence' => true)); $this->_charsets[$charset] = true; } catch (Horde_Imap_Client_Exception $e) { $this->_charsets[$charset] = $e->getCode() !== Horde_Imap_Client_Exception::BADCHARSET; } $this->notify(); return $this->_charsets[$charset]; }
public function inconsistentCharsetsInAndOrSearchesProvider() { $ob = new Horde_Imap_Client_Search_Query(); $ob->text('foo'); $ob->charset('UTF-8', false); $ob2 = new Horde_Imap_Client_Search_Query(); $ob2->text('foo2'); $ob2->charset('ISO-8859-1', false); $ob2->andSearch($ob); $ob3 = new Horde_Imap_Client_Search_Query(); $ob3->text('foo2'); $ob3->charset('ISO-8859-1', false); $ob3->orSearch($ob); return array(array($ob2), array($ob3)); }
/** * Performs the filtering specified in the rules. * * @param integer $change The timestamp of the latest rule change during * the current session. */ protected function _perform($change) { $api = $this->_params['api']; $notification = $this->_params['notification']; /* Indices that will be ignored by subsequent rules. */ $ignore_ids = array(); /* Only do filtering if: 1. We have not done filtering before -or- 2. The mailbox has changed -or- 3. The rules have changed. */ $cache = $api->getCache(); if ($cache !== false && $cache == $change) { return; } $filters = Ingo_Storage_FilterIterator_Skip::create($this->_params['storage'], $this->_params['skip']); /* Parse through the rules, one-by-one. */ foreach ($filters as $rule) { /* Check to make sure this is a valid rule and that the rule is not disabled. */ if (!$this->_validRule($rule) || $rule->disable) { continue; } switch ($class = get_class($rule)) { case 'Ingo_Rule_System_Blacklist': case 'Ingo_Rule_System_Whitelist': $addr = $rule->addresses; $bl_folder = $class === 'Ingo_Rule_System_Blacklist' ? $rule->mailbox : null; /* If list is empty, move on. */ if (empty($addr)) { continue; } $addr = new Horde_Mail_Rfc822_List($addr); $query = $this->_getQuery(); $or_ob = new Horde_Imap_Client_Search_Query(); foreach ($addr->bare_addresses as $val) { $ob = new Horde_Imap_Client_Search_Query(); $ob->charset('UTF-8', false); $ob->headerText('from', $val); $or_ob->orSearch(array($ob)); } $query->andSearch(array($or_ob)); $indices = $api->search($query); if (!($msgs = $api->fetchEnvelope($indices))) { continue; } /* Remove any indices that got in there by way of partial * address match. */ $remove = array(); foreach ($msgs as $v) { foreach ($v->getEnvelope()->from as $v2) { if (!$addr->contains($v2)) { $remove[] = $v->getUid(); break; } } } if ($remove) { $indices = array_diff($indices, $remove); } if ($class === 'Ingo_Rule_System_Blacklist') { $indices = array_diff($indices, $ignore_ids); if (!empty($indices)) { if (!empty($bl_folder)) { $api->moveMessages($indices, $bl_folder); } else { $api->deleteMessages($indices); } $notification->push(sprintf(_("Filter activity: %s message(s) that matched the blacklist were deleted."), count($indices)), 'horde.message'); } } else { $ignore_ids = $indices; } break; case 'Ingo_Rule_User_Discard': case 'Ingo_Rule_User_Keep': case 'Ingo_Rule_User_Move': case 'Ingo_Rule_User_MoveKeep': $base_query = $this->_getQuery(); $query = new Horde_Imap_Client_Search_Query(); foreach ($rule->conditions as $val) { $ob = new Horde_Imap_Client_Search_Query(); if (!empty($val['type']) && $val['type'] == Ingo_Rule_User::TEST_SIZE) { $ob->size($val['value'], $val['match'] == 'greater than'); } elseif (!empty($val['type']) && $val['type'] == Ingo_Rule_User::TEST_BODY) { $ob->charset('UTF-8', false); $ob->text($val['value'], true, $val['match'] == 'not contain'); } else { if (strpos($val['field'], ',') == false) { $ob->charset('UTF-8', false); $ob->headerText($val['field'], $val['value'], $val['match'] == 'not contain'); } else { foreach (explode(',', $val['field']) as $header) { $hdr_ob = new Horde_Imap_Client_Search_Query(); $hdr_ob->charset('UTF-8', false); $hdr_ob->headerText($header, $val['value'], $val['match'] == 'not contain'); if ($val['match'] == 'contains') { $ob->orSearch(array($hdr_ob)); } elseif ($val['match'] == 'not contain') { $ob->andSearch(array($hdr_ob)); } } } } switch ($rule->combine) { case Ingo_Rule_User::COMBINE_ALL: $query->andSearch(array($ob)); break; case Ingo_Rule_User::COMBINE_ANY: $query->orSearch(array($ob)); break; } } $base_query->andSearch(array($query)); $indices = $api->search($base_query); if ($indices = array_diff($indices, $ignore_ids)) { if ($rule->stop) { /* If the stop action is set, add these * indices to the list of ids that will be * ignored by subsequent rules. */ $ignore_ids = array_unique($indices + $ignore_ids); } /* Set the flags. */ if ($class !== 'Ingo_Rule_User_Discard') { $flags = array(); if ($rule->flags & Ingo_Rule_User::FLAG_ANSWERED) { $flags[] = '\\answered'; } if ($rule->flags & Ingo_Rule_User::FLAG_DELETED) { $flags[] = '\\deleted'; } if ($rule->flags & Ingo_Rule_User::FLAG_FLAGGED) { $flags[] = '\\flagged'; } if ($rule->flags & Ingo_Rule_User::FLAG_SEEN) { $flags[] = '\\seen'; } if (!empty($flags)) { $api->setMessageFlags($indices, $flags); } } switch ($class) { case 'Ingo_Rule_User_Keep': /* Add these indices to the ignore list. */ $ignore_ids = array_unique($indices + $ignore_ids); break; case 'Ingo_Rule_User_Move': /* We need to grab the envelope first. */ if ($this->_params['show_filter_msg'] && !($fetch = $api->fetchEnvelope($indices))) { continue 2; } $mbox = new Horde_Imap_Client_Mailbox($rule->value); /* Move the messages to the requested mailbox. */ $api->moveMessages($indices, strval($mbox)); /* Display notification message(s). */ if ($this->_params['show_filter_msg']) { foreach ($fetch as $msg) { $envelope = $msg->getEnvelope(); $notification->push(sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been moved to the folder \"%s\"."), !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject) : _("[No Subject]"), !empty($envelope->from) ? strval($envelope->from) : _("[No Sender]"), $mbox), 'horde.message'); } } else { $notification->push(sprintf(_("Filter activity: %s message(s) have been moved to the folder \"%s\"."), count($indices), $mbox), 'horde.message'); } break; case 'Ingo_Rule_User_Discard': /* We need to grab the envelope first. */ if ($this->_params['show_filter_msg'] && !($fetch = $api->fetchEnvelope($indices))) { continue; } /* Delete the messages now. */ $api->deleteMessages($indices); /* Display notification message(s). */ if ($this->_params['show_filter_msg']) { foreach ($fetch as $msg) { $envelope = $msg->getEnvelope(); $notification->push(sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been deleted."), !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject) : _("[No Subject]"), !empty($envelope->from) ? strval($envelope->from) : _("[No Sender]")), 'horde.message'); } } else { $notification->push(sprintf(_("Filter activity: %s message(s) have been deleted."), count($indices)), 'horde.message'); } break; case 'Ingo_Rule_User_MoveKeep': $mbox = new Horde_Imap_Client_Mailbox($rule->value); /* Copy the messages to the requested mailbox. */ $api->copyMessages($indices, strval($mbox)); /* Display notification message(s). */ if ($this->_params['show_filter_msg']) { if (!($fetch = $api->fetchEnvelope($indices))) { continue; } foreach ($fetch as $msg) { $envelope = $msg->getEnvelope(); $notification->push(sprintf(_("Filter activity: The message \"%s\" from \"%s\" has been copied to the folder \"%s\"."), !empty($envelope->subject) ? Horde_Mime::decode($envelope->subject) : _("[No Subject]"), !empty($envelope->from) ? strval($envelope->from) : _("[No Sender]"), $mbox), 'horde.message'); } } else { $notification->push(sprintf(_("Filter activity: %s message(s) have been copied to the folder \"%s\"."), count($indices), $mbox), 'horde.message'); } } } break; } } /* Set cache flag. */ $api->storeCache($change); }
public function testSerialize() { $ob = new Horde_Imap_Client_Search_Query(); $ob->ids(new Horde_Imap_Client_Ids('1:3'), true); $ob->text('foo'); $ob->charset('US-ASCII', false); $this->assertEquals('BODY foo NOT UID 1:3', strval(unserialize(serialize($ob)))); }
/** * Determines if the given charset is valid for search-related queries. * This check pertains just to the basic IMAP SEARCH command. * * @param string $charset The query charset. * * @return boolean True if server supports this charset. */ public function validSearchCharset($charset) { $charset = strtoupper($charset); if ($charset == 'US-ASCII') { return true; } if (!isset($this->_init['s_charset'][$charset])) { $s_charset = $this->_init['s_charset']; /* Use a dummy search query and search for BADCHARSET response. */ $query = new Horde_Imap_Client_Search_Query(); $query->charset($charset, false); $query->ids($this->getIdsOb(1, true)); $query->text('a'); try { $this->search('INBOX', $query, array('nocache' => true, 'sequence' => true)); $s_charset[$charset] = true; } catch (Horde_Imap_Client_Exception $e) { $s_charset[$charset] = $e->getCode() !== Horde_Imap_Client_Exception::BADCHARSET; } $this->_setInit('s_charset', $s_charset); } return $this->_init['s_charset'][$charset]; }
/** * Perform an IMAP search based on a SEARCH request. * * @param array $query The search query. * * @return array The results array containing an array of hashes: * 'uniqueid' => [The unique identifier of the result] * 'searchfolderid' => [The mailbox name that this result comes from] * * @throws Horde_ActiveSync_Exception */ protected function _doQuery(array $query) { $imap_query = new Horde_Imap_Client_Search_Query(); $imap_query->charset('UTF-8', false); $mboxes = array(); $results = array(); foreach ($query as $q) { switch ($q['op']) { case Horde_ActiveSync_Request_Search::SEARCH_AND: return $this->_doQuery(array($q['value']), $range); default: foreach ($q as $key => $value) { switch ($key) { case 'FolderType': if ($value != Horde_ActiveSync::CLASS_EMAIL) { throw new Horde_ActiveSync_Exception('Only Email folders are supported.'); } break; case 'serverid': $mboxes[] = new Horde_Imap_Client_Mailbox($value); break; case Horde_ActiveSync_Message_Mail::POOMMAIL_DATERECEIVED: if ($q['op'] == Horde_ActiveSync_Request_Search::SEARCH_GREATERTHAN) { $query_range = Horde_Imap_Client_Search_Query::DATE_SINCE; } elseif ($q['op'] == Horde_ActiveSync_Request_Search::SEARCH_LESSTHAN) { $query_range = Horde_Imap_Client_Search_Query::DATE_BEFORE; } else { $query_range = Horde_Imap_Client_Search_Query::DATE_ON; } $imap_query->dateSearch($value, $query_range); break; case Horde_ActiveSync_Request_Search::SEARCH_FREETEXT: $imap_query->text($value, false); break; case 'subquery': $imap_query->andSearch(array($this->_buildSubQuery($value))); } } } } if (empty($mboxes)) { foreach ($this->getMailboxes() as $mailbox) { $mboxes[] = $mailbox['ob']; } } foreach ($mboxes as $mbox) { try { $search_res = $this->_getImapOb()->search($mbox, $imap_query, array('results' => array(Horde_Imap_Client::SEARCH_RESULTS_MATCH, Horde_Imap_Client::SEARCH_RESULTS_SAVE, Horde_Imap_Client::SEARCH_RESULTS_COUNT), 'sort' => array(Horde_Imap_Client::SORT_REVERSE, Horde_Imap_Client::SORT_ARRIVAL))); } catch (Horde_Imap_Client_Exception $e) { throw new Horde_ActiveSync_Exception($e); } if ($search_res['count'] == 0) { continue; } $ids = $search_res['match']->ids; foreach ($ids as $id) { $results[] = array('uniqueid' => $mbox->utf8 . ':' . $id, 'searchfolderid' => $mbox->utf8); } if (!empty($range)) { preg_match('/(.*)\\-(.*)/', $range, $matches); $return_count = $matches[2] - $matches[1]; $results = array_slice($results, $matches[1], $return_count + 1, true); } } return $results; }