gXbfB#) ۻbis_IIߪ ۻbis_IIߪ ۻbis_IIߪ ۻbis_II4&D.5;Aϳކ:}Wۻp%7ޔ_#5L@?ss\,fa\eChɛ+MMX,-\_[6Eq_uC^avh ->]+/Wg׿>|"d2D^1=]mwgFN5K]OElf5F \wgFN5K]OwgFN5K]OwgFN5K]O[_׮|S 6 iS&XVŰįwgFN5K]OwgFN5K]OwgFN5K]OW eWD, $*N a}9淚o},Q]ʹc$XlYwgFN5K]OQ+RŞԲ&M.x ۻbis_IIߪ ۻbis_IIߪ ۻbis_II߄}BkH1n@31JѰZ+]U7GM~ع@VHi=Ko-W}/-9]+n)ϮPanٹu+8$!Ã|a*}/<*)Uʓgtmz.|g~:"Di}$IZ{ -hMGd6;L{~XM-I.5J@/ ׽&1ҔdSB 3]#/G>TAT)۷53*-cLnY8#$:`PHd$[5c, @ K>N$d[虠 zQhbls2oBfzLKCkw9WQHwR2GOBIU.AηRFO݀2GOBIU.`΍:E8M2GOBIU. c ^SP.W^R"e u J?t_ũ̕&u2YX0'Lg;C F_J ëKQ3' ])/_j"#:\/A_뵦LfN !nbԟ.X0 n=| ,-/It-q[#O7'"I\v򱞯r-Ee 7w6Q8w74^(w%Ha<$° K ⯒k@:Ⱥ dnQ2d?WNoy8%ϰK?KA~ 4l $-53rXÖtՎGÍ[ mKxk'ۑN<1FZ = 80ˆ!I8/bAK8`G*wM'èi'wާYբ}-xz{뇨FaVNiM 44A^ΞhE%OBm2HYhXmE ,JerT(ovBS jMfoZi%XG;ި`$14E6 Ӗr ʛg)Nijht=[pȴ 䳆@{ -Tp ۧo暻<, ExfW5)#x*C(Aޢ19)1R&".1AY˙Qr/k2=x>IV0/V{\4ܼ(䱼(F &[_BwoPWZ˓bO?1O=~RȄb#a%4$JaK O=9` c~H~\k]?'p~+f%]{b8;tI/Tt[ig癴S`ׯ2`Uoٯ9.v5[,OU!uJ ]9{f;lK ]wcBG-zP6,3|@:%HYhi&H' FGߺun.bbz$}XT@hH T0r# 嬳ҋ= Lۜ<@ѱac,Ԗqgg\?~ҜԟOʘ)8gԭ}_ (G倆v4PO HFΎ/˅'aTFX~궡-+ԟ}Oo2dA9{6<F{.%D*(YDJYz5~c`2܅&vPf3}N> 3I?)4e~).]#ƶqzS1~yo6\-u\!E!OK"q$IxY19;w&fo`e94\76#sU_] 4l~QNu M&_7RaؙX!C[gJN]UZ)ƈ0&<3Ũ699+nKe"aR\! `EAfj1L)\%[P4g.cБԗxqwdbڊ SDR>,du*|./cu]5؝>)> 3 EP@N'9ˆZuoB;F U$)-9k"DƮ@/r9"YLz7?Җ!"͒dI9're{tʝBf;zaiciunt($this->result->records); // update counter if ($nocount) { $this->result->count = $cnt; } else if ($this->list_page <= 1) { if ($cnt < $this->page_size && $subset == 0) { $this->result->count = $cnt; } else if (isset($this->cache['count'])) { $this->result->count = $this->cache['count']; } else { $this->result->count = $this->_count(); } } return $this->result; } /** * Search contacts * * @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 Search mode. Sum of rcube_addressbook::SEARCH_* * @param bool $select True if results are requested, False if count only * @param bool $nocount True to skip the count query (select only) * @param array $required List of fields that cannot be empty * * @return rcube_result_set Contact records and 'count' value */ public function search($fields, $value, $mode = 0, $select = true, $nocount = false, $required = []) { if (!is_array($required) && !empty($required)) { $required = [$required]; } $where = $post_search = []; $mode = intval($mode); // direct ID search if ($fields == 'ID' || $fields == $this->primary_key) { $ids = !is_array($value) ? explode(self::SEPARATOR, $value) : $value; $ids = $this->db->array2list($ids, 'integer'); $where[] = $this->primary_key . ' IN (' . $ids . ')'; } else if (is_array($value)) { foreach ((array) $fields as $idx => $col) { $val = $value[$idx]; if (!strlen($val)) { continue; } // table column if ($col == 'email' && ($mode & rcube_addressbook::SEARCH_STRICT)) { $where[] = $this->db->ilike($col, $val); } else if (in_array($col, $this->table_cols)) { $where[] = $this->fulltext_sql_where($val, $mode, $col); } else { $where[] = '1 = 0'; // unsupported column } } } else { // fulltext search in all fields if ($fields == '*') { $fields = ['name', 'email']; } // require each word in to be present in one of the fields $words = ($mode & rcube_addressbook::SEARCH_STRICT) ? [$value] : rcube_utils::tokenize_string($value, 1); foreach ($words as $word) { $groups = []; foreach ((array) $fields as $idx => $col) { if ($col == 'email' && ($mode & rcube_addressbook::SEARCH_STRICT)) { $groups[] = $this->db->ilike($col, $word); } else if (in_array($col, $this->table_cols)) { $groups[] = $this->fulltext_sql_where($word, $mode, $col); } } $where[] = '(' . implode(' OR ', $groups) . ')'; } } foreach (array_intersect($required, $this->table_cols) as $col) { $where[] = $this->db->quote_identifier($col) . ' <> ' . $this->db->quote(''); } if (!empty($where)) { // use AND operator for advanced searches $where = implode(' AND ', $where); $this->set_search_set($where); if ($select) { $this->list_records(null, 0, $nocount); } else { $this->result = $this->count(); } } else { $this->result = new rcube_result_set(); } return $this->result; } /** * Count number of available contacts in database * * @return int Contacts count */ protected function _count() { // count contacts for this user $sql_result = $this->db->query( "SELECT COUNT(`address_id`) AS cnt" . " FROM " . $this->db->table_name($this->db_name, true) . " WHERE `user_id` = ? AND `type` = ?" . ($this->filter ? " AND (" . $this->filter . ")" : ""), $this->user_id, $this->type ); $sql_arr = $this->db->fetch_assoc($sql_result); $this->cache['count'] = (int) $sql_arr['cnt']; return $this->cache['count']; } /** * Get a specific contact record * * @param mixed $id Record identifier(s) * @param bool $assoc Enables returning associative array * * @return rcube_result_set|array Result object with all record fields */ function get_record($id, $assoc = false) { // return cached result if ($this->result && ($first = $this->result->first()) && $first[$this->primary_key] == $id) { return $assoc ? $first : $this->result; } $this->db->query( "SELECT * FROM " . $this->db->table_name($this->db_name, true) . " WHERE `address_id` = ? AND `user_id` = ?", $id, $this->user_id ); $this->result = null; if ($record = $this->db->fetch_assoc()) { $record['ID'] = $record['address_id']; $this->result = new rcube_result_set(1); $this->result->add($record); } return $assoc && !empty($record) ? $record : $this->result; } /** * Check the given data before saving. * If input not valid, the message to display can be fetched using get_error() * * @param array &$save_data Associative array with data to save * @param bool $autofix Try to fix/complete record automatically * * @return bool True if input is valid, False if not. */ public function validate(&$save_data, $autofix = false) { $email = array_filter($this->get_col_values('email', $save_data, true)); // require email if (empty($email) || count($email) > 1) { $this->set_error(self::ERROR_VALIDATE, 'noemailwarning'); return false; } $email = $email[0]; // check validity of the email address if (!rcube_utils::check_email(rcube_utils::idn_to_ascii($email))) { $rcube = rcube::get_instance(); $error = $rcube->gettext(['name' => 'emailformaterror', 'vars' => ['email' => $email]]); $this->set_error(self::ERROR_VALIDATE, $error); return false; } return true; } /** * Create a new contact record * * @param array $save_data Associative array with save data * @param bool $check Enables validity checks * * @return int|bool The created record ID on success, False on error */ function insert($save_data, $check = false) { if (!is_array($save_data)) { return false; } if ($check && ($existing = $this->search('email', $save_data['email'], false, false))) { if ($existing->count) { return false; } } $this->cache = null; $this->db->query( "INSERT INTO " . $this->db->table_name($this->db_name, true) . " (`user_id`, `changed`, `type`, `name`, `email`)" . " VALUES (?, " . $this->db->now() . ", ?, ?, ?)", $this->user_id, $this->type, $save_data['name'], $save_data['email'] ); return $this->db->insert_id($this->db_name); } /** * Update a specific contact record * * @param mixed $id Record identifier * @param array $save_cols Associative array with save data * * @return bool True on success, False on error */ function update($id, $save_cols) { return false; } /** * Delete one or more contact records * * @param array $ids Record identifiers * @param bool $force Remove record(s) irreversible (unsupported) * * @return int|false Number of removed records */ function delete($ids, $force = true) { if (!is_array($ids)) { $ids = explode(self::SEPARATOR, $ids); } $ids = $this->db->array2list($ids, 'integer'); // flag record as deleted (always) $this->db->query( "DELETE FROM " . $this->db->table_name($this->db_name, true) . " WHERE `user_id` = ? AND `type` = ? AND `address_id` IN ($ids)", $this->user_id, $this->type ); $this->cache = null; return $this->db->affected_rows(); } /** * Remove all records from the database * * @param bool $with_groups Remove also groups * * @return int Number of removed records */ function delete_all($with_groups = false) { $this->db->query("DELETE FROM " . $this->db->table_name($this->db_name, true) . " WHERE `user_id` = ? AND `type` = ?", $this->user_id, $this->type ); $this->cache = null; return $this->db->affected_rows(); } }