abdfb4d0 |
1 | <?php |
134e4174 |
2 | |
35586184 |
3 | /** |
4 | * addressbook.php |
5 | * |
35586184 |
6 | * Manage personal address book. |
7 | * |
4b5049de |
8 | * @copyright © 1999-2007 The SquirrelMail Project Team |
4b4abf93 |
9 | * @license http://opensource.org/licenses/gpl-license.php GNU Public License |
30967a1e |
10 | * @version $Id$ |
8f6f9ba5 |
11 | * @package squirrelmail |
de00443c |
12 | * @subpackage addressbook |
35586184 |
13 | */ |
14 | |
ebd2391c |
15 | /** This is the addressbook page */ |
16 | define('PAGE_NAME', 'addressbook'); |
17 | |
30967a1e |
18 | /** |
202bcbcc |
19 | * Include the SquirrelMail initialization file. |
30967a1e |
20 | */ |
202bcbcc |
21 | include('../include/init.php'); |
86725763 |
22 | |
8f6f9ba5 |
23 | /** SquirrelMail required files. */ |
df4162cb |
24 | /* address book functions */ |
202bcbcc |
25 | require_once(SM_PATH . 'functions/addressbook.php'); |
3f92c0c7 |
26 | include_once(SM_PATH . 'templates/util_addressbook.php'); |
27 | |
df4162cb |
28 | /* form functions */ |
202bcbcc |
29 | require_once(SM_PATH . 'functions/forms.php'); |
ffd8224c |
30 | |
8f6f9ba5 |
31 | /** lets get the global vars we may need */ |
0b97a708 |
32 | |
33 | /* From the address form */ |
a71b394e |
34 | sqgetGlobalVar('addaddr', $addaddr, SQ_POST); |
35 | sqgetGlobalVar('editaddr', $editaddr, SQ_POST); |
36 | sqgetGlobalVar('deladdr', $deladdr, SQ_POST); |
f4f64c58 |
37 | sqgetGlobalVar('compose_to', $compose_to, SQ_POST); |
a71b394e |
38 | sqgetGlobalVar('sel', $sel, SQ_POST); |
39 | sqgetGlobalVar('oldnick', $oldnick, SQ_POST); |
40 | sqgetGlobalVar('backend', $backend, SQ_POST); |
41 | sqgetGlobalVar('doedit', $doedit, SQ_POST); |
4fe67ca6 |
42 | $page_size = $abook_show_num; |
43 | if (!sqGetGlobalVar('page_number', $page_number, SQ_FORM)) |
44 | if (!sqGetGlobalVar('current_page_number', $page_number, SQ_FORM)) |
45 | $page_number = 1; |
46 | if (!sqGetGlobalVar('show_all', $show_all, SQ_FORM)) |
47 | $show_all = 0; |
0b97a708 |
48 | |
08e71631 |
49 | /* Get sorting order */ |
50 | $abook_sort_order = get_abook_sort(); |
51 | |
10d82708 |
52 | // Create page header before addressbook_init in order to |
53 | // display error messages correctly, unless we might be |
54 | // redirecting the browser to the compose page. |
55 | // |
56 | if ((empty($compose_to)) || sizeof($sel) < 1) |
57 | displayPageHeader($color); |
703fa6b5 |
58 | |
de00443c |
59 | /* Open addressbook with error messages on. |
60 | remote backends (LDAP) are enabled because they can be used. (list_addr function) |
61 | */ |
62 | $abook = addressbook_init(true, false); |
ced653f3 |
63 | |
4fe67ca6 |
64 | // FIXME: do we really have to stop use of address book when localbackend is not present? |
daba719e |
65 | if($abook->localbackend == 0) { |
a71b394e |
66 | plain_error_message(_("No personal address book is defined. Contact administrator.")); |
daba719e |
67 | exit(); |
68 | } |
ffd8224c |
69 | |
a71b394e |
70 | $current_backend = $abook->localbackend; |
caa596b2 |
71 | if (sqgetGlobalVar('new_bnum', $new_backend, SQ_FORM) |
72 | && array_key_exists($new_backend, $abook->backends)) { |
a71b394e |
73 | $current_backend = (int) $new_backend; |
74 | } |
75 | |
76 | $abook_selection = ' '; |
77 | $list_backends = array(); |
78 | if (count($abook->backends) > 1) { |
79 | foreach($abook->get_backend_list() as $oBackend) { |
80 | if ($oBackend->listing) { |
81 | $list_backends[$oBackend->bnum]=$oBackend->sname; |
82 | } |
83 | } |
84 | if (count($list_backends)>1) { |
85 | $abook_selection = addSelect('new_bnum',$list_backends,$current_backend,true) |
86 | .addSubmit(_("Change"),'change_abook'); |
87 | } |
88 | } |
89 | |
daba719e |
90 | $defdata = array(); |
91 | $formerror = ''; |
92 | $abortform = false; |
93 | $showaddrlist = true; |
94 | $defselected = array(); |
07dcee9f |
95 | $form_url = 'addressbook.php'; |
daba719e |
96 | |
f6c945b9 |
97 | /* Handle user's actions */ |
1e12d1ff |
98 | if(sqgetGlobalVar('REQUEST_METHOD', $req_method, SQ_SERVER) && $req_method == 'POST') { |
daba719e |
99 | |
f6c945b9 |
100 | /************************************************** |
101 | * Add new address * |
102 | **************************************************/ |
39b26252 |
103 | if (isset($addaddr)) { |
a123157f |
104 | if (isset($backend)) { |
105 | $r = $abook->add($addaddr, $backend); |
106 | } else { |
107 | $r = $abook->add($addaddr, $abook->localbackend); |
c6554ec0 |
108 | } |
ffd8224c |
109 | |
f6c945b9 |
110 | /* Handle error messages */ |
111 | if (!$r) { |
112 | /* Remove backend name from error string */ |
ffd8224c |
113 | $errstr = $abook->error; |
114 | $errstr = ereg_replace('^\[.*\] *', '', $errstr); |
115 | |
116 | $formerror = $errstr; |
117 | $showaddrlist = false; |
118 | $defdata = $addaddr; |
119 | } |
daba719e |
120 | } else { |
ffd8224c |
121 | |
f6c945b9 |
122 | /************************************************ |
123 | * Delete address(es) * |
124 | ************************************************/ |
125 | if ((!empty($deladdr)) && sizeof($sel) > 0) { |
daba719e |
126 | $orig_sel = $sel; |
127 | sort($sel); |
128 | |
f4f64c58 |
129 | /* The selected addresses are identified by "backend_nickname". * |
f6c945b9 |
130 | * Sort the list and process one backend at the time */ |
daba719e |
131 | $prevback = -1; |
132 | $subsel = array(); |
133 | $delfailed = false; |
134 | |
f6c945b9 |
135 | for ($i = 0 ; (($i < sizeof($sel)) && !$delfailed) ; $i++) { |
f4f64c58 |
136 | list($sbackend, $snick) = explode('_', $sel[$i], 2); |
daba719e |
137 | |
f6c945b9 |
138 | /* When we get to a new backend, process addresses in * |
139 | * previous one. */ |
140 | if ($prevback != $sbackend && $prevback != -1) { |
daba719e |
141 | |
142 | $r = $abook->remove($subsel, $prevback); |
f6c945b9 |
143 | if (!$r) { |
daba719e |
144 | $formerror = $abook->error; |
145 | $i = sizeof($sel); |
146 | $delfailed = true; |
147 | break; |
148 | } |
149 | $subsel = array(); |
150 | } |
151 | |
f6c945b9 |
152 | /* Queue for processing */ |
daba719e |
153 | array_push($subsel, $snick); |
154 | $prevback = $sbackend; |
ffd8224c |
155 | } |
ffd8224c |
156 | |
f6c945b9 |
157 | if (!$delfailed) { |
daba719e |
158 | $r = $abook->remove($subsel, $prevback); |
f6c945b9 |
159 | if (!$r) { /* Handle errors */ |
daba719e |
160 | $formerror = $abook->error; |
161 | $delfailed = true; |
162 | } |
ffd8224c |
163 | } |
ffd8224c |
164 | |
f6c945b9 |
165 | if ($delfailed) { |
daba719e |
166 | $showaddrlist = true; |
167 | $defselected = $orig_sel; |
ffd8224c |
168 | } |
ffd8224c |
169 | |
f4f64c58 |
170 | /************************************************ |
171 | * Compose to selected address(es) * |
172 | ************************************************/ |
173 | } else if ((!empty($compose_to)) && sizeof($sel) > 0) { |
174 | $orig_sel = $sel; |
175 | sort($sel); |
176 | |
177 | // The selected addresses are identified by "backend_nickname" |
178 | $lookup_failed = false; |
179 | $send_to = ''; |
180 | |
181 | for ($i = 0 ; (($i < sizeof($sel)) && !$lookup_failed) ; $i++) { |
182 | list($sbackend, $snick) = explode('_', $sel[$i], 2); |
183 | |
184 | $data = $abook->lookup($snick, $sbackend); |
185 | |
186 | if (!$data) { |
187 | $formerror = $abook->error; |
188 | $lookup_failed = true; |
189 | break; |
190 | } else { |
191 | $addr = $abook->full_address($data); |
192 | if (!empty($addr)) |
193 | $send_to .= $addr . ', '; |
194 | } |
195 | } |
196 | |
197 | |
198 | if ($lookup_failed || empty($send_to)) { |
199 | $showaddrlist = true; |
200 | $defselected = $sel; |
10d82708 |
201 | |
202 | // we skipped the page header above for this functionality, so add it here |
203 | displayPageHeader($color); |
f4f64c58 |
204 | } |
205 | |
206 | |
207 | // send off to compose screen |
208 | else { |
209 | $send_to = trim($send_to, ', '); |
210 | header('Location: ' . $base_uri . 'src/compose.php?send_to=' . rawurlencode($send_to)); |
211 | exit; |
212 | } |
213 | |
daba719e |
214 | } else { |
215 | |
f6c945b9 |
216 | /*********************************************** |
217 | * Update/modify address * |
218 | ***********************************************/ |
219 | if (!empty($editaddr)) { |
f6c945b9 |
220 | /* Stage one: Copy data into form */ |
daba719e |
221 | if (isset($sel) && sizeof($sel) > 0) { |
222 | if(sizeof($sel) > 1) { |
223 | $formerror = _("You can only edit one address at the time"); |
224 | $showaddrlist = true; |
225 | $defselected = $sel; |
226 | } else { |
227 | $abortform = true; |
f4f64c58 |
228 | list($ebackend, $enick) = explode('_', current($sel), 2); |
daba719e |
229 | $olddata = $abook->lookup($enick, $ebackend); |
5b61a40d |
230 | // Test if $olddata really contains anything and return an error message if it doesn't |
231 | if (!$olddata) { |
232 | error_box(nl2br(htmlspecialchars($abook->error))); |
233 | } else { |
234 | /* Display the "new address" form */ |
caa596b2 |
235 | echo abook_create_form($form_url, 'editaddr', |
236 | _("Update address"), |
237 | _("Update address"), |
238 | $current_backend, |
239 | $olddata); |
5b61a40d |
240 | echo addHidden('oldnick', $olddata['nickname']). |
241 | addHidden('backend', $olddata['backend']). |
242 | addHidden('doedit', '1'). |
243 | '</form>'; |
244 | } |
daba719e |
245 | } |
3e87f870 |
246 | } elseif ($doedit == 1) { |
f6c945b9 |
247 | /* Stage two: Write new data */ |
3e87f870 |
248 | $newdata = $editaddr; |
249 | $r = $abook->modify($oldnick, $newdata, $backend); |
daba719e |
250 | |
3e87f870 |
251 | /* Handle error messages */ |
252 | if (!$r) { |
253 | /* Display error */ |
3c656c5f |
254 | plain_error_message( nl2br(htmlspecialchars($abook->error))); |
3e87f870 |
255 | |
256 | /* Display the "new address" form again */ |
caa596b2 |
257 | echo abook_create_form($form_url, 'editaddr', |
258 | _("Update address"), |
259 | _("Update address"), |
260 | $current_backend, |
261 | $newdata); |
3e87f870 |
262 | echo addHidden('oldnick', $oldnick). |
263 | addHidden('backend', $backend). |
264 | addHidden('doedit', '1'). |
265 | "\n" . '</form>'; |
daba719e |
266 | $abortform = true; |
267 | } |
3e87f870 |
268 | } else { |
269 | /** |
f8a1ed5a |
270 | * $editaddr is set, but $sel (address selection in address listing) |
271 | * and $doedit (address edit form) are not set. |
3e87f870 |
272 | * Assume that user clicked on "Edit address" without selecting any address. |
273 | */ |
274 | $formerror = _("Please select address that you want to edit"); |
275 | $showaddrlist = true; |
276 | } /* end of edit stage detection */ |
f4f64c58 |
277 | } /* !empty($editaddr) - Update/modify address */ |
278 | } /* (!empty($deladdr)) && sizeof($sel) > 0 - Delete address(es) |
279 | or (!empty($compose_to)) && sizeof($sel) > 0 - Compose to address(es) */ |
280 | } /* !empty($addaddr['nickname']) - Add new address */ |
daba719e |
281 | |
282 | // Some times we end output before forms are printed |
283 | if($abortform) { |
4fe67ca6 |
284 | //FIXME: use footer.tpl; remove HTML from core |
056a005c |
285 | echo "</body></html>\n"; |
286 | exit(); |
ffd8224c |
287 | } |
daba719e |
288 | } |
ffd8224c |
289 | |
290 | |
f6c945b9 |
291 | /* =================================================================== * |
292 | * The following is only executed on a GET request, or on a POST when * |
293 | * a user is added, or when "delete" or "modify" was successful. * |
294 | * =================================================================== */ |
ffd8224c |
295 | |
f6c945b9 |
296 | /* Display error messages */ |
297 | if (!empty($formerror)) { |
a71b394e |
298 | plain_error_message(nl2br(htmlspecialchars($formerror))); |
daba719e |
299 | } |
ffd8224c |
300 | |
301 | |
f6c945b9 |
302 | /* Display the address management part */ |
a71b394e |
303 | $addresses = array(); |
304 | while (list($k, $backend) = each ($abook->backends)) { |
305 | $a = array(); |
306 | $a['BackendID'] = $backend->bnum; |
307 | $a['BackendSource'] = $backend->sname; |
308 | $a['BackendWritable'] = $backend->writeable; |
309 | $a['Addresses'] = array(); |
310 | |
4fe67ca6 |
311 | // don't do address lookup if we are not viewing that backend |
312 | // |
313 | if ($backend->bnum == $current_backend) { |
314 | $alist = $abook->list_addr($backend->bnum); |
5b1c13d3 |
315 | |
4fe67ca6 |
316 | /* check return (array with data or boolean false) */ |
317 | if (is_array($alist)) { |
318 | usort($alist,'alistcmp'); |
319 | |
320 | $a['Addresses'] = formatAddressList($alist); |
a71b394e |
321 | |
4fe67ca6 |
322 | $addresses[$backend->bnum] = $a; |
323 | } else { |
324 | // list_addr() returns boolean |
325 | plain_error_message(nl2br(htmlspecialchars($abook->error))); |
326 | } |
5b1c13d3 |
327 | } else { |
4fe67ca6 |
328 | $addresses[$backend->bnum] = $a; |
329 | } |
330 | } |
331 | |
332 | |
333 | $current_page_args = array( |
334 | 'abook_sort_order' => $abook_sort_order, |
335 | 'new_bnum' => $current_backend, |
336 | 'page_number' => $page_number, |
337 | ); |
338 | |
339 | |
340 | // note that plugins can add to $current_page_args as well as |
341 | // filter the address list |
342 | // |
343 | $temp = array(&$addresses, &$current_backend, &$page_number, &$current_page_args); |
344 | do_hook('abook_list_filter', $temp); |
345 | |
346 | |
347 | // NOTE to address book backend authors and plugin authors: if a backend does |
348 | // pagination (which might be more efficient), it needs to place a key |
349 | // in every address listing it returns called "paginated", whose value |
350 | // should evaluate to boolean TRUE. However, if a plugin will also be |
351 | // used on the hook above to filter the addresses (perhaps by group), then |
352 | // the backend should be made compatible with the filtering plugin and |
353 | // should do the actual filtering too. Otherwise, the backend will paginate |
354 | // before filtering has taken place, the output of which is clearly wrong. |
355 | // It is proposed that filtering be based on a GET/POST variable called |
356 | // "abook_groups_X" where X is the current backend number. The value of |
357 | // this varaible would be an array of possible filter names, which the |
358 | // plugin and the backend would both know about. The plugin would only |
359 | // filter based on that value if the backend didn't already do it. The |
360 | // backend can insert a "grouped" key into all address listings, whose |
361 | // value evaluates to boolean TRUE, telling the plugin not to do any |
362 | // filtering itself. For an example of this implementation, see the |
363 | // Address Book Grouping and Pagination plugin. |
364 | |
365 | |
366 | // if no pagination was done by a plugin or the abook |
367 | // backend (which is indicated by the presence of a |
368 | // "paginated" key within all of the address entries |
369 | // in the list of addresses for the backend currently |
370 | // being viewed), then we provide default pagination |
371 | // |
372 | $total_addresses = 0; |
373 | if (!$show_all |
374 | && is_array($addresses[$current_backend]['Addresses']) |
375 | && empty($addresses[$current_backend]['Addresses'][0]['paginated'])) { |
376 | |
377 | // at this point, we assume the current list is |
378 | // the *full* list |
379 | // |
380 | $total_addresses = sizeof($addresses[$current_backend]['Addresses']); |
381 | |
382 | // iterate through all the entries, building list of addresses |
383 | // to keep based on current page |
384 | // |
385 | $new_address_list = array(); |
386 | $total_pages = ceil($total_addresses / $page_size); |
387 | if ($page_number > $total_pages) $page_number = $total_pages; |
388 | $page_count = 1; |
389 | $page_item_count = 0; |
390 | foreach ($addresses[$current_backend]['Addresses'] as $addr) { |
391 | $page_item_count++; |
392 | if ($page_item_count > $page_size) { |
393 | $page_count++; |
394 | $page_item_count = 1; |
395 | } |
396 | if ($page_count == $page_number) |
397 | $new_address_list[] = $addr; |
5b1c13d3 |
398 | } |
4fe67ca6 |
399 | $addresses[$current_backend]['Addresses'] = $new_address_list; |
400 | |
a71b394e |
401 | } |
daba719e |
402 | |
403 | |
a71b394e |
404 | if ($showaddrlist) { |
a71b394e |
405 | |
4fe67ca6 |
406 | $oTemplate->assign('show_all', $show_all); |
407 | $oTemplate->assign('page_number', $page_number); |
408 | $oTemplate->assign('page_size', $page_size); |
409 | $oTemplate->assign('total_addresses', $total_addresses); |
410 | $oTemplate->assign('abook_compact_paginator', $abook_compact_paginator); |
411 | $oTemplate->assign('abook_page_selector', $abook_page_selector); |
412 | $oTemplate->assign('current_page_args', $current_page_args); |
413 | $oTemplate->assign('abook_page_selector_max', $abook_page_selector_max); |
a71b394e |
414 | $oTemplate->assign('addresses', $addresses); |
415 | $oTemplate->assign('current_backend', $current_backend); |
416 | $oTemplate->assign('backends', $list_backends); |
a140c3b1 |
417 | $oTemplate->assign('abook_has_extra_field', $abook->add_extra_field); |
4fe67ca6 |
418 | $oTemplate->assign('compose_new_win', $compose_new_win); |
419 | $oTemplate->assign('compose_height', $compose_height); |
420 | $oTemplate->assign('compose_width', $compose_width); |
421 | $oTemplate->assign('form_action', $form_url); |
a71b394e |
422 | |
423 | $oTemplate->display('addressbook_list.tpl'); |
424 | |
a71b394e |
425 | } |
426 | |
f6c945b9 |
427 | /* Display the "new address" form */ |
caa596b2 |
428 | //FIXME: Remove HTML from here! (echo abook_create_form() is OK, since it is all template based output |
c1ac62d4 |
429 | echo '<a name="AddAddress"></a>' . "\n"; |
caa596b2 |
430 | echo abook_create_form($form_url, 'addaddr', |
431 | _("Add to address book"), |
432 | _("Add address"), |
433 | $current_backend, |
434 | $defdata); |
fc93f97c |
435 | echo "</form>\n"; |
daba719e |
436 | |
df4162cb |
437 | /* Hook for extra address book blocks */ |
6e515418 |
438 | do_hook('addressbook_bottom', $null); |
a71b394e |
439 | |
5c4ff7bf |
440 | $oTemplate->display('footer.tpl'); |