display error box with more details.
[squirrelmail.git] / functions / addressbook.php
1 <?php
2 /**
3 * functions/addressbook.php - Functions and classes for the addressbook system
4 *
5 * Copyright (c) 1999-2005 The SquirrelMail Project Team
6 * Licensed under the GNU GPL. For full terms see the file COPYING.
7 *
8 * Functions require SM_PATH and support of forms.php functions
9 *
10 * @version $Id$
11 * @package squirrelmail
12 * @subpackage addressbook
13 */
14
15 /**
16 * If SM_PATH isn't defined, define it. Required to include files.
17 * @ignore
18 */
19 if (!defined('SM_PATH')) {
20 define('SM_PATH','../');
21 }
22
23 /* make sure that display_messages.php is loaded */
24 include_once(SM_PATH . 'functions/display_messages.php');
25
26 global $addrbook_dsn, $addrbook_global_dsn;
27
28 /**
29 Create and initialize an addressbook object.
30 Returns the created object
31 */
32 function addressbook_init($showerr = true, $onlylocal = false) {
33 global $data_dir, $username, $color, $ldap_server, $address_book_global_filename;
34 global $addrbook_dsn, $addrbook_table;
35 global $abook_global_file, $abook_global_file_writeable;
36 global $addrbook_global_dsn, $addrbook_global_table, $addrbook_global_writeable, $addrbook_global_listing;
37
38 /* Create a new addressbook object */
39 $abook = new AddressBook;
40
41 /* Create empty error message */
42 $abook_init_error='';
43
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 */
74 if (isset($abook_global_file) && isset($abook_global_file_writeable)
75 && trim($abook_global_file)!=''){
76 // Detect place of address book
77 if (! preg_match("/[\/\\\]/",$abook_global_file)) {
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;
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));
95
96 /* global abook init error is not fatal. add error message and continue */
97 if (!$r && $showerr) {
98 $abook_init_error.=_("Error initializing global addressbook.") . "<br />" . $abook->error;
99 }
100 }
101
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)) {
106 $addrbook_global_table = 'global_abook';
107 }
108 $r = $abook->add_backend('database',
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));
115 }
116
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.
121 * @since 1.5.1
122 */
123 $hookReturn = do_hook('abook_init', $abook, $r);
124 $abook = $hookReturn[1];
125 $r = $hookReturn[2];
126
127 if ($onlylocal) {
128 /* display error message, if present */
129 if ($abook_init_error!='' && $showerr) {
130 error_box($abook_init_error,$color);
131 }
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:") .
143 "<br />\n", $param['host']);
144 echo '&nbsp;' . $abook->error;
145 exit;
146 }
147 }
148 }
149 }
150
151 /**
152 * display address book init errors.
153 */
154 if ($abook_init_error!='' && $showerr) {
155 error_box($abook_init_error,$color);
156 }
157 /* Return the initialized object */
158 return $abook;
159 }
160
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 */
172 function 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
185
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.
189 * Note: this can return now since we don't support 4.0.4 anymore.
190 */
191 function addressbook_cmp($a,$b) {
192
193 if($a['backend'] > $b['backend']) {
194 return 1;
195 } else if($a['backend'] < $b['backend']) {
196 return -1;
197 }
198
199 return (strtolower($a['name']) > strtolower($b['name'])) ? 1 : -1;
200
201 }
202
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 */
212 function 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 */
233 function 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
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 */
275 function list_writable_backends($name) {
276 global $color, $abook;
277 if ( $name != 'addaddr' ) { return; }
278 $writeable_abook = 1;
279 if ( $abook->numbackends > 1 ) {
280 $backends = $abook->get_backend_list();
281 $writeable_abooks=array();
282 while (list($undef,$v) = each($backends)) {
283 if ($v->writeable) {
284 // add each backend to array
285 $writeable_abooks[$v->bnum]=$v->sname;
286 // save backend number
287 $writeable_abook=$v->bnum;
288 }
289 }
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 }
297 }
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";
303 }
304
305 /**
306 * Sort array by the key "name"
307 */
308 function 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 */
352 function 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 */
380 function 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
402
403 /**
404 * This is the main address book class that connect all the
405 * backends and provide services to the functions above.
406 * @package squirrelmail
407 * @subpackage addressbook
408 */
409 class AddressBook {
410 /**
411 * Enabled address book backends
412 * @var array
413 */
414 var $backends = array();
415 /**
416 * Number of enabled backends
417 * @var integer
418 */
419 var $numbackends = 0;
420 /**
421 * Error messages
422 * @var string
423 */
424 var $error = '';
425 /**
426 * id of backend with personal address book
427 * @var integer
428 */
429 var $localbackend = 0;
430 /**
431 * Name of backend with personal address book
432 * @var string
433 */
434 var $localbackendname = '';
435
436 /**
437 * Constructor function.
438 */
439 function AddressBook() {
440 $this->localbackendname = _("Personal address book");
441 }
442
443 /**
444 * Return an array of backends of a given type,
445 * or all backends if no type is specified.
446 * @param string $type backend type
447 * @return array list of backends
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 }
455 }
456 return $ret;
457 }
458
459
460 /* ========================== Public ======================== */
461
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
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;
482
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 }
491
492
493 /**
494 * create string with name and email address
495 *
496 * This function takes a $row array as returned by the addressbook
497 * search and returns an e-mail address with the full name or
498 * nickname optionally prepended.
499 * @param array $row address book entry
500 * @return string email address with real name prepended
501 */
502 function full_address($row) {
503 global $addrsrch_fullname, $data_dir, $username;
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']);
508 return $name . ' <' . trim($row['email']) . '>';
509 } else {
510 return trim($row['email']);
511 }
512 }
513
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 */
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 {
538 $this->error .= "<br />\n" . $backend->error;
539 $failed++;
540 }
541 }
542
543 /* Only fail if all backends failed */
544 if( $failed >= sizeof( $sel ) ) {
545 $ret = FALSE;
546 }
547
548 } else {
549
550 /* Search only one backend */
551
552 $ret = $this->backends[$bnum]->search($expression);
553 if (!is_array($ret)) {
554 $this->error .= "<br />\n" . $this->backends[$bnum]->error;
555 $ret = FALSE;
556 }
557 }
558
559 return( $ret );
560 }
561
562
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 */
569 function s_search($expression, $bnum = -1) {
570
571 $ret = $this->search($expression, $bnum);
572 if ( is_array( $ret ) ) {
573 usort($ret, 'addressbook_cmp');
574 }
575 return $ret;
576 }
577
578
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.
585 */
586 function lookup($alias, $bnum = -1) {
587
588 $ret = array();
589
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 }
599
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 }
613
614 return $ret;
615 }
616
617
618 /**
619 * Return all addresses
620 * @param integer $bnum backend number
621 * @return array search results
622 */
623 function list_addr($bnum = -1) {
624 $ret = array();
625
626 if ($bnum == -1) {
627 $sel = $this->get_backend_list('');
628 } else {
629 $sel = array(0 => &$this->backends[$bnum]);
630 }
631
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 }
643
644 return $ret;
645 }
646
647 /**
648 * Create a new address
649 * @param array $userdata added address record
650 * @param integer $bnum backend number
651 * @return integer the backend number that the/ address was added
652 * to, or false if it failed.
653 */
654 function add($userdata, $bnum) {
655
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 }
672
673 if (eregi('[ \\:\\|\\#\\"\\!]', $userdata['nickname'])) {
674 $this->error = _("Nickname contains illegal characters");
675 return false;
676 }
677
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 }
683
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 }
692
693 return false; // Not reached
694 } /* end of add() */
695
696
697 /**
698 * Remove the entries from address book
699 * @param mixed $alias entries that have to be removed. Can be string with nickname or array with list of nicknames
700 * @param integer $bnum backend number
701 * @return bool true if removed successfully. false if there s an error. $this->error contains error message
702 */
703 function remove($alias, $bnum) {
704
705 /* Check input */
706 if (empty($alias)) {
707 return true;
708 }
709
710 /* Convert string to single element array */
711 if (!is_array($alias)) {
712 $alias = array(0 => $alias);
713 }
714
715 /* Check that specified backend is writable */
716 if (!$this->backends[$bnum]->writeable) {
717 $this->error = _("Addressbook is read-only");
718 return false;
719 }
720
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 }
729
730 return FALSE; /* Not reached */
731 } /* end of remove() */
732
733
734 /**
735 * Modify entry in address book
736 * @param string $alias nickname
737 * @param array $userdata newdata
738 * @param integer $bnum backend number
739 */
740 function modify($alias, $userdata, $bnum) {
741
742 /* Check input */
743 if (empty($alias) || !is_string($alias)) {
744 return true;
745 }
746
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 }
760
761 if (eregi('[\\: \\|\\#"\\!]', $userdata['nickname'])) {
762 $this->error = _("Nickname contains illegal characters");
763 return false;
764 }
765
766 if (empty($userdata['nickname'])) {
767 $userdata['nickname'] = $userdata['email'];
768 }
769
770 /* Check that specified backend is writable */
771 if (!$this->backends[$bnum]->writeable) {
772 $this->error = _("Addressbook is read-only");;
773 return false;
774 }
775
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 }
784
785 return FALSE; /* Not reached */
786 } /* end of modify() */
787
788
789 } /* End of class Addressbook */
790
791 /**
792 * Generic backend that all other backends extend
793 * @package squirrelmail
794 * @subpackage addressbook
795 */
796 class addressbook_backend {
797
798 /* Variables that all backends must provide. */
799 /**
800 * Backend type
801 *
802 * Can be 'local' or 'remote'
803 * @var string backend type
804 */
805 var $btype = 'dummy';
806 /**
807 * Internal backend name
808 * @var string
809 */
810 var $bname = 'dummy';
811 /**
812 * Displayed backend name
813 * @var string
814 */
815 var $sname = 'Dummy backend';
816
817 /*
818 * Variables common for all backends, but that
819 * should not be changed by the backends.
820 */
821 /**
822 * Backend number
823 * @var integer
824 */
825 var $bnum = -1;
826 /**
827 * Error messages
828 * @var string
829 */
830 var $error = '';
831 /**
832 * Writeable flag
833 * @var bool
834 */
835 var $writeable = false;
836
837 /**
838 * Set error message
839 * @param string $string error message
840 * @return bool
841 */
842 function set_error($string) {
843 $this->error = '[' . $this->sname . '] ' . $string;
844 return false;
845 }
846
847
848 /* ========================== Public ======================== */
849
850 /**
851 * Search for entries in backend
852 * @param string $expression
853 * @return bool
854 */
855 function search($expression) {
856 $this->set_error('search not implemented');
857 return false;
858 }
859
860 /**
861 * Find entry in backend by alias
862 * @param string $alias name used for id
863 * @return bool
864 */
865 function lookup($alias) {
866 $this->set_error('lookup not implemented');
867 return false;
868 }
869
870 /**
871 * List all entries in backend
872 * @return bool
873 */
874 function list_addr() {
875 $this->set_error('list_addr not implemented');
876 return false;
877 }
878
879 /**
880 * Add entry to backend
881 * @param array userdata
882 * @return bool
883 */
884 function add($userdata) {
885 $this->set_error('add not implemented');
886 return false;
887 }
888
889 /**
890 * Remove entry from backend
891 * @param string $alias name used for id
892 * @return bool
893 */
894 function remove($alias) {
895 $this->set_error('delete not implemented');
896 return false;
897 }
898
899 /**
900 * Modify entry in backend
901 * @param string $alias name used for id
902 * @param array $newuserdata new data
903 * @return bool
904 */
905 function modify($alias, $newuserdata) {
906 $this->set_error('modify not implemented');
907 return false;
908 }
909 }
910
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
916 require_once(SM_PATH . 'functions/abook_local_file.php');
917 require_once(SM_PATH . 'functions/abook_ldap_server.php');
918
919 /* Only load database backend if database is configured */
920 if((isset($addrbook_dsn) && !empty($addrbook_dsn)) ||
921 (isset($addrbook_global_dsn) && !empty($addrbook_global_dsn)) ) {
922 include_once(SM_PATH . 'functions/abook_database.php');
923 }
924
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.
930 * @since 1.5.1
931 */
932 do_hook('abook_add_class');
933
934 ?>