952e3230d92f256796e3c6d6c9661ab172fc8f83
1 <?php
3 class addressbook extends plugin
4 {
5 /* Definitions */
6 var $plHeadline= "Addressbook";
7 var $plDescription= "This does something";
9 /* Phonelist attributes */
10 var $telephone_list = array();
11 var $start= 0;
12 var $search_for= "*";
13 var $search_base= "";
14 var $search_type= "";
15 var $new_dn= "";
16 var $orig_cn= "";
17 var $storage_base= "";
18 var $orig_storage_base= "";
20 var $sn= "";
21 var $cn= "";
22 var $givenName= "";
23 var $mail= "";
24 var $title= "";
25 var $personalTitle= "";
26 var $initials= "";
27 var $homePostalAddress= "";
28 var $homePhone= "";
29 var $mobile= "";
30 var $o= "";
31 var $postalAddress= "";
32 var $l= "";
33 var $postalCode= "";
34 var $st= "";
35 var $ou= "";
36 var $telephoneNumber= "";
37 var $facsimileTelephoneNumber= "";
38 var $pager= "";
40 /* attribute list for save action */
41 var $attributes= array("sn", "givenName", "mail", "title",
42 "initials", "homePostalAddress", "displayName",
43 "homePhone", "mobile", "o", "postalAddress", "l",
44 "postalCode", "st", "ou", "telephoneNumber",
45 "facsimileTelephoneNumber", "pager");
46 var $objectclasses= array("top", "person", "organizationalPerson", "inetOrgPerson");
48 function addressbook ($config, $dn= NULL)
49 {
50 /* Include config object */
51 $this->config= $config;
53 #FIXME: ACL is set to default for testing
54 $this->acl= "#all#";
56 /* Get global filter config */
57 if (!is_global("phonefilter")){
58 $ui= get_userinfo();
59 $base= get_base_from_people($ui->dn);
60 $phonefilter= array("search_base" => $base,
61 "organizational" => "checked",
62 "global" => "checked",
63 "search_for" => "*",
64 "object_type" => "*");
65 register_global("phonefilter", $phonefilter);
66 }
67 }
69 function execute()
70 {
71 $smarty= get_smarty();
73 #! Hickert
74 /*prevent empty variables for smarty*/
75 foreach($this->attributes as $atr) $smarty->assign($atr,"");
77 /* Save formular information */
78 $phonefilter= get_global("phonefilter");
79 foreach( array("search_for", "search_base", "object_type") as $type){
80 if (isset($_POST[$type])){
81 $phonefilter[$type]= $_POST[$type];
82 }
83 $this->$type= $phonefilter[$type];
84 }
85 if (isset($_POST['search_base'])){
86 foreach( array("organizational", "global") as $type){
87 if (isset($_POST[$type])){
88 $phonefilter[$type]= "checked";
89 } else {
90 $phonefilter[$type]= "";
91 }
92 }
93 }
95 /* Search string */
96 $s= $phonefilter['search_for'];
97 if ($s == "") {
98 $s= "*";
99 }
100 if (isset($_GET['search'])){
101 $s= validate(mb_substr($_GET['search'], 0, 1, "UTF8"))."*";
102 if ($s == "**"){
103 $s= "*";
104 }
105 $this->search_for= $s;
106 $phonefilter['search_for']= $s;
107 }
108 register_global("phonefilter", $phonefilter);
110 /* Perform actions with CTI hook */
111 if (isset($_GET['target'])
112 && isset($_GET['dial'])
113 && isset($this->config->current['CTIHOOK'])){
115 $dialmode= $_GET['dial'];
116 if ($dialmode == "telephoneNumber" ||
117 $dialmode == "mobile" ||
118 $dialmode == "homePhone"){
120 /* Get target */
121 $ldap= $this->config->get_ldap_link();
122 $ldap->cat(base64_decode($_GET['target']));
123 $attrs= $ldap->fetch();
124 if (isset($attrs["$dialmode"])){
125 $target= $attrs[$dialmode][0];
126 } else {
127 $target= "";
128 }
130 /* Get source */
131 $ui= get_userinfo();
132 $ldap->cat($ui->dn);
133 $attrs= $ldap->fetch();
134 if (isset($attrs["telephoneNumber"])){
135 $source= $attrs['telephoneNumber'][0];
136 } else {
137 $source= "";
138 }
140 /* Save to session */
141 $_SESSION['source']= $source;
142 $_SESSION['target']= $target;
144 /* Perform call */
145 if ($target != "" && $source != ""){
146 $smarty->assign("phone_image", get_template_path('images/phone.png'));
147 $smarty->assign("dial_info", sprintf(_("Dial from %s to %s now?"), "<b style='font-size:22px; color:red'>".$source."</b>", "<b style='font-size:22px;color:red'>".$target."</b>"));
148 return($smarty->fetch(get_template_path('dial.tpl', TRUE)));
149 return;
150 } else {
151 print_red (_("You have no personal phone number set. Please change that in order to perform direct dials."));
152 }
153 }
155 }
157 /* Finally dial */
158 if (isset($_POST['dial']) && isset($_SESSION['source']) && isset($_SESSION['target'])){
159 exec ($this->config->current['CTIHOOK']." '".$_SESSION['source']."' '".$_SESSION['target']."'", $dummy, $retval);
160 unset($_SESSION['source']);
161 unset($_SESSION['target']);
162 }
164 /* Delete entry? */
165 if (isset($_POST['delete_entry_confirm'])){
167 /* Some nice guy may send this as POST, so we've to check
168 for the permissions again. */
169 if (chkacl($this->acl, "delete") == ""){
171 /* Delete request is permitted, perform LDAP action */
172 $ldap= $this->config->get_ldap_link();
173 $ldap->rmdir ($this->dn);
174 gosa_log ("Address book object'".$this->dn."' has been removed");
176 } else {
178 /* Normally this shouldn't be reached, send some extra
179 logs to notify the administrator */
180 print_red (_("You are not allowed to delete this entry!"));
181 gosa_log ("Warning: '".$this->ui->uid."' tried to trick address book deletion.");
182 }
184 /* Remove lock file after successfull deletion */
185 del_lock ($this->dn);
187 /* Clean up */
188 if (isset($_SESSION['saved_start'])){
189 $_GET['start']= $_SESSION['saved_start'];
190 }
191 unset($_SESSION['show_info']);
192 unset($_SESSION['saved_start']);
193 }
195 /* Delete entry? */
196 if (isset($_POST['delete_cancel'])){
197 del_lock ($this->dn);
198 }
200 /* Save address entry? */
201 if (isset($_POST['save'])){
202 $this->save_object();
203 $this->storage_base= $_POST['storage_base'];
205 /* Perform checks */
206 $message= $this->check ();
208 /* No errors, save object */
209 if (count ($message) == 0){
210 $this->save();
211 gosa_log ("Addressbook object '".$this->dn."' has been saved");
213 /* Clean up */
214 if (isset($_SESSION['saved_start'])){
215 $_GET['start']= $_SESSION['saved_start'];
216 }
217 $_SESSION['show_info']= $this->dn;
218 unset($_SESSION['saved_start']);
219 } else {
220 /* Errors found, show message */
221 show_errors ($message);
222 }
223 }
225 /* Close info window */
226 if (isset($_GET['close']) || isset($_POST['cancel'])){
227 if (isset($_SESSION['saved_start'])){
228 $_GET['start']= $_SESSION['saved_start'];
229 }
230 unset($_SESSION['show_info']);
231 unset($_SESSION['saved_start']);
232 }
234 /* Start address book edit mode? */
235 if (isset($_GET['global'])){
236 if (!isset($_SESSION['saved_start']) && isset($_GET['start'])){
237 $_SESSION['saved_start']= $_GET['start'];
238 }
239 switch ($_GET['global']){
240 case "add":
241 $this->dn= "new";
242 $this->orig_cn= "";
244 /* Clean values */
245 foreach ($this->attributes as $name){
246 $this->$name= "";
247 }
248 $this->storage_base= $this->config->current["BASE"];
249 break;
250 case "edit":
251 /* Clean values */
252 foreach ($this->attributes as $name){
253 $this->$name= "";
254 }
255 $this->dn= $_SESSION['show_info'];
256 $this->load();
257 $this->orig_cn= $this->cn;
258 break;
259 case "remove":
260 $this->dn= $_SESSION['show_info'];
262 /* Load permissions for selected 'dn' and check if
263 we're allowed to remove this 'dn' */
264 $ui= get_userinfo();
265 $dn= preg_replace("/,dc=addressbook,/", "", $this->dn);
266 $acl= get_permissions ($dn, $ui->subtreeACL);
267 $this->acl= get_module_permission($acl, "global-addressbook", $dn);
268 if (chkacl($this->acl, "delete") == ""){
270 /* Check locking, save current plugin in 'back_plugin', so
271 the dialog knows where to return. */
272 if (($user= get_lock($this->dn)) != ""){
273 return(gen_locked_message ($user, $this->dn));
274 }
276 /* Lock the current entry, so nobody will edit it during deletion */
277 add_lock ($this->dn, $ui->dn);
278 $smarty->assign("info", sprintf(_("You're about to delete the entry %s."), $this->dn));
279 return($smarty->fetch(get_template_path('remove.tpl', TRUE)));
280 } else {
282 /* Obviously the user isn't allowed to delete. Show message and
283 clean session. */
284 print_red (_("You are not allowed to delete this entry!"));
285 }
286 }
287 $_SESSION['show_info']= "ADD";
288 }
290 /* Open info window */
291 if (isset($_GET['show'])){
292 if (!isset($_SESSION['saved_start'])){
293 $_SESSION['saved_start']= $_GET['start'];
294 }
295 $_SESSION['show_info']= base64_decode($_GET['show']);
296 }
298 /* Get ldap link / build filter */
299 $ldap= $this->config->get_ldap_link();
300 $this->telephone_list= array ();
302 /* Assemble bases */
303 $bases= array();
304 $filter= "";
305 if ($phonefilter['global'] == "checked"){
306 $bases[]= preg_replace("/".$this->config->current['BASE']."/", "dc=addressbook,".$this->config->current['BASE'], $this->search_base);
307 } else {
308 $filter= '(objectClass=gosaAccount)';
309 }
310 if ($phonefilter['organizational'] == "checked"){
311 $bases[]= $this->search_base;
312 }
313 foreach ($bases as $base){
314 $ldap->cd ($base);
315 if ($phonefilter['object_type'] == '*'){
316 $ldap->search ("(&(objectClass=person)$filter(!(objectClass=gosaUserTemplate))".
317 "(|(uid=$s)(homePhone=$s)(telephoneNumber=$s)".
318 "(facsimileTelephoneNumber=$s)(mobile=$s)(givenName=$s)(sn=$s)))", array("sn", "givenName", "telephoneNumber", "facsimileTelephoneNumber", "mobile", "homePhone", "uid", "mail", "cn"));
319 } else {
320 $ldap->search ("(&$filter(!(objectClass=gosaUserTemplate))".
321 "(".$phonefilter['object_type']."=$s))", array("sn", "givenName", "telephoneNumber", "facsimileTelephoneNumber", "mobile", "homePhone", "uid", "mail", "cn"));
322 }
324 /* Build current list, error reporting is off, because many of the
325 objects may not be defined after LDAP queries. Asking for presence
326 first is too much overhead. */
327 error_reporting(0);
332 /* Walk through LDAP results */
333 while ($attrs= $ldap->fetch()){
335 #! hickert
336 /* prevent empty vaiables */
337 foreach($this->attributes as $atr) {
338 if(!isset($attrs[$atr][0])) {
339 $attrs[$atr][0] = "";
340 }
341 }
342 if(!isset($_GET['start'])) $_GET['start']="";
345 /* Only show lines that have set any mail or phone informations */
346 if (isset($attrs['telephoneNumber'][0]) ||
347 isset($attrs['facsimileTelephoneNumber'][0]) ||
348 isset($attrs['mobile'][0]) ||
349 isset($attrs['homePhone'][0]) ||
350 isset($attrs['mail'][0])){
352 $this->telephone_list[$attrs['sn'][0].$attrs['dn']]=
354 "<td class=\"phonelist\" title=\"".$attrs['sn'][0].", ".$attrs['givenName'][0]."\" onClick='location.href=\"main.php?plug=".validate($_GET['plug'])."&start=".validate($_GET['start'])."&show=".base64_encode($attrs['dn'])."\"'><a href=\"main.php?plug=".validate($_GET['plug'])."&start=".validate($_GET['start'])."&show=".base64_encode($attrs['dn'])."\">".$attrs['sn'][0].", ".$attrs['givenName'][0].
355 "</a>
356 </td>
357 <td title=\""._("Dial")." ".$attrs['telephoneNumber'][0]."\">
358 <a href=\"main.php?plug=".validate($_GET['plug'])."&dial=telephoneNumber&start=".validate($_GET['start'])."&target=".base64_encode($attrs['dn'])."\">".$attrs['telephoneNumber'][0]."
359 </a>
360 </td>
361 <td title=\"".$attrs['facsimileTelephoneNumber'][0]."\">
362 ".$attrs['facsimileTelephoneNumber'][0]."
363 </td>
364 <td title=\""._("Dial")." ".$attrs['mobile'][0]."\">
365 <a href=\"main.php?plug=".validate($_GET['plug'])."&dial=mobile&start=".validate($_GET['start'])."&target=".base64_encode($attrs['dn'])."\">".$attrs['mobile'][0]."
366 </a>
367 </td>
368 <td title=\""._("Dial")." ".$attrs['homePhone'][0]."\">
369 <a href=\"main.php?plug=".validate($_GET['plug'])."&dial=homePhone&start=".validate($_GET['start'])."&target=".base64_encode($attrs['dn'])."\">".$attrs['homePhone'][0]."
370 </a>
371 </td>
372 <td>
373 <a href=\"getvcard.php?dn=".base64_encode($attrs['dn'])."\">
374 <img align=\"top\" border=0 src=\"images/save.png\" alt=\"vcf\" title=\"".sprintf(_("Save contact for %s as vcard"), $attrs['givenName'][0]." ".$attrs['sn'][0])."\">
375 </a>";
377 if (isset($attrs['mail'])){
378 $dest= sprintf(_("Send mail to %s"), $attrs['mail'][0]);
379 $this->telephone_list[$attrs['sn'][0].$attrs['dn']].=
380 "<a href=\"mailto:".$attrs['givenName'][0]." ".$attrs['sn'][0]." <".$attrs['mail'][0].">\">".
381 "<img align=\"top\" border=0 src=\"images/mailto.png\"".
382 "alt=\"vcf\" title=\"$dest\"></a>";
383 }
384 $this->telephone_list[$attrs['sn'][0].$attrs['dn']].= "</td>";
385 }
386 }
387 error_reporting(E_ALL);
388 }
390 /* Sort up list */
391 ksort ($this->telephone_list);
392 reset ($this->telephone_list);
394 /* Fill template variables */
395 $smarty->assign("search_for", $this->search_for);
396 $smarty->assign("object_type", $this->object_type);
397 $smarty->assign("deplist", $this->config->idepartments);
398 $smarty->assign("depselect", $this->search_base);
399 $smarty->assign("global", $phonefilter['global']);
400 $smarty->assign("organizational", $phonefilter['organizational']);
401 $smarty->assign("search_image", get_template_path('images/search.png'));
402 $smarty->assign("tree_image", get_template_path('images/tree.png'));
403 $smarty->assign("infoimage", get_template_path('images/info.png'));
404 $smarty->assign("actionimage", get_template_path('images/action.png'));
405 $smarty->assign("launchimage", get_template_path('images/launch.png'));
407 /* Generate alphabet */
408 $alphabet= generate_alphabet();
410 /* Build list output */
411 $output= "";
412 $mod= 0;
414 #! hickert
415 if(!isset($_SESSION['show_info'])) $smarty->assign("show_info", "");;
417 if (isset($_SESSION['show_info'])){
418 $range= 4;
419 $smarty->assign("show_info", "1");
420 $smarty->assign("url", "main.php?plug=".validate($_GET['plug'])."&close=1");
422 switch ($_SESSION['show_info']){
424 case "ADD":
425 $smarty->assign ('storage_base', $this->storage_base);
426 $smarty->assign ('address_info',
427 get_template_path('address_edit.tpl', TRUE));
428 break;
430 default:
431 $smarty->assign ('address_info',
432 get_template_path('address_info.tpl', TRUE));
433 break;
434 }
436 /* Fill variables from LDAP */
437 # FIXME: Missing ACL support for addressbook yet
438 if ($_SESSION['show_info'] != "ADD"){
439 $ldap->cat($_SESSION['show_info']);
440 $info= $ldap->fetch();
441 }
442 foreach ($this->attributes as $name){
443 if ($_SESSION['show_info'] != "ADD" && isset($info["$name"][0])){
444 error_reporting(0);
445 /* Special treatment for phone attributes */
446 if ($name == "mobile" ||
447 $name == "homePhone" ||
448 $name == "telephoneNumber"){
449 $smarty->assign("info_$name",
450 "<a title=\""._("Dial")." ".$info["$name"][0]."\" href=\"main.php?plug=".validate($_GET['plug'])."&dial=$name&start=".validate($_GET['start'])."&target=".base64_encode($_SESSION['show_info'])."\">".$info["$name"][0]."</a>");
451 } else {
452 $smarty->assign("info_$name", preg_replace("/\n/", "<br>", $info["$name"][0]));
453 }
454 error_reporting(E_ALL);
455 } elseif ($_SESSION['show_info'] == "ADD") {
456 $smarty->assign("info_$name", $this->$name);
457 } else {
458 $smarty->assign("info_$name", "-");
459 }
460 }
461 if (preg_match("/,dc=addressbook,/", $_SESSION['show_info'])){
462 $storage= _("global addressbook");
463 $smarty->assign("internal", 0);
464 } else {
465 $storage= _("organizations user database");
466 $smarty->assign("internal", 1);
467 }
468 if ($_SESSION['show_info'] != "ADD"){
469 $smarty->assign("storage_info", sprintf(_("Contact stored in %s"), $storage));
470 } else {
471 $smarty->assign("storage_info", _("Creating new entry in"));
472 }
473 } else {
474 $range= 20;
475 $smarty->assign("internal", 1);
476 }
477 if (isset($_GET['start'])){
478 $this->start= validate($_GET['start']);
479 }
480 foreach ($this->telephone_list as $val){
481 if ($mod < $this->start) {
482 $mod++;
483 continue;
484 }
485 if ($mod >= ($this->start + $range)){
486 $mod++;
487 break;
488 }
489 if ( ($mod++) & 1){
490 $col= "style=\"background-color: #ECECEC;\"";
491 } else {
492 $col= "style=\"background-color: #F5F5F5;\"";
493 }
494 $output.= "<tr $col>\n$val</tr>\n";
495 }
496 $smarty->assign("search_result", $output);
497 $smarty->assign("apply", apply_filter());
498 $smarty->assign("alphabet", $alphabet);
499 $smarty->assign("range_selector", range_selector(count($this->telephone_list), $this->start, $range));
500 $tmp= array("*" => _("All"), "sn" => _("Name"), "givenName" => _("Given name"),
501 "telephoneNumber" => _("Work phone"), "mobile" => _("Cell phone"),
502 "homePhone" => _("Home phone"), "uid" => _("User ID"));
503 natsort($tmp);
504 $smarty->assign("objlist", $tmp);
506 /* Show main page */
507 $smarty->assign ('personal_image', get_template_path('images/addr_personal.png'));
508 $smarty->assign ('home_image', get_template_path('images/addr_home.png'));
509 $smarty->assign ('company_image', get_template_path('images/addr_company.png'));
510 $smarty->assign ('add_image', get_template_path('images/editpaste.png'));
511 $smarty->assign ('edit_image', get_template_path('images/edit.png'));
512 $smarty->assign ('delete_image', get_template_path('images/editdelete.png'));
513 return($smarty->fetch(get_template_path('contents.tpl', TRUE)));
514 }
517 function check()
518 {
519 $message= array();
521 /* must: sn, givenName */
522 if ($this->sn == ""){
523 $message[]= _("The required field 'Name' is not set.");
524 return ($message);
525 }
526 if ($this->givenName == ""){
527 $message[]= _("The required field 'Given name' is not set.");
528 return ($message);
529 }
531 /* Check for valid name definition */
532 if (preg_match ("/[\\\\]/", $this->sn)){
533 $message[]= _("The field 'Name' contains invalid characters.");
534 }
535 if (preg_match ("/[\\\\]/", $this->givenName)){
536 $message[]= _("The field 'Given name' contains invalid characters.");
537 }
539 /* Check phone numbers */
540 if (!is_phone_nr($this->homePhone)){
541 $message[]= _("The field 'Phone' contains an invalid phone number.");
542 }
543 if (!is_phone_nr($this->telephoneNumber)){
544 $message[]= _("The field 'Phone' contains an invalid phone number.");
545 }
546 if (!is_phone_nr($this->facsimileTelephoneNumber)){
547 $message[]= _("The field 'Fax' contains an invalid phone number.");
548 }
549 if (!is_phone_nr($this->mobile)){
550 $message[]= _("The field 'Mobile' contains an invalid phone number.");
551 }
552 if (!is_phone_nr($this->pager)){
553 $message[]= _("The field 'Pager' contains an invalid phone number.");
554 }
556 /* Check for reserved characers */
557 if (preg_match ('/[,+"<>;]/', $this->givenName)){
558 $message[]= _("The field 'Given name' contains invalid characters.");
559 }
560 if (preg_match ('/[,+"<>;]/', $this->sn)){
561 $message[]= _("The field 'Name' contains invalid characters.");
562 }
564 /* Check mail */
565 if (!is_email($this->mail)){
566 $message[]= _("Please enter a valid email address in 'Primary address' field.");
567 }
569 /* Assemble cn/dn */
570 $this->cn= $this->givenName." ".$this->sn;
571 if ($this->orig_cn != $this->cn || $this->storage_base != $this->orig_storage_base){
572 $this->new_dn= $this->create_unique_dn("cn", preg_replace("/,*".$this->config->current['BASE']."$/", "", $this->storage_base).",dc=addressbook,".$this->config->current['BASE']);
573 if ($this->new_dn == "none"){
574 $message[]= _("Cannot create a unique DN for your entry. Please fill more formular fields.");
575 return ($message);
576 }
577 } else {
578 $this->new_dn= $this->dn;
579 }
581 $ui= get_userinfo();
582 $dn= preg_replace("/,dc=addressbook,/", "", $this->new_dn);
583 $acl= get_permissions ($dn, $ui->subtreeACL);
584 $acl= get_module_permission($acl, "global-addressbook", $this->dn);
585 if ($_SESSION['show_info'] == "ADD" && chkacl($acl, "create") != ""){
586 $message[]= _("You have no permissions to create or modify a global address book entry.");
587 }
589 return ($message);
590 }
593 function load()
594 {
595 /* Load base attributes */
596 plugin::plugin ($this->config, $this->dn);
597 $this->storage_base= preg_replace('/^[^,]+,/', '', preg_replace('/dc=addressbook,/', '', $this->dn));
598 }
601 function save()
602 {
603 /* First use parents methods to do some basic fillup in $this->attrs */
604 plugin::save ();
606 $this->attrs['cn']= $this->cn;
607 $this->attrs['displayName']= $this->givenName." ".$this->sn;
609 /* Move entry if it got another name... */
610 if ($this->dn != "new" && $this->dn != $this->new_dn){
611 $this->move($this->dn, $this->new_dn);
612 }
613 $this->dn= $this->new_dn;
615 /* Save data. Using 'modify' implies that the entry is already present, use 'add' for
616 new entries. So do a check first... */
617 $ldap= $this->config->get_ldap_link();
618 $ldap->cat ($this->dn);
619 if ($ldap->fetch()){
620 $mode= "modify";
621 } else {
622 $mode= "add";
623 $ldap->cd($this->config->current['BASE']);
624 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $this->dn));
625 }
627 /* Finally write data with selected 'mode' */
628 $ldap->cd ($this->dn);
629 $ldap->$mode ($this->attrs);
630 if (show_ldap_error($ldap->get_error())){
631 return (1);
632 }
633 }
635 }
637 ?>