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