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