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