Browse Source

adding phpdoc blocks in addressbook classes (one more backend to go)
adding global file based address book support.
global_file backend removed (code reuse)
administrator plugin still need some mods, but it is dark outside and i'll
finish it later.

tokul 21 năm trước cách đây
mục cha
commit
1c0b53d316
5 tập tin đã thay đổi với 291 bổ sung257 xóa
  1. 55 6
      config/conf.pl
  2. 11 0
      config/config_default.php
  3. 0 194
      functions/abook_global_file.php
  4. 66 19
      functions/abook_local_file.php
  5. 159 38
      functions/addressbook.php

+ 55 - 6
config/conf.pl

@@ -299,6 +299,8 @@ $prefs_val_field = 'prefval'            if ( !$prefs_val_field );
 $addrbook_global_table = 'global_abook' if ( !$addrbook_global_table );
 $addrbook_global_writeable = 'false'    if ( !$addrbook_global_writeable );
 $addrbook_global_listing = 'false'      if ( !$addrbook_global_listing );
+$abook_global_file = ''                 if ( !$abook_global_file);
+$abook_global_file_writeable = 'false'  if ( !$abook_global_file_writeable);
 $use_smtp_tls= 'false'                  if ( !$use_smtp_tls);
 $smtp_auth_mech = 'none'                if ( !$smtp_auth_mech );
 $use_imap_tls = 'false'                 if ( !$use_imap_tls );
@@ -357,7 +359,7 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) ) {
         print "3.  Folder Defaults\n";
         print "4.  General Options\n";
         print "5.  Themes\n";
-        print "6.  Address Books (LDAP)\n";
+        print "6.  Address Books\n";
         print "7.  Message of the Day (MOTD)\n";
         print "8.  Plugins\n";
         print "9.  Database\n";
@@ -498,13 +500,14 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) ) {
         print "\n";
         print "R   Return to Main Menu\n";
     } elsif ( $menu == 6 ) {
-        print $WHT. "Address Books (LDAP)\n" . $NRM;
-        print "1.  Change Servers\n";
+        print $WHT. "Address Books\n" . $NRM;
+        print "1.  Change LDAP Servers\n";
         for ( $count = 0 ; $count <= $#ldap_host ; $count++ ) {
             print "    >  $ldap_host[$count]\n";
         }
-        print
-          "2.  Use Javascript Address Book Search  : $WHT$default_use_javascript_addr_book$NRM\n";
+        print "2.  Use Javascript address book search  : $WHT$default_use_javascript_addr_book$NRM\n";
+        print "3.  Use global file address book        : $WHT$abook_global_file$NRM\n";
+        print "4.  Allow writing into global file address book : $WHT$abook_global_file_writeable$NRM\n";
         print "\n";
         print "R   Return to Main Menu\n";
     } elsif ( $menu == 7 ) {
@@ -713,6 +716,8 @@ while ( ( $command ne "q" ) && ( $command ne "Q" ) ) {
         } elsif ( $menu == 6 ) {
             if    ( $command == 1 ) { command61(); }
             elsif ( $command == 2 ) { command62(); }
+            elsif ( $command == 3 ) { $abook_global_file=command63(); }
+            elsif ( $command == 4 ) { command64(); }
         } elsif ( $menu == 7 ) {
             if ( $command == 1 ) { $motd = command71(); }
         } elsif ( $menu == 8 ) {
@@ -2565,6 +2570,46 @@ sub command62 {
     return $default_use_javascript_addr_book;
 }
 
+# global filebased address book
+sub command63 {
+    print "If you want to use global file address book, then you\n";
+    print "must set this option to a valid value. If option does\n";
+    print "not have path elements, system assumes that file is\n";
+    print "stored in data directory. If relative path is set, it is\n";
+    print "relative to main squirrelmail directory. If value is empty,\n";
+    print "address book is not enabled.\n";
+    print "\n";
+
+    print "[$WHT$abook_global_file$NRM]: $WHT";
+    $new_abook_global_file = <STDIN>;
+    if ( $new_abook_global_file eq "\n" ) {
+        $new_abook_global_file = $abook_global_file;
+    } else {
+        $new_abook_global_file =~ s/[\r\n]//g;
+    }
+    return $new_abook_global_file;
+}
+
+# writing into global filebased abook control
+sub command64 {
+    print "\n";
+
+    if ( lc($abook_global_file_writeable) eq 'true' ) {
+        $default_value = "y";
+    } else {
+        $abook_global_file_writeable = 'false';
+        $default_value               = "n";
+    }
+    print "Allow writting into global file address book (y/n) [$WHT$default_value$NRM]: $WHT";
+    $new_show = <STDIN>;
+    if ( ( $new_show =~ /^y\n/i ) || ( ( $new_show =~ /^\n/ ) && ( $default_value eq "y" ) ) ) {
+        $abook_global_file_writeable = 'true';
+    } else {
+        $abook_global_file_writeable = 'false';
+    }
+    return $abook_global_file_writeable;
+}
+
 sub command91 {
     print "If you want to store your users address book details in a database then\n";
     print "you need to set this DSN to a valid value. The format for this is:\n";
@@ -3258,9 +3303,13 @@ sub save_data {
     # string
         print CF "\$addrbook_global_table = '$addrbook_global_table';\n";
     # boolean
-        print CF "\$addrbook_global_writeable = $addrbook_global_writeable;\n\n";
+        print CF "\$addrbook_global_writeable = $addrbook_global_writeable;\n";
     # boolean
         print CF "\$addrbook_global_listing = $addrbook_global_listing;\n\n";
+    # string
+        print CF "\$abook_global_file = '$abook_global_file';\n";
+    # boolean
+        print CF "\$abook_global_file_writeable = $abook_global_file_writeable;\n\n";
     # boolean
         print CF "\$no_list_for_subscribe = $no_list_for_subscribe;\n";
 

+ 11 - 0
config/config_default.php

@@ -734,6 +734,17 @@ $theme[36]['NAME'] = 'Redmond';
  */
 $default_use_javascript_addr_book = false;
 
+/**
+ * Shared filebased address book
+ * @global string $abook_global_file
+ */
+$abook_global_file = '';
+
+/**
+ * Writing into shared address book control
+ * @global bool $abook_global_file_writeable
+ */
+$abook_global_file_writeable = false;
 
 /**
  * MOTD

+ 0 - 194
functions/abook_global_file.php

@@ -1,194 +0,0 @@
-<?php
-
-/**
- * abook_global_file.php
- *
- * Copyright (c) 1999-2004 The SquirrelMail Project Team
- * Licensed under the GNU GPL. For full terms see the file COPYING.
- *
- * Backend for addressbook as a pipe separated file
- *
- * An array with the following elements must be passed to
- * the class constructor (elements marked ? are optional):
- *
- * NOTE. This class should not be used directly. Use the
- *       "AddressBook" class instead.
- *
- * Make sure you configure this before using it!
- *
- * @version $Id$
- * @package squirrelmail
- * @subpackage addressbook
- */
-
-/**
- * Undocumented class - fixme
- * @package squirrelmail
- */
-class abook_global_file extends addressbook_backend {
-    var $btype = 'local';
-    var $bname = 'global_file';
-
-    var $filehandle = 0;
-
-    /* ========================== Private ======================= */
-
-    /* Constructor */
-    function abook_global_file() {
-        global $address_book_global_filename;
-        $this->global_filename = $address_book_global_filename;
-
-        $this->sname = _("Global address book");
-
-        $this->open(true);
-    }
-
-    /* Open the addressbook file and store the file pointer.
-     * Use $file as the file to open, or the class' own
-     * filename property. If $param is empty and file is
-     * open, do nothing. */
-    function open($new = false) {
-        $this->error = '';
-
-        /* Return true is file is open and $new is unset */
-        if($this->filehandle && !$new) {
-            return true;
-        }
-
-        /* Check that new file exists */
-        if (! file_exists($this->global_filename) ||
-            ! is_readable($this->global_filename)) {
-            return $this->set_error($this->global_filename . ': ' .
-                _("No such file or directory"));
-        }
-
-        /* Close old file, if any */
-        if ($this->filehandle) {
-            $this->close();
-        }
-
-        /* Open file, read only. */
-        $fh = @fopen($this->global_filename, 'r');
-        $this->writeable  = false;
-        if(! $fh) {
-            return $this->set_error($this->global_filename . ': ' .
-                _("Open failed"));
-        }
-
-        $this->filehandle = &$fh;
-        return true;
-    }
-
-    /* Close the file and forget the filehandle */
-    function close() {
-        @fclose($this->filehandle);
-        $this->filehandle = 0;
-        $this->global_filename   = '';
-        $this->writable   = false;
-    }
-
-    /* ========================== Public ======================== */
-
-    /* Search the file */
-    function search($expr) {
-
-        /* To be replaced by advanded search expression parsing */
-        if(is_array($expr)) {
-            return;
-        }
-
-        /* Make regexp from glob'ed expression
-         * May want to quote other special characters like (, ), -, [, ], etc. */
-        $expr = str_replace('?', '.', $expr);
-        $expr = str_replace('*', '.*', $expr);
-
-        $res = array();
-        if(!$this->open()) {
-            return false;
-        }
-
-        @rewind($this->filehandle);
-
-        while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
-            $line = join(' ', $row);
-            if (eregi($expr, $line)) {
-                $res[] = array('nickname'  => $row[0],
-                               'name'      => $row[1] . ' ' . $row[2],
-                               'firstname' => $row[1],
-                               'lastname'  => $row[2],
-                               'email'     => $row[3],
-                               'label'     => $row[4],
-                               'backend'   => $this->bnum,
-                               'source'    => &$this->sname);
-            }
-        }
-
-        return $res;
-    }
-
-    /* Lookup alias */
-    function lookup($alias) {
-        if (empty($alias)) {
-            return array();
-        }
-
-        $alias = strtolower($alias);
-
-        $this->open();
-        @rewind($this->filehandle);
-
-        while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
-            if (strtolower($row[0]) == $alias) {
-                return array('nickname'  => $row[0],
-                             'name'      => $row[1] . ' ' . $row[2],
-                             'firstname' => $row[1],
-                             'lastname'  => $row[2],
-                             'email'     => $row[3],
-                             'label'     => $row[4],
-                             'backend'   => $this->bnum,
-                             'source'    => &$this->sname);
-            }
-        }
-
-        return array();
-    }
-
-    /* List all addresses */
-    function list_addr() {
-        $res = array();
-        $this->open();
-        @rewind($this->filehandle);
-
-        while ($row = @fgetcsv($this->filehandle, 2048, '|')) {
-            $res[] = array('nickname'  => $row[0],
-                           'name'      => $row[1] . ' ' . $row[2],
-                           'firstname' => $row[1],
-                           'lastname'  => $row[2],
-                           'email'     => $row[3],
-                           'label'     => $row[4],
-                           'backend'   => $this->bnum,
-                           'source'    => &$this->sname);
-        }
-        return $res;
-    }
-
-    /* Add address */
-    function add($userdata) {
-        $this->set_error(_("Can not modify global address book"));
-        return false;
-    }
-
-    /* Delete address */
-    function remove($alias) {
-        $this->set_error(_("Can not modify global address book"));
-        return false;
-    }
-
-    /* Modify address */
-    function modify($alias, $userdata) {
-        $this->set_error(_("Can not modify global address book"));
-        return false;
-    }
-
-} /* End of class abook_local_file */
-?>

+ 66 - 19
functions/abook_local_file.php

@@ -28,18 +28,48 @@
  * @package squirrelmail
  */
 class abook_local_file extends addressbook_backend {
-    /** @var string backend type */
+    /**
+     * Backend type
+     * @var string 
+     */
     var $btype = 'local';
-    /** @var string backend name */
+    /**
+     * Backend name
+     * @var string
+     */
     var $bname = 'local_file';
 
-    /** @var string file used to store data */
-    var $filename   = '';
-    /** @var object file handle */
+    /**
+     * File used to store data
+     * @var string
+     */
+    var $filename = '';
+    /**
+     * File handle
+     * @var object
+     */
     var $filehandle = 0;
-    /** @var bool create file if it is not present */
-    var $create     = false;
-    /** @var string umask of the file */
+    /**
+     * Create file, if it not present
+     * @var bool
+     */
+    var $create = false;
+    /**
+     * Detect, if address book is writeable by checking file permisions
+     * @var bool
+     */
+    var $detect_writeable   = true;
+    /**
+     * Control write access to address book
+     *
+     * Option does not have any effect, if 'detect_writeable' is 'true'
+     * @var bool
+     */
+    var $writeable = false;
+    /**
+     * Umask of the file
+     * @var string
+     */
     var $umask;
 
     /* ========================== Private ======================= */
@@ -70,9 +100,15 @@ class abook_local_file extends addressbook_backend {
             if(isset($param['umask'])) {
                 $this->umask = $param['umask'];
             }
-            if(!empty($param['name'])) {
+            if(isset($param['name'])) {
                 $this->sname = $param['name'];
             }
+            if(isset($param['detect_writeable'])) {
+                $this->detect_writeable = $param['detect_writeable'];
+            }
+            if(!empty($param['writeable'])) {
+                $this->writeable = $param['writeable'];
+            }
 
             $this->open(true);
         } else {
@@ -92,6 +128,7 @@ class abook_local_file extends addressbook_backend {
         $this->error = '';
         $file   = $this->filename;
         $create = $this->create;
+        $fopenmode = ($this->writeable ? 'a+' : 'r');
 
         /* Return true is file is open and $new is unset */
         if($this->filehandle && !$new) {
@@ -106,22 +143,32 @@ class abook_local_file extends addressbook_backend {
         /* Close old file, if any */
         if($this->filehandle) { $this->close(); }
 
-        /* Open file. First try to open for reading and writing,
-         * but fall back to read only. */
         umask($this->umask);
-        $fh = @fopen($file, 'a+');
-        if($fh) {
-            $this->filehandle = &$fh;
-            $this->filename   = $file;
-            $this->writeable  = true;
+        if (! $this->detect_writeable) {
+            $fh = @fopen($file,$fopenmode);
+            if ($fh) {
+                $this->filehandle = &$fh;
+                $this->filename = $file;
+            } else {
+                return $this->set_error("$file: " . _("Open failed"));
+            }
         } else {
-            $fh = @fopen($file, 'r');
+            /* Open file. First try to open for reading and writing,
+             * but fall back to read only. */
+            $fh = @fopen($file, 'a+');
             if($fh) {
                 $this->filehandle = &$fh;
                 $this->filename   = $file;
-                $this->writeable  = false;
+                $this->writeable  = true;
             } else {
-                return $this->set_error("$file: " . _("Open failed"));
+                $fh = @fopen($file, 'r');
+                if($fh) {
+                    $this->filehandle = &$fh;
+                    $this->filename   = $file;
+                    $this->writeable  = false;
+                } else {
+                    return $this->set_error("$file: " . _("Open failed"));
+                }
             }
         }
         return true;

+ 159 - 38
functions/addressbook.php

@@ -39,6 +39,7 @@ global $addrbook_dsn, $addrbook_global_dsn;
 function addressbook_init($showerr = true, $onlylocal = false) {
     global $data_dir, $username, $ldap_server, $address_book_global_filename;
     global $addrbook_dsn, $addrbook_table;
+    global $abook_global_file, $abook_global_file_writeable;
     global $addrbook_global_dsn, $addrbook_global_table, $addrbook_global_writeable, $addrbook_global_listing;
 
     /* Create a new addressbook object */
@@ -74,8 +75,22 @@ function addressbook_init($showerr = true, $onlylocal = false) {
     }
 
     /* This would be for the global addressbook */
-    if (isset($address_book_global_filename)) {
-        $r = $abook->add_backend('global_file');
+    if (isset($abook_global_file) && isset($abook_global_file_writeable)
+	&& trim($abook_global_file)!=''){
+        // Detect place of address book
+        if (! preg_match("/[\/\\\]/",$abook_global_file)) {
+            // no path chars
+            $abook_global_filename=$data_dir . $abook_global_file;
+        } elseif (preg_match("/^\/|\w:/",$abook_global_file)) {
+            // full path is set in options (starts with slash or x:)
+            $abook_global_filename=$abook_global_file;
+        } else {
+            $abook_global_filename=SM_PATH . $abook_global_file;
+        }
+        $r = $abook->add_backend('local_file',array('filename'=>$abook_global_filename,
+                                                    'name' => _("Global address book"),
+                                                    'detect_writeable' => false,
+                                                    'writeable'=> $abook_global_file_writeable));
         if (!$r && $showerr) {
             echo _("Error initializing global addressbook.");
             exit;
@@ -367,21 +382,44 @@ function show_abook_sort_button($abook_sort_order, $alt_tag, $Down, $Up ) {
  * @subpackage addressbook
  */
 class AddressBook {
-
+    /**
+     * Enabled address book backends
+     * @var array
+     */
     var $backends    = array();
+    /**
+     * Number of enabled backends
+     * @var integer
+     */
     var $numbackends = 0;
+    /**
+     * Error messages
+     * @var string
+     */
     var $error       = '';
+    /**
+     * id of backend with personal address book
+     * @var integer
+     */
     var $localbackend = 0;
+    /**
+     * Name of backend with personal address book
+     * @var string
+     */
     var $localbackendname = '';
 
-      // Constructor function.
+    /**
+     * Constructor function.
+     */
     function AddressBook() {
         $this->localbackendname = _("Personal address book");
     }
 
-    /*
+    /**
      * Return an array of backends of a given type,
      * or all backends if no type is specified.
+     * @param string $type backend type
+     * @return array list of backends
      */
     function get_backend_list($type = '') {
         $ret = array();
@@ -394,13 +432,15 @@ class AddressBook {
     }
 
 
-    /*
-       ========================== Public ========================
+    /* ========================== Public ======================== */
 
-        Add a new backend. $backend is the name of a backend
-        (without the abook_ prefix), and $param is an optional
-        mixed variable that is passed to the backend constructor.
-        See each of the backend classes for valid parameters.
+    /**
+     * Add a new backend.
+     *
+     * @param string $backend backend name (without the abook_ prefix)
+     * @param mixed optional variable that is passed to the backend constructor.
+     * See each of the backend classes for valid parameters
+     * @return integer number of backends
      */
     function add_backend($backend, $param = '') {
         $backend_name = 'abook_' . $backend;
@@ -425,12 +465,15 @@ class AddressBook {
     }
 
 
-    /*
+    /**
+     * create string with name and email address
+     *
      * This function takes a $row array as returned by the addressbook
      * search and returns an e-mail address with the full name or
      * nickname optionally prepended.
+     * @param array $row address book entry
+     * @return string email address with real name prepended
      */
-
     function full_address($row) {
         global $addrsrch_fullname, $data_dir, $username;
         $prefix = getPref($data_dir, $username, 'addrsrch_fullname');
@@ -443,10 +486,15 @@ class AddressBook {
         }
     }
 
-    /*
-        Return a list of addresses matching expression in
-        all backends of a given type.
-    */
+    /**
+     * Search for entries in address books
+     *
+     * Return a list of addresses matching expression in
+     * all backends of a given type.
+     * @param string $expression search expression
+     * @param integer $bnum backend number. default to search in all backends
+     * @return array search results
+     */
     function search($expression, $bnum = -1) {
         $ret = array();
         $this->error = '';
@@ -487,7 +535,12 @@ class AddressBook {
     }
 
 
-    /* Return a sorted search */
+    /**
+     * Sorted search
+     * @param string $expression search expression
+     * @param integer $bnum backend number. default to search in all backends
+     * @return array search results
+     */
     function s_search($expression, $bnum = -1) {
 
         $ret = $this->search($expression, $bnum);
@@ -498,9 +551,12 @@ class AddressBook {
     }
 
 
-    /*
-     *  Lookup an address by alias. Only possible in
-     *  local backends.
+    /**
+     * Lookup an address by alias.
+     * Only possible in local backends.
+     * @param string $alias
+     * @param integer backend number
+     * @return array lookup results. False, if not found.
      */
     function lookup($alias, $bnum = -1) {
 
@@ -534,12 +590,16 @@ class AddressBook {
     }
 
 
-    /* Return all addresses */
+    /**
+     * Return all addresses
+     * @param integer $bnum backend number
+     * @return array search results
+     */
     function list_addr($bnum = -1) {
         $ret = array();
 
         if ($bnum == -1) {
-            $sel = $this->get_backend_list('local');
+            $sel = $this->get_backend_list('');
         } else {
             $sel = array(0 => &$this->backends[$bnum]);
         }
@@ -559,9 +619,11 @@ class AddressBook {
         return $ret;
     }
 
-    /*
-     * Create a new address from $userdata, in backend $bnum.
-     * Return the backend number that the/ address was added
+    /**
+     * Create a new address 
+     * @param array $userdata added address record
+     * @param integer $bnum backend number
+     * @return integer the backend number that the/ address was added
      * to, or false if it failed.
      */
     function add($userdata, $bnum) {
@@ -607,9 +669,11 @@ class AddressBook {
     } /* end of add() */
 
 
-    /*
-     * Remove the user identified by $alias from backend $bnum
-     * If $alias is an array, all users in the array are removed.
+    /**
+     * Remove the entries from address book
+     * @param mixed $alias entries that have to be removed. Can be string with nickname or array with list of nicknames 
+     * @param integer $bnum backend number
+     * @return bool true if removed successfully. false if there s an error. $this->error contains error message
      */
     function remove($alias, $bnum) {
 
@@ -642,9 +706,11 @@ class AddressBook {
     } /* end of remove() */
 
 
-    /*
-     * Remove the user identified by $alias from backend $bnum
-     * If $alias is an array, all users in the array are removed.
+    /**
+     * Modify entry in address book
+     * @param string $alias nickname
+     * @param array $userdata newdata
+     * @param integer $bnum backend number
      */
     function modify($alias, $userdata, $bnum) {
 
@@ -705,18 +771,49 @@ class AddressBook {
 class addressbook_backend {
 
     /* Variables that all backends must provide. */
+    /**
+     * Backend type
+     *
+     * Can be 'local' or 'remote'
+     * @var string backend type
+     */
     var $btype      = 'dummy';
+    /**
+     * Internal backend name
+     * @var string
+     */
     var $bname      = 'dummy';
+    /**
+     * Displayed backend name
+     * @var string
+     */
     var $sname      = 'Dummy backend';
 
     /*
      * Variables common for all backends, but that
      * should not be changed by the backends.
      */
+    /**
+     * Backend number
+     * @var integer
+     */
     var $bnum       = -1;
+    /**
+     * Error messages
+     * @var string
+     */
     var $error      = '';
+    /**
+     * Writeable flag
+     * @var bool
+     */
     var $writeable  = false;
 
+    /**
+     * Set error message
+     * @param string $string error message
+     * @return bool
+     */
     function set_error($string) {
         $this->error = '[' . $this->sname . '] ' . $string;
         return false;
@@ -725,36 +822,65 @@ class addressbook_backend {
 
     /* ========================== Public ======================== */
 
+    /**
+     * Search for entries in backend
+     * @param string $expression
+     * @return bool
+     */
     function search($expression) {
         $this->set_error('search not implemented');
         return false;
     }
 
+    /**
+     * Find entry in backend by alias
+     * @param string $alias name used for id
+     * @return bool
+     */
     function lookup($alias) {
         $this->set_error('lookup not implemented');
         return false;
     }
 
+    /**
+     * List all entries in backend
+     * @return bool
+     */
     function list_addr() {
         $this->set_error('list_addr not implemented');
         return false;
     }
 
+    /**
+     * Add entry to backend
+     * @param array userdata
+     * @return bool
+     */
     function add($userdata) {
         $this->set_error('add not implemented');
         return false;
     }
 
+    /**
+     * Remove entry from backend
+     * @param string $alias name used for id
+     * @return bool
+     */
     function remove($alias) {
         $this->set_error('delete not implemented');
         return false;
     }
 
+    /**
+     * Modify entry in backend
+     * @param string $alias name used for id
+     * @param array $newuserdata new data
+     * @return bool
+     */
     function modify($alias, $newuserdata) {
         $this->set_error('modify not implemented');
         return false;
     }
-
 }
 
 /*
@@ -765,11 +891,6 @@ class addressbook_backend {
 require_once(SM_PATH . 'functions/abook_local_file.php');
 require_once(SM_PATH . 'functions/abook_ldap_server.php');
 
-/* Use this if you wanna have a global address book */
-if (isset($address_book_global_filename)) {
-    include_once(SM_PATH . 'functions/abook_global_file.php');
-}
-
 /* Only load database backend if database is configured */
 if((isset($addrbook_dsn) && !empty($addrbook_dsn)) ||
  (isset($addrbook_global_dsn) && !empty($addrbook_global_dsn)) ) {