addressbook.php 27 KB

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