1 <?php
2 /*
3 This code is part of GOsa (https://gosa.gonicus.de)
4 Copyright (C) 2003 Cajus Pollmeier
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
21 /*! \brief The plugin base class
22 \author Cajus Pollmeier <pollmeier@gonicus.de>
23 \version 2.00
24 \date 24.07.2003
26 This is the base class for all plugins. It can be used standalone or
27 can be included by the tabs class. All management should be done
28 within this class. Extend your plugins from this class.
29 */
31 class plugin
32 {
33 /*!
34 \brief Reference to parent object
36 This variable is used when the plugin is included in tabs
37 and keeps reference to the tab class. Communication to other
38 tabs is possible by 'name'. So the 'fax' plugin can ask the
39 'userinfo' plugin for the fax number.
41 \sa tab
42 */
43 var $parent= NULL;
45 /*!
46 \brief Configuration container
48 Access to global configuration
49 */
50 var $config= NULL;
52 /*!
53 \brief Mark plugin as account
55 Defines whether this plugin is defined as an account or not.
56 This has consequences for the plugin to be saved from tab
57 mode. If it is set to 'FALSE' the tab will call the delete
58 function, else the save function. Should be set to 'TRUE' if
59 the construtor detects a valid LDAP object.
61 \sa plugin::plugin()
62 */
63 var $is_account= FALSE;
64 var $initially_was_account= FALSE;
66 /*!
67 \brief Mark plugin as template
69 Defines whether we are creating a template or a normal object.
70 Has conseqences on the way execute() shows the formular and how
71 save() puts the data to LDAP.
73 \sa plugin::save() plugin::execute()
74 */
75 var $is_template= FALSE;
76 var $ignore_account= FALSE;
77 var $is_modified= FALSE;
79 /*!
80 \brief Represent temporary LDAP data
82 This is only used internally.
83 */
84 var $attrs= array();
86 /* Keep set of conflicting plugins */
87 var $conflicts= array();
89 /* Save unit tags */
90 var $gosaUnitTag= "";
91 var $skipTagging= FALSE;
93 /*!
94 \brief Used standard values
96 dn
97 */
98 var $dn= "";
99 var $uid= "";
100 var $sn= "";
101 var $givenName= "";
102 var $acl= "*none*";
103 var $dialog= FALSE;
105 /* attribute list for save action */
106 var $attributes= array();
107 var $objectclasses= array();
108 var $new= TRUE;
109 var $saved_attributes= array();
111 /* This can be set to render the tabulators in another stylesheet */
112 var $pl_notify= FALSE;
114 /*! \brief plugin constructor
116 If 'dn' is set, the node loads the given 'dn' from LDAP
118 \param dn Distinguished name to initialize plugin from
119 \sa plugin()
120 */
121 function plugin ($config, $dn= NULL, $parent= NULL)
122 {
123 /* Configuration is fine, allways */
124 $this->config= $config;
125 $this->dn= $dn;
127 /* Handle new accounts, don't read information from LDAP */
128 if ($dn == "new"){
129 return;
130 }
132 /* Get LDAP descriptor */
133 $ldap= $this->config->get_ldap_link();
134 if ($dn != NULL){
136 /* Load data to 'attrs' and save 'dn' */
137 if ($parent != NULL){
138 $this->attrs= $parent->attrs;
139 } else {
140 $ldap->cat ($dn);
141 $this->attrs= $ldap->fetch();
142 }
144 /* Copy needed attributes */
145 foreach ($this->attributes as $val){
146 $found= array_key_ics($val, $this->attrs);
147 if ($found != ""){
148 $this->$val= $this->attrs["$found"][0];
149 }
150 }
152 /* gosaUnitTag loading... */
153 if (isset($this->attrs['gosaUnitTag'][0])){
154 $this->gosaUnitTag= $this->attrs['gosaUnitTag'][0];
155 }
157 /* Set the template flag according to the existence of objectClass
158 gosaUserTemplate */
159 if (isset($this->attrs['objectClass'])){
160 if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
161 $this->is_template= TRUE;
162 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
163 "found", "Template check");
164 }
165 }
167 /* Is Account? */
168 error_reporting(0);
169 $found= TRUE;
170 foreach ($this->objectclasses as $obj){
171 if (preg_match('/top/i', $obj)){
172 continue;
173 }
174 if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){
175 $found= FALSE;
176 break;
177 }
178 }
179 error_reporting(E_ALL);
180 if ($found){
181 $this->is_account= TRUE;
182 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
183 "found", "Object check");
184 }
186 /* Prepare saved attributes */
187 $this->saved_attributes= $this->attrs;
188 foreach ($this->saved_attributes as $index => $value){
189 if (preg_match('/^[0-9]+$/', $index)){
190 unset($this->saved_attributes[$index]);
191 continue;
192 }
193 if (!in_array($index, $this->attributes) && $index != "objectClass"){
194 unset($this->saved_attributes[$index]);
195 continue;
196 }
197 if ($this->saved_attributes[$index]["count"] == 1){
198 $tmp= $this->saved_attributes[$index][0];
199 unset($this->saved_attributes[$index]);
200 $this->saved_attributes[$index]= $tmp;
201 continue;
202 }
204 unset($this->saved_attributes["$index"]["count"]);
205 }
206 }
208 /* Save initial account state */
209 $this->initially_was_account= $this->is_account;
210 }
212 /*! \brief execute plugin
214 Generates the html output for this node
215 */
216 function execute()
217 {
218 # This one is empty currently. Fabian - please fill in the docu code
219 $_SESSION['current_class_for_help'] = get_class($this);
220 /* Reset Lock message POST/GET check array, to prevent perg_match errors*/
221 $_SESSION['LOCK_VARS_TO_USE'] =array();
222 }
224 /*! \brief execute plugin
225 Removes object from parent
226 */
227 function remove_from_parent()
228 {
229 /* include global link_info */
230 $ldap= $this->config->get_ldap_link();
232 /* Get current objectClasses in order to add the required ones */
233 $ldap->cat($this->dn);
234 $tmp= $ldap->fetch ();
235 if (isset($tmp['objectClass'])){
236 $oc= $tmp['objectClass'];
237 } else {
238 $oc= array("count" => 0);
239 }
241 /* Remove objectClasses from entry */
242 $ldap->cd($this->dn);
243 $this->attrs= array();
244 $this->attrs['objectClass']= array();
245 for ($i= 0; $i<$oc["count"]; $i++){
246 if (!in_array_ics($oc[$i], $this->objectclasses)){
247 $this->attrs['objectClass'][]= $oc[$i];
248 }
249 }
251 /* Unset attributes from entry */
252 foreach ($this->attributes as $val){
253 $this->attrs["$val"]= array();
254 }
256 /* Unset account info */
257 $this->is_account= FALSE;
259 /* Do not write in plugin base class, this must be done by
260 children, since there are normally additional attribs,
261 lists, etc. */
262 /*
263 $ldap->modify($this->attrs);
264 */
265 }
268 /* Save data to object */
269 function save_object()
270 {
271 /* Save values to object */
272 foreach ($this->attributes as $val){
273 if (chkacl ($this->acl, "$val") == "" && isset ($_POST["$val"])){
274 /* Check for modifications */
275 if ((get_magic_quotes_gpc()) && !is_array($_POST["$val"])) {
276 $data= stripcslashes($_POST["$val"]);
277 } else {
278 $data= $this->$val = $_POST["$val"];
279 }
280 if ($this->$val != $data){
281 $this->is_modified= TRUE;
282 }
284 /* Okay, how can I explain this fix ...
285 * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds.
286 * So IE posts these 'unselectable' option, with value = chr(194)
287 * chr(194) seems to be the in between the ...option> </option.. because there is no value=".." specified in these option fields
288 * This was added for W3c compliance, but now causes these ... ldap errors ...
289 * So we set these Fields to ""; a normal empty string, and we can check these values in plugin::check() again ...
290 */
291 if(isset($data[0]) && $data[0] == chr(194)) {
292 $data = "";
293 }
294 $this->$val= $data;
295 }
296 }
297 }
300 /* Save data to LDAP, depending on is_account we save or delete */
301 function save()
302 {
303 /* include global link_info */
304 $ldap= $this->config->get_ldap_link();
306 /* Start with empty array */
307 $this->attrs= array();
309 /* Get current objectClasses in order to add the required ones */
310 $ldap->cat($this->dn);
312 $tmp= $ldap->fetch ();
314 if (isset($tmp['objectClass'])){
315 $oc= $tmp["objectClass"];
316 $this->new= FALSE;
317 } else {
318 $oc= array("count" => 0);
319 $this->new= TRUE;
320 }
322 /* Load (minimum) attributes, add missing ones */
323 $this->attrs['objectClass']= $this->objectclasses;
324 for ($i= 0; $i<$oc["count"]; $i++){
325 if (!in_array_ics($oc[$i], $this->objectclasses)){
326 $this->attrs['objectClass'][]= $oc[$i];
327 }
328 }
330 /* Copy standard attributes */
331 foreach ($this->attributes as $val){
332 if ($this->$val != ""){
333 $this->attrs["$val"]= $this->$val;
334 } elseif (!$this->new) {
335 $this->attrs["$val"]= array();
336 }
337 }
339 /* Handle tagging */
340 $this->tag_attrs(&$this->attrs);
341 }
344 function cleanup()
345 {
346 foreach ($this->attrs as $index => $value){
348 /* Convert arrays with one element to non arrays, if the saved
349 attributes are no array, too */
350 if (is_array($this->attrs[$index]) &&
351 count ($this->attrs[$index]) == 1 &&
352 isset($this->saved_attributes[$index]) &&
353 !is_array($this->saved_attributes[$index])){
355 $tmp= $this->attrs[$index][0];
356 $this->attrs[$index]= $tmp;
357 }
359 /* Remove emtpy arrays if they do not differ */
360 if (is_array($this->attrs[$index]) &&
361 count($this->attrs[$index]) == 0 &&
362 !isset($this->saved_attributes[$index])){
364 unset ($this->attrs[$index]);
365 continue;
366 }
368 /* Remove single attributes that do not differ */
369 if (!is_array($this->attrs[$index]) &&
370 isset($this->saved_attributes[$index]) &&
371 !is_array($this->saved_attributes[$index]) &&
372 $this->attrs[$index] == $this->saved_attributes[$index]){
374 unset ($this->attrs[$index]);
375 continue;
376 }
378 /* Remove arrays that do not differ */
379 if (is_array($this->attrs[$index]) &&
380 isset($this->saved_attributes[$index]) &&
381 is_array($this->saved_attributes[$index])){
383 if (!array_differs($this->attrs[$index],$this->saved_attributes[$index])){
384 unset ($this->attrs[$index]);
385 continue;
386 }
387 }
388 }
390 /* Update saved attributes and ensure that next cleanups will be successful too */
391 foreach($this->attrs as $name => $value){
392 $this->saved_attributes[$name] = $value;
393 }
394 }
396 /* Check formular input */
397 function check()
398 {
399 $message= array();
401 /* Skip if we've no config object */
402 if (!isset($this->config)){
403 return $message;
404 }
406 /* Find hooks entries for this class */
407 $command= search_config($this->config->data['MENU'], get_class($this), "CHECK");
408 if ($command == "" && isset($this->config->data['TABS'])){
409 $command= search_config($this->config->data['TABS'], get_class($this), "CHECK");
410 }
412 if ($command != ""){
414 if (!check_command($command)){
415 $message[]= sprintf(_("Command '%s', specified as CHECK hook for plugin '%s' doesn't seem to exist."), $command,
416 get_class($this));
417 } else {
419 /* Generate "ldif" for check hook */
420 $ldif= "dn: $this->dn\n";
422 /* ... objectClasses */
423 foreach ($this->objectclasses as $oc){
424 $ldif.= "objectClass: $oc\n";
425 }
427 /* ... attributes */
428 foreach ($this->attributes as $attr){
429 if ($this->$attr == ""){
430 continue;
431 }
432 if (is_array($this->$attr)){
433 foreach ($this->$attr as $val){
434 $ldif.= "$attr: $val\n";
435 }
436 } else {
437 $ldif.= "$attr: ".$this->$attr."\n";
438 }
439 }
441 /* Append empty line */
442 $ldif.= "\n";
444 /* Feed "ldif" into hook and retrieve result*/
445 $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
446 $fh= proc_open($command, $descriptorspec, $pipes);
447 if (is_resource($fh)) {
448 fwrite ($pipes[0], $ldif);
449 fclose($pipes[0]);
451 $result= stream_get_contents($pipes[1]);
452 if ($result != ""){
453 $message[]= $result;
454 }
456 fclose($pipes[1]);
457 fclose($pipes[2]);
458 proc_close($fh);
459 }
460 }
462 }
464 return ($message);
465 }
467 /* Adapt from template, using 'dn' */
468 function adapt_from_template($dn)
469 {
470 /* Include global link_info */
471 $ldap= $this->config->get_ldap_link();
473 /* Load requested 'dn' to 'attrs' */
474 $ldap->cat ($dn);
475 $this->attrs= $ldap->fetch();
477 /* Walk through attributes */
478 foreach ($this->attributes as $val){
480 if (isset($this->attrs["$val"][0])){
482 /* If attribute is set, replace dynamic parts:
483 %sn, %givenName and %uid. Fill these in our local variables. */
484 $value= $this->attrs["$val"][0];
486 foreach (array("sn", "givenName", "uid") as $repl){
487 if (preg_match("/%$repl/i", $value)){
488 $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
489 }
490 }
491 $this->$val= $value;
492 }
493 }
495 /* Is Account? */
496 $found= TRUE;
497 foreach ($this->objectclasses as $obj){
498 if (preg_match('/top/i', $obj)){
499 continue;
500 }
501 if (!in_array_ics ($obj, $this->attrs['objectClass'])){
502 $found= FALSE;
503 break;
504 }
505 }
506 if ($found){
507 $this->is_account= TRUE;
508 }
509 }
511 /* Indicate whether a password change is needed or not */
512 function password_change_needed()
513 {
514 return FALSE;
515 }
517 /* Show header message for tab dialogs */
518 function show_header($button_text, $text, $disabled= FALSE)
519 {
520 $state = "disabled";
521 if($this->is_account && $this->acl == "#all#"){
522 $state= "";
523 }elseif(!$this->is_account && chkacl($this->acl,"create") == ""){
524 $state= "";
525 }
527 if ($disabled == TRUE){
528 $state= "disabled";
529 }
531 $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
532 $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".$state.">".
533 "<p class=\"seperator\"> </p></td></tr></table>";
535 return($display);
536 }
538 function postcreate($add_attrs= array())
539 {
540 /* Find postcreate entries for this class */
541 $command= search_config($this->config->data['MENU'], get_class($this), "POSTCREATE");
542 if ($command == "" && isset($this->config->data['TABS'])){
543 $command= search_config($this->config->data['TABS'], get_class($this), "POSTCREATE");
544 }
546 if ($command != ""){
548 /* Additional attributes */
549 foreach ($add_attrs as $name => $value){
550 $command= preg_replace("/%$name( |$)/", "$value ", $command);
551 }
553 /* Walk through attribute list */
554 foreach ($this->attributes as $attr){
555 if (!is_array($this->$attr)){
556 $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
557 }
558 }
559 $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
561 if (check_command($command)){
562 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
563 $command, "Execute");
564 exec($command,$arr);
565 foreach($arr as $str){
566 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
567 $command, "Result: ".$str);
568 }
569 } else {
570 $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
571 print_red ($message);
572 }
573 }
574 }
576 function postmodify($add_attrs= array())
577 {
578 /* Find postcreate entries for this class */
579 $command= search_config($this->config->data['MENU'], get_class($this), "POSTMODIFY");
580 if ($command == "" && isset($this->config->data['TABS'])){
581 $command= search_config($this->config->data['TABS'], get_class($this), "POSTMODIFY");
582 }
584 if ($command != ""){
586 /* Additional attributes */
587 foreach ($add_attrs as $name => $value){
588 $command= preg_replace("/%$name( |$)/", "$value ", $command);
589 }
591 /* Walk through attribute list */
592 foreach ($this->attributes as $attr){
593 if (!is_array($this->$attr)){
594 $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
595 }
596 }
597 $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
599 if (check_command($command)){
600 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
601 $command, "Execute");
603 exec($command,$arr);
604 foreach($arr as $str){
605 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
606 $command, "Result: ".$str);
607 }
608 } else {
609 $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
610 print_red ($message);
611 }
612 }
613 }
615 function postremove($add_attrs= array())
616 {
617 /* Find postremove entries for this class */
618 $command= search_config($this->config->data['MENU'], get_class($this), "POSTREMOVE");
619 if ($command == "" && isset($this->config->data['TABS'])){
620 $command= search_config($this->config->data['TABS'], get_class($this), "POSTREMOVE");
621 }
623 if ($command != ""){
625 /* Additional attributes */
626 foreach ($add_attrs as $name => $value){
627 $command= preg_replace("/%$name( |$)/", "$value ", $command);
628 }
630 /* Walk through attribute list */
631 foreach ($this->attributes as $attr){
632 if (!is_array($this->$attr)){
633 $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
634 }
635 }
636 $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
638 if (check_command($command)){
639 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
640 $command, "Execute");
642 exec($command,$arr);
643 foreach($arr as $str){
644 @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
645 $command, "Result: ".$str);
646 }
647 } else {
648 $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
649 print_red ($message);
650 }
651 }
652 }
654 /* Create unique DN */
655 function create_unique_dn($attribute, $base)
656 {
657 $ldap= $this->config->get_ldap_link();
658 $base= preg_replace("/^,*/", "", $base);
660 /* Try to use plain entry first */
661 $dn= "$attribute=".$this->$attribute.",$base";
662 $ldap->cat ($dn, array('dn'));
663 if (!$ldap->fetch()){
664 return ($dn);
665 }
667 /* Look for additional attributes */
668 foreach ($this->attributes as $attr){
669 if ($attr == $attribute || $this->$attr == ""){
670 continue;
671 }
673 $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
674 $ldap->cat ($dn, array('dn'));
675 if (!$ldap->fetch()){
676 return ($dn);
677 }
678 }
680 /* None found */
681 return ("none");
682 }
684 function rebind($ldap, $referral)
685 {
686 $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
687 if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
688 $this->error = "Success";
689 $this->hascon=true;
690 $this->reconnect= true;
691 return (0);
692 } else {
693 $this->error = "Could not bind to " . $credentials['ADMIN'];
694 return NULL;
695 }
696 }
698 /* This is a workaround function. */
699 function copy($src_dn, $dst_dn)
700 {
701 /* Rename dn in possible object groups */
702 $ldap= $this->config->get_ldap_link();
703 $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.@LDAP::prepare4filter($src_dn).'))',
704 array('cn'));
705 while ($attrs= $ldap->fetch()){
706 $og= new ogroup($this->config, $ldap->getDN());
707 unset($og->member[$src_dn]);
708 $og->member[$dst_dn]= $dst_dn;
709 $og->save ();
710 }
712 $ldap->cat($dst_dn);
713 $attrs= $ldap->fetch();
714 if (count($attrs)){
715 trigger_error("Trying to overwrite ".@LDAP::fix($dst_dn).", which already exists.",
716 E_USER_WARNING);
717 return (FALSE);
718 }
720 $ldap->cat($src_dn);
721 $attrs= $ldap->fetch();
722 if (!count($attrs)){
723 trigger_error("Trying to move ".@LDAP::fix($src_dn).", which does not seem to exist.",
724 E_USER_WARNING);
725 return (FALSE);
726 }
728 /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
729 $ds= ldap_connect($this->config->current['SERVER']);
730 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
731 if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
732 ldap_set_rebind_proc($ds, array(&$this, "rebind"));
733 }
735 $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
736 error_reporting (0);
737 $sr=ldap_read($ds, @LDAP::fix($src_dn), "objectClass=*");
739 /* Fill data from LDAP */
740 $new= array();
741 if ($sr) {
742 $ei=ldap_first_entry($ds, $sr);
743 if ($ei) {
744 foreach($attrs as $attr => $val){
745 if ($info = ldap_get_values_len($ds, $ei, $attr)){
746 for ($i= 0; $i<$info['count']; $i++){
747 if ($info['count'] == 1){
748 $new[$attr]= $info[$i];
749 } else {
750 $new[$attr][]= $info[$i];
751 }
752 }
753 }
754 }
755 }
756 }
758 /* close conncetion */
759 error_reporting (E_ALL);
760 ldap_unbind($ds);
762 /* Adapt naming attribute */
763 $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
764 $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
765 $new[$dst_name]= @LDAP::fix($dst_val);
767 /* Check if this is a department.
768 * If it is a dep. && there is a , override in his ou
769 * change \2C to , again, else this entry can't be saved ...
770 */
771 if((isset($new['ou'])) &&( preg_match("/\\,/",$new['ou']))){
772 $new['ou'] = preg_replace("/\\\\,/",",",$new['ou']);
773 }
775 /* Save copy */
776 $ldap->connect();
777 $ldap->cd($this->config->current['BASE']);
779 $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
781 /* FAIvariable=.../..., cn=..
782 could not be saved, because the attribute FAIvariable was different to
783 the dn FAIvariable=..., cn=... */
784 if(in_array_ics("FAIdebconfInfo",$new['objectClass'])){
785 $new['FAIvariable'] = $ldap->fix($new['FAIvariable']);
786 }
787 $ldap->cd($dst_dn);
788 $ldap->add($new);
790 if ($ldap->error != "Success"){
791 trigger_error("Trying to save $dst_dn failed.",
792 E_USER_WARNING);
793 return(FALSE);
794 }
796 return (TRUE);
797 }
800 function move($src_dn, $dst_dn)
801 {
803 /* Do not copy if only upper- lowercase has changed */
804 if(strtolower($src_dn) == strtolower($dst_dn)){
805 return(TRUE);
806 }
808 /* Copy source to destination */
809 if (!$this->copy($src_dn, $dst_dn)){
810 return (FALSE);
811 }
813 /* Delete source */
814 $ldap= $this->config->get_ldap_link();
815 $ldap->rmdir($src_dn);
816 if ($ldap->error != "Success"){
817 trigger_error("Trying to delete $src_dn failed.",
818 E_USER_WARNING);
819 return (FALSE);
820 }
822 return (TRUE);
823 }
826 /* Move/Rename complete trees */
827 function recursive_move($src_dn, $dst_dn)
828 {
829 /* Check if the destination entry exists */
830 $ldap= $this->config->get_ldap_link();
832 /* Check if destination exists - abort */
833 $ldap->cat($dst_dn, array('dn'));
834 if ($ldap->fetch()){
835 trigger_error("recursive_move $dst_dn already exists.",
836 E_USER_WARNING);
837 return (FALSE);
838 }
840 /* Perform a search for all objects to be moved */
841 $objects= array();
842 $ldap->cd($src_dn);
843 $ldap->search("(objectClass=*)", array("dn"));
844 while($attrs= $ldap->fetch()){
845 $dn= $attrs['dn'];
846 $objects[$dn]= strlen($dn);
847 }
849 /* Sort objects by indent level */
850 asort($objects);
851 reset($objects);
853 /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
854 foreach ($objects as $object => $len){
855 $src= $object;
856 $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
857 if (!$this->copy($src, $dst)){
858 return (FALSE);
859 }
860 }
862 /* Remove src_dn */
863 $ldap->cd($src_dn);
864 $ldap->recursive_remove();
865 return (TRUE);
866 }
869 function handle_post_events($mode, $add_attrs= array())
870 {
871 switch ($mode){
872 case "add":
873 $this->postcreate($add_attrs);
874 break;
876 case "modify":
877 $this->postmodify($add_attrs);
878 break;
880 case "remove":
881 $this->postremove($add_attrs);
882 break;
883 }
884 }
887 function saveCopyDialog(){
888 }
891 function getCopyDialog(){
892 return(array("string"=>"","status"=>""));
893 }
896 function PrepareForCopyPaste($source){
897 $todo = $this->attributes;
898 if(isset($this->CopyPasteVars)){
899 $todo = array_merge($todo,$this->CopyPasteVars);
900 }
901 $todo[] = "is_account";
902 foreach($todo as $var){
903 if (isset($source->$var)){
904 $this->$var= $source->$var;
905 }
906 }
907 }
910 function tag_attrs($at, $dn= "", $tag= "", $show= false)
911 {
912 /* Skip tagging?
913 If this is called from departmentGeneric, we have to skip this
914 tagging procedure.
915 */
916 if($this->skipTagging){
917 return;
918 }
920 /* No dn? Self-operation... */
921 if ($dn == ""){
922 $dn= $this->dn;
924 /* No tag? Find it yourself... */
925 if ($tag == ""){
926 $len= strlen($dn);
928 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
929 $relevant= array();
930 foreach ($this->config->adepartments as $key => $ntag){
932 /* This one is bigger than our dn, its not relevant... */
933 if ($len <= strlen($key)){
934 continue;
935 }
937 /* This one matches with the latter part. Break and don't fix this entry */
938 if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
939 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
940 $relevant[strlen($key)]= $ntag;
941 continue;
942 }
944 }
946 /* If we've some relevant tags to set, just get the longest one */
947 if (count($relevant)){
948 ksort($relevant);
949 $tmp= array_keys($relevant);
950 $idx= end($tmp);
951 $tag= $relevant[$idx];
952 $this->gosaUnitTag= $tag;
953 }
954 }
955 }
957 /* Remove tags that may already be here... */
958 remove_objectClass("gosaAdministrativeUnitTag", &$at);
959 if (isset($at['gosaUnitTag'])){
960 unset($at['gosaUnitTag']);
961 }
963 /* Set tag? */
964 if ($tag != ""){
965 add_objectClass("gosaAdministrativeUnitTag", &$at);
966 $at['gosaUnitTag']= $tag;
967 }
968 }
971 function handle_object_tagging($dn= "", $tag= "", $show= false)
972 {
973 //FIXME: How to optimize this? We have at least two
974 // LDAP accesses per object. It would be a good
975 // idea to have it integrated.
977 /* No dn? Self-operation... */
978 if ($dn == ""){
979 $dn= $this->dn;
981 /* No tag? Find it yourself... */
982 if ($tag == ""){
983 $len= strlen($dn);
985 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
986 $relevant= array();
987 foreach ($this->config->adepartments as $key => $ntag){
989 /* This one is bigger than our dn, its not relevant... */
990 if ($len <= strlen($key)){
991 continue;
992 }
994 /* This one matches with the latter part. Break and don't fix this entry */
995 if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
996 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
997 $relevant[strlen($key)]= $ntag;
998 continue;
999 }
1001 }
1003 /* If we've some relevant tags to set, just get the longest one */
1004 if (count($relevant)){
1005 ksort($relevant);
1006 $tmp= array_keys($relevant);
1007 $idx= end($tmp);
1008 $tag= $relevant[$idx];
1009 $this->gosaUnitTag= $tag;
1010 }
1011 }
1012 }
1015 /* Set tag? */
1016 if ($tag != ""){
1017 /* Set objectclass and attribute */
1018 $ldap= $this->config->get_ldap_link();
1019 $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
1020 $attrs= $ldap->fetch();
1021 if(isset($attrs['gosaUnitTag'][0]) && $attrs['gosaUnitTag'][0] == $tag){
1022 if ($show) {
1023 echo sprintf(_("Object '%s' is already tagged"), @LDAP::fix($dn))."<br>";
1024 flush();
1025 }
1026 return;
1027 }
1028 if (count($attrs)){
1029 if ($show){
1030 echo sprintf(_("Adding tag (%s) to object '%s'"), $tag, @LDAP::fix($dn))."<br>";
1031 flush();
1032 }
1033 $nattrs= array("gosaUnitTag" => $tag);
1034 $nattrs['objectClass']= array();
1035 for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
1036 $oc= $attrs['objectClass'][$i];
1037 if ($oc != "gosaAdministrativeUnitTag"){
1038 $nattrs['objectClass'][]= $oc;
1039 }
1040 }
1041 $nattrs['objectClass'][]= "gosaAdministrativeUnitTag";
1042 $ldap->cd($dn);
1043 $ldap->modify($nattrs);
1044 show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
1045 } else {
1046 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not tagging ($tag) $dn - seems to have moved away", "Tagging");
1047 }
1049 } else {
1050 /* Remove objectclass and attribute */
1051 $ldap= $this->config->get_ldap_link();
1052 $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
1053 $attrs= $ldap->fetch();
1054 if (isset($attrs['objectClass']) && !in_array_ics("gosaAdministrativeUnitTag", $attrs['objectClass'])){
1055 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "$dn is not tagged", "Tagging");
1056 return;
1057 }
1058 if (count($attrs)){
1059 if ($show){
1060 echo sprintf(_("Removing tag from object '%s'"), @LDAP::fix($dn))."<br>";
1061 flush();
1062 }
1063 $nattrs= array("gosaUnitTag" => array());
1064 $nattrs['objectClass']= array();
1065 for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
1066 $oc= $attrs['objectClass'][$i];
1067 if ($oc != "gosaAdministrativeUnitTag"){
1068 $nattrs['objectClass'][]= $oc;
1069 }
1070 }
1071 $ldap->cd($dn);
1072 $ldap->modify($nattrs);
1073 show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
1074 } else {
1075 @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not removing tag ($tag) $dn - seems to have moved away", "Tagging");
1076 }
1077 }
1079 }
1082 /* Add possibility to stop remove process */
1083 function allow_remove()
1084 {
1085 $reason= "";
1086 return $reason;
1087 }
1089 }
1090 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1091 ?>