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