squirrelmail-webmail  1.4.22
About: SquirrelMail is a standards-based webmail package with strong MIME support, address books, and folder manipulation (written in PHP4).
  Fossies Dox: squirrelmail-webmail-1.4.22.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

addressbook.php
Go to the documentation of this file.
1 <?php
2 
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 
27 
32 function addressbook_init($showerr = true, $onlylocal = false) {
33  global $data_dir, $username, $color, $ldap_server, $address_book_global_filename;
35  // Shared file based address book globals
37  // Shared DB based address book globals
39  // Record size restriction in file based address books
41 
42  /* Create a new addressbook object */
43  $abook = new AddressBook;
44 
45  /* Create empty error message */
46  $abook_init_error='';
47 
48  /*
49  Always add a local backend. We use *either* file-based *or* a
50  database addressbook. If $addrbook_dsn is set, the database
51  backend is used. If not, addressbooks are stores in files.
52  */
53  if (isset($addrbook_dsn) && !empty($addrbook_dsn)) {
54  /* Database */
55  if (!isset($addrbook_table) || empty($addrbook_table)) {
56  $addrbook_table = 'address';
57  }
58  $r = $abook->add_backend('database', Array('dsn' => $addrbook_dsn,
59  'owner' => $username,
60  'table' => $addrbook_table));
61  if (!$r && $showerr) {
62  $abook_init_error.=_("Error initializing address book database.") .' '. $abook->error;
63  }
64  } else {
65  /* File */
66  $filename = getHashedFile($username, $data_dir, "$username.abook");
67  $r = $abook->add_backend('local_file', Array('filename' => $filename,
68  'umask' => 0077,
69  'line_length' => $abook_file_line_length,
70  'create' => true));
71  if(!$r && $showerr) {
72  $abook_init_error.=sprintf( _("Error opening file %s"), $filename );
73  }
74  }
75 
76  /* This would be for the global addressbook */
78  && trim($abook_global_file)!=''){
79  // Detect place of address book
80  if (! preg_match("/[\/\\\]/",$abook_global_file)) {
81  /* no path chars, address book stored in data directory
82  * make sure that there is a slash between data directory
83  * and address book file name
84  */
85  $abook_global_filename=$data_dir
86  . ((substr($data_dir, -1) != '/') ? '/' : '')
88  } elseif (preg_match("/^\/|\w:/",$abook_global_file)) {
89  // full path is set in options (starts with slash or x:)
90  $abook_global_filename=$abook_global_file;
91  } else {
92  $abook_global_filename=SM_PATH . $abook_global_file;
93  }
94  $r = $abook->add_backend('local_file',array('filename'=>$abook_global_filename,
95  'name' => _("Global address book"),
96  'detect_writeable' => false,
97  'line_length' => $abook_file_line_length,
98  'writeable'=> $abook_global_file_writeable,
99  'listing' => $abook_global_file_listing));
100  if (!$r && $showerr) {
101  if ($abook_init_error!='') $abook_init_error.="\n";
102  $abook_init_error.=_("Error initializing global address book.") . "\n" . $abook->error;
103  }
104  }
105 
106  /* Load global addressbook from SQL if configured */
107  if (isset($addrbook_global_dsn) && !empty($addrbook_global_dsn)) {
108  /* Database configured */
109  if (!isset($addrbook_global_table) || empty($addrbook_global_table)) {
110  $addrbook_global_table = 'global_abook';
111  }
112  $r = $abook->add_backend('database',
113  Array('dsn' => $addrbook_global_dsn,
114  'owner' => 'global',
115  'name' => _("Global address book"),
116  'writeable' => $addrbook_global_writeable,
117  'listing' => $addrbook_global_listing,
118  'table' => $addrbook_global_table));
119  if (!$r && $showerr) {
120  if ($abook_init_error!='') $abook_init_error.="\n";
121  $abook_init_error.=_("Error initializing global address book.") . "\n" . $abook->error;
122  }
123  }
124 
125  /*
126  * hook allows to include different address book backends.
127  * plugins should extract $abook and $r from arguments
128  * and use same add_backend commands as above functions.
129  * @since 1.5.1 and 1.4.5
130  */
131  $hookReturn = do_hook('abook_init', $abook, $r);
132  $abook = $hookReturn[1];
133  $r = $hookReturn[2];
134 
135  if (! $onlylocal) {
136  /* Load configured LDAP servers (if PHP has LDAP support) */
137  if (isset($ldap_server) && is_array($ldap_server) && function_exists('ldap_connect')) {
138  reset($ldap_server);
139  while (list($undef,$param) = each($ldap_server)) {
140  if (is_array($param)) {
141  $r = $abook->add_backend('ldap_server', $param);
142  if (!$r && $showerr) {
143  if ($abook_init_error!='') $abook_init_error.="\n";
144  $abook_init_error.=sprintf(_("Error initializing LDAP server %s:") .
145  "\n", $param['host']);
146  $abook_init_error.= $abook->error;
147  }
148  }
149  }
150  }
151  } // end of remote abook backends init
152 
156  if ($abook_init_error!='' && $showerr) {
157  $abook_init_error = htmlspecialchars($abook_init_error);
158  error_box($abook_init_error,$color);
159  }
160 
161  /* Return the initialized object */
162  return $abook;
163 }
164 
165 
166 /*
167  * Had to move this function outside of the Addressbook Class
168  * PHP 4.0.4 Seemed to be having problems with inline functions.
169  */
170 function addressbook_cmp($a,$b) {
171 
172  if($a['backend'] > $b['backend']) {
173  return 1;
174  } else if($a['backend'] < $b['backend']) {
175  return -1;
176  }
177 
178  return (strtolower($a['name']) > strtolower($b['name'])) ? 1 : -1;
179 
180 }
181 
185 function alistcmp($a,$b) {
187 
188  switch ($abook_sort_order) {
189  case 0:
190  case 1:
191  $abook_sort='nickname';
192  break;
193  case 4:
194  case 5:
195  $abook_sort='email';
196  break;
197  case 6:
198  case 7:
199  $abook_sort='label';
200  break;
201  case 2:
202  case 3:
203  case 8:
204  default:
205  $abook_sort='name';
206  }
207 
208  if ($a['backend'] > $b['backend']) {
209  return 1;
210  } else {
211  if ($a['backend'] < $b['backend']) {
212  return -1;
213  }
214  }
215 
216  if( (($abook_sort_order+2) % 2) == 1) {
217  return (strtolower($a[$abook_sort]) < strtolower($b[$abook_sort])) ? 1 : -1;
218  } else {
219  return (strtolower($a[$abook_sort]) > strtolower($b[$abook_sort])) ? 1 : -1;
220  }
221 }
222 
229 function get_abook_sort() {
230  global $data_dir, $username;
231 
232  /* get sorting order */
233  if(sqgetGlobalVar('abook_sort_order', $temp, SQ_GET)) {
234  $abook_sort_order = (int) $temp;
235 
236  if ($abook_sort_order < 0 or $abook_sort_order > 8)
238 
239  setPref($data_dir, $username, 'abook_sort_order', $abook_sort_order);
240  } else {
241  /* get previous sorting options. default to unsorted */
242  $abook_sort_order = getPref($data_dir, $username, 'abook_sort_order', 8);
243  }
244 
245  return $abook_sort_order;
246 }
247 
258 function show_abook_sort_button($abook_sort_order, $alt_tag, $Down, $Up ) {
259  global $form_url;
260 
261  /* Figure out which image we want to use. */
262  if ($abook_sort_order != $Up && $abook_sort_order != $Down) {
263  $img = 'sort_none.png';
264  $which = $Up;
265  } elseif ($abook_sort_order == $Up) {
266  $img = 'up_pointer.png';
267  $which = $Down;
268  } else {
269  $img = 'down_pointer.png';
270  $which = 8;
271  }
272 
273  /* Now that we have everything figured out, show the actual button. */
274  return ' <a href="' . $form_url .'?abook_sort_order=' . $which
275  . '"><img src="../images/' . $img
276  . '" border="0" width="12" height="10" alt="' . $alt_tag . '" title="'
277  . _("Click here to change the sorting of the address list") .'" /></a>';
278 }
279 
280 
287 class AddressBook {
288 
289  var $backends = array();
290  var $numbackends = 0;
291  var $error = '';
292  var $localbackend = 0;
294  var $add_extra_field = false;
295 
296  // Constructor function.
297  function AddressBook() {
298  $this->localbackendname = _("Personal address book");
299  }
300 
301  /*
302  * Return an array of backends of a given type,
303  * or all backends if no type is specified.
304  */
305  function get_backend_list($type = '') {
306  $ret = array();
307  for ($i = 1 ; $i <= $this->numbackends ; $i++) {
308  if (empty($type) || $type == $this->backends[$i]->btype) {
309  $ret[] = &$this->backends[$i];
310  }
311  }
312  return $ret;
313  }
314 
315 
316  /*
317  ========================== Public ========================
318 
319  Add a new backend. $backend is the name of a backend
320  (without the abook_ prefix), and $param is an optional
321  mixed variable that is passed to the backend constructor.
322  See each of the backend classes for valid parameters.
323  */
324  function add_backend($backend, $param = '') {
325  $backend_name = 'abook_' . $backend;
326  eval('$newback = new ' . $backend_name . '($param);');
327  if(!empty($newback->error)) {
328  $this->error = $newback->error;
329  return false;
330  }
331 
332  $this->numbackends++;
333 
334  $newback->bnum = $this->numbackends;
335  $this->backends[$this->numbackends] = $newback;
336 
337  /* Store ID of first local backend added */
338  if ($this->localbackend == 0 && $newback->btype == 'local') {
339  $this->localbackend = $this->numbackends;
340  $this->localbackendname = $newback->sname;
341  }
342 
343  return $this->numbackends;
344  }
345 
346 
347  /*
348  * This function takes a $row array as returned by the addressbook
349  * search and returns an e-mail address with the full name or
350  * nickname optionally prepended.
351  */
352 
353  function full_address($row) {
354  global $data_dir, $username;
355  $addrsrch_fullname = getPref($data_dir, $username, 'addrsrch_fullname', 'fullname');
356 
357  // allow multiple addresses in one row (poor person's grouping - bah)
358  // (separate with commas)
359  //
360  $return = '';
361  $addresses = explode(',', $row['email']);
362  foreach ($addresses as $address) {
363 
364  if (!empty($return)) $return .= ', ';
365 
366  if ($addrsrch_fullname == 'fullname')
367  $return .= '"' . $row['name'] . '" <' . trim($address) . '>';
368  else if ($addrsrch_fullname == 'nickname')
369  $return .= '"' . $row['nickname'] . '" <' . trim($address) . '>';
370  else // "noprefix"
371  $return .= trim($address);
372 
373  }
374 
375  return $return;
376  }
377 
378  /*
379  Return a list of addresses matching expression in
380  all backends of a given type.
381  */
382  function search($expression, $bnum = -1) {
383  $ret = array();
384  $this->error = '';
385 
386  /* Search all backends */
387  if ($bnum == -1) {
388  $sel = $this->get_backend_list('');
389  $failed = 0;
390  for ($i = 0 ; $i < sizeof($sel) ; $i++) {
391  $backend = &$sel[$i];
392  $backend->error = '';
393  $res = $backend->search($expression);
394  if (is_array($res)) {
395  $ret = array_merge($ret, $res);
396  } else {
397  $this->error .= "\n" . $backend->error;
398  $failed++;
399  }
400  }
401 
402  /* Only fail if all backends failed */
403  if( $failed >= sizeof( $sel ) ) {
404  $ret = FALSE;
405  }
406 
407  } else {
408 
409  /* Search only one backend */
410 
411  $ret = $this->backends[$bnum]->search($expression);
412  if (!is_array($ret)) {
413  $this->error .= "\n" . $this->backends[$bnum]->error;
414  $ret = FALSE;
415  }
416  }
417 
418  return( $ret );
419  }
420 
421 
422  /* Return a sorted search */
423  function s_search($expression, $bnum = -1) {
424 
425  $ret = $this->search($expression, $bnum);
426  if ( is_array( $ret ) ) {
427  usort($ret, 'addressbook_cmp');
428  }
429  return $ret;
430  }
431 
432 
433  /*
434  * Lookup an address by the indicated field. Only
435  * possible in local backends.
436  */
437  function lookup($value, $bnum = -1, $field = SM_ABOOK_FIELD_NICKNAME) {
438 
439  $ret = array();
440 
441  if ($bnum > -1) {
442  $res = $this->backends[$bnum]->lookup($value, $field);
443  if (is_array($res)) {
444  return $res;
445  } else {
446  $this->error = $this->backends[$bnum]->error;
447  return false;
448  }
449  }
450 
451  $sel = $this->get_backend_list('local');
452  for ($i = 0 ; $i < sizeof($sel) ; $i++) {
453  $backend = &$sel[$i];
454  $backend->error = '';
455  $res = $backend->lookup($value, $field);
456 
457  // return an address if one is found
458  // (empty array means lookup concluded
459  // but no result found - in this case,
460  // proceed to next backend)
461  //
462  if (is_array($res)) {
463  if (!empty($res)) return $res;
464  } else {
465  $this->error = $backend->error;
466  return false;
467  }
468  }
469 
470  return $ret;
471  }
472 
473 
474  /* Return all addresses */
475  function list_addr($bnum = -1) {
476  $ret = array();
477 
478  if ($bnum == -1) {
479  $sel = $this->get_backend_list('');
480  } else {
481  $sel = array(0 => &$this->backends[$bnum]);
482  }
483 
484  for ($i = 0 ; $i < sizeof($sel) ; $i++) {
485  $backend = &$sel[$i];
486  $backend->error = '';
487  $res = $backend->list_addr();
488  if (is_array($res)) {
489  $ret = array_merge($ret, $res);
490  } else {
491  $this->error = $backend->error;
492  return false;
493  }
494  }
495 
496  return $ret;
497  }
498 
499  /*
500  * Create a new address from $userdata, in backend $bnum.
501  * Return the backend number that the/ address was added
502  * to, or false if it failed.
503  */
504  function add($userdata, $bnum) {
505 
506  /* Validate data */
507  if (!is_array($userdata)) {
508  $this->error = _("Invalid input data");
509  return false;
510  }
511  if (empty($userdata['firstname']) && empty($userdata['lastname'])) {
512  $this->error = _("Name is missing");
513  return false;
514  }
515  if (empty($userdata['email'])) {
516  $this->error = _("E-mail address is missing");
517  return false;
518  }
519  if (empty($userdata['nickname'])) {
520  $userdata['nickname'] = $userdata['email'];
521  }
522 
523  if (preg_match('/[ :|#"!]/', $userdata['nickname'])) {
524  $this->error = _("Nickname contains illegal characters");
525  return false;
526  }
527 
528  /* Check that specified backend accept new entries */
529  if (!$this->backends[$bnum]->writeable) {
530  $this->error = _("Address book is read-only");
531  return false;
532  }
533 
534  /* Add address to backend */
535  $res = $this->backends[$bnum]->add($userdata);
536  if ($res) {
537  return $bnum;
538  } else {
539  $this->error = $this->backends[$bnum]->error;
540  return false;
541  }
542 
543  return false; // Not reached
544  } /* end of add() */
545 
546 
547  /*
548  * Remove the user identified by $alias from backend $bnum
549  * If $alias is an array, all users in the array are removed.
550  */
551  function remove($alias, $bnum) {
552 
553  /* Check input */
554  if (empty($alias)) {
555  return true;
556  }
557 
558  /* Convert string to single element array */
559  if (!is_array($alias)) {
560  $alias = array(0 => $alias);
561  }
562 
563  /* Check that specified backend is writable */
564  if (!$this->backends[$bnum]->writeable) {
565  $this->error = _("Address book is read-only");
566  return false;
567  }
568 
569  /* Remove user from backend */
570  $res = $this->backends[$bnum]->remove($alias);
571  if ($res) {
572  return $bnum;
573  } else {
574  $this->error = $this->backends[$bnum]->error;
575  return false;
576  }
577 
578  return FALSE; /* Not reached */
579  } /* end of remove() */
580 
581 
582  /*
583  * Remove the user identified by $alias from backend $bnum
584  * If $alias is an array, all users in the array are removed.
585  */
586  function modify($alias, $userdata, $bnum) {
587 
588  /* Check input */
589  if (empty($alias) || !is_string($alias)) {
590  return true;
591  }
592 
593  /* Validate data */
594  if(!is_array($userdata)) {
595  $this->error = _("Invalid input data");
596  return false;
597  }
598  if (empty($userdata['firstname']) && empty($userdata['lastname'])) {
599  $this->error = _("Name is missing");
600  return false;
601  }
602  if (empty($userdata['email'])) {
603  $this->error = _("E-mail address is missing");
604  return false;
605  }
606 
607  if (preg_match('/[: |#"!]/', $userdata['nickname'])) {
608  $this->error = _("Nickname contains illegal characters");
609  return false;
610  }
611 
612  if (empty($userdata['nickname'])) {
613  $userdata['nickname'] = $userdata['email'];
614  }
615 
616  /* Check that specified backend is writable */
617  if (!$this->backends[$bnum]->writeable) {
618  $this->error = _("Address book is read-only");;
619  return false;
620  }
621 
622  /* Modify user in backend */
623  $res = $this->backends[$bnum]->modify($alias, $userdata);
624  if ($res) {
625  return $bnum;
626  } else {
627  $this->error = $this->backends[$bnum]->error;
628  return false;
629  }
630 
631  return FALSE; /* Not reached */
632  } /* end of modify() */
633 
634 
635 } /* End of class Addressbook */
636 
642 
643  /* Variables that all backends must provide. */
644  var $btype = 'dummy';
645  var $bname = 'dummy';
646  var $sname = 'Dummy backend';
647 
648  /*
649  * Variables common for all backends, but that
650  * should not be changed by the backends.
651  */
652  var $bnum = -1;
653  var $error = '';
654  var $writeable = false;
655 
656  function set_error($string) {
657  $this->error = '[' . $this->sname . '] ' . $string;
658  return false;
659  }
660 
661 
662  /* ========================== Public ======================== */
663 
664  function search($expression) {
665  $this->set_error('search not implemented');
666  return false;
667  }
668 
669  function lookup($value, $field) {
670  $this->set_error('lookup not implemented');
671  return false;
672  }
673 
674  function list_addr() {
675  $this->set_error('list_addr not implemented');
676  return false;
677  }
678 
679  function add($userdata) {
680  $this->set_error('add not implemented');
681  return false;
682  }
683 
684  function remove($alias) {
685  $this->set_error('delete not implemented');
686  return false;
687  }
688 
689  function modify($alias, $newuserdata) {
690  $this->set_error('modify not implemented');
691  return false;
692  }
693 
694 }
695 
696 /*
697  PHP 5 requires that the class be made first, which seems rather
698  logical, and should have been the way it was generated the first time.
699 */
700 
701 require_once(SM_PATH . 'functions/abook_local_file.php');
702 require_once(SM_PATH . 'functions/abook_ldap_server.php');
703 
704 /* Only load database backend if database is configured */
705 if((isset($addrbook_dsn) && !empty($addrbook_dsn)) ||
706  (isset($addrbook_global_dsn) && !empty($addrbook_global_dsn))) {
707  include_once(SM_PATH . 'functions/abook_database.php');
708 }
709 
710 /*
711  * hook allows adding different address book classes.
712  * class must follow address book class coding standards.
713  *
714  * see addressbook_backend class and functions/abook_*.php files.
715  * @since 1.5.1 and 1.4.5
716  */
717 do_hook('abook_add_class');
SM_ABOOK_FIELD_NICKNAME
const SM_ABOOK_FIELD_NICKNAME
Definition: constants.php:57
elseif
if(! sqgetGlobalVar('sound', $sound, SQ_GET)) elseif($sound=='(none)')
Definition: testsound.php:25
sqgetGlobalVar
sqgetGlobalVar($name, &$value, $search=SQ_INORDER)
Definition: global.php:344
$ret
$ret
Definition: webmail.php:172
get_abook_sort
get_abook_sort()
Definition: addressbook.php:229
getPref
getPref($data_dir, $username, $string, $default='')
Definition: db_prefs.php:316
AddressBook\$add_extra_field
$add_extra_field
Definition: addressbook.php:294
$addrbook_global_dsn
global $addrbook_global_dsn
Definition: addressbook.php:26
AddressBook\full_address
full_address($row)
Definition: addressbook.php:353
$abook_global_file
$abook_global_file
Definition: config_default.php:893
addressbook_backend\$bname
$bname
Definition: addressbook.php:645
show_abook_sort_button
show_abook_sort_button($abook_sort_order, $alt_tag, $Down, $Up)
Definition: addressbook.php:258
$data_dir
$data_dir
Definition: config_default.php:499
AddressBook\$localbackend
$localbackend
Definition: addressbook.php:292
AddressBook\add_backend
add_backend($backend, $param='')
Definition: addressbook.php:324
setPref
setPref($data_dir, $username, $string, $set_to)
Definition: db_prefs.php:352
sprintf
powered by Systran sprintf(_("Number of supported language pairs: %s"), '36').' '
Definition: options.php:107
addressbook_backend\modify
modify($alias, $newuserdata)
Definition: addressbook.php:689
AddressBook\add
add($userdata, $bnum)
Definition: addressbook.php:504
AddressBook\$backends
$backends
Definition: addressbook.php:289
addressbook_backend\set_error
set_error($string)
Definition: addressbook.php:656
$username
global $username
Definition: validate.php:55
do_hook
do_hook($name)
Definition: plugin.php:42
$addrbook_dsn
global $addrbook_dsn
Definition: addressbook.php:26
addressbook_backend\$sname
$sname
Definition: addressbook.php:646
$addrbook_table
$addrbook_table
Definition: config_default.php:966
AddressBook\lookup
lookup($value, $bnum=-1, $field=SM_ABOOK_FIELD_NICKNAME)
Definition: addressbook.php:437
$abook
$abook
Definition: addressbook.php:167
addressbook_backend\$error
$error
Definition: addressbook.php:653
$abook_global_file_writeable
$abook_global_file_writeable
Definition: config_default.php:900
$addrbook_global_table
$addrbook_global_table
Definition: config_default.php:988
addressbook_cmp
addressbook_cmp($a, $b)
Definition: addressbook.php:170
$abook_global_file_listing
$abook_global_file_listing
Definition: config_default.php:907
AddressBook\s_search
s_search($expression, $bnum=-1)
Definition: addressbook.php:423
$addrbook_global_writeable
$addrbook_global_writeable
Definition: config_default.php:994
$abook_file_line_length
$abook_file_line_length
Definition: config_default.php:925
AddressBook\modify
modify($alias, $userdata, $bnum)
Definition: addressbook.php:586
$addrsrch_fullname
$addrsrch_fullname
Definition: load_prefs.php:225
addressbook_backend\list_addr
list_addr()
Definition: addressbook.php:674
alistcmp
alistcmp($a, $b)
Definition: addressbook.php:185
$form_url
$form_url
Definition: addressbook.php:180
SQ_GET
const SQ_GET
Definition: global.php:16
SM_PATH
const SM_PATH
Definition: addressbook.php:22
$r
while(count($Left) > 0) $r
Definition: darkness.php:103
addressbook_backend
Definition: addressbook.php:641
addressbook_backend\$writeable
$writeable
Definition: addressbook.php:654
addressbook_backend\$bnum
$bnum
Definition: addressbook.php:652
AddressBook\$localbackendname
$localbackendname
Definition: addressbook.php:293
addressbook_backend\search
search($expression)
Definition: addressbook.php:664
addressbook_backend\add
add($userdata)
Definition: addressbook.php:679
$filename
if(isset($override_type0)) if(isset($override_type1)) $filename
Definition: download.php:97
_
_($str)
Definition: gettext.php:160
AddressBook\list_addr
list_addr($bnum=-1)
Definition: addressbook.php:475
getHashedFile
getHashedFile($username, $dir, $datafile, $hash_search=true)
Definition: prefs.php:56
AddressBook\get_backend_list
get_backend_list($type='')
Definition: addressbook.php:305
addressbook_backend\lookup
lookup($value, $field)
Definition: addressbook.php:669
$color
$color
Definition: load_prefs.php:28
AddressBook
Definition: addressbook.php:287
$sel
$sel
Definition: login.php:44
addressbook_backend\$btype
$btype
Definition: addressbook.php:644
AddressBook\$error
$error
Definition: addressbook.php:291
AddressBook\AddressBook
AddressBook()
Definition: addressbook.php:297
AddressBook\search
search($expression, $bnum=-1)
Definition: addressbook.php:382
AddressBook\$numbackends
$numbackends
Definition: addressbook.php:290
$abook_sort_order
$abook_sort_order
Definition: addressbook.php:57
$addrbook_global_listing
$addrbook_global_listing
Definition: config_default.php:1000
addressbook_init
addressbook_init($showerr=true, $onlylocal=false)
Definition: addressbook.php:32
error_box
error_box($string, $color)
Definition: display_messages.php:116