diff --git a/program/lib/Roundcube/rcube_addressbook.php b/program/lib/Roundcube/rcube_addressbook.php index ae72dcd02..3943fcf8a 100644 --- a/program/lib/Roundcube/rcube_addressbook.php +++ b/program/lib/Roundcube/rcube_addressbook.php @@ -24,14 +24,20 @@ */ abstract class rcube_addressbook { - /** constants for error reporting **/ + // constants for error reporting const ERROR_READ_ONLY = 1; const ERROR_NO_CONNECTION = 2; const ERROR_VALIDATE = 3; const ERROR_SAVING = 4; const ERROR_SEARCH = 5; - /** public properties (mandatory) */ + // search modes + const SEARCH_ALL = 0; + const SEARCH_STRICT = 1; + const SEARCH_PREFIX = 2; + const SEARCH_GROUPS = 4; + + // public properties (mandatory) public $primary_key; public $groups = false; public $export_groups = true; @@ -102,13 +108,11 @@ abstract class rcube_addressbook * * @param array List of fields to search in * @param string Search value - * @param int Matching mode: - * 0 - partial (*abc*), - * 1 - strict (=), - * 2 - prefix (abc*) + * @param int Search mode. Sum of self::SEARCH_*. * @param boolean True if results are requested, False if count only * @param boolean True to skip the count query (select only) * @param array List of fields that cannot be empty + * * @return object rcube_result_set List of contact records and 'count' value */ abstract function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()); @@ -333,10 +337,7 @@ abstract class rcube_addressbook * List all active contact groups of this source * * @param string Optional search string to match group name - * @param int Matching mode: - * 0 - partial (*abc*), - * 1 - strict (=), - * 2 - prefix (abc*) + * @param int Search mode. Sum of self::SEARCH_* * * @return array Indexed list of contact groups, each a hash array */ @@ -668,16 +669,14 @@ abstract class rcube_addressbook // composite field, e.g. address foreach ((array)$value as $val) { $val = mb_strtolower($val); - switch ($mode) { - case 1: - $got = ($val == $search); - break; - case 2: + if ($mode & self::SEARCH_STRICT) { + $got = ($val == $search); + } + else if ($mode & self::SEARCH_PREFIX) { $got = ($search == substr($val, 0, strlen($search))); - break; - - default: + } + else { $got = (strpos($val, $search) !== false); } diff --git a/program/lib/Roundcube/rcube_contacts.php b/program/lib/Roundcube/rcube_contacts.php index a5f03bc7c..498571561 100644 --- a/program/lib/Roundcube/rcube_contacts.php +++ b/program/lib/Roundcube/rcube_contacts.php @@ -130,10 +130,7 @@ class rcube_contacts extends rcube_addressbook * List all active contact groups of this source * * @param string $search Search string to match group name - * @param int $mode Matching mode: - * 0 - partial (*abc*), - * 1 - strict (=), - * 2 - prefix (abc*) + * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* * * @return array Indexed list of contact groups, each a hash array */ @@ -141,18 +138,18 @@ class rcube_contacts extends rcube_addressbook { $results = array(); - if (!$this->groups) + if (!$this->groups) { return $results; + } if ($search) { - switch (intval($mode)) { - case 1: + if ($mode & rcube_addressbook::SEARCH_STRICT) { $sql_filter = $this->db->ilike('name', $search); - break; - case 2: + } + else if ($mode & rcube_addressbook::SEARCH_PREFIX) { $sql_filter = $this->db->ilike('name', $search . '%'); - break; - default: + } + else { $sql_filter = $this->db->ilike('name', '%' . $search . '%'); } @@ -283,10 +280,7 @@ class rcube_contacts extends rcube_addressbook * * @param mixed $fields The field name or array of field names to search in * @param mixed $value Search value (or array of values when $fields is array) - * @param int $mode Matching mode: - * 0 - partial (*abc*), - * 1 - strict (=), - * 2 - prefix (abc*) + * @param int $mode Search mode. Sum of rcube_addressbook::SEARCH_* * @param boolean $select True if results are requested, False if count only * @param boolean $nocount True to skip the count query (select only) * @param array $required List of fields that cannot be empty @@ -337,7 +331,7 @@ class rcube_contacts extends rcube_addressbook } else { // require each word in to be present in one of the fields - $words = $mode == 1 ? array($value) : rcube_utils::tokenize_string($value, 1); + $words = ($mode & rcube_addressbook::SEARCH_STRICT) ? array($value) : rcube_utils::tokenize_string($value, 1); foreach ($words as $word) { $groups = array(); foreach ((array)$fields as $idx => $col) { @@ -450,18 +444,17 @@ class rcube_contacts extends rcube_addressbook $where = array(); foreach ($words as $word) { - switch ($mode) { - case 1: // strict + if ($mode & rcube_addressbook::SEARCH_STRICT) { $where[] = '(' . $this->db->ilike($col, $word) . ' OR ' . $this->db->ilike($col, $word . $AS . '%') . ' OR ' . $this->db->ilike($col, '%' . $AS . $word . $AS . '%') . ' OR ' . $this->db->ilike($col, '%' . $AS . $word) . ')'; - break; - case 2: // prefix + } + else if ($mode & rcube_addressbook::SEARCH_PREFIX) { $where[] = '(' . $this->db->ilike($col, $word . '%') . ' OR ' . $this->db->ilike($col, '%' . $AS . $word . '%') . ')'; - break; - default: // partial + } + else { $where[] = $this->db->ilike($col, '%' . $word . '%'); } } diff --git a/program/lib/Roundcube/rcube_ldap.php b/program/lib/Roundcube/rcube_ldap.php index 857b10daf..894453a07 100644 --- a/program/lib/Roundcube/rcube_ldap.php +++ b/program/lib/Roundcube/rcube_ldap.php @@ -731,10 +731,7 @@ class rcube_ldap extends rcube_addressbook * * @param mixed $fields The field name of array of field names to search in * @param mixed $value Search value (or array of values when $fields is array) - * @param int $mode Matching mode: - * 0 - partial (*abc*), - * 1 - strict (=), - * 2 - prefix (abc*) + * @param int $mode Matching mode. Sum of rcube_addressbook::SEARCH_* * @param boolean $select True if results are requested, False if count only * @param boolean $nocount (Not used) * @param array $required List of fields that cannot be empty @@ -765,7 +762,7 @@ class rcube_ldap extends rcube_addressbook if ($this->prop['vlv_search'] && $this->ready && join(',', (array)$fields) == join(',', $list_fields)) { $this->result = new rcube_result_set(0); - $this->ldap->config_set('fuzzy_search', intval($this->prop['fuzzy_search'] && $mode != 1)); + $this->ldap->config_set('fuzzy_search', intval($this->prop['fuzzy_search'] && !($mode & rcube_addressbook::SEARCH_STRICT))); $ldap_data = $this->ldap->search($this->base_dn, $this->prop['filter'], $this->prop['scope'], $this->prop['attributes'], array('search' => $value /*, 'sort' => $this->prop['sort'] */)); if ($ldap_data === false) { @@ -797,9 +794,9 @@ class rcube_ldap extends rcube_addressbook // set wildcards $wp = $ws = ''; - if (!empty($this->prop['fuzzy_search']) && $mode != 1) { + if (!empty($this->prop['fuzzy_search']) && !($mode & rcube_addressbook::SEARCH_STRICT)) { $ws = '*'; - if (!$mode) { + if (!($mode & rcube_addressbook::SEARCH_PREFIX)) { $wp = '*'; } } @@ -865,10 +862,12 @@ class rcube_ldap extends rcube_addressbook // avoid double-wildcard if $value is empty $filter = preg_replace('/\*+/', '*', $filter); + if ($mode & rcube_addressbook::SEARCH_GROUPS) { + $filter = 'e:' . $filter; + } + // set filter string and execute search - // @FIXME: we need a better way to detect/define when groups are allowed in the result - $prefix = empty($required) ? 'e:' : ''; - $this->set_search_set($prefix . $filter); + $this->set_search_set($filter); if ($select) $this->list_records(); @@ -1689,10 +1688,7 @@ class rcube_ldap extends rcube_addressbook * List all active contact groups of this source * * @param string Optional search string to match group name - * @param int Matching mode: - * 0 - partial (*abc*), - * 1 - strict (=), - * 2 - prefix (abc*) + * @param int Matching mode. Sum of rcube_addressbook::SEARCH_* * * @return array Indexed list of contact groups, each a hash array */ @@ -1784,9 +1780,11 @@ class rcube_ldap extends rcube_addressbook if ($search !== null) { // set wildcards $wp = $ws = ''; - if (!empty($this->prop['fuzzy_search']) && $mode != 1) { + if (!empty($this->prop['fuzzy_search']) && !($mode & rcube_addressbook::SEARCH_STRICT)) { $ws = '*'; - $wp = !$mode ? '*' : ''; + if (!($mode & rcube_addressbook::SEARCH_PREFIX)) { + $wp = '*'; + } } $filter = "(&$filter($name_attr=$wp" . rcube_ldap_generic::quote_string($search) . "$ws))"; $props['search'] = $wp . $search . $ws; diff --git a/program/steps/addressbook/search.inc b/program/steps/addressbook/search.inc index cba1eec08..6a938cef8 100644 --- a/program/steps/addressbook/search.inc +++ b/program/steps/addressbook/search.inc @@ -139,6 +139,7 @@ function rcmail_contact_search() // Values matching mode $mode = (int) $RCMAIL->config->get('addressbook_search_mode'); + $mode |= rcube_addressbook::SEARCH_GROUPS; // get sources list $sources = $RCMAIL->get_address_sources(); diff --git a/program/steps/mail/autocomplete.inc b/program/steps/mail/autocomplete.inc index 31480ca76..bc1b3570c 100644 --- a/program/steps/mail/autocomplete.inc +++ b/program/steps/mail/autocomplete.inc @@ -63,6 +63,7 @@ if (!empty($book_types) && strlen($search)) { $sort_keys = array(); $books_num = count($book_types); $search_lc = mb_strtolower($search); + $mode |= rcube_addressbook::SEARCH_GROUPS; foreach ($book_types as $abook_id) { $abook = $RCMAIL->get_address_book($abook_id); diff --git a/program/steps/mail/list_contacts.inc b/program/steps/mail/list_contacts.inc index 7077b5f98..50cf387c3 100644 --- a/program/steps/mail/list_contacts.inc +++ b/program/steps/mail/list_contacts.inc @@ -117,7 +117,6 @@ else if (!empty($result) && $result->count > 0) { } } - // update env $OUTPUT->set_env('contactdata', $jsresult); $OUTPUT->set_env('pagecount', ceil($result->count / $page_size)); diff --git a/program/steps/mail/search_contacts.inc b/program/steps/mail/search_contacts.inc index 944aae13c..2ee0fc808 100644 --- a/program/steps/mail/search_contacts.inc +++ b/program/steps/mail/search_contacts.inc @@ -28,6 +28,7 @@ $page_size = $RCMAIL->config->get('addressbook_pagesize', $RCMAIL->config->g $records = array(); $search_set = array(); $jsresult = array(); +$search_mode |= rcube_addressbook::SEARCH_GROUPS; foreach ($sources as $s) { $source = $RCMAIL->get_address_book($s['id']); @@ -75,7 +76,9 @@ $result->records = array_values($records); if (!empty($result) && $result->count > 0) { // create javascript list while ($row = $result->next()) { - $name = rcube_addressbook::compose_list_name($row); + $name = rcube_addressbook::compose_list_name($row); + $classname = $row['_type'] == 'group' ? 'group' : 'person'; + $keyname = $row['_type'] == 'group' ? 'contactgroup' : 'contact'; // add record for every email address of the contact // (same as in list_contacts.inc) @@ -86,9 +89,9 @@ if (!empty($result) && $result->count > 0) { $title = rcube_addressbook::compose_search_name($row, $email, $name); $OUTPUT->command('add_contact_row', $row_id, array( - 'contact' => html::a(array('title' => $title), rcube::Q($name ?: $email) . + $keyname => html::a(array('title' => $title), rcube::Q($name ?: $email) . ($name && count($emails) > 1 ? ' ' . html::span('email', rcube::Q($email)) : '') - )), 'person'); + )), $classname); } }