Mercurial > hg > rc2
comparison program/lib/Roundcube/rcube_user.php @ 0:4681f974d28b
vanilla 1.3.3 distro, I hope
author | Charlie Root |
---|---|
date | Thu, 04 Jan 2018 15:52:31 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4681f974d28b |
---|---|
1 <?php | |
2 | |
3 /** | |
4 +-----------------------------------------------------------------------+ | |
5 | This file is part of the Roundcube Webmail client | | |
6 | Copyright (C) 2005-2012, The Roundcube Dev Team | | |
7 | | | |
8 | Licensed under the GNU General Public License version 3 or | | |
9 | any later version with exceptions for skins & plugins. | | |
10 | See the README file for a full license statement. | | |
11 | | | |
12 | PURPOSE: | | |
13 | This class represents a system user linked and provides access | | |
14 | to the related database records. | | |
15 +-----------------------------------------------------------------------+ | |
16 | Author: Thomas Bruederli <roundcube@gmail.com> | | |
17 | Author: Aleksander Machniak <alec@alec.pl> | | |
18 +-----------------------------------------------------------------------+ | |
19 */ | |
20 | |
21 /** | |
22 * Class representing a system user | |
23 * | |
24 * @package Framework | |
25 * @subpackage Core | |
26 */ | |
27 class rcube_user | |
28 { | |
29 public $ID; | |
30 public $data; | |
31 public $language; | |
32 public $prefs; | |
33 | |
34 /** | |
35 * Holds database connection. | |
36 * | |
37 * @var rcube_db | |
38 */ | |
39 private $db; | |
40 | |
41 /** | |
42 * Framework object. | |
43 * | |
44 * @var rcube | |
45 */ | |
46 private $rc; | |
47 | |
48 /** | |
49 * Internal identities cache | |
50 * | |
51 * @var array | |
52 */ | |
53 private $identities = array(); | |
54 | |
55 /** | |
56 * Internal emails cache | |
57 * | |
58 * @var array | |
59 */ | |
60 private $emails; | |
61 | |
62 | |
63 const SEARCH_ADDRESSBOOK = 1; | |
64 const SEARCH_MAIL = 2; | |
65 | |
66 /** | |
67 * Object constructor | |
68 * | |
69 * @param int $id User id | |
70 * @param array $sql_arr SQL result set | |
71 */ | |
72 function __construct($id = null, $sql_arr = null) | |
73 { | |
74 $this->rc = rcube::get_instance(); | |
75 $this->db = $this->rc->get_dbh(); | |
76 | |
77 if ($id && !$sql_arr) { | |
78 $sql_result = $this->db->query( | |
79 "SELECT * FROM " . $this->db->table_name('users', true) | |
80 . " WHERE `user_id` = ?", $id); | |
81 $sql_arr = $this->db->fetch_assoc($sql_result); | |
82 } | |
83 | |
84 if (!empty($sql_arr)) { | |
85 $this->ID = $sql_arr['user_id']; | |
86 $this->data = $sql_arr; | |
87 $this->language = $sql_arr['language']; | |
88 } | |
89 } | |
90 | |
91 /** | |
92 * Build a user name string (as e-mail address) | |
93 * | |
94 * @param string $part Username part (empty or 'local' or 'domain', 'mail') | |
95 * @return string Full user name or its part | |
96 */ | |
97 function get_username($part = null) | |
98 { | |
99 if ($this->data['username']) { | |
100 // return real name | |
101 if (!$part) { | |
102 return $this->data['username']; | |
103 } | |
104 | |
105 list($local, $domain) = explode('@', $this->data['username']); | |
106 | |
107 // at least we should always have the local part | |
108 if ($part == 'local') { | |
109 return $local; | |
110 } | |
111 // if no domain was provided... | |
112 if (empty($domain)) { | |
113 $domain = $this->rc->config->mail_domain($this->data['mail_host']); | |
114 } | |
115 | |
116 if ($part == 'domain') { | |
117 return $domain; | |
118 } | |
119 | |
120 if (!empty($domain)) | |
121 return $local . '@' . $domain; | |
122 else | |
123 return $local; | |
124 } | |
125 | |
126 return false; | |
127 } | |
128 | |
129 /** | |
130 * Get the preferences saved for this user | |
131 * | |
132 * @return array Hash array with prefs | |
133 */ | |
134 function get_prefs() | |
135 { | |
136 if (isset($this->prefs)) { | |
137 return $this->prefs; | |
138 } | |
139 | |
140 $this->prefs = array(); | |
141 | |
142 if (!empty($this->language)) | |
143 $this->prefs['language'] = $this->language; | |
144 | |
145 if ($this->ID) { | |
146 // Preferences from session (write-master is unavailable) | |
147 if (!empty($_SESSION['preferences'])) { | |
148 // Check last write attempt time, try to write again (every 5 minutes) | |
149 if ($_SESSION['preferences_time'] < time() - 5 * 60) { | |
150 $saved_prefs = unserialize($_SESSION['preferences']); | |
151 $this->rc->session->remove('preferences'); | |
152 $this->rc->session->remove('preferences_time'); | |
153 $this->save_prefs($saved_prefs); | |
154 } | |
155 else { | |
156 $this->data['preferences'] = $_SESSION['preferences']; | |
157 } | |
158 } | |
159 | |
160 if ($this->data['preferences']) { | |
161 $this->prefs += (array)unserialize($this->data['preferences']); | |
162 } | |
163 } | |
164 | |
165 return $this->prefs; | |
166 } | |
167 | |
168 /** | |
169 * Write the given user prefs to the user's record | |
170 * | |
171 * @param array $a_user_prefs User prefs to save | |
172 * @param bool $no_session Simplified language/preferences handling | |
173 * | |
174 * @return boolean True on success, False on failure | |
175 */ | |
176 function save_prefs($a_user_prefs, $no_session = false) | |
177 { | |
178 if (!$this->ID) | |
179 return false; | |
180 | |
181 $plugin = $this->rc->plugins->exec_hook('preferences_update', array( | |
182 'userid' => $this->ID, 'prefs' => $a_user_prefs, 'old' => (array)$this->get_prefs())); | |
183 | |
184 if (!empty($plugin['abort'])) { | |
185 return; | |
186 } | |
187 | |
188 $a_user_prefs = $plugin['prefs']; | |
189 $old_prefs = $plugin['old']; | |
190 $config = $this->rc->config; | |
191 $defaults = $config->all(); | |
192 | |
193 // merge (partial) prefs array with existing settings | |
194 $this->prefs = $save_prefs = $a_user_prefs + $old_prefs; | |
195 unset($save_prefs['language']); | |
196 | |
197 // don't save prefs with default values if they haven't been changed yet | |
198 // Warning: we use result of rcube_config::all() here instead of just get() (#5782) | |
199 foreach ($a_user_prefs as $key => $value) { | |
200 if ($value === null || (!isset($old_prefs[$key]) && $value === $defaults[$key])) { | |
201 unset($save_prefs[$key]); | |
202 } | |
203 } | |
204 | |
205 $save_prefs = serialize($save_prefs); | |
206 if (!$no_session) { | |
207 $this->language = $_SESSION['language']; | |
208 } | |
209 | |
210 $this->db->query( | |
211 "UPDATE ".$this->db->table_name('users', true). | |
212 " SET `preferences` = ?, `language` = ?". | |
213 " WHERE `user_id` = ?", | |
214 $save_prefs, | |
215 $this->language, | |
216 $this->ID); | |
217 | |
218 // Update success | |
219 if ($this->db->affected_rows() !== false) { | |
220 $this->data['preferences'] = $save_prefs; | |
221 | |
222 if (!$no_session) { | |
223 $config->set_user_prefs($this->prefs); | |
224 | |
225 if (isset($_SESSION['preferences'])) { | |
226 $this->rc->session->remove('preferences'); | |
227 $this->rc->session->remove('preferences_time'); | |
228 } | |
229 } | |
230 | |
231 return true; | |
232 } | |
233 // Update error, but we are using replication (we have read-only DB connection) | |
234 // and we are storing session not in the SQL database | |
235 // we can store preferences in session and try to write later (see get_prefs()) | |
236 else if (!$no_session && $this->db->is_replicated() | |
237 && $config->get('session_storage', 'db') != 'db' | |
238 ) { | |
239 $_SESSION['preferences'] = $save_prefs; | |
240 $_SESSION['preferences_time'] = time(); | |
241 $config->set_user_prefs($this->prefs); | |
242 $this->data['preferences'] = $save_prefs; | |
243 } | |
244 | |
245 return false; | |
246 } | |
247 | |
248 /** | |
249 * Generate a unique hash to identify this user whith | |
250 */ | |
251 function get_hash() | |
252 { | |
253 $prefs = $this->get_prefs(); | |
254 | |
255 // generate a random hash and store it in user prefs | |
256 if (empty($prefs['client_hash'])) { | |
257 $prefs['client_hash'] = rcube_utils::random_bytes(16); | |
258 $this->save_prefs(array('client_hash' => $prefs['client_hash'])); | |
259 } | |
260 | |
261 return $prefs['client_hash']; | |
262 } | |
263 | |
264 /** | |
265 * Return a list of all user emails (from identities) | |
266 * | |
267 * @param bool Return only default identity | |
268 * | |
269 * @return array List of emails (identity_id, name, email) | |
270 */ | |
271 function list_emails($default = false) | |
272 { | |
273 if ($this->emails === null) { | |
274 $this->emails = array(); | |
275 | |
276 $sql_result = $this->db->query( | |
277 "SELECT `identity_id`, `name`, `email`" | |
278 ." FROM " . $this->db->table_name('identities', true) | |
279 ." WHERE `user_id` = ? AND `del` <> 1" | |
280 ." ORDER BY `standard` DESC, `name` ASC, `email` ASC, `identity_id` ASC", | |
281 $this->ID); | |
282 | |
283 while ($sql_arr = $this->db->fetch_assoc($sql_result)) { | |
284 $this->emails[] = $sql_arr; | |
285 } | |
286 } | |
287 | |
288 return $default ? $this->emails[0] : $this->emails; | |
289 } | |
290 | |
291 /** | |
292 * Get default identity of this user | |
293 * | |
294 * @param int $id Identity ID. If empty, the default identity is returned | |
295 * @return array Hash array with all cols of the identity record | |
296 */ | |
297 function get_identity($id = null) | |
298 { | |
299 $id = (int)$id; | |
300 // cache identities for better performance | |
301 if (!array_key_exists($id, $this->identities)) { | |
302 $result = $this->list_identities($id ? "AND `identity_id` = $id" : ''); | |
303 $this->identities[$id] = $result[0]; | |
304 } | |
305 | |
306 return $this->identities[$id]; | |
307 } | |
308 | |
309 /** | |
310 * Return a list of all identities linked with this user | |
311 * | |
312 * @param string $sql_add Optional WHERE clauses | |
313 * @param bool $formatted Format identity email and name | |
314 * | |
315 * @return array List of identities | |
316 */ | |
317 function list_identities($sql_add = '', $formatted = false) | |
318 { | |
319 $result = array(); | |
320 | |
321 $sql_result = $this->db->query( | |
322 "SELECT * FROM ".$this->db->table_name('identities', true). | |
323 " WHERE `del` <> 1 AND `user_id` = ?". | |
324 ($sql_add ? " ".$sql_add : ""). | |
325 " ORDER BY `standard` DESC, `name` ASC, `email` ASC, `identity_id` ASC", | |
326 $this->ID); | |
327 | |
328 while ($sql_arr = $this->db->fetch_assoc($sql_result)) { | |
329 if ($formatted) { | |
330 $ascii_email = format_email($sql_arr['email']); | |
331 $utf8_email = format_email(rcube_utils::idn_to_utf8($ascii_email)); | |
332 | |
333 $sql_arr['email_ascii'] = $ascii_email; | |
334 $sql_arr['email'] = $utf8_email; | |
335 $sql_arr['ident'] = format_email_recipient($ascii_email, $sql_arr['name']); | |
336 } | |
337 | |
338 $result[] = $sql_arr; | |
339 } | |
340 | |
341 return $result; | |
342 } | |
343 | |
344 /** | |
345 * Update a specific identity record | |
346 * | |
347 * @param int $iid Identity ID | |
348 * @param array $data Hash array with col->value pairs to save | |
349 * @return boolean True if saved successfully, false if nothing changed | |
350 */ | |
351 function update_identity($iid, $data) | |
352 { | |
353 if (!$this->ID) | |
354 return false; | |
355 | |
356 $query_cols = $query_params = array(); | |
357 | |
358 foreach ((array)$data as $col => $value) { | |
359 $query_cols[] = $this->db->quote_identifier($col) . ' = ?'; | |
360 $query_params[] = $value; | |
361 } | |
362 $query_params[] = $iid; | |
363 $query_params[] = $this->ID; | |
364 | |
365 $sql = "UPDATE ".$this->db->table_name('identities', true). | |
366 " SET `changed` = ".$this->db->now().", ".join(', ', $query_cols). | |
367 " WHERE `identity_id` = ?". | |
368 " AND `user_id` = ?". | |
369 " AND `del` <> 1"; | |
370 | |
371 call_user_func_array(array($this->db, 'query'), | |
372 array_merge(array($sql), $query_params)); | |
373 | |
374 // clear the cache | |
375 $this->identities = array(); | |
376 $this->emails = null; | |
377 | |
378 return $this->db->affected_rows(); | |
379 } | |
380 | |
381 /** | |
382 * Create a new identity record linked with this user | |
383 * | |
384 * @param array $data Hash array with col->value pairs to save | |
385 * @return int The inserted identity ID or false on error | |
386 */ | |
387 function insert_identity($data) | |
388 { | |
389 if (!$this->ID) | |
390 return false; | |
391 | |
392 unset($data['user_id']); | |
393 | |
394 $insert_cols = $insert_values = array(); | |
395 foreach ((array)$data as $col => $value) { | |
396 $insert_cols[] = $this->db->quote_identifier($col); | |
397 $insert_values[] = $value; | |
398 } | |
399 $insert_cols[] = $this->db->quote_identifier('user_id'); | |
400 $insert_values[] = $this->ID; | |
401 | |
402 $sql = "INSERT INTO ".$this->db->table_name('identities', true). | |
403 " (`changed`, ".join(', ', $insert_cols).")". | |
404 " VALUES (".$this->db->now().", ".join(', ', array_pad(array(), count($insert_values), '?')).")"; | |
405 | |
406 call_user_func_array(array($this->db, 'query'), | |
407 array_merge(array($sql), $insert_values)); | |
408 | |
409 // clear the cache | |
410 $this->identities = array(); | |
411 $this->emails = null; | |
412 | |
413 return $this->db->insert_id('identities'); | |
414 } | |
415 | |
416 /** | |
417 * Mark the given identity as deleted | |
418 * | |
419 * @param int $iid Identity ID | |
420 * @return boolean True if deleted successfully, false if nothing changed | |
421 */ | |
422 function delete_identity($iid) | |
423 { | |
424 if (!$this->ID) | |
425 return false; | |
426 | |
427 $sql_result = $this->db->query( | |
428 "SELECT count(*) AS ident_count FROM ".$this->db->table_name('identities', true). | |
429 " WHERE `user_id` = ? AND `del` <> 1", | |
430 $this->ID); | |
431 | |
432 $sql_arr = $this->db->fetch_assoc($sql_result); | |
433 | |
434 // we'll not delete last identity | |
435 if ($sql_arr['ident_count'] <= 1) | |
436 return -1; | |
437 | |
438 $this->db->query( | |
439 "UPDATE ".$this->db->table_name('identities', true). | |
440 " SET `del` = 1, `changed` = ".$this->db->now(). | |
441 " WHERE `user_id` = ?". | |
442 " AND `identity_id` = ?", | |
443 $this->ID, | |
444 $iid); | |
445 | |
446 // clear the cache | |
447 $this->identities = array(); | |
448 $this->emails = null; | |
449 | |
450 return $this->db->affected_rows(); | |
451 } | |
452 | |
453 /** | |
454 * Make this identity the default one for this user | |
455 * | |
456 * @param int $iid The identity ID | |
457 */ | |
458 function set_default($iid) | |
459 { | |
460 if ($this->ID && $iid) { | |
461 $this->db->query( | |
462 "UPDATE ".$this->db->table_name('identities', true). | |
463 " SET `standard` = '0'". | |
464 " WHERE `user_id` = ? AND `identity_id` <> ?", | |
465 $this->ID, | |
466 $iid); | |
467 | |
468 unset($this->identities[0]); | |
469 } | |
470 } | |
471 | |
472 /** | |
473 * Update user's last_login timestamp | |
474 */ | |
475 function touch() | |
476 { | |
477 if ($this->ID) { | |
478 $this->db->query( | |
479 "UPDATE ".$this->db->table_name('users', true). | |
480 " SET `last_login` = ".$this->db->now(). | |
481 " WHERE `user_id` = ?", | |
482 $this->ID); | |
483 } | |
484 } | |
485 | |
486 /** | |
487 * Update user's failed_login timestamp and counter | |
488 */ | |
489 function failed_login() | |
490 { | |
491 if ($this->ID && ($rate = (int) $this->rc->config->get('login_rate_limit', 3))) { | |
492 if (empty($this->data['failed_login'])) { | |
493 $failed_login = new DateTime('now'); | |
494 $counter = 1; | |
495 } | |
496 else { | |
497 $failed_login = new DateTime($this->data['failed_login']); | |
498 $threshold = new DateTime('- 60 seconds'); | |
499 | |
500 if ($failed_login < $threshold) { | |
501 $failed_login = new DateTime('now'); | |
502 $counter = 1; | |
503 } | |
504 } | |
505 | |
506 $this->db->query( | |
507 "UPDATE " . $this->db->table_name('users', true) | |
508 . " SET `failed_login` = ?" | |
509 . ", `failed_login_counter` = " . ($counter ?: "`failed_login_counter` + 1") | |
510 . " WHERE `user_id` = ?", | |
511 $failed_login, $this->ID); | |
512 } | |
513 } | |
514 | |
515 /** | |
516 * Checks if the account is locked, e.g. as a result of brute-force prevention | |
517 */ | |
518 function is_locked() | |
519 { | |
520 if (empty($this->data['failed_login'])) { | |
521 return false; | |
522 } | |
523 | |
524 if ($rate = (int) $this->rc->config->get('login_rate_limit', 3)) { | |
525 $last_failed = new DateTime($this->data['failed_login']); | |
526 $threshold = new DateTime('- 60 seconds'); | |
527 | |
528 if ($last_failed > $threshold && $this->data['failed_login_counter'] >= $rate) { | |
529 return true; | |
530 } | |
531 } | |
532 | |
533 return false; | |
534 } | |
535 | |
536 /** | |
537 * Clear the saved object state | |
538 */ | |
539 function reset() | |
540 { | |
541 $this->ID = null; | |
542 $this->data = null; | |
543 } | |
544 | |
545 /** | |
546 * Find a user record matching the given name and host | |
547 * | |
548 * @param string $user IMAP user name | |
549 * @param string $host IMAP host name | |
550 * @return rcube_user New user instance | |
551 */ | |
552 static function query($user, $host) | |
553 { | |
554 $dbh = rcube::get_instance()->get_dbh(); | |
555 $config = rcube::get_instance()->config; | |
556 | |
557 // query for matching user name | |
558 $sql_result = $dbh->query("SELECT * FROM " . $dbh->table_name('users', true) | |
559 ." WHERE `mail_host` = ? AND `username` = ?", $host, $user); | |
560 | |
561 $sql_arr = $dbh->fetch_assoc($sql_result); | |
562 | |
563 // username not found, try aliases from identities | |
564 if (empty($sql_arr) && $config->get('user_aliases') && strpos($user, '@')) { | |
565 $sql_result = $dbh->limitquery("SELECT u.*" | |
566 ." FROM " . $dbh->table_name('users', true) . " u" | |
567 ." JOIN " . $dbh->table_name('identities', true) . " i ON (i.`user_id` = u.`user_id`)" | |
568 ." WHERE `email` = ? AND `del` <> 1", 0, 1, $user); | |
569 | |
570 $sql_arr = $dbh->fetch_assoc($sql_result); | |
571 } | |
572 | |
573 // user already registered -> overwrite username | |
574 if ($sql_arr) { | |
575 return new rcube_user($sql_arr['user_id'], $sql_arr); | |
576 } | |
577 | |
578 return false; | |
579 } | |
580 | |
581 /** | |
582 * Create a new user record and return a rcube_user instance | |
583 * | |
584 * @param string $user IMAP user name | |
585 * @param string $host IMAP host | |
586 * @return rcube_user New user instance | |
587 */ | |
588 static function create($user, $host) | |
589 { | |
590 $user_name = ''; | |
591 $user_email = ''; | |
592 $rcube = rcube::get_instance(); | |
593 $dbh = $rcube->get_dbh(); | |
594 | |
595 // try to resolve user in virtuser table and file | |
596 if ($email_list = self::user2email($user, false, true)) { | |
597 $user_email = is_array($email_list[0]) ? $email_list[0]['email'] : $email_list[0]; | |
598 } | |
599 | |
600 $data = $rcube->plugins->exec_hook('user_create', array( | |
601 'host' => $host, | |
602 'user' => $user, | |
603 'user_name' => $user_name, | |
604 'user_email' => $user_email, | |
605 'email_list' => $email_list, | |
606 'language' => $_SESSION['language'], | |
607 )); | |
608 | |
609 // plugin aborted this operation | |
610 if ($data['abort']) { | |
611 return false; | |
612 } | |
613 | |
614 $dbh->query( | |
615 "INSERT INTO ".$dbh->table_name('users', true). | |
616 " (`created`, `last_login`, `username`, `mail_host`, `language`)". | |
617 " VALUES (".$dbh->now().", ".$dbh->now().", ?, ?, ?)", | |
618 $data['user'], | |
619 $data['host'], | |
620 $data['language']); | |
621 | |
622 if ($user_id = $dbh->insert_id('users')) { | |
623 // create rcube_user instance to make plugin hooks work | |
624 $user_instance = new rcube_user($user_id, array( | |
625 'user_id' => $user_id, | |
626 'username' => $data['user'], | |
627 'mail_host' => $data['host'], | |
628 'language' => $data['language'], | |
629 )); | |
630 $rcube->user = $user_instance; | |
631 $mail_domain = $rcube->config->mail_domain($data['host']); | |
632 $user_name = $data['user_name']; | |
633 $user_email = $data['user_email']; | |
634 $email_list = $data['email_list']; | |
635 | |
636 if (empty($email_list)) { | |
637 if (empty($user_email)) { | |
638 $user_email = strpos($data['user'], '@') ? $user : sprintf('%s@%s', $data['user'], $mail_domain); | |
639 } | |
640 $email_list[] = $user_email; | |
641 } | |
642 // identities_level check | |
643 else if (count($email_list) > 1 && $rcube->config->get('identities_level', 0) > 1) { | |
644 $email_list = array($email_list[0]); | |
645 } | |
646 | |
647 if (empty($user_name)) { | |
648 $user_name = $data['user']; | |
649 } | |
650 | |
651 // create new identities records | |
652 $standard = 1; | |
653 foreach ($email_list as $row) { | |
654 $record = array(); | |
655 | |
656 if (is_array($row)) { | |
657 if (empty($row['email'])) { | |
658 continue; | |
659 } | |
660 $record = $row; | |
661 } | |
662 else { | |
663 $record['email'] = $row; | |
664 } | |
665 | |
666 if (empty($record['name'])) { | |
667 $record['name'] = $user_name != $record['email'] ? $user_name : ''; | |
668 } | |
669 | |
670 $record['user_id'] = $user_id; | |
671 $record['standard'] = $standard; | |
672 | |
673 $plugin = $rcube->plugins->exec_hook('identity_create', | |
674 array('login' => true, 'record' => $record)); | |
675 | |
676 if (!$plugin['abort'] && $plugin['record']['email']) { | |
677 $rcube->user->insert_identity($plugin['record']); | |
678 } | |
679 $standard = 0; | |
680 } | |
681 } | |
682 else { | |
683 rcube::raise_error(array( | |
684 'code' => 500, | |
685 'type' => 'php', | |
686 'line' => __LINE__, | |
687 'file' => __FILE__, | |
688 'message' => "Failed to create new user"), true, false); | |
689 } | |
690 | |
691 return $user_id ? $user_instance : false; | |
692 } | |
693 | |
694 /** | |
695 * Resolve username using a virtuser plugins | |
696 * | |
697 * @param string $email E-mail address to resolve | |
698 * @return string Resolved IMAP username | |
699 */ | |
700 static function email2user($email) | |
701 { | |
702 $rcube = rcube::get_instance(); | |
703 $plugin = $rcube->plugins->exec_hook('email2user', | |
704 array('email' => $email, 'user' => NULL)); | |
705 | |
706 return $plugin['user']; | |
707 } | |
708 | |
709 /** | |
710 * Resolve e-mail address from virtuser plugins | |
711 * | |
712 * @param string $user User name | |
713 * @param boolean $first If true returns first found entry | |
714 * @param boolean $extended If true returns email as array (email and name for identity) | |
715 * @return mixed Resolved e-mail address string or array of strings | |
716 */ | |
717 static function user2email($user, $first=true, $extended=false) | |
718 { | |
719 $rcube = rcube::get_instance(); | |
720 $plugin = $rcube->plugins->exec_hook('user2email', | |
721 array('email' => NULL, 'user' => $user, | |
722 'first' => $first, 'extended' => $extended)); | |
723 | |
724 return empty($plugin['email']) ? NULL : $plugin['email']; | |
725 } | |
726 | |
727 /** | |
728 * Return a list of saved searches linked with this user | |
729 * | |
730 * @param int $type Search type | |
731 * | |
732 * @return array List of saved searches indexed by search ID | |
733 */ | |
734 function list_searches($type) | |
735 { | |
736 $plugin = $this->rc->plugins->exec_hook('saved_search_list', array('type' => $type)); | |
737 | |
738 if ($plugin['abort']) { | |
739 return (array) $plugin['result']; | |
740 } | |
741 | |
742 $result = array(); | |
743 | |
744 $sql_result = $this->db->query( | |
745 "SELECT `search_id` AS id, `name`" | |
746 ." FROM ".$this->db->table_name('searches', true) | |
747 ." WHERE `user_id` = ? AND `type` = ?" | |
748 ." ORDER BY `name`", | |
749 (int) $this->ID, (int) $type); | |
750 | |
751 while ($sql_arr = $this->db->fetch_assoc($sql_result)) { | |
752 $sql_arr['data'] = unserialize($sql_arr['data']); | |
753 $result[$sql_arr['id']] = $sql_arr; | |
754 } | |
755 | |
756 return $result; | |
757 } | |
758 | |
759 /** | |
760 * Return saved search data. | |
761 * | |
762 * @param int $id Row identifier | |
763 * | |
764 * @return array Data | |
765 */ | |
766 function get_search($id) | |
767 { | |
768 $plugin = $this->rc->plugins->exec_hook('saved_search_get', array('id' => $id)); | |
769 | |
770 if ($plugin['abort']) { | |
771 return $plugin['result']; | |
772 } | |
773 | |
774 $sql_result = $this->db->query( | |
775 "SELECT `name`, `data`, `type`" | |
776 . " FROM ".$this->db->table_name('searches', true) | |
777 . " WHERE `user_id` = ?" | |
778 ." AND `search_id` = ?", | |
779 (int) $this->ID, (int) $id); | |
780 | |
781 while ($sql_arr = $this->db->fetch_assoc($sql_result)) { | |
782 return array( | |
783 'id' => $id, | |
784 'name' => $sql_arr['name'], | |
785 'type' => $sql_arr['type'], | |
786 'data' => unserialize($sql_arr['data']), | |
787 ); | |
788 } | |
789 | |
790 return null; | |
791 } | |
792 | |
793 /** | |
794 * Deletes given saved search record | |
795 * | |
796 * @param int $sid Search ID | |
797 * | |
798 * @return boolean True if deleted successfully, false if nothing changed | |
799 */ | |
800 function delete_search($sid) | |
801 { | |
802 if (!$this->ID) | |
803 return false; | |
804 | |
805 $this->db->query( | |
806 "DELETE FROM ".$this->db->table_name('searches', true) | |
807 ." WHERE `user_id` = ?" | |
808 ." AND `search_id` = ?", | |
809 (int) $this->ID, $sid); | |
810 | |
811 return $this->db->affected_rows(); | |
812 } | |
813 | |
814 /** | |
815 * Create a new saved search record linked with this user | |
816 * | |
817 * @param array $data Hash array with col->value pairs to save | |
818 * | |
819 * @return int The inserted search ID or false on error | |
820 */ | |
821 function insert_search($data) | |
822 { | |
823 if (!$this->ID) | |
824 return false; | |
825 | |
826 $insert_cols[] = 'user_id'; | |
827 $insert_values[] = (int) $this->ID; | |
828 $insert_cols[] = $this->db->quote_identifier('type'); | |
829 $insert_values[] = (int) $data['type']; | |
830 $insert_cols[] = $this->db->quote_identifier('name'); | |
831 $insert_values[] = $data['name']; | |
832 $insert_cols[] = $this->db->quote_identifier('data'); | |
833 $insert_values[] = serialize($data['data']); | |
834 | |
835 $sql = "INSERT INTO ".$this->db->table_name('searches', true) | |
836 ." (".join(', ', $insert_cols).")" | |
837 ." VALUES (".join(', ', array_pad(array(), count($insert_values), '?')).")"; | |
838 | |
839 call_user_func_array(array($this->db, 'query'), | |
840 array_merge(array($sql), $insert_values)); | |
841 | |
842 return $this->db->insert_id('searches'); | |
843 } | |
844 } |