X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=functions%2Fabook_database.php;h=8ae859e02720cbef01a353a8f323d2d188dfea58;hp=20efeb65eec468c02407131b996b198d90deed1e;hb=daf777102978219856d97b6b4e93f8b5815db234;hpb=62f7daa5b0686061e12aeeee9866c195488c0d44 diff --git a/functions/abook_database.php b/functions/abook_database.php index 20efeb65..8ae859e0 100644 --- a/functions/abook_database.php +++ b/functions/abook_database.php @@ -3,10 +3,34 @@ /** * abook_database.php * - * Copyright (c) 1999-2004 The SquirrelMail Project Team - * Licensed under the GNU GPL. For full terms see the file COPYING. + * Supported database schema + *
+ *  owner varchar(128) NOT NULL
+ *  nickname varchar(16) NOT NULL
+ *  firstname varchar(128) 
+ *  lastname varchar(128)
+ *  email varchar(128) NOT NULL
+ *  label varchar(255)
+ *  PRIMARY KEY (owner,nickname)
+ * 
* - * Backend for personal addressbook stored in a database, + * @copyright © 1999-2007 The SquirrelMail Project Team + * @license http://opensource.org/licenses/gpl-license.php GNU Public License + * @version $Id$ + * @package squirrelmail + * @subpackage addressbook + */ + +/** + * Needs the DB functions + * Don't display errors here. Error will be set in class constructor function. + */ +@include_once('DB.php'); + +/** + * Address book in a database backend + * + * Backend for personal/shared address book stored in a database, * accessed using the DB-classes in PEAR. * * IMPORTANT: The PEAR modules must be in the include path @@ -14,57 +38,87 @@ * * An array with the following elements must be passed to * the class constructor (elements marked ? are optional): - * - * dsn => database DNS (see PEAR for syntax) - * table => table to store addresses in (must exist) - * owner => current user (owner of address data) - * ? writeable => set writeable flag (true/false) - * + *
+ *   dsn       => database DNS (see PEAR for syntax)
+ *   table     => table to store addresses in (must exist)
+ *   owner     => current user (owner of address data)
+ * ? name      => name of address book
+ * ? writeable => set writeable flag (true/false)
+ * ? listing   => enable/disable listing
+ * 
* The table used should have the following columns: * owner, nickname, firstname, lastname, email, label * The pair (owner,nickname) should be unique (primary key). * * NOTE. This class should not be used directly. Use the * "AddressBook" class instead. - * - * @version $Id$ * @package squirrelmail * @subpackage addressbook */ - -/** Needs the DB functions */ -if (!include_once('DB.php')) { - // same error also in db_prefs.php - require_once(SM_PATH . 'functions/display_messages.php'); - $error = _("Could not include PEAR database functions required for the database backend.") . "
\n"; - $error .= sprintf(_("Is PEAR installed, and is the include path set correctly to find %s?"), - 'DB.php') . "
\n"; - $error .= _("Please contact your system administrator and report this error."); - error_box($error, $color); - exit; -} - -/** - * Undocumented class - stores the addressbook in a sql database - * @package squirrelmail - */ class abook_database extends addressbook_backend { + /** + * Backend type + * @var string + */ var $btype = 'local'; + /** + * Backend name + * @var string + */ var $bname = 'database'; + /** + * Data Source Name (connection description) + * @var string + */ var $dsn = ''; + /** + * Table that stores addresses + * @var string + */ var $table = ''; + /** + * Owner name + * + * Limits list of database entries visible to end user + * @var string + */ var $owner = ''; + /** + * Database Handle + * @var resource + */ var $dbh = false; - + /** + * Enable/disable writing into address book + * @var bool + */ var $writeable = true; + /** + * Enable/disable address book listing + * @var bool + */ + var $listing = true; /* ========================== Private ======================= */ - /* Constructor */ + /** + * Constructor + * @param array $param address book backend options + */ function abook_database($param) { $this->sname = _("Personal address book"); + /* test if Pear DB class is available and freak out if it is not */ + if (! class_exists('DB')) { + // same error also in db_prefs.php + $error = _("Could not include PEAR database functions required for the database backend.") . "\n"; + $error .= sprintf(_("Is PEAR installed, and is the include path set correctly to find %s?"), + 'DB.php') . "\n"; + $error .= _("Please contact your system administrator and report this error."); + return $this->set_error($error); + } + if (is_array($param)) { if (empty($param['dsn']) || empty($param['table']) || @@ -96,7 +150,11 @@ class abook_database extends addressbook_backend { } - /* Open the database. New connection if $new is true */ + /** + * Open the database. + * @param bool $new new connection if it is true + * @return bool + */ function open($new = false) { $this->error = ''; @@ -118,10 +176,19 @@ class abook_database extends addressbook_backend { } $this->dbh = $dbh; + + /** + * field names are lowercased. + * We use unquoted identifiers and they use upper case in Oracle + */ + $this->dbh->setOption('portability', DB_PORTABILITY_LOWERCASE); + return true; } - /* Close the file and forget the filehandle */ + /** + * Close the file and forget the filehandle + */ function close() { $this->dbh->disconnect(); $this->dbh = false; @@ -129,8 +196,15 @@ class abook_database extends addressbook_backend { /* ========================== Public ======================== */ - /* Search the file */ - function &search($expr) { + /** + * Search the database + * + * Backend supports only * and ? wildcards. Complex eregs are not supported. + * Search is case insensitive. + * @param string $expr search expression + * @return array search results. boolean false on error + */ + function search($expr) { $ret = array(); if(!$this->open()) { return false; @@ -141,15 +215,30 @@ class abook_database extends addressbook_backend { return; } - /* Make regexp from glob'ed expression */ + // don't allow wide search when listing is disabled. + if ($expr=='*' && ! $this->listing) + return array(); + + /* lowercase expression in order to make it case insensitive */ + $expr = strtolower($expr); + + /* escape SQL wildcards */ + $expr = str_replace('_', '\\_', $expr); + $expr = str_replace('%', '\\%', $expr); + + /* Convert wildcards to SQL syntax */ $expr = str_replace('?', '_', $expr); $expr = str_replace('*', '%', $expr); $expr = $this->dbh->quoteString($expr); $expr = "%$expr%"; + /* create escape expression */ + $escape = 'ESCAPE \'' . $this->dbh->quoteString('\\') . '\''; + $query = sprintf("SELECT * FROM %s WHERE owner='%s' AND " . - "(firstname LIKE '%s' OR lastname LIKE '%s')", - $this->table, $this->owner, $expr, $expr); + "(LOWER(firstname) LIKE '%s' %s OR LOWER(lastname) LIKE '%s' %s)", + $this->table, $this->owner, $expr, $escape, $expr, $escape); + $res = $this->dbh->query($query); if (DB::isError($res)) { @@ -159,7 +248,7 @@ class abook_database extends addressbook_backend { while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) { array_push($ret, array('nickname' => $row['nickname'], - 'name' => "$row[firstname] $row[lastname]", + 'name' => $this->fullname($row['firstname'], $row['lastname']), 'firstname' => $row['firstname'], 'lastname' => $row['lastname'], 'email' => $row['email'], @@ -170,8 +259,12 @@ class abook_database extends addressbook_backend { return $ret; } - /* Lookup alias */ - function &lookup($alias) { + /** + * Lookup alias + * @param string $alias alias + * @return array search results + */ + function lookup($alias) { if (empty($alias)) { return array(); } @@ -194,7 +287,7 @@ class abook_database extends addressbook_backend { if ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) { return array('nickname' => $row['nickname'], - 'name' => "$row[firstname] $row[lastname]", + 'name' => $this->fullname($row['firstname'], $row['lastname']), 'firstname' => $row['firstname'], 'lastname' => $row['lastname'], 'email' => $row['email'], @@ -205,16 +298,19 @@ class abook_database extends addressbook_backend { return array(); } - /* List all addresses */ - function &list_addr() { + /** + * List all addresses + * @return array search results + */ + function list_addr() { $ret = array(); if (!$this->open()) { return false; } - if(isset($this->listing) && !$this->listing) { - return array(); - } + if(isset($this->listing) && !$this->listing) { + return array(); + } $query = sprintf("SELECT * FROM %s WHERE owner='%s'", @@ -229,7 +325,7 @@ class abook_database extends addressbook_backend { while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) { array_push($ret, array('nickname' => $row['nickname'], - 'name' => "$row[firstname] $row[lastname]", + 'name' => $this->fullname($row['firstname'], $row['lastname']), 'firstname' => $row['firstname'], 'lastname' => $row['lastname'], 'email' => $row['email'], @@ -240,10 +336,14 @@ class abook_database extends addressbook_backend { return $ret; } - /* Add address */ + /** + * Add address + * @param array $userdata added data + * @return bool + */ function add($userdata) { if (!$this->writeable) { - return $this->set_error(_("Addressbook is read-only")); + return $this->set_error(_("Address book is read-only")); } if (!$this->open()) { @@ -253,8 +353,7 @@ class abook_database extends addressbook_backend { /* See if user exist already */ $ret = $this->lookup($userdata['nickname']); if (!empty($ret)) { - return $this->set_error(sprintf(_("User '%s' already exist"), - $ret['nickname'])); + return $this->set_error(sprintf(_("User \"%s\" already exists"),$ret['nickname'])); } /* Create query */ @@ -264,25 +363,30 @@ class abook_database extends addressbook_backend { $this->table, $this->owner, $this->dbh->quoteString($userdata['nickname']), $this->dbh->quoteString($userdata['firstname']), - $this->dbh->quoteString($userdata['lastname']), + $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')), $this->dbh->quoteString($userdata['email']), - $this->dbh->quoteString($userdata['label']) ); + $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')) ); /* Do the insert */ $r = $this->dbh->simpleQuery($query); - if ($r == DB_OK) { - return true; + + /* Check for errors */ + if (DB::isError($r)) { + return $this->set_error(sprintf(_("Database error: %s"), + DB::errorMessage($r))); } - - /* Fail */ - return $this->set_error(sprintf(_("Database error: %s"), - DB::errorMessage($r))); + return true; } - /* Delete address */ + /** + * Deletes address book entries + * @param array $alias aliases that have to be deleted. numerical + * array with nickname values + * @return bool + */ function remove($alias) { if (!$this->writeable) { - return $this->set_error(_("Addressbook is read-only")); + return $this->set_error(_("Address book is read-only")); } if (!$this->open()) { @@ -303,19 +407,24 @@ class abook_database extends addressbook_backend { /* Delete entry */ $r = $this->dbh->simpleQuery($query); - if ($r == DB_OK) { - return true; - } - /* Fail */ - return $this->set_error(sprintf(_("Database error: %s"), - DB::errorMessage($r))); + /* Check for errors */ + if (DB::isError($r)) { + return $this->set_error(sprintf(_("Database error: %s"), + DB::errorMessage($r))); + } + return true; } - /* Modify address */ + /** + * Modify address + * @param string $alias modified alias + * @param array $userdata new data + * @return bool + */ function modify($alias, $userdata) { if (!$this->writeable) { - return $this->set_error(_("Addressbook is read-only")); + return $this->set_error(_("Address book is read-only")); } if (!$this->open()) { @@ -325,8 +434,17 @@ class abook_database extends addressbook_backend { /* See if user exist */ $ret = $this->lookup($alias); if (empty($ret)) { - return $this->set_error(sprintf(_("User '%s' does not exist"), - $alias)); + return $this->set_error(sprintf(_("User \"%s\" does not exist"),$alias)); + } + + /* make sure that new nickname is not used */ + if (strtolower($alias) != strtolower($userdata['nickname'])) { + /* same check as in add() */ + $ret = $this->lookup($userdata['nickname']); + if (!empty($ret)) { + $error = sprintf(_("User '%s' already exist."), $ret['nickname']); + return $this->set_error($error); + } } /* Create query */ @@ -336,23 +454,22 @@ class abook_database extends addressbook_backend { $this->table, $this->dbh->quoteString($userdata['nickname']), $this->dbh->quoteString($userdata['firstname']), - $this->dbh->quoteString($userdata['lastname']), + $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')), $this->dbh->quoteString($userdata['email']), - $this->dbh->quoteString($userdata['label']), + $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')), $this->owner, $this->dbh->quoteString($alias) ); /* Do the insert */ $r = $this->dbh->simpleQuery($query); - if ($r == DB_OK) { - return true; - } - /* Fail */ - return $this->set_error(sprintf(_("Database error: %s"), - DB::errorMessage($r))); + /* Check for errors */ + if (DB::isError($r)) { + return $this->set_error(sprintf(_("Database error: %s"), + DB::errorMessage($r))); + } + return true; } } /* End of class abook_database */ // vim: et ts=4 -?> \ No newline at end of file