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