Source for file addressbook.php

Documentation is available at addressbook.php

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

Documentation generated on Sat, 07 Oct 2006 16:08:47 +0300 by phpDocumentor 1.3.0RC6