removing debuggin entry. /me bad.
[squirrelmail.git] / functions / addressbook.php
CommitLineData
5100704d 1<?php
35586184 2/**
6ad2bbe2 3 * functions/addressbook.php - Functions and classes for the addressbook system
35586184 4 *
6c84ba1e 5 * Copyright (c) 1999-2005 The SquirrelMail Project Team
35586184 6 * Licensed under the GNU GPL. For full terms see the file COPYING.
7 *
6ad2bbe2 8 * Functions require SM_PATH and support of forms.php functions
35586184 9 *
a9d318b0 10 * @version $Id$
d6c32258 11 * @package squirrelmail
a9d318b0 12 * @subpackage addressbook
35586184 13 */
14
04875ae0 15/**
16 * If SM_PATH isn't defined, define it. Required to include files.
17 * @ignore
18 */
19if (!defined('SM_PATH')) {
20 define('SM_PATH','../');
21}
22
23/* make sure that display_messages.php is loaded */
24include_once(SM_PATH . 'functions/display_messages.php');
25
30e9932c 26global $addrbook_dsn, $addrbook_global_dsn;
81fa4801 27
d6c32258 28/**
81fa4801 29 Create and initialize an addressbook object.
30 Returns the created object
31*/
32function addressbook_init($showerr = true, $onlylocal = false) {
04875ae0 33 global $data_dir, $username, $color, $ldap_server, $address_book_global_filename;
81fa4801 34 global $addrbook_dsn, $addrbook_table;
4272758c 35 global $abook_global_file, $abook_global_file_writeable;
30e9932c 36 global $addrbook_global_dsn, $addrbook_global_table, $addrbook_global_writeable, $addrbook_global_listing;
81fa4801 37
38 /* Create a new addressbook object */
39 $abook = new AddressBook;
40
04875ae0 41 /* Create empty error message */
42 $abook_init_error='';
43
81fa4801 44 /*
45 Always add a local backend. We use *either* file-based *or* a
46 database addressbook. If $addrbook_dsn is set, the database
47 backend is used. If not, addressbooks are stores in files.
48 */
49 if (isset($addrbook_dsn) && !empty($addrbook_dsn)) {
50 /* Database */
51 if (!isset($addrbook_table) || empty($addrbook_table)) {
52 $addrbook_table = 'address';
53 }
54 $r = $abook->add_backend('database', Array('dsn' => $addrbook_dsn,
55 'owner' => $username,
56 'table' => $addrbook_table));
57 if (!$r && $showerr) {
58 echo _("Error initializing addressbook database.");
59 exit;
60 }
61 } else {
62 /* File */
63 $filename = getHashedFile($username, $data_dir, "$username.abook");
64 $r = $abook->add_backend('local_file', Array('filename' => $filename,
65 'create' => true));
66 if(!$r && $showerr) {
67 printf( _("Error opening file %s"), $filename );
68 exit;
69 }
70
71 }
72
73 /* This would be for the global addressbook */
4272758c 74 if (isset($abook_global_file) && isset($abook_global_file_writeable)
91e0dccc 75 && trim($abook_global_file)!=''){
4272758c 76 // Detect place of address book
77 if (! preg_match("/[\/\\\]/",$abook_global_file)) {
e4a468a7 78 /* no path chars, address book stored in data directory
79 * make sure that there is a slash between data directory
80 * and address book file name
81 */
82 $abook_global_filename=$data_dir
83 . ((substr($data_dir, -1) != '/') ? '/' : '')
84 . $abook_global_file;
4272758c 85 } elseif (preg_match("/^\/|\w:/",$abook_global_file)) {
86 // full path is set in options (starts with slash or x:)
87 $abook_global_filename=$abook_global_file;
88 } else {
89 $abook_global_filename=SM_PATH . $abook_global_file;
90 }
91 $r = $abook->add_backend('local_file',array('filename'=>$abook_global_filename,
92 'name' => _("Global address book"),
93 'detect_writeable' => false,
94 'writeable'=> $abook_global_file_writeable));
04875ae0 95
96 /* global abook init error is not fatal. add error message and continue */
81fa4801 97 if (!$r && $showerr) {
04875ae0 98 $abook_init_error.=_("Error initializing global addressbook.") . "<br />" . $abook->error;
81fa4801 99 }
100 }
101
30e9932c 102 /* Load global addressbook from SQL if configured */
103 if (isset($addrbook_global_dsn) && !empty($addrbook_global_dsn)) {
104 /* Database configured */
105 if (!isset($addrbook_global_table) || empty($addrbook_global_table)) {
c1ac62d4 106 $addrbook_global_table = 'global_abook';
30e9932c 107 }
108 $r = $abook->add_backend('database',
c1ac62d4 109 Array('dsn' => $addrbook_global_dsn,
110 'owner' => 'global',
111 'name' => _("Global address book"),
112 'writeable' => $addrbook_global_writeable,
113 'listing' => $addrbook_global_listing,
114 'table' => $addrbook_global_table));
30e9932c 115 }
116
df788686 117 /*
118 * hook allows to include different address book backends.
119 * plugins should extract $abook and $r from arguments
120 * and use same add_backend commands as above functions.
e4a468a7 121 * @since 1.5.1
df788686 122 */
123 $hookReturn = do_hook('abook_init', $abook, $r);
124 $abook = $hookReturn[1];
125 $r = $hookReturn[2];
62f7daa5 126
81fa4801 127 if ($onlylocal) {
04875ae0 128 /* display error message, if present */
129 if ($abook_init_error!='' && $showerr) {
130 error_box($abook_init_error,$color);
131 }
81fa4801 132 return $abook;
133 }
134
135 /* Load configured LDAP servers (if PHP has LDAP support) */
136 if (isset($ldap_server) && is_array($ldap_server) && function_exists('ldap_connect')) {
137 reset($ldap_server);
138 while (list($undef,$param) = each($ldap_server)) {
139 if (is_array($param)) {
140 $r = $abook->add_backend('ldap_server', $param);
141 if (!$r && $showerr) {
142 printf( '&nbsp;' . _("Error initializing LDAP server %s:") .
6fd95361 143 "<br />\n", $param['host']);
81fa4801 144 echo '&nbsp;' . $abook->error;
145 exit;
146 }
147 }
148 }
149 }
4935919f 150
04875ae0 151 /**
152 * display address book init errors.
153 */
154 if ($abook_init_error!='' && $showerr) {
155 error_box($abook_init_error,$color);
156 }
81fa4801 157 /* Return the initialized object */
158 return $abook;
4935919f 159}
160
c1ac62d4 161/**
162 * Display the "new address" form
163 *
164 * Form is not closed and you must add closing form tag.
165 * @since 1.5.1
166 * @param string $form_url form action url
167 * @param string $name form name
168 * @param string $title form title
169 * @param string $button form button name
170 * @param array $defdata values of form fields
171 */
172function abook_create_form($form_url,$name,$title,$button,$defdata=array()) {
173 global $color;
174 echo addForm($form_url, 'post', 'f_add').
175 html_tag( 'table',
176 html_tag( 'tr',
177 html_tag( 'td', "\n". '<strong>' . $title . '</strong>' . "\n",
178 'center', $color[0]
179 )
180 )
181 , 'center', '', 'width="100%"' ) ."\n";
182 address_form($name, $button, $defdata);
183}
184
4935919f 185
81fa4801 186/*
187 * Had to move this function outside of the Addressbook Class
188 * PHP 4.0.4 Seemed to be having problems with inline functions.
abd74f7d 189 * Note: this can return now since we don't support 4.0.4 anymore.
62f7daa5 190 */
81fa4801 191function addressbook_cmp($a,$b) {
4935919f 192
81fa4801 193 if($a['backend'] > $b['backend']) {
194 return 1;
195 } else if($a['backend'] < $b['backend']) {
196 return -1;
197 }
62f7daa5 198
81fa4801 199 return (strtolower($a['name']) > strtolower($b['name'])) ? 1 : -1;
4935919f 200
81fa4801 201}
4935919f 202
c1ac62d4 203/**
204 * Make an input field
205 * @param string $label
206 * @param string $field
207 * @param string $name
208 * @param string $size
209 * @param array $values
210 * @param string $add
211 */
212function addressbook_inp_field($label, $field, $name, $size, $values, $add='') {
213 global $color;
214 $value = ( isset($values[$field]) ? $values[$field] : '');
215
216 if (is_array($value)) {
217 $td_str = addSelect($name.'['.$field.']', $value);
218 } else {
219 $td_str = addInput($name.'['.$field.']', $value, $size);
220 }
221 $td_str .= $add ;
222
223 return html_tag( 'tr' ,
224 html_tag( 'td', $label . ':', 'right', $color[4]) .
225 html_tag( 'td', $td_str, 'left', $color[4])
226 )
227 . "\n";
228}
229
230/**
231 * Output form to add and modify address data
232 */
233function address_form($name, $submittext, $values = array()) {
234 global $color, $squirrelmail_language;
235
236 if ($squirrelmail_language == 'ja_JP') {
237 echo html_tag( 'table',
238 addressbook_inp_field(_("Nickname"), 'nickname', $name, 15, $values,
239 ' <small>' . _("Must be unique") . '</small>') .
240 addressbook_inp_field(_("E-mail address"), 'email', $name, 45, $values, '') .
241 addressbook_inp_field(_("Last name"), 'lastname', $name, 45, $values, '') .
242 addressbook_inp_field(_("First name"), 'firstname', $name, 45, $values, '') .
243 addressbook_inp_field(_("Additional info"), 'label', $name, 45, $values, '') .
244 list_writable_backends($name) .
245 html_tag( 'tr',
246 html_tag( 'td',
247 addSubmit($submittext, $name.'[SUBMIT]'),
248 'center', $color[4], 'colspan="2"')
249 )
250 , 'center', '', 'border="0" cellpadding="1" width="90%"') ."\n";
251 } else {
252 echo html_tag( 'table',
253 addressbook_inp_field(_("Nickname"), 'nickname', $name, 15, $values,
254 ' <small>' . _("Must be unique") . '</small>') .
255 addressbook_inp_field(_("E-mail address"), 'email', $name, 45, $values, '') .
256 addressbook_inp_field(_("First name"), 'firstname', $name, 45, $values, '') .
257 addressbook_inp_field(_("Last name"), 'lastname', $name, 45, $values, '') .
258 addressbook_inp_field(_("Additional info"), 'label', $name, 45, $values, '') .
259 list_writable_backends($name) .
260 html_tag( 'tr',
261 html_tag( 'td',
262 addSubmit($submittext, $name.'[SUBMIT]') ,
263 'center', $color[4], 'colspan="2"')
264 )
265 , 'center', '', 'border="0" cellpadding="1" width="90%"') ."\n";
266 }
267}
268
6ad2bbe2 269/**
270 * Provides list of writeable backends.
271 * Works only when address is added ($name='addaddr')
272 * @param string $name name of form
273 * @return string html formated backend field (select or hidden)
274 */
c1ac62d4 275function list_writable_backends($name) {
276 global $color, $abook;
277 if ( $name != 'addaddr' ) { return; }
6ad2bbe2 278 $writeable_abook = 1;
c1ac62d4 279 if ( $abook->numbackends > 1 ) {
c1ac62d4 280 $backends = $abook->get_backend_list();
6ad2bbe2 281 $writeable_abooks=array();
c1ac62d4 282 while (list($undef,$v) = each($backends)) {
283 if ($v->writeable) {
6ad2bbe2 284 // add each backend to array
285 $writeable_abooks[$v->bnum]=$v->sname;
286 // save backend number
287 $writeable_abook=$v->bnum;
c1ac62d4 288 }
289 }
6ad2bbe2 290 if (count($writeable_abooks)>1) {
291 // we have more than one writeable backend
292 $ret=addSelect('backend',$writeable_abooks,null,true);
293 return html_tag( 'tr',
294 html_tag( 'td', _("Add to:"),'right', $color[4] ) .
295 html_tag( 'td', $ret, 'left', $color[4] )) . "\n";
296 }
c1ac62d4 297 }
6ad2bbe2 298 // Only one backend exists or is writeable.
299 return html_tag( 'tr',
300 html_tag( 'td',
301 addHidden('backend', $writeable_abook),
302 'center', $color[4], 'colspan="2"')) . "\n";
c1ac62d4 303}
304
305/**
306 * Sort array by the key "name"
307 */
308function alistcmp($a,$b) {
309 $abook_sort_order=get_abook_sort();
310
311 switch ($abook_sort_order) {
312 case 0:
313 case 1:
314 $abook_sort='nickname';
315 break;
316 case 4:
317 case 5:
318 $abook_sort='email';
319 break;
320 case 6:
321 case 7:
322 $abook_sort='label';
323 break;
324 case 2:
325 case 3:
326 case 8:
327 default:
328 $abook_sort='name';
329 }
330
331 if ($a['backend'] > $b['backend']) {
332 return 1;
333 } else {
334 if ($a['backend'] < $b['backend']) {
335 return -1;
336 }
337 }
338
339 if( (($abook_sort_order+2) % 2) == 1) {
340 return (strtolower($a[$abook_sort]) < strtolower($b[$abook_sort])) ? 1 : -1;
341 } else {
342 return (strtolower($a[$abook_sort]) > strtolower($b[$abook_sort])) ? 1 : -1;
343 }
344}
345
346/**
347 * Address book sorting options
348 *
349 * returns address book sorting order
350 * @return integer book sorting options order
351 */
352function get_abook_sort() {
353 global $data_dir, $username;
354
355 /* get sorting order */
356 if(sqgetGlobalVar('abook_sort_order', $temp, SQ_GET)) {
357 $abook_sort_order = (int) $temp;
358
359 if ($abook_sort_order < 0 or $abook_sort_order > 8)
360 $abook_sort_order=8;
361
362 setPref($data_dir, $username, 'abook_sort_order', $abook_sort_order);
363 } else {
364 /* get previous sorting options. default to unsorted */
365 $abook_sort_order = getPref($data_dir, $username, 'abook_sort_order', 8);
366 }
367
368 return $abook_sort_order;
369}
370
371/**
372 * This function shows the address book sort button.
373 *
374 * @param integer $abook_sort_order current sort value
375 * @param string $alt_tag alt tag value (string visible to text only browsers)
376 * @param integer $Down sort value when list is sorted ascending
377 * @param integer $Up sort value when list is sorted descending
378 * @return string html code with sorting images and urls
379 */
380function show_abook_sort_button($abook_sort_order, $alt_tag, $Down, $Up ) {
381 global $form_url;
382
383 /* Figure out which image we want to use. */
384 if ($abook_sort_order != $Up && $abook_sort_order != $Down) {
385 $img = 'sort_none.png';
386 $which = $Up;
387 } elseif ($abook_sort_order == $Up) {
388 $img = 'up_pointer.png';
389 $which = $Down;
390 } else {
391 $img = 'down_pointer.png';
392 $which = 8;
393 }
394
395 /* Now that we have everything figured out, show the actual button. */
396 return ' <a href="' . $form_url .'?abook_sort_order=' . $which
397 . '"><img src="../images/' . $img
398 . '" border="0" width="12" height="10" alt="' . $alt_tag . '" title="'
399 . _("Click here to change the sorting of the address list") .'" /></a>';
400}
401
4935919f 402
8f6f9ba5 403/**
81fa4801 404 * This is the main address book class that connect all the
405 * backends and provide services to the functions above.
8f6f9ba5 406 * @package squirrelmail
c1ac62d4 407 * @subpackage addressbook
81fa4801 408 */
81fa4801 409class AddressBook {
4272758c 410 /**
411 * Enabled address book backends
412 * @var array
413 */
81fa4801 414 var $backends = array();
4272758c 415 /**
416 * Number of enabled backends
417 * @var integer
418 */
81fa4801 419 var $numbackends = 0;
4272758c 420 /**
421 * Error messages
422 * @var string
423 */
81fa4801 424 var $error = '';
4272758c 425 /**
426 * id of backend with personal address book
427 * @var integer
428 */
81fa4801 429 var $localbackend = 0;
4272758c 430 /**
431 * Name of backend with personal address book
432 * @var string
433 */
81fa4801 434 var $localbackendname = '';
62f7daa5 435
4272758c 436 /**
437 * Constructor function.
438 */
81fa4801 439 function AddressBook() {
c6b8b46c 440 $this->localbackendname = _("Personal address book");
81fa4801 441 }
4935919f 442
4272758c 443 /**
81fa4801 444 * Return an array of backends of a given type,
445 * or all backends if no type is specified.
4272758c 446 * @param string $type backend type
447 * @return array list of backends
81fa4801 448 */
449 function get_backend_list($type = '') {
450 $ret = array();
451 for ($i = 1 ; $i <= $this->numbackends ; $i++) {
452 if (empty($type) || $type == $this->backends[$i]->btype) {
453 $ret[] = &$this->backends[$i];
454 }
4935919f 455 }
81fa4801 456 return $ret;
457 }
4935919f 458
459
4272758c 460 /* ========================== Public ======================== */
81fa4801 461
4272758c 462 /**
463 * Add a new backend.
464 *
465 * @param string $backend backend name (without the abook_ prefix)
466 * @param mixed optional variable that is passed to the backend constructor.
467 * See each of the backend classes for valid parameters
468 * @return integer number of backends
81fa4801 469 */
470 function add_backend($backend, $param = '') {
471 $backend_name = 'abook_' . $backend;
472 eval('$newback = new ' . $backend_name . '($param);');
473 if(!empty($newback->error)) {
474 $this->error = $newback->error;
475 return false;
476 }
477
478 $this->numbackends++;
479
480 $newback->bnum = $this->numbackends;
481 $this->backends[$this->numbackends] = $newback;
62f7daa5 482
81fa4801 483 /* Store ID of first local backend added */
484 if ($this->localbackend == 0 && $newback->btype == 'local') {
485 $this->localbackend = $this->numbackends;
486 $this->localbackendname = $newback->sname;
487 }
488
489 return $this->numbackends;
490 }
4935919f 491
4935919f 492
4272758c 493 /**
494 * create string with name and email address
495 *
62f7daa5 496 * This function takes a $row array as returned by the addressbook
2e542990 497 * search and returns an e-mail address with the full name or
498 * nickname optionally prepended.
4272758c 499 * @param array $row address book entry
500 * @return string email address with real name prepended
2e542990 501 */
2e542990 502 function full_address($row) {
1ba8cd6b 503 global $addrsrch_fullname, $data_dir, $username;
20ad4fdd 504 $prefix = getPref($data_dir, $username, 'addrsrch_fullname');
505 if (($prefix != "" || (isset($addrsrch_fullname) &&
506 $prefix == $addrsrch_fullname)) && $prefix != 'noprefix') {
507 $name = ($prefix == 'nickname' ? $row['nickname'] : $row['name']);
2e542990 508 return $name . ' <' . trim($row['email']) . '>';
509 } else {
510 return trim($row['email']);
511 }
512 }
513
4272758c 514 /**
515 * Search for entries in address books
516 *
517 * Return a list of addresses matching expression in
518 * all backends of a given type.
519 * @param string $expression search expression
520 * @param integer $bnum backend number. default to search in all backends
521 * @return array search results
522 */
81fa4801 523 function search($expression, $bnum = -1) {
524 $ret = array();
525 $this->error = '';
526
527 /* Search all backends */
528 if ($bnum == -1) {
529 $sel = $this->get_backend_list('');
530 $failed = 0;
531 for ($i = 0 ; $i < sizeof($sel) ; $i++) {
532 $backend = &$sel[$i];
533 $backend->error = '';
534 $res = $backend->search($expression);
535 if (is_array($res)) {
536 $ret = array_merge($ret, $res);
537 } else {
6fd95361 538 $this->error .= "<br />\n" . $backend->error;
81fa4801 539 $failed++;
75e19c7f 540 }
541 }
4935919f 542
81fa4801 543 /* Only fail if all backends failed */
544 if( $failed >= sizeof( $sel ) ) {
545 $ret = FALSE;
4935919f 546 }
4935919f 547
81fa4801 548 } else {
4935919f 549
81fa4801 550 /* Search only one backend */
4935919f 551
81fa4801 552 $ret = $this->backends[$bnum]->search($expression);
553 if (!is_array($ret)) {
6fd95361 554 $this->error .= "<br />\n" . $this->backends[$bnum]->error;
81fa4801 555 $ret = FALSE;
556 }
557 }
558
559 return( $ret );
4935919f 560 }
561
562
4272758c 563 /**
564 * Sorted search
565 * @param string $expression search expression
566 * @param integer $bnum backend number. default to search in all backends
567 * @return array search results
568 */
81fa4801 569 function s_search($expression, $bnum = -1) {
62f7daa5 570
81fa4801 571 $ret = $this->search($expression, $bnum);
572 if ( is_array( $ret ) ) {
573 usort($ret, 'addressbook_cmp');
62f7daa5 574 }
81fa4801 575 return $ret;
576 }
4935919f 577
578
4272758c 579 /**
580 * Lookup an address by alias.
581 * Only possible in local backends.
582 * @param string $alias
583 * @param integer backend number
584 * @return array lookup results. False, if not found.
81fa4801 585 */
586 function lookup($alias, $bnum = -1) {
62f7daa5 587
81fa4801 588 $ret = array();
62f7daa5 589
81fa4801 590 if ($bnum > -1) {
591 $res = $this->backends[$bnum]->lookup($alias);
592 if (is_array($res)) {
593 return $res;
594 } else {
595 $this->error = $backend->error;
596 return false;
597 }
598 }
62f7daa5 599
81fa4801 600 $sel = $this->get_backend_list('local');
601 for ($i = 0 ; $i < sizeof($sel) ; $i++) {
602 $backend = &$sel[$i];
603 $backend->error = '';
604 $res = $backend->lookup($alias);
605 if (is_array($res)) {
606 if(!empty($res))
607 return $res;
608 } else {
609 $this->error = $backend->error;
610 return false;
611 }
612 }
62f7daa5 613
81fa4801 614 return $ret;
4935919f 615 }
616
4935919f 617
4272758c 618 /**
619 * Return all addresses
620 * @param integer $bnum backend number
621 * @return array search results
622 */
81fa4801 623 function list_addr($bnum = -1) {
624 $ret = array();
62f7daa5 625
81fa4801 626 if ($bnum == -1) {
4272758c 627 $sel = $this->get_backend_list('');
81fa4801 628 } else {
629 $sel = array(0 => &$this->backends[$bnum]);
630 }
62f7daa5 631
81fa4801 632 for ($i = 0 ; $i < sizeof($sel) ; $i++) {
633 $backend = &$sel[$i];
634 $backend->error = '';
635 $res = $backend->list_addr();
636 if (is_array($res)) {
637 $ret = array_merge($ret, $res);
638 } else {
639 $this->error = $backend->error;
640 return false;
641 }
642 }
62f7daa5 643
81fa4801 644 return $ret;
645 }
4935919f 646
4272758c 647 /**
91e0dccc 648 * Create a new address
4272758c 649 * @param array $userdata added address record
650 * @param integer $bnum backend number
651 * @return integer the backend number that the/ address was added
81fa4801 652 * to, or false if it failed.
653 */
654 function add($userdata, $bnum) {
62f7daa5 655
81fa4801 656 /* Validate data */
657 if (!is_array($userdata)) {
658 $this->error = _("Invalid input data");
659 return false;
660 }
661 if (empty($userdata['firstname']) && empty($userdata['lastname'])) {
662 $this->error = _("Name is missing");
663 return false;
664 }
665 if (empty($userdata['email'])) {
666 $this->error = _("E-mail address is missing");
667 return false;
668 }
669 if (empty($userdata['nickname'])) {
670 $userdata['nickname'] = $userdata['email'];
671 }
62f7daa5 672
81fa4801 673 if (eregi('[ \\:\\|\\#\\"\\!]', $userdata['nickname'])) {
674 $this->error = _("Nickname contains illegal characters");
675 return false;
676 }
62f7daa5 677
81fa4801 678 /* Check that specified backend accept new entries */
679 if (!$this->backends[$bnum]->writeable) {
680 $this->error = _("Addressbook is read-only");
681 return false;
682 }
62f7daa5 683
81fa4801 684 /* Add address to backend */
685 $res = $this->backends[$bnum]->add($userdata);
686 if ($res) {
687 return $bnum;
688 } else {
689 $this->error = $this->backends[$bnum]->error;
690 return false;
691 }
62f7daa5 692
81fa4801 693 return false; // Not reached
694 } /* end of add() */
695
696
4272758c 697 /**
698 * Remove the entries from address book
91e0dccc 699 * @param mixed $alias entries that have to be removed. Can be string with nickname or array with list of nicknames
4272758c 700 * @param integer $bnum backend number
701 * @return bool true if removed successfully. false if there s an error. $this->error contains error message
81fa4801 702 */
703 function remove($alias, $bnum) {
62f7daa5 704
81fa4801 705 /* Check input */
706 if (empty($alias)) {
707 return true;
708 }
62f7daa5 709
81fa4801 710 /* Convert string to single element array */
711 if (!is_array($alias)) {
712 $alias = array(0 => $alias);
713 }
62f7daa5 714
715 /* Check that specified backend is writable */
81fa4801 716 if (!$this->backends[$bnum]->writeable) {
717 $this->error = _("Addressbook is read-only");
718 return false;
719 }
62f7daa5 720
81fa4801 721 /* Remove user from backend */
722 $res = $this->backends[$bnum]->remove($alias);
723 if ($res) {
724 return $bnum;
725 } else {
726 $this->error = $this->backends[$bnum]->error;
727 return false;
728 }
62f7daa5 729
81fa4801 730 return FALSE; /* Not reached */
731 } /* end of remove() */
732
733
4272758c 734 /**
735 * Modify entry in address book
736 * @param string $alias nickname
737 * @param array $userdata newdata
738 * @param integer $bnum backend number
81fa4801 739 */
740 function modify($alias, $userdata, $bnum) {
62f7daa5 741
81fa4801 742 /* Check input */
743 if (empty($alias) || !is_string($alias)) {
744 return true;
745 }
62f7daa5 746
81fa4801 747 /* Validate data */
748 if(!is_array($userdata)) {
749 $this->error = _("Invalid input data");
750 return false;
751 }
752 if (empty($userdata['firstname']) && empty($userdata['lastname'])) {
753 $this->error = _("Name is missing");
754 return false;
755 }
756 if (empty($userdata['email'])) {
757 $this->error = _("E-mail address is missing");
758 return false;
759 }
62f7daa5 760
81fa4801 761 if (eregi('[\\: \\|\\#"\\!]', $userdata['nickname'])) {
762 $this->error = _("Nickname contains illegal characters");
763 return false;
764 }
62f7daa5 765
81fa4801 766 if (empty($userdata['nickname'])) {
767 $userdata['nickname'] = $userdata['email'];
768 }
62f7daa5 769
770 /* Check that specified backend is writable */
81fa4801 771 if (!$this->backends[$bnum]->writeable) {
772 $this->error = _("Addressbook is read-only");;
773 return false;
774 }
62f7daa5 775
81fa4801 776 /* Modify user in backend */
777 $res = $this->backends[$bnum]->modify($alias, $userdata);
778 if ($res) {
779 return $bnum;
780 } else {
781 $this->error = $this->backends[$bnum]->error;
782 return false;
783 }
62f7daa5 784
81fa4801 785 return FALSE; /* Not reached */
786 } /* end of modify() */
62f7daa5 787
788
81fa4801 789} /* End of class Addressbook */
790
8f6f9ba5 791/**
81fa4801 792 * Generic backend that all other backends extend
8f6f9ba5 793 * @package squirrelmail
c1ac62d4 794 * @subpackage addressbook
81fa4801 795 */
796class addressbook_backend {
797
798 /* Variables that all backends must provide. */
4272758c 799 /**
800 * Backend type
801 *
802 * Can be 'local' or 'remote'
803 * @var string backend type
804 */
81fa4801 805 var $btype = 'dummy';
4272758c 806 /**
807 * Internal backend name
808 * @var string
809 */
81fa4801 810 var $bname = 'dummy';
4272758c 811 /**
812 * Displayed backend name
813 * @var string
814 */
81fa4801 815 var $sname = 'Dummy backend';
62f7daa5 816
81fa4801 817 /*
818 * Variables common for all backends, but that
819 * should not be changed by the backends.
820 */
4272758c 821 /**
822 * Backend number
823 * @var integer
824 */
81fa4801 825 var $bnum = -1;
4272758c 826 /**
827 * Error messages
828 * @var string
829 */
81fa4801 830 var $error = '';
4272758c 831 /**
832 * Writeable flag
833 * @var bool
834 */
81fa4801 835 var $writeable = false;
62f7daa5 836
4272758c 837 /**
838 * Set error message
839 * @param string $string error message
840 * @return bool
841 */
81fa4801 842 function set_error($string) {
843 $this->error = '[' . $this->sname . '] ' . $string;
844 return false;
845 }
62f7daa5 846
847
81fa4801 848 /* ========================== Public ======================== */
62f7daa5 849
4272758c 850 /**
851 * Search for entries in backend
852 * @param string $expression
853 * @return bool
854 */
81fa4801 855 function search($expression) {
856 $this->set_error('search not implemented');
857 return false;
858 }
62f7daa5 859
4272758c 860 /**
861 * Find entry in backend by alias
862 * @param string $alias name used for id
863 * @return bool
864 */
81fa4801 865 function lookup($alias) {
866 $this->set_error('lookup not implemented');
867 return false;
a10110a5 868 }
62f7daa5 869
4272758c 870 /**
871 * List all entries in backend
872 * @return bool
873 */
81fa4801 874 function list_addr() {
875 $this->set_error('list_addr not implemented');
876 return false;
877 }
62f7daa5 878
4272758c 879 /**
880 * Add entry to backend
881 * @param array userdata
882 * @return bool
883 */
81fa4801 884 function add($userdata) {
885 $this->set_error('add not implemented');
886 return false;
887 }
62f7daa5 888
4272758c 889 /**
890 * Remove entry from backend
891 * @param string $alias name used for id
892 * @return bool
893 */
81fa4801 894 function remove($alias) {
895 $this->set_error('delete not implemented');
896 return false;
897 }
62f7daa5 898
4272758c 899 /**
900 * Modify entry in backend
901 * @param string $alias name used for id
902 * @param array $newuserdata new data
903 * @return bool
904 */
81fa4801 905 function modify($alias, $newuserdata) {
906 $this->set_error('modify not implemented');
907 return false;
908 }
81fa4801 909}
910
0419106e 911/*
912 PHP 5 requires that the class be made first, which seems rather
913 logical, and should have been the way it was generated the first time.
914*/
915
916require_once(SM_PATH . 'functions/abook_local_file.php');
917require_once(SM_PATH . 'functions/abook_ldap_server.php');
918
0419106e 919/* Only load database backend if database is configured */
62f7daa5 920if((isset($addrbook_dsn) && !empty($addrbook_dsn)) ||
30e9932c 921 (isset($addrbook_global_dsn) && !empty($addrbook_global_dsn)) ) {
0419106e 922 include_once(SM_PATH . 'functions/abook_database.php');
923}
924
df788686 925/*
926 * hook allows adding different address book classes.
927 * class must follow address book class coding standards.
928 *
929 * see addressbook_backend class and functions/abook_*.php files.
e4a468a7 930 * @since 1.5.1
df788686 931 */
932do_hook('abook_add_class');
0419106e 933
796f91d9 934?>