Changeset f21a04c in github


Ignore:
Timestamp:
Nov 10, 2011 2:57:56 AM (19 months ago)
Author:
alecpl <alec@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.8
Children:
d617566
Parents:
81f5dd7
Message:
  • Add option to define matching method for addressbook search (#1486564, #1487907)
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    r62c8618 rf21a04c  
    22=========================== 
    33 
     4- Add option to define matching method for addressbook search (#1486564, #1487907) 
    45- Make email recipients separator configurable 
    56- Fix so folders with \Noinferiors attribute aren't listed in parent selector 
  • config/main.inc.php.dist

    r62c8618 rf21a04c  
    628628$rcmail_config['address_template'] = '{street}<br/>{locality} {zipcode}<br/>{country} {region}'; 
    629629 
     630// Matching mode for addressbook search (including autocompletion) 
     631// 0 - partial (*abc*), default 
     632// 1 - strict (abc) 
     633// 2 - prefix (abc*) 
     634// Note: For LDAP sources fuzzy_search must be enabled to use 'partial' or 'prefix' mode 
     635$rcmail_config['addressbook_search_mode'] = 0; 
     636 
    630637// ---------------------------------- 
    631638// USER PREFERENCES 
  • program/include/rcube_addressbook.php

    rdc6c4f4 rf21a04c  
    9797     * @param array   List of fields to search in 
    9898     * @param string  Search value 
     99     * @param int     Matching mode: 
     100     *                0 - partial (*abc*), 
     101     *                1 - strict (=), 
     102     *                2 - prefix (abc*) 
    99103     * @param boolean True if results are requested, False if count only 
    100104     * @param boolean True to skip the count query (select only) 
     
    102106     * @return object rcube_result_set List of contact records and 'count' value 
    103107     */ 
    104     abstract function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()); 
     108    abstract function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()); 
    105109 
    106110    /** 
  • program/include/rcube_contacts.php

    r5e90652 rf21a04c  
    178178            " AND user_id=?", 
    179179            $group_id, $this->user_id); 
    180              
     180 
    181181        if ($sql_result && ($sql_arr = $this->db->fetch_assoc($sql_result))) { 
    182182            $sql_arr['ID'] = $sql_arr['contactgroup_id']; 
    183183            return $sql_arr; 
    184184        } 
    185          
     185 
    186186        return null; 
    187187    } 
     
    269269     * @param mixed   $fields   The field name of array of field names to search in 
    270270     * @param mixed   $value    Search value (or array of values when $fields is array) 
    271      * @param boolean $strict   True for strict (=), False for partial (LIKE) matching 
     271     * @param int     $mode     Matching mode: 
     272     *                          0 - partial (*abc*), 
     273     *                          1 - strict (=), 
     274     *                          2 - prefix (abc*) 
    272275     * @param boolean $select   True if results are requested, False if count only 
    273276     * @param boolean $nocount  True to skip the count query (select only) 
     
    276279     * @return object rcube_result_set Contact records and 'count' value 
    277280     */ 
    278     function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) 
     281    function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()) 
    279282    { 
    280283        if (!is_array($fields)) 
     
    284287 
    285288        $where = $and_where = array(); 
     289        $mode = intval($mode); 
    286290 
    287291        foreach ($fields as $idx => $col) { 
     
    296300            else if ($col == '*') { 
    297301                $words = array(); 
    298                 foreach (explode(" ", self::normalize_string($value)) as $word) 
    299                     $words[] = $this->db->ilike('words', '%'.$word.'%'); 
     302                foreach (explode(" ", self::normalize_string($value)) as $word) { 
     303                    switch ($mode) { 
     304                    case 1: // strict 
     305                        $words[] = '(' . $this->db->ilike('words', $word.' %') 
     306                            . ' OR ' . $this->db->ilike('words', '% '.$word.' %') 
     307                            . ' OR ' . $this->db->ilike('words', '% '.$word) . ')'; 
     308                        break; 
     309                    case 2: // prefix 
     310                        $words[] = '(' . $this->db->ilike('words', $word.'%') 
     311                            . ' OR ' . $this->db->ilike('words', '% '.$word.'%') . ')'; 
     312                        break; 
     313                    default: // partial 
     314                        $words[] = $this->db->ilike('words', '%'.$word.'%'); 
     315                    } 
     316                } 
    300317                $where[] = '(' . join(' AND ', $words) . ')'; 
    301318            } 
     
    304321                // table column 
    305322                if (in_array($col, $this->table_cols)) { 
    306                     if ($strict) { 
     323                    switch ($mode) { 
     324                    case 1: // strict 
    307325                        $where[] = $this->db->quoteIdentifier($col).' = '.$this->db->quote($val); 
    308                     } 
    309                     else { 
     326                        break; 
     327                    case 2: // prefix 
     328                        $where[] = $this->db->ilike($col, $val.'%'); 
     329                        break; 
     330                    default: // partial 
    310331                        $where[] = $this->db->ilike($col, '%'.$val.'%'); 
    311332                    } 
     
    314335                else { 
    315336                    if (in_array($col, $this->fulltext_cols)) { 
    316                         foreach (explode(" ", self::normalize_string($val)) as $word) 
    317                             $words[] = $this->db->ilike('words', '%'.$word.'%'); 
     337                        foreach (explode(" ", self::normalize_string($val)) as $word) { 
     338                            switch ($mode) { 
     339                            case 1: // strict 
     340                                $words[] = '(' . $this->db->ilike('words', $word.' %') 
     341                                    . ' OR ' . $this->db->ilike('words', '% '.$word.' %') 
     342                                    . ' OR ' . $this->db->ilike('words', '% '.$word) . ')'; 
     343                                break; 
     344                            case 2: // prefix 
     345                                $words[] = '(' . $this->db->ilike('words', $word.'%') 
     346                                    . ' OR ' . $this->db->ilike('words', ' '.$word.'%') . ')'; 
     347                                break; 
     348                            default: // partial 
     349                                $words[] = $this->db->ilike('words', '%'.$word.'%'); 
     350                            } 
     351                        } 
    318352                        $where[] = '(' . join(' AND ', $words) . ')'; 
    319353                    } 
     
    363397                        foreach ((array)$row[$col] as $value) { 
    364398                            // composite field, e.g. address 
    365                             if (is_array($value)) { 
    366                                 $value = implode($value); 
    367                             } 
    368                             $value = mb_strtolower($value); 
    369                             if (($strict && $value == $search) || (!$strict && strpos($value, $search) !== false)) { 
    370                                 $found[$colname] = true; 
    371                                 break; 
     399                            foreach ((array)$value as $val) { 
     400                                $val = mb_strtolower($val); 
     401                                switch ($mode) { 
     402                                case 1: 
     403                                    $got = ($val == $search); 
     404                                    break; 
     405                                case 2: 
     406                                    $got = ($search == substr($val, 0, strlen($search))); 
     407                                    break; 
     408                                default: 
     409                                    $got = (strpos($val, $search) !== false); 
     410                                    break; 
     411                                } 
     412 
     413                                if ($got) { 
     414                                    $found[$colname] = true; 
     415                                    break 2; 
     416                                } 
    372417                            } 
    373418                        } 
  • program/include/rcube_ldap.php

    r06744da rf21a04c  
    699699     * @param mixed   $fields   The field name of array of field names to search in 
    700700     * @param mixed   $value    Search value (or array of values when $fields is array) 
    701      * @param boolean $strict   True for strict, False for partial (fuzzy) matching 
     701     * @param int     $mode     Matching mode: 
     702     *                          0 - partial (*abc*), 
     703     *                          1 - strict (=), 
     704     *                          2 - prefix (abc*) 
    702705     * @param boolean $select   True if results are requested, False if count only 
    703706     * @param boolean $nocount  (Not used) 
     
    706709     * @return array  Indexed list of contact records and 'count' value 
    707710     */ 
    708     function search($fields, $value, $strict=false, $select=true, $nocount=false, $required=array()) 
    709     { 
     711    function search($fields, $value, $mode=0, $select=true, $nocount=false, $required=array()) 
     712    { 
     713        $mode = intval($mode); 
     714 
    710715        // special treatment for ID-based search 
    711716        if ($fields == 'ID' || $fields == $this->primary_key) 
     
    739744 
    740745            // get all entries of this page and post-filter those that really match the query 
     746            $search = mb_strtolower($value); 
    741747            $this->result = new rcube_result_set(0); 
    742748            $entries = ldap_get_entries($this->conn, $this->ldap_result); 
     749 
    743750            for ($i = 0; $i < $entries['count']; $i++) { 
    744751                $rec = $this->_ldap2result($entries[$i]); 
    745                 if (stripos($rec['name'] . $rec['email'], $value) !== false) { 
    746                     $this->result->add($rec); 
    747                     $this->result->count++; 
     752                foreach (array('email', 'name') as $f) { 
     753                    $val = mb_strtolower($rec[$f]); 
     754                    switch ($mode) { 
     755                    case 1: 
     756                        $got = ($val == $search); 
     757                        break; 
     758                    case 2: 
     759                        $got = ($search == substr($val, 0, strlen($search))); 
     760                        break; 
     761                    default: 
     762                        $got = (strpos($val, $search) !== false); 
     763                        break; 
     764                    } 
     765 
     766                    if ($got) { 
     767                        $this->result->add($rec); 
     768                        $this->result->count++; 
     769                        break; 
     770                    } 
    748771                } 
    749772            } 
     
    754777        // use AND operator for advanced searches 
    755778        $filter = is_array($value) ? '(&' : '(|'; 
    756         $wc     = !$strict && $this->prop['fuzzy_search'] ? '*' : ''; 
     779        // set wildcards 
     780        $wp = $ws = ''; 
     781        if (!empty($this->prop['fuzzy_search']) && $mode != 1) { 
     782            $ws = '*'; 
     783            if (!$mode) { 
     784                $wp = '*'; 
     785            } 
     786        } 
    757787 
    758788        if ($fields == '*') 
     
    768798            { 
    769799                foreach ($this->prop['search_fields'] as $field) { 
    770                     $filter .= "($field=$wc" . $this->_quote_string($value) . "$wc)"; 
     800                    $filter .= "($field=$wp" . $this->_quote_string($value) . "$ws)"; 
    771801                } 
    772802            } 
     
    777807                $val = is_array($value) ? $value[$idx] : $value; 
    778808                if ($f = $this->_map_field($field)) { 
    779                     $filter .= "($f=$wc" . $this->_quote_string($val) . "$wc)"; 
     809                    $filter .= "($f=$wp" . $this->_quote_string($val) . "$ws)"; 
    780810                } 
    781811            } 
     
    14341464        $groups = array(); 
    14351465        if ($search) { 
    1436             $search = strtolower($search); 
     1466            $search = mb_strtolower($search); 
    14371467            foreach ($group_cache as $group) { 
    1438                 if (strstr(strtolower($group['name']), $search)) 
     1468                if (strpos(mb_strtolower($group['name']), $search) !== false) 
    14391469                    $groups[] = $group; 
    14401470            } 
     
    15121542            } 
    15131543 
    1514             $group_sortnames[] = strtolower($ldap_data[$i][$sort_attr][0]); 
     1544            $group_sortnames[] = mb_strtolower($ldap_data[$i][$sort_attr][0]); 
    15151545        } 
    15161546 
  • program/steps/addressbook/copy.inc

    r2d761bb rf21a04c  
    6161        // Note: Some addressbooks allows empty email address field 
    6262        if (!empty($a_record['email'])) 
    63             $result = $TARGET->search('email', $a_record['email'], true, true, true); 
     63            $result = $TARGET->search('email', $a_record['email'], 1, true, true); 
    6464        else if (!empty($a_record['name'])) 
    65             $result = $TARGET->search('name', $a_record['name'], true, true, true); 
     65            $result = $TARGET->search('name', $a_record['name'], 1, true, true); 
    6666        else 
    6767            $result = new rcube_result_set(); 
  • program/steps/addressbook/import.inc

    r4d4a2fa rf21a04c  
    175175      if (!$replace && $email) { 
    176176        // compare e-mail address 
    177         $existing = $CONTACTS->search('email', $email, false, false); 
     177        $existing = $CONTACTS->search('email', $email, 1, false); 
    178178        if (!$existing->count && $vcard->displayname) {  // compare display name 
    179           $existing = $CONTACTS->search('name', $vcard->displayname, false, false); 
     179          $existing = $CONTACTS->search('name', $vcard->displayname, 1, false); 
    180180        } 
    181181        if ($existing->count) { 
  • program/steps/addressbook/mailto.inc

    rdc6c4f4 rf21a04c  
    3232        $CONTACTS->set_page(1); 
    3333        $CONTACTS->set_pagesize(count($cid) + 2); // +2 to skip counting query 
    34         $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid, false, true, true, 'email'); 
     34        $recipients = $CONTACTS->search($CONTACTS->primary_key, $cid, 0, true, true, 'email'); 
    3535    } 
    3636} 
  • program/steps/addressbook/save.inc

    r5db6f96 rf21a04c  
    163163  $existing = false; 
    164164  foreach ($CONTACTS->get_col_values('email', $a_record, true) as $email) { 
    165       if ($email && ($res = $CONTACTS->search('email', $email, false, false, true)) && $res->count) { 
     165      if ($email && ($res = $CONTACTS->search('email', $email, 1, false, true)) && $res->count) { 
    166166          $OUTPUT->show_message('contactexists', 'notice', null, false); 
    167167          break; 
  • program/steps/addressbook/search.inc

    rb104e39 rf21a04c  
    138138    } 
    139139 
     140    // Values matching mode 
     141    $mode = (int) $RCMAIL->config->get('addressbook_search_mode'); 
     142 
    140143    // get sources list 
    141144    $sources    = $RCMAIL->get_address_sources(); 
     
    169172 
    170173        // get contacts count 
    171         $result = $source->search($fields, $search, false, false); 
     174        $result = $source->search($fields, $search, $mode, false); 
    172175 
    173176        if (!$result->count) { 
  • program/steps/mail/addcontact.inc

    r39cafac rf21a04c  
    5151      $OUTPUT->send(); 
    5252    } 
    53      
     53 
    5454    $email = rcube_idn_to_ascii($contact['email']); 
    5555    if (!check_email($email, false)) { 
     
    6666      // TODO: show dialog to complete record 
    6767      // if ($error['type'] == rcube_addressbook::ERROR_VALIDATE) { } 
    68        
     68 
    6969      $OUTPUT->show_message($error['message'] ? $error['message'] : 'errorsavingcontact', 'error'); 
    7070      $OUTPUT->send(); 
     
    7272 
    7373    // check for existing contacts 
    74     $existing = $CONTACTS->search('email', $contact['email'], true, false); 
     74    $existing = $CONTACTS->search('email', $contact['email'], 1, false); 
    7575 
    7676    if ($done = $existing->count) 
  • program/steps/mail/autocomplete.inc

    r62c8618 rf21a04c  
    4242 
    4343$MAXNUM = (int)$RCMAIL->config->get('autocomplete_max', 15); 
     44$mode   = (int) $RCMAIL->config->get('addressbook_search_mode'); 
    4445$search = get_input_value('_search', RCUBE_INPUT_GPC, true); 
    4546$source = get_input_value('_source', RCUBE_INPUT_GPC); 
     
    5960    $abook->set_pagesize($MAXNUM); 
    6061 
    61     if ($result = $abook->search(array('email','name'), $search, false, true, true, 'email')) { 
     62    if ($result = $abook->search(array('email','name'), $search, $mode, true, true, 'email')) { 
    6263      while ($sql_arr = $result->iterate()) { 
    6364        // Contact can have more than one e-mail address 
     
    8384 
    8485    // also list matching contact groups 
    85     if ($abook->groups) { 
     86    if ($abook->groups && count($contacts) < $MAXNUM) { 
    8687      foreach ($abook->list_groups($search) as $group) { 
    8788        $abook->reset(); 
Note: See TracChangeset for help on using the changeset viewer.