X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=functions%2Fabook_database.php;h=4e78697a73867fdc9f610cd3105bcc012384d9ae;hb=f48a90cae0cc40392dd10b2384d8a5d45bd91984;hp=c35ec9d0f6d6c4233ad63ef4b6598d90f02253c8;hpb=6c84ba1ec45ab854c37b6f65c5b4d84ab1c7aad4;p=squirrelmail.git diff --git a/functions/abook_database.php b/functions/abook_database.php index c35ec9d0..4e78697a 100644 --- a/functions/abook_database.php +++ b/functions/abook_database.php @@ -1,26 +1,31 @@ + * 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) + * * + * @copyright © 1999-2009 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 */ -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; -} +/** + * 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 @@ -102,7 +107,17 @@ class abook_database extends addressbook_backend { * @param array $param address book backend options */ function abook_database($param) { - $this->sname = _("Personal address book"); + $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']) || @@ -136,7 +151,7 @@ class abook_database extends addressbook_backend { /** - * Open the database. + * Open the database. * @param bool $new new connection if it is true * @return bool */ @@ -161,6 +176,13 @@ 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; } @@ -172,14 +194,45 @@ class abook_database extends addressbook_backend { $this->dbh = false; } + /** + * Determine internal database field name given one of + * the SquirrelMail SM_ABOOK_FIELD_* constants + * + * @param integer $field The SM_ABOOK_FIELD_* contant to look up + * + * @return string The desired field name, or the string "ERROR" + * if the $field is not understood (the caller + * is responsible for handing errors) + * + */ + function get_field_name($field) { + switch ($field) { + case SM_ABOOK_FIELD_NICKNAME: + return 'nickname'; + case SM_ABOOK_FIELD_FIRSTNAME: + return 'firstname'; + case SM_ABOOK_FIELD_LASTNAME: + return 'lastname'; + case SM_ABOOK_FIELD_EMAIL: + return 'email'; + case SM_ABOOK_FIELD_LABEL: + return 'label'; + default: + return 'ERROR'; + } + } + /* ========================== Public ======================== */ /** * 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 + * @return array search results. boolean false on error */ - function &search($expr) { + function search($expr) { $ret = array(); if(!$this->open()) { return false; @@ -190,15 +243,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)) { @@ -208,7 +276,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'], @@ -220,23 +288,42 @@ class abook_database extends addressbook_backend { } /** - * Lookup alias - * @param string $alias alias - * @return array search results + * Lookup an address by the indicated field. + * + * @param string $value The value to look up + * @param integer $field The field to look in, should be one + * of the SM_ABOOK_FIELD_* constants + * defined in include/constants.php + * (OPTIONAL; defaults to nickname field) + * NOTE: uniqueness is only guaranteed + * when the nickname field is used here; + * otherwise, the first matching address + * is returned. + * + * @return array Array with lookup results when the value + * was found, an empty array if the value was + * not found. + * */ - function &lookup($alias) { - if (empty($alias)) { + function lookup($value, $field=SM_ABOOK_FIELD_NICKNAME) { + if (empty($value)) { return array(); } - $alias = strtolower($alias); + $value = strtolower($value); if (!$this->open()) { return false; } - $query = sprintf("SELECT * FROM %s WHERE owner='%s' AND LOWER(nickname)='%s'", - $this->table, $this->owner, $this->dbh->quoteString($alias)); + $db_field = $this->get_field_name($field); + if ($db_field == 'ERROR') { + return $this->set_error(sprintf(_("Unknown field name: %s"), $field)); + } + + $query = sprintf("SELECT * FROM %s WHERE owner = '%s' AND LOWER(%s) = '%s'", + $this->table, $this->owner, $db_field, + $this->dbh->quoteString($value)); $res = $this->dbh->query($query); @@ -247,7 +334,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'], @@ -259,10 +346,10 @@ class abook_database extends addressbook_backend { } /** - * List all addresses + * List all addresses * @return array search results */ - function &list_addr() { + function list_addr() { $ret = array(); if (!$this->open()) { return false; @@ -285,7 +372,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'], @@ -303,7 +390,7 @@ class abook_database extends addressbook_backend { */ 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()) { @@ -313,8 +400,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 */ @@ -324,29 +410,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 - * @param string $alias alias that has to be deleted + * 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()) { @@ -367,13 +454,13 @@ 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; } /** @@ -384,7 +471,7 @@ class abook_database extends addressbook_backend { */ 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()) { @@ -394,8 +481,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 */ @@ -405,23 +501,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