extra sanitizing was added in B and Q header decoding, when SquirrelMail tried to
[squirrelmail.git] / functions / abook_database.php
CommitLineData
9b9474d6 1<?php
4b4abf93 2
35586184 3/**
4 * abook_database.php
5 *
47ccfad4 6 * @copyright &copy; 1999-2006 The SquirrelMail Project Team
4b4abf93 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
a9d318b0 8 * @version $Id$
d6c32258 9 * @package squirrelmail
a9d318b0 10 * @subpackage addressbook
35586184 11 */
d6c32258 12
62f7daa5 13/** Needs the DB functions */
c9fcea56 14if (!include_once('DB.php')) {
15 // same error also in db_prefs.php
c9fcea56 16 $error = _("Could not include PEAR database functions required for the database backend.") . "<br />\n";
2ad4cea9 17 $error .= sprintf(_("Is PEAR installed, and is the include path set correctly to find %s?"),
18 '<tt>DB.php</tt>') . "<br />\n";
c9fcea56 19 $error .= _("Please contact your system administrator and report this error.");
20 error_box($error, $color);
17fca61d 21 exit;
c9fcea56 22}
d6c32258 23
24/**
0541c5ae 25 * Address book in a database backend
26 *
27 * Backend for personal/shared address book stored in a database,
28 * accessed using the DB-classes in PEAR.
29 *
30 * IMPORTANT: The PEAR modules must be in the include path
31 * for this class to work.
32 *
33 * An array with the following elements must be passed to
34 * the class constructor (elements marked ? are optional):
35 * <pre>
36 * dsn => database DNS (see PEAR for syntax)
37 * table => table to store addresses in (must exist)
38 * owner => current user (owner of address data)
39 * ? name => name of address book
40 * ? writeable => set writeable flag (true/false)
41 * ? listing => enable/disable listing
42 * </pre>
43 * The table used should have the following columns:
44 * owner, nickname, firstname, lastname, email, label
45 * The pair (owner,nickname) should be unique (primary key).
46 *
47 * NOTE. This class should not be used directly. Use the
48 * "AddressBook" class instead.
d6c32258 49 * @package squirrelmail
0541c5ae 50 * @subpackage addressbook
d6c32258 51 */
9b9474d6 52class abook_database extends addressbook_backend {
0541c5ae 53 /**
54 * Backend type
55 * @var string
56 */
9b9474d6 57 var $btype = 'local';
0541c5ae 58 /**
59 * Backend name
60 * @var string
61 */
9b9474d6 62 var $bname = 'database';
62f7daa5 63
0541c5ae 64 /**
65 * Data Source Name (connection description)
66 * @var string
67 */
9b9474d6 68 var $dsn = '';
0541c5ae 69 /**
70 * Table that stores addresses
71 * @var string
72 */
9b9474d6 73 var $table = '';
0541c5ae 74 /**
75 * Owner name
76 *
77 * Limits list of database entries visible to end user
78 * @var string
79 */
9b9474d6 80 var $owner = '';
0541c5ae 81 /**
82 * Database Handle
83 * @var resource
84 */
9b9474d6 85 var $dbh = false;
0541c5ae 86 /**
87 * Enable/disable writing into address book
88 * @var bool
89 */
9b9474d6 90 var $writeable = true;
0541c5ae 91 /**
92 * Enable/disable address book listing
93 * @var bool
94 */
95 var $listing = true;
62f7daa5 96
9b9474d6 97 /* ========================== Private ======================= */
62f7daa5 98
0541c5ae 99 /**
100 * Constructor
101 * @param array $param address book backend options
102 */
9b9474d6 103 function abook_database($param) {
104 $this->sname = _("Personal address book");
62f7daa5 105
9b9474d6 106 if (is_array($param)) {
62f7daa5 107 if (empty($param['dsn']) ||
108 empty($param['table']) ||
9b9474d6 109 empty($param['owner'])) {
110 return $this->set_error('Invalid parameters');
111 }
62f7daa5 112
91be2362 113 $this->dsn = $param['dsn'];
114 $this->table = $param['table'];
115 $this->owner = $param['owner'];
62f7daa5 116
9b9474d6 117 if (!empty($param['name'])) {
91be2362 118 $this->sname = $param['name'];
9b9474d6 119 }
7902aca2 120
9b9474d6 121 if (isset($param['writeable'])) {
91be2362 122 $this->writeable = $param['writeable'];
9b9474d6 123 }
7902aca2 124
30e9932c 125 if (isset($param['listing'])) {
126 $this->listing = $param['listing'];
127 }
128
7902aca2 129 $this->open(true);
9b9474d6 130 }
131 else {
91be2362 132 return $this->set_error('Invalid argument to constructor');
9b9474d6 133 }
134 }
62f7daa5 135
136
0541c5ae 137 /**
e50f5ac2 138 * Open the database.
0541c5ae 139 * @param bool $new new connection if it is true
140 * @return bool
141 */
9b9474d6 142 function open($new = false) {
143 $this->error = '';
62f7daa5 144
9b9474d6 145 /* Return true is file is open and $new is unset */
146 if ($this->dbh && !$new) {
7902aca2 147 return true;
9b9474d6 148 }
62f7daa5 149
9b9474d6 150 /* Close old file, if any */
151 if ($this->dbh) {
152 $this->close();
153 }
62f7daa5 154
9b9474d6 155 $dbh = DB::connect($this->dsn, true);
62f7daa5 156
286fe80b 157 if (DB::isError($dbh)) {
701c9c6b 158 return $this->set_error(sprintf(_("Database error: %s"),
7902aca2 159 DB::errorMessage($dbh)));
9b9474d6 160 }
62f7daa5 161
9b9474d6 162 $this->dbh = $dbh;
163 return true;
164 }
7902aca2 165
0541c5ae 166 /**
167 * Close the file and forget the filehandle
168 */
9b9474d6 169 function close() {
170 $this->dbh->disconnect();
171 $this->dbh = false;
172 }
7902aca2 173
9b9474d6 174 /* ========================== Public ======================== */
62f7daa5 175
0541c5ae 176 /**
177 * Search the database
178 * @param string $expr search expression
179 * @return array search results
180 */
aa8c4265 181 function search($expr) {
9b9474d6 182 $ret = array();
183 if(!$this->open()) {
7902aca2 184 return false;
9b9474d6 185 }
30e9932c 186
9b9474d6 187 /* To be replaced by advanded search expression parsing */
188 if (is_array($expr)) {
189 return;
190 }
191
327e2d96 192 // don't allow wide search when listing is disabled.
193 if ($expr=='*' && ! $this->listing)
194 return array();
195
9b9474d6 196 /* Make regexp from glob'ed expression */
197 $expr = str_replace('?', '_', $expr);
198 $expr = str_replace('*', '%', $expr);
199 $expr = $this->dbh->quoteString($expr);
200 $expr = "%$expr%";
201
202 $query = sprintf("SELECT * FROM %s WHERE owner='%s' AND " .
203 "(firstname LIKE '%s' OR lastname LIKE '%s')",
204 $this->table, $this->owner, $expr, $expr);
205 $res = $this->dbh->query($query);
206
207 if (DB::isError($res)) {
701c9c6b 208 return $this->set_error(sprintf(_("Database error: %s"),
7902aca2 209 DB::errorMessage($res)));
9b9474d6 210 }
7902aca2 211
9b9474d6 212 while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
91be2362 213 array_push($ret, array('nickname' => $row['nickname'],
214 'name' => "$row[firstname] $row[lastname]",
215 'firstname' => $row['firstname'],
216 'lastname' => $row['lastname'],
217 'email' => $row['email'],
218 'label' => $row['label'],
219 'backend' => $this->bnum,
220 'source' => &$this->sname));
9b9474d6 221 }
222 return $ret;
223 }
62f7daa5 224
0541c5ae 225 /**
226 * Lookup alias
227 * @param string $alias alias
228 * @return array search results
229 */
aa8c4265 230 function lookup($alias) {
9b9474d6 231 if (empty($alias)) {
7902aca2 232 return array();
9b9474d6 233 }
62f7daa5 234
9b9474d6 235 $alias = strtolower($alias);
7902aca2 236
9b9474d6 237 if (!$this->open()) {
7902aca2 238 return false;
9b9474d6 239 }
62f7daa5 240
2c90a9f2 241 $query = sprintf("SELECT * FROM %s WHERE owner='%s' AND LOWER(nickname)='%s'",
11f2b6ba 242 $this->table, $this->owner, $this->dbh->quoteString($alias));
7902aca2 243
9b9474d6 244 $res = $this->dbh->query($query);
7902aca2 245
9b9474d6 246 if (DB::isError($res)) {
701c9c6b 247 return $this->set_error(sprintf(_("Database error: %s"),
7902aca2 248 DB::errorMessage($res)));
9b9474d6 249 }
7902aca2 250
9b9474d6 251 if ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
91be2362 252 return array('nickname' => $row['nickname'],
253 'name' => "$row[firstname] $row[lastname]",
254 'firstname' => $row['firstname'],
255 'lastname' => $row['lastname'],
256 'email' => $row['email'],
257 'label' => $row['label'],
258 'backend' => $this->bnum,
259 'source' => &$this->sname);
9b9474d6 260 }
261 return array();
262 }
263
0541c5ae 264 /**
e50f5ac2 265 * List all addresses
0541c5ae 266 * @return array search results
267 */
aa8c4265 268 function list_addr() {
9b9474d6 269 $ret = array();
270 if (!$this->open()) {
7902aca2 271 return false;
9b9474d6 272 }
62f7daa5 273
91e0dccc 274 if(isset($this->listing) && !$this->listing) {
275 return array();
276 }
30e9932c 277
7902aca2 278
9b9474d6 279 $query = sprintf("SELECT * FROM %s WHERE owner='%s'",
280 $this->table, $this->owner);
7902aca2 281
9b9474d6 282 $res = $this->dbh->query($query);
62f7daa5 283
9b9474d6 284 if (DB::isError($res)) {
701c9c6b 285 return $this->set_error(sprintf(_("Database error: %s"),
7902aca2 286 DB::errorMessage($res)));
9b9474d6 287 }
7902aca2 288
9b9474d6 289 while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
91be2362 290 array_push($ret, array('nickname' => $row['nickname'],
291 'name' => "$row[firstname] $row[lastname]",
292 'firstname' => $row['firstname'],
293 'lastname' => $row['lastname'],
294 'email' => $row['email'],
295 'label' => $row['label'],
296 'backend' => $this->bnum,
297 'source' => &$this->sname));
9b9474d6 298 }
299 return $ret;
300 }
7902aca2 301
0541c5ae 302 /**
303 * Add address
304 * @param array $userdata added data
305 * @return bool
306 */
9b9474d6 307 function add($userdata) {
308 if (!$this->writeable) {
701c9c6b 309 return $this->set_error(_("Addressbook is read-only"));
9b9474d6 310 }
7902aca2 311
9b9474d6 312 if (!$this->open()) {
7902aca2 313 return false;
9b9474d6 314 }
62f7daa5 315
9b9474d6 316 /* See if user exist already */
317 $ret = $this->lookup($userdata['nickname']);
318 if (!empty($ret)) {
2706a0b1 319 return $this->set_error(sprintf(_("User \"%s\" already exists"),$ret['nickname']));
9b9474d6 320 }
321
322 /* Create query */
323 $query = sprintf("INSERT INTO %s (owner, nickname, firstname, " .
324 "lastname, email, label) VALUES('%s','%s','%s'," .
325 "'%s','%s','%s')",
326 $this->table, $this->owner,
327 $this->dbh->quoteString($userdata['nickname']),
62f7daa5 328 $this->dbh->quoteString($userdata['firstname']),
8419c13b 329 $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
62f7daa5 330 $this->dbh->quoteString($userdata['email']),
8419c13b 331 $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')) );
9b9474d6 332
333 /* Do the insert */
7902aca2 334 $r = $this->dbh->simpleQuery($query);
9b9474d6 335 if ($r == DB_OK) {
336 return true;
337 }
7902aca2 338
9b9474d6 339 /* Fail */
701c9c6b 340 return $this->set_error(sprintf(_("Database error: %s"),
7902aca2 341 DB::errorMessage($r)));
9b9474d6 342 }
7902aca2 343
0541c5ae 344 /**
345 * Delete address
346 * @param string $alias alias that has to be deleted
347 * @return bool
348 */
9b9474d6 349 function remove($alias) {
350 if (!$this->writeable) {
701c9c6b 351 return $this->set_error(_("Addressbook is read-only"));
9b9474d6 352 }
7902aca2 353
9b9474d6 354 if (!$this->open()) {
7902aca2 355 return false;
9b9474d6 356 }
62f7daa5 357
9b9474d6 358 /* Create query */
359 $query = sprintf("DELETE FROM %s WHERE owner='%s' AND (",
360 $this->table, $this->owner);
7902aca2 361
9b9474d6 362 $sepstr = '';
363 while (list($undef, $nickname) = each($alias)) {
16a973d7 364 $query .= sprintf("%s nickname='%s' ", $sepstr,
7902aca2 365 $this->dbh->quoteString($nickname));
91be2362 366 $sepstr = 'OR';
9b9474d6 367 }
368 $query .= ')';
7902aca2 369
9b9474d6 370 /* Delete entry */
371 $r = $this->dbh->simpleQuery($query);
372 if ($r == DB_OK) {
373 return true;
374 }
7902aca2 375
9b9474d6 376 /* Fail */
377 return $this->set_error(sprintf(_("Database error: %s"),
7902aca2 378 DB::errorMessage($r)));
9b9474d6 379 }
7902aca2 380
0541c5ae 381 /**
382 * Modify address
383 * @param string $alias modified alias
384 * @param array $userdata new data
385 * @return bool
386 */
9b9474d6 387 function modify($alias, $userdata) {
388 if (!$this->writeable) {
701c9c6b 389 return $this->set_error(_("Addressbook is read-only"));
9b9474d6 390 }
7902aca2 391
9b9474d6 392 if (!$this->open()) {
7902aca2 393 return false;
9b9474d6 394 }
62f7daa5 395
9b9474d6 396 /* See if user exist */
397 $ret = $this->lookup($alias);
398 if (empty($ret)) {
2706a0b1 399 return $this->set_error(sprintf(_("User \"%s\" does not exist"),$alias));
9b9474d6 400 }
401
402 /* Create query */
403 $query = sprintf("UPDATE %s SET nickname='%s', firstname='%s', ".
404 "lastname='%s', email='%s', label='%s' ".
405 "WHERE owner='%s' AND nickname='%s'",
62f7daa5 406 $this->table,
9b9474d6 407 $this->dbh->quoteString($userdata['nickname']),
62f7daa5 408 $this->dbh->quoteString($userdata['firstname']),
8419c13b 409 $this->dbh->quoteString((!empty($userdata['lastname'])?$userdata['lastname']:'')),
62f7daa5 410 $this->dbh->quoteString($userdata['email']),
8419c13b 411 $this->dbh->quoteString((!empty($userdata['label'])?$userdata['label']:'')),
9b9474d6 412 $this->owner,
413 $this->dbh->quoteString($alias) );
414
415 /* Do the insert */
416 $r = $this->dbh->simpleQuery($query);
417 if ($r == DB_OK) {
418 return true;
419 }
7902aca2 420
9b9474d6 421 /* Fail */
422 return $this->set_error(sprintf(_("Database error: %s"),
423 DB::errorMessage($r)));
424 }
425} /* End of class abook_database */
7902aca2 426
c9fcea56 427// vim: et ts=4
8419c13b 428?>