5100704d |
1 | <?php |
2 | |
3 | /** |
4 | ** addressbook.php |
5 | ** |
6 | ** Functions and classes for the addressbook system. |
7 | ** |
245a6892 |
8 | ** $Id$ |
5100704d |
9 | **/ |
10 | |
11 | $addressbook_php = true; |
12 | |
13 | // Include backends here. |
b9bfd165 |
14 | include('../functions/abook_local_file.php'); |
15 | include('../functions/abook_ldap_server.php'); |
5100704d |
16 | |
0515b57a |
17 | |
5100704d |
18 | // Create and initialize an addressbook object. |
19 | // Returns the created object |
0d273153 |
20 | function addressbook_init($showerr = true, $onlylocal = false) { |
5100704d |
21 | global $data_dir, $username, $ldap_server; |
22 | |
23 | // Create a new addressbook object |
24 | $abook = new AddressBook; |
25 | |
26 | // Always add a local backend |
b9bfd165 |
27 | $filename = sprintf('%s%s.abook', $data_dir, $username); |
28 | $r = $abook->add_backend('local_file', Array('filename' => $filename, |
29 | 'create' => true)); |
0d273153 |
30 | if(!$r && $showerr) { |
1e62e50e |
31 | printf(_("Error opening file %s"), $filename); |
5100704d |
32 | exit; |
33 | } |
0d273153 |
34 | |
35 | if($onlylocal) |
36 | return $abook; |
5100704d |
37 | |
95a4d303 |
38 | // Load configured LDAP servers (if PHP has LDAP support) |
b9bfd165 |
39 | if(is_array($ldap_server) && function_exists('ldap_connect')) { |
1ed2b1e0 |
40 | reset($ldap_server); |
fb16d219 |
41 | while(list($undef,$param) = each($ldap_server)) { |
1ed2b1e0 |
42 | if(is_array($param)) { |
b9bfd165 |
43 | $r = $abook->add_backend('ldap_server', $param); |
1ed2b1e0 |
44 | if(!$r && $showerr) { |
b9bfd165 |
45 | printf(' ' . _("Error initializing LDAP server %s:") . |
46 | "<BR>\n", $param['host']); |
47 | print(' ' . $abook->error); |
1ed2b1e0 |
48 | exit; |
49 | } |
50 | } |
51 | } |
799b9070 |
52 | } |
5100704d |
53 | |
54 | // Return the initialized object |
55 | return $abook; |
56 | } |
57 | |
0515b57a |
58 | |
59 | // Had to move this function outside of the Addressbook Class |
60 | // PHP 4.0.4 Seemed to be having problems with inline functions. |
61 | function cmp($a,$b) { |
b9bfd165 |
62 | if($a['backend'] > $b['backend']) |
0515b57a |
63 | return 1; |
b9bfd165 |
64 | else if($a['backend'] < $b['backend']) |
0515b57a |
65 | return -1; |
b9bfd165 |
66 | return (strtolower($a['name']) > strtolower($b['name'])) ? 1 : -1; |
0515b57a |
67 | } |
5100704d |
68 | |
69 | |
70 | /** |
71 | ** This is the main address book class that connect all the |
72 | ** backends and provide services to the functions above. |
73 | ** |
74 | **/ |
0515b57a |
75 | |
5100704d |
76 | class AddressBook { |
77 | var $backends = array(); |
78 | var $numbackends = 0; |
b9bfd165 |
79 | var $error = ''; |
ce916cdf |
80 | var $localbackend = 0; |
b9bfd165 |
81 | var $localbackendname = ''; |
5100704d |
82 | |
83 | // Constructor function. |
84 | function AddressBook() { |
1ed2b1e0 |
85 | $localbackendname = _("Personal address book"); |
5100704d |
86 | } |
87 | |
88 | // Return an array of backends of a given type, |
89 | // or all backends if no type is specified. |
b9bfd165 |
90 | function get_backend_list($type = '') { |
5100704d |
91 | $ret = array(); |
92 | for($i = 1 ; $i <= $this->numbackends ; $i++) { |
93 | if(empty($type) || $type == $this->backends[$i]->btype) { |
94 | array_push($ret, &$this->backends[$i]); |
95 | } |
96 | } |
97 | return $ret; |
98 | } |
99 | |
100 | |
101 | // ========================== Public ======================== |
102 | |
103 | // Add a new backend. $backend is the name of a backend |
104 | // (without the abook_ prefix), and $param is an optional |
105 | // mixed variable that is passed to the backend constructor. |
106 | // See each of the backend classes for valid parameters. |
b9bfd165 |
107 | function add_backend($backend, $param = '') { |
108 | $backend_name = 'abook_' . $backend; |
5100704d |
109 | eval("\$newback = new $backend_name(\$param);"); |
110 | if(!empty($newback->error)) { |
111 | $this->error = $newback->error; |
112 | return false; |
113 | } |
114 | |
115 | $this->numbackends++; |
116 | |
117 | $newback->bnum = $this->numbackends; |
118 | $this->backends[$this->numbackends] = $newback; |
ce916cdf |
119 | |
120 | // Store ID of first local backend added |
b9bfd165 |
121 | if($this->localbackend == 0 && $newback->btype == 'local') { |
ce916cdf |
122 | $this->localbackend = $this->numbackends; |
1ed2b1e0 |
123 | $this->localbackendname = $newback->sname; |
124 | } |
ce916cdf |
125 | |
5100704d |
126 | return $this->numbackends; |
127 | } |
128 | |
129 | |
130 | // Return a list of addresses matching expression in |
131 | // all backends of a given type. |
2f73dc15 |
132 | function search($expression, $bnum = -1) { |
5100704d |
133 | $ret = array(); |
b9bfd165 |
134 | $this->error = ''; |
5100704d |
135 | |
2f73dc15 |
136 | // Search all backends |
137 | if($bnum == -1) { |
b9bfd165 |
138 | $sel = $this->get_backend_list(''); |
2f73dc15 |
139 | $failed = 0; |
140 | for($i = 0 ; $i < sizeof($sel) ; $i++) { |
141 | $backend = &$sel[$i]; |
b9bfd165 |
142 | $backend->error = ''; |
2f73dc15 |
143 | $res = $backend->search($expression); |
144 | if(is_array($res)) { |
145 | $ret = array_merge($ret, $res); |
146 | } else { |
b9bfd165 |
147 | $this->error .= "<br>\n" . $backend->error; |
2f73dc15 |
148 | $failed++; |
149 | } |
5100704d |
150 | } |
2f73dc15 |
151 | |
152 | // Only fail if all backends failed |
153 | if($failed >= sizeof($sel)) |
154 | return false; |
155 | |
5100704d |
156 | } |
157 | |
2f73dc15 |
158 | // Search only one backend |
159 | else { |
160 | $ret = $this->backends[$bnum]->search($expression); |
161 | if(!is_array($ret)) { |
b9bfd165 |
162 | $this->error .= "<br>\n" . $this->backends[$bnum]->error; |
2f73dc15 |
163 | return false; |
164 | } |
165 | } |
0d273153 |
166 | |
5100704d |
167 | return $ret; |
168 | } |
169 | |
0515b57a |
170 | |
5100704d |
171 | // Return a sorted search |
2f73dc15 |
172 | function s_search($expression, $bnum = -1) { |
0515b57a |
173 | |
174 | $ret = $this->search($expression, $bnum); |
175 | if(!is_array($ret)) |
176 | return $ret; |
177 | usort($ret, 'cmp'); |
178 | return $ret; |
5100704d |
179 | } |
180 | |
181 | |
182 | // Lookup an address by alias. Only possible in |
183 | // local backends. |
1ed2b1e0 |
184 | function lookup($alias, $bnum = -1) { |
5100704d |
185 | $ret = array(); |
186 | |
1ed2b1e0 |
187 | if($bnum > -1) { |
188 | $res = $this->backends[$bnum]->lookup($alias); |
189 | if(is_array($res)) { |
190 | return $res; |
191 | } else { |
192 | $this->error = $backend->error; |
193 | return false; |
194 | } |
195 | } |
196 | |
b9bfd165 |
197 | $sel = $this->get_backend_list('local'); |
5100704d |
198 | for($i = 0 ; $i < sizeof($sel) ; $i++) { |
199 | $backend = &$sel[$i]; |
b9bfd165 |
200 | $backend->error = ''; |
5100704d |
201 | $res = $backend->lookup($alias); |
202 | if(is_array($res)) { |
1ed2b1e0 |
203 | if(!empty($res)) |
204 | return $res; |
5100704d |
205 | } else { |
206 | $this->error = $backend->error; |
207 | return false; |
208 | } |
209 | } |
210 | |
211 | return $ret; |
212 | } |
213 | |
214 | |
215 | // Return all addresses |
2f73dc15 |
216 | function list_addr($bnum = -1) { |
5100704d |
217 | $ret = array(); |
218 | |
2f73dc15 |
219 | if($bnum == -1) |
b9bfd165 |
220 | $sel = $this->get_backend_list('local'); |
2f73dc15 |
221 | else |
222 | $sel = array(0 => &$this->backends[$bnum]); |
223 | |
5100704d |
224 | for($i = 0 ; $i < sizeof($sel) ; $i++) { |
225 | $backend = &$sel[$i]; |
b9bfd165 |
226 | $backend->error = ''; |
5100704d |
227 | $res = $backend->list_addr(); |
228 | if(is_array($res)) { |
229 | $ret = array_merge($ret, $res); |
230 | } else { |
231 | $this->error = $backend->error; |
232 | return false; |
233 | } |
234 | } |
235 | |
236 | return $ret; |
237 | } |
238 | |
239 | |
240 | // Create a new address from $userdata, in backend $bnum. |
241 | // Return the backend number that the/ address was added |
242 | // to, or false if it failed. |
243 | function add($userdata, $bnum) { |
244 | |
245 | // Validate data |
246 | if(!is_array($userdata)) { |
247 | $this->error = _("Invalid input data"); |
248 | return false; |
249 | } |
b9bfd165 |
250 | if(empty($userdata['firstname']) && |
251 | empty($userdata['lastname'])) { |
5100704d |
252 | $this->error = _("Name is missing"); |
253 | return false; |
254 | } |
b9bfd165 |
255 | if(empty($userdata['email'])) { |
5100704d |
256 | $this->error = _("E-mail address is missing"); |
257 | return false; |
258 | } |
b9bfd165 |
259 | if(empty($userdata['nickname'])) { |
260 | $userdata['nickname'] = $userdata['email']; |
5100704d |
261 | } |
262 | |
b9bfd165 |
263 | if(eregi("[\: \|\#\"\!]", $userdata['nickname'])) { |
1ed2b1e0 |
264 | $this->error = _("Nickname contain illegal characters"); |
265 | return false; |
266 | } |
267 | |
5100704d |
268 | // Check that specified backend accept new entries |
269 | if(!$this->backends[$bnum]->writeable) { |
1e62e50e |
270 | $this->error = _("Addressbook is read-only"); |
5100704d |
271 | return false; |
272 | } |
273 | |
274 | // Add address to backend |
275 | $res = $this->backends[$bnum]->add($userdata); |
276 | if($res) { |
277 | return $bnum; |
278 | } else { |
279 | $this->error = $this->backends[$bnum]->error; |
280 | return false; |
281 | } |
282 | |
283 | return false; // Not reached |
1ed2b1e0 |
284 | } // end of add() |
5100704d |
285 | |
1ed2b1e0 |
286 | |
287 | // Remove the user identified by $alias from backend $bnum |
288 | // If $alias is an array, all users in the array are removed. |
289 | function remove($alias, $bnum) { |
290 | |
291 | // Check input |
292 | if(empty($alias)) |
293 | return true; |
294 | |
295 | // Convert string to single element array |
296 | if(!is_array($alias)) |
297 | $alias = array(0 => $alias); |
298 | |
299 | // Check that specified backend is writable |
300 | if(!$this->backends[$bnum]->writeable) { |
301 | $this->error = _("Addressbook is read-only"); |
302 | return false; |
303 | } |
304 | |
305 | // Remove user from backend |
306 | $res = $this->backends[$bnum]->remove($alias); |
307 | if($res) { |
308 | return $bnum; |
309 | } else { |
310 | $this->error = $this->backends[$bnum]->error; |
311 | return false; |
312 | } |
313 | |
314 | return false; // Not reached |
315 | } // end of remove() |
316 | |
317 | |
318 | // Remove the user identified by $alias from backend $bnum |
319 | // If $alias is an array, all users in the array are removed. |
320 | function modify($alias, $userdata, $bnum) { |
321 | |
322 | // Check input |
323 | if(empty($alias) || !is_string($alias)) |
324 | return true; |
325 | |
326 | // Validate data |
327 | if(!is_array($userdata)) { |
328 | $this->error = _("Invalid input data"); |
329 | return false; |
330 | } |
b9bfd165 |
331 | if(empty($userdata['firstname']) && |
332 | empty($userdata['lastname'])) { |
1ed2b1e0 |
333 | $this->error = _("Name is missing"); |
334 | return false; |
335 | } |
b9bfd165 |
336 | if(empty($userdata['email'])) { |
1ed2b1e0 |
337 | $this->error = _("E-mail address is missing"); |
338 | return false; |
339 | } |
d9fdc8d3 |
340 | |
b9bfd165 |
341 | if(eregi("[\: \|\#\"\!]", $userdata['nickname'])) { |
d9fdc8d3 |
342 | $this->error = _("Nickname contain illegal characters"); |
343 | return false; |
344 | } |
345 | |
b9bfd165 |
346 | if(empty($userdata['nickname'])) { |
347 | $userdata['nickname'] = $userdata['email']; |
1ed2b1e0 |
348 | } |
349 | |
350 | // Check that specified backend is writable |
351 | if(!$this->backends[$bnum]->writeable) { |
d9fdc8d3 |
352 | $this->error = _("Addressbook is read-only");; |
1ed2b1e0 |
353 | return false; |
354 | } |
355 | |
356 | // Modify user in backend |
357 | $res = $this->backends[$bnum]->modify($alias, $userdata); |
358 | if($res) { |
359 | return $bnum; |
360 | } else { |
361 | $this->error = $this->backends[$bnum]->error; |
362 | return false; |
363 | } |
364 | |
365 | return false; // Not reached |
366 | } // end of modify() |
367 | |
5100704d |
368 | |
0515b57a |
369 | } // End of class Addressbook |
5100704d |
370 | |
371 | /** |
372 | ** Generic backend that all other backends extend |
373 | **/ |
374 | class addressbook_backend { |
375 | |
376 | // Variables that all backends must provide. |
b9bfd165 |
377 | var $btype = 'dummy'; |
378 | var $bname = 'dummy'; |
379 | var $sname = 'Dummy backend'; |
5100704d |
380 | |
381 | // Variables common for all backends, but that |
382 | // should not be changed by the backends. |
383 | var $bnum = -1; |
b9bfd165 |
384 | var $error = ''; |
5100704d |
385 | var $writeable = false; |
386 | |
387 | function set_error($string) { |
b9bfd165 |
388 | $this->error = '[' . $this->sname . '] ' . $string; |
5100704d |
389 | return false; |
390 | } |
391 | |
392 | |
393 | // ========================== Public ======================== |
394 | |
395 | function search($expression) { |
b9bfd165 |
396 | $this->set_error('search not implemented'); |
5100704d |
397 | return false; |
398 | } |
399 | |
400 | function lookup($alias) { |
b9bfd165 |
401 | $this->set_error('lookup not implemented'); |
5100704d |
402 | return false; |
403 | } |
404 | |
405 | function list_addr() { |
b9bfd165 |
406 | $this->set_error('list_addr not implemented'); |
5100704d |
407 | return false; |
408 | } |
409 | |
410 | function add($userdata) { |
b9bfd165 |
411 | $this->set_error('add not implemented'); |
5100704d |
412 | return false; |
413 | } |
414 | |
1ed2b1e0 |
415 | function remove($alias) { |
b9bfd165 |
416 | $this->set_error('delete not implemented'); |
1ed2b1e0 |
417 | return false; |
418 | } |
419 | |
420 | function modify($alias, $newuserdata) { |
b9bfd165 |
421 | $this->set_error('modify not implemented'); |
1ed2b1e0 |
422 | return false; |
423 | } |
424 | |
5100704d |
425 | } |
426 | |
427 | ?> |