Code

Fixed removing, too
[gosa.git] / include / class_plugin.inc
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   /* Save unit tags */
87   var $gosaUnitTag= "";
89   /*!
90     \brief Used standard values
92     dn
93    */
94   var $dn= "";
95   var $uid= "";
96   var $sn= "";
97   var $givenName= "";
98   var $acl= "*none*";
99   var $dialog= FALSE;
101   /* attribute list for save action */
102   var $attributes= array();
103   var $objectclasses= array();
104   var $new= TRUE;
105   var $saved_attributes= array();
107   /*! \brief plugin constructor
109     If 'dn' is set, the node loads the given 'dn' from LDAP
111     \param dn Distinguished name to initialize plugin from
112     \sa plugin()
113    */
114   function plugin ($config, $dn= NULL)
115   {
116     /* Configuration is fine, allways */
117     $this->config= $config;     
118     $this->dn= $dn;
120     /* Handle new accounts, don't read information from LDAP */
121     if ($dn == "new"){
122       return;
123     }
125     /* Get LDAP descriptor */
126     $ldap= $this->config->get_ldap_link();
127     if ($dn != NULL){
129       /* Load data to 'attrs' and save 'dn' */
130       $ldap->cat ($dn);
131       $this->attrs= $ldap->fetch();
133       /* Copy needed attributes */
134       foreach ($this->attributes as $val){
135         $found= array_key_ics($val, $this->attrs);
136         if ($found != ""){
137           $this->$val= $this->attrs["$found"][0];
138         }
139       }
141       /* gosaUnitTag loading... */
142       if (isset($this->attrs['gosaUnitTag'][0])){
143         $this->gosaUnitTag= $this->attrs['gosaUnitTag'][0];
144       }
146       /* Set the template flag according to the existence of objectClass
147          gosaUserTemplate */
148       if (isset($this->attrs['objectClass'])){
149         if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
150           $this->is_template= TRUE;
151           @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
152               "found", "Template check");
153         }
154       }
156       /* Is Account? */
157       error_reporting(0);
158       $found= TRUE;
159       foreach ($this->objectclasses as $obj){
160         if (preg_match('/top/i', $obj)){
161           continue;
162         }
163         if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){
164           $found= FALSE;
165           break;
166         }
167       }
168       error_reporting(E_ALL);
169       if ($found){
170         $this->is_account= TRUE;
171         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
172             "found", "Object check");
173       }
175       /* Prepare saved attributes */
176       $this->saved_attributes= $this->attrs;
177       foreach ($this->saved_attributes as $index => $value){
178         if (preg_match('/^[0-9]+$/', $index)){
179           unset($this->saved_attributes[$index]);
180           continue;
181         }
182         if (!in_array($index, $this->attributes) && $index != "objectClass"){
183           unset($this->saved_attributes[$index]);
184           continue;
185         }
186         if ($this->saved_attributes[$index]["count"] == 1){
187           $tmp= $this->saved_attributes[$index][0];
188           unset($this->saved_attributes[$index]);
189           $this->saved_attributes[$index]= $tmp;
190           continue;
191         }
193         unset($this->saved_attributes["$index"]["count"]);
194       }
195     }
197     /* Save initial account state */
198     $this->initially_was_account= $this->is_account;
199   }
201   /*! \brief execute plugin
203     Generates the html output for this node
204    */
205   function execute()
206   {
207     # This one is empty currently. Fabian - please fill in the docu code
208     $_SESSION['current_class_for_help'] = get_class($this);
209     /* Reset Lock message POST/GET check array, to prevent perg_match errors*/
210     $_SESSION['LOCK_VARS_TO_USE'] =array();
211   }
213   /*! \brief execute plugin
214      Removes object from parent
215    */
216   function remove_from_parent()
217   {
218     /* include global link_info */
219     $ldap= $this->config->get_ldap_link();
221     /* Get current objectClasses in order to add the required ones */
222     $ldap->cat($this->dn);
223     $tmp= $ldap->fetch ();
224     if (isset($tmp['objectClass'])){
225       $oc= $tmp['objectClass'];
226     } else {
227       $oc= array("count" => 0);
228     }
230     /* Remove objectClasses from entry */
231     $ldap->cd($this->dn);
232     $this->attrs= array();
233     $this->attrs['objectClass']= array();
234     for ($i= 0; $i<$oc["count"]; $i++){
235       if (!in_array_ics($oc[$i], $this->objectclasses)){
236         $this->attrs['objectClass'][]= $oc[$i];
237       }
238     }
240     /* Unset attributes from entry */
241     foreach ($this->attributes as $val){
242       $this->attrs["$val"]= array();
243     }
245     /* Unset account info */
246     $this->is_account= FALSE;
248     /* Do not write in plugin base class, this must be done by
249        children, since there are normally additional attribs,
250        lists, etc. */
251     /*
252        $ldap->modify($this->attrs);
253      */
254   }
257   /* Save data to object */
258   function save_object()
259   {
260     /* Save values to object */
261     foreach ($this->attributes as $val){
262       if (chkacl ($this->acl, "$val") == "" && isset ($_POST["$val"])){
263         /* Check for modifications */
264         if (get_magic_quotes_gpc()) {
265           $data= stripcslashes($_POST["$val"]);
266         } else {
267           $data= $this->$val = $_POST["$val"];
268         }
269         if ($this->$val != $data){
270           $this->is_modified= TRUE;
271         }
272     
273         /* Okay, how can I explain this fix ... 
274          * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds. 
275          * So IE posts these 'unselectable' option, with value = chr(194) 
276          * chr(194) seems to be the &nbsp; in between the ...option>&nbsp;</option.. because there is no value=".." specified in these option fields  
277          * This &nbsp; was added for W3c compliance, but now causes these ... ldap errors ... 
278          * So we set these Fields to ""; a normal empty string, and we can check these values in plugin::check() again ...
279          */
280         if(isset($data[0]) && $data[0] == chr(194)) {
281           $data = "";  
282         }
283         $this->$val= $data;
284       }
285     }
286   }
289   /* Save data to LDAP, depending on is_account we save or delete */
290   function save()
291   {
292     /* include global link_info */
293     $ldap= $this->config->get_ldap_link();
295     /* Start with empty array */
296     $this->attrs= array();
298     /* Get current objectClasses in order to add the required ones */
299     $ldap->cat($this->dn);
300     
301     $tmp= $ldap->fetch ();
302     
303     if (isset($tmp['objectClass'])){
304       $oc= $tmp["objectClass"];
305       $this->new= FALSE;
306     } else {
307       $oc= array("count" => 0);
308       $this->new= TRUE;
309     }
311     /* Load (minimum) attributes, add missing ones */
312     $this->attrs['objectClass']= $this->objectclasses;
313     for ($i= 0; $i<$oc["count"]; $i++){
314       if (!in_array_ics($oc[$i], $this->objectclasses)){
315         $this->attrs['objectClass'][]= $oc[$i];
316       }
317     }
319     /* Copy standard attributes */
320     foreach ($this->attributes as $val){
321       if ($this->$val != ""){
322         $this->attrs["$val"]= $this->$val;
323       } elseif (!$this->new) {
324         $this->attrs["$val"]= array();
325       }
326     }
328   }
331   function cleanup()
332   {
333     foreach ($this->attrs as $index => $value){
335       /* Convert arrays with one element to non arrays, if the saved
336          attributes are no array, too */
337       if (is_array($this->attrs[$index]) && 
338           count ($this->attrs[$index]) == 1 &&
339           isset($this->saved_attributes[$index]) &&
340           !is_array($this->saved_attributes[$index])){
341           
342         $tmp= $this->attrs[$index][0];
343         $this->attrs[$index]= $tmp;
344       }
346       /* Remove emtpy arrays if they do not differ */
347       if (is_array($this->attrs[$index]) &&
348           count($this->attrs[$index]) == 0 &&
349           !isset($this->saved_attributes[$index])){
350           
351         unset ($this->attrs[$index]);
352         continue;
353       }
355       /* Remove single attributes that do not differ */
356       if (!is_array($this->attrs[$index]) &&
357           isset($this->saved_attributes[$index]) &&
358           !is_array($this->saved_attributes[$index]) &&
359           $this->attrs[$index] == $this->saved_attributes[$index]){
361         unset ($this->attrs[$index]);
362         continue;
363       }
365       /* Remove arrays that do not differ */
366       if (is_array($this->attrs[$index]) && 
367           isset($this->saved_attributes[$index]) &&
368           is_array($this->saved_attributes[$index])){
369           
370         if (!array_differs($this->attrs[$index],$this->saved_attributes[$index])){
371           unset ($this->attrs[$index]);
372           continue;
373         }
374       }
375     }
376   }
378   /* Check formular input */
379   function check()
380   {
381     $message= array();
383     /* Skip if we've no config object */
384     if (!isset($this->config)){
385       return $message;
386     }
388     /* Find hooks entries for this class */
389     $command= search_config($this->config->data['MENU'], get_class($this), "CHECK");
390     if ($command == "" && isset($this->config->data['TABS'])){
391       $command= search_config($this->config->data['TABS'], get_class($this), "CHECK");
392     }
394     if ($command != ""){
396       if (!check_command($command)){
397         $message[]= sprintf(_("Command '%s', specified as CHECK hook for plugin '%s' doesn't seem to exist."), $command,
398                             get_class($this));
399       } else {
401         /* Generate "ldif" for check hook */
402         $ldif= "dn: $this->dn\n";
403         
404         /* ... objectClasses */
405         foreach ($this->objectclasses as $oc){
406           $ldif.= "objectClass: $oc\n";
407         }
408         
409         /* ... attributes */
410         foreach ($this->attributes as $attr){
411           if ($this->$attr == ""){
412             continue;
413           }
414           if (is_array($this->$attr)){
415             foreach ($this->$attr as $val){
416               $ldif.= "$attr: $val\n";
417             }
418           } else {
419               $ldif.= "$attr: ".$this->$attr."\n";
420           }
421         }
423         /* Append empty line */
424         $ldif.= "\n";
426         /* Feed "ldif" into hook and retrieve result*/
427         $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
428         $fh= proc_open($command, $descriptorspec, $pipes);
429         if (is_resource($fh)) {
430           fwrite ($pipes[0], $ldif);
431           fclose($pipes[0]);
432           
433           $result= stream_get_contents($pipes[1]);
434           if ($result != ""){
435             $message[]= $result;
436           }
437           
438           fclose($pipes[1]);
439           fclose($pipes[2]);
440           proc_close($fh);
441         }
442       }
444     }
446     return ($message);
447   }
449   /* Adapt from template, using 'dn' */
450   function adapt_from_template($dn)
451   {
452     /* Include global link_info */
453     $ldap= $this->config->get_ldap_link();
455     /* Load requested 'dn' to 'attrs' */
456     $ldap->cat ($dn);
457     $this->attrs= $ldap->fetch();
459     /* Walk through attributes */
460     foreach ($this->attributes as $val){
462       if (isset($this->attrs["$val"][0])){
464         /* If attribute is set, replace dynamic parts: 
465            %sn, %givenName and %uid. Fill these in our local variables. */
466         $value= $this->attrs["$val"][0];
468         foreach (array("sn", "givenName", "uid") as $repl){
469           if (preg_match("/%$repl/i", $value)){
470             $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
471           }
472         }
473         $this->$val= $value;
474       }
475     }
477     /* Is Account? */
478     $found= TRUE;
479     foreach ($this->objectclasses as $obj){
480       if (preg_match('/top/i', $obj)){
481         continue;
482       }
483       if (!in_array_ics ($obj, $this->attrs['objectClass'])){
484         $found= FALSE;
485         break;
486       }
487     }
488     if ($found){
489       $this->is_account= TRUE;
490     }
491   }
493   /* Indicate whether a password change is needed or not */
494   function password_change_needed()
495   {
496     return FALSE;
497   }
499   /* Show header message for tab dialogs */
500   function show_header($button_text, $text, $disabled= FALSE)
501   {
502     if ($disabled == TRUE){
503       $state= "disabled";
504     } else {
505       $state= "";
506     }
507     $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
508     $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".
509       chkacl($this->acl, "all")." ".$state.
510       "><p class=\"seperator\">&nbsp;</p></td></tr></table>";
512     return($display);
513   }
515   function postcreate($add_attrs= array())
516   {
517     /* Find postcreate entries for this class */
518     $command= search_config($this->config->data['MENU'], get_class($this), "POSTCREATE");
519     if ($command == "" && isset($this->config->data['TABS'])){
520       $command= search_config($this->config->data['TABS'], get_class($this), "POSTCREATE");
521     }
523     if ($command != ""){
524       /* Walk through attribute list */
525       foreach ($this->attributes as $attr){
526         if (!is_array($this->$attr)){
527           $command= preg_replace("/%$attr/", $this->$attr, $command);
528         }
529       }
530       $command= preg_replace("/%dn/", $this->dn, $command);
532       /* Additional attributes */
533       foreach ($add_attrs as $name => $value){
534         $command= preg_replace("/%$name/", $value, $command);
535       }
537       if (check_command($command)){
538         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
539             $command, "Execute");
541         exec($command);
542       } else {
543         $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
544         print_red ($message);
545       }
546     }
547   }
549   function postmodify($add_attrs= array())
550   {
551     /* Find postcreate entries for this class */
552     $command= search_config($this->config->data['MENU'], get_class($this), "POSTMODIFY");
553     if ($command == "" && isset($this->config->data['TABS'])){
554       $command= search_config($this->config->data['TABS'], get_class($this), "POSTMODIFY");
555     }
557     if ($command != ""){
558       /* Walk through attribute list */
559       foreach ($this->attributes as $attr){
560         if (!is_array($this->$attr)){
561           $command= preg_replace("/%$attr/", $this->$attr, $command);
562         }
563       }
564       $command= preg_replace("/%dn/", $this->dn, $command);
566       /* Additional attributes */
567       foreach ($add_attrs as $name => $value){
568         $command= preg_replace("/%$name/", $value, $command);
569       }
571       if (check_command($command)){
572         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
573             $command, "Execute");
575         exec($command);
576       } else {
577         $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
578         print_red ($message);
579       }
580     }
581   }
583   function postremove($add_attrs= array())
584   {
585     /* Find postremove entries for this class */
586     $command= search_config($this->config->data['MENU'], get_class($this), "POSTREMOVE");
587     if ($command == "" && isset($this->config->data['TABS'])){
588       $command= search_config($this->config->data['TABS'], get_class($this), "POSTREMOVE");
589     }
591     if ($command != ""){
592       /* Walk through attribute list */
593       foreach ($this->attributes as $attr){
594         if (!is_array($this->$attr)){
595           $command= preg_replace("/%$attr/", $this->$attr, $command);
596         }
597       }
598       $command= preg_replace("/%dn/", $this->dn, $command);
600       /* Additional attributes */
601       foreach ($add_attrs as $name => $value){
602         $command= preg_replace("/%$name/", $value, $command);
603       }
605       if (check_command($command)){
606         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
607             $command, "Execute");
609         exec($command);
610       } else {
611         $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
612         print_red ($message);
613       }
614     }
615   }
617   /* Create unique DN */
618   function create_unique_dn($attribute, $base)
619   {
620     $ldap= $this->config->get_ldap_link();
621     $base= preg_replace("/^,*/", "", $base);
623     /* Try to use plain entry first */
624     $dn= "$attribute=".$this->$attribute.",$base";
625     $ldap->cat ($dn);
626     if (!$ldap->fetch()){
627       return ($dn);
628     }
630     /* Look for additional attributes */
631     foreach ($this->attributes as $attr){
632       if ($attr == $attribute || $this->$attr == ""){
633         continue;
634       }
636       $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
637       $ldap->cat ($dn);
638       if (!$ldap->fetch()){
639         return ($dn);
640       }
641     }
643     /* None found */
644     return ("none");
645   }
647   function rebind($ldap, $referral)
648   {
649     $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
650     if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
651       $this->error = "Success";
652       $this->hascon=true;
653       $this->reconnect= true;
654       return (0);
655     } else {
656       $this->error = "Could not bind to " . $credentials['ADMIN'];
657       return NULL;
658     }
659   }
661   /* This is a workaround function. */
662   function copy($src_dn, $dst_dn)
663   {
664     /* Rename dn in possible object groups */
665     $ldap= $this->config->get_ldap_link();
666     $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.$src_dn.'))',
667         array('cn'));
668     while ($attrs= $ldap->fetch()){
669       $og= new ogroup($this->config, $ldap->getDN());
670       unset($og->member[$src_dn]);
671       $og->member[$dst_dn]= $dst_dn;
672       $og->save ();
673     }
675     $ldap->cat($dst_dn);
676     $attrs= $ldap->fetch();
677     if (count($attrs)){
678       trigger_error("Trying to overwrite $dst_dn, which already exists.",
679           E_USER_WARNING);
680       return (FALSE);
681     }
683     $ldap->cat($src_dn);
684     $attrs= array();
685     $attrs= $ldap->fetch();
686     if (!count($attrs)){
687       trigger_error("Trying to move $src_dn, which does not seem to exist.",
688           E_USER_WARNING);
689       return (FALSE);
690     }
692     /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
693     $ds= ldap_connect($this->config->current['SERVER']);
694     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
695     if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
696       ldap_set_rebind_proc($ds, array(&$this, "rebind"));
697     }
699     $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
700     error_reporting (0);
701     $sr=ldap_read($ds, $ldap->fix($src_dn), "objectClass=*");
703     /* Fill data from LDAP */
704     $new= array();
705     if ($sr) {
706       $ei=ldap_first_entry($ds, $sr);
707       if ($ei) {
708         foreach($attrs as $attr => $val){
709           if ($info = ldap_get_values_len($ds, $ei, $attr)){
710             for ($i= 0; $i<$info['count']; $i++){
711               if ($info['count'] == 1){
712                 $new[$attr]= $info[$i];
713               } else {
714                 $new[$attr][]= $info[$i];
715               }
716             }
717           }
718         }
719       }
720     }
722     /* close conncetion */
723     error_reporting (E_ALL);
724     ldap_unbind($ds);
726     /* Adapt naming attribute */
727     $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
728     $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
729     $new[$dst_name]= $dst_val;
731     /* Check if this is a department.
732      * If it is a dep. && there is a , override in his ou 
733      *  change \2C to , again, else this entry can't be saved ...
734      */
735     if((isset($new['ou'])) &&( preg_match("/\\\\2C/",$new['ou']))){
736       $new['ou'] = preg_replace("/\\\\2C/",",",$new['ou']);
737     }
739     /* Save copy */
740     $ldap->connect();
741     $ldap->cd($this->config->current['BASE']);
742     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
743     $ldap->cd($dst_dn);
744     $ldap->add($new);
746     if ($ldap->error != "Success"){
747       trigger_error("Trying to save $dst_dn failed.",
748           E_USER_WARNING);
749       return(FALSE);
750     }
752     return (TRUE);
753   }
756   function move($src_dn, $dst_dn)
757   {
758     /* Copy source to destination */
759     if (!$this->copy($src_dn, $dst_dn)){
760       return (FALSE);
761     }
763     /* Delete source */
764     $ldap= $this->config->get_ldap_link();
765     $ldap->rmdir($src_dn);
766     if ($ldap->error != "Success"){
767       trigger_error("Trying to delete $src_dn failed.",
768           E_USER_WARNING);
769       return (FALSE);
770     }
772     return (TRUE);
773   }
776   /* Move/Rename complete trees */
777   function recursive_move($src_dn, $dst_dn)
778   {
779     /* Check if the destination entry exists */
780     $ldap= $this->config->get_ldap_link();
782     /* Check if destination exists - abort */
783     $ldap->cat($dst_dn);
784     if ($ldap->fetch()){
785       trigger_error("recursive_move $dst_dn already exists.",
786           E_USER_WARNING);
787       return (FALSE);
788     }
790     /* Perform a search for all objects to be moved */
791     $objects= array();
792     $ldap->cd($src_dn);
793     $ldap->search("(objectClass=*)", array("dn"));
794     while($attrs= $ldap->fetch()){
795       $dn= $attrs['dn'];
796       $objects[$dn]= strlen($dn);
797     }
799     /* Sort objects by indent level */
800     asort($objects);
801     reset($objects);
803     /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
804     foreach ($objects as $object => $len){
805       $src= $object;
806       $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
807       if (!$this->copy($src, $dst)){
808         return (FALSE);
809       }
810     }
812     /* Remove src_dn */
813     $ldap->cd($src_dn);
814     $ldap->recursive_remove();
815     return (TRUE);
816   }
819   function handle_post_events($mode, $add_attrs= array())
820   {
821     switch ($mode){
822       case "add":
823         $this->postcreate($add_attrs);
824       break;
826       case "modify":
827         $this->postmodify($add_attrs);
828       break;
830       case "remove":
831         $this->postremove($add_attrs);
832       break;
833     }
834   }
837   function saveCopyDialog(){
838   }
841   function getCopyDialog(){
842     return(array("string"=>"","status"=>""));
843   }
846   function PrepareForCopyPaste($source){
847     $todo = $this->attributes;
848     if(isset($this->CopyPasteVars)){
849       $todo = array_merge($todo,$this->CopyPasteVars);
850     }
851     $todo[] = "is_account";
852     foreach($todo as $var){
853       $this->$var = $source->$var;
854     }
855   }
858   function handle_object_tagging($dn= "", $tag= "")
859   {
860     //FIXME: How to optimize this? We have at least two
861     //       LDAP accesses per object. It would be a good
862     //       idea to have it integrated.
863   
864     /* No dn? Self-operation... */
865     if ($dn == ""){
866       $dn= $this->dn;
867     
868       /* No tag? Find it yourself... */
869       if ($tag == ""){
870         $len= strlen($dn);
872         echo "DEBUG: No tag for $dn - looking for one...<br>";
873         $relevant= array();
874         foreach ($this->config->adepartments as $key => $ntag){
876           /* This one is bigger than our dn, its not relevant... */
877           if ($len <= strlen($key)){
878             continue;
879           }
881           /* This one matches with the latter part. Break and don't fix this entry */
882           if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
883             echo "DEBUG: Possibly relevant: $key<br>";
884             $relevant[strlen($key)]= $ntag;
885             continue;
886           }
888         }
890         /* If we've some relevant tags to set, just get the longest one */
891         if (count($relevant)){
892           ksort($relevant);
893           $tmp= array_keys($relevant);
894           $idx= end($tmp);
895           $tag= $relevant[$idx];
896           $this->gosaUnitTag= $tag;
897         }
898       }
899     }
900  
902     /* Set tag? */
903     if ($tag != ""){
904       /* Set objectclass and attribute */
905       $ldap= $this->config->get_ldap_link();
906       $ldap->cat($dn);
907       $attrs= $ldap->fetch();
908       if(isset($attrs['gosaUnitTag'][0]) && $attrs['gosaUnitTag'][0] == $tag){
909         echo "DEBUG: $dn is already tagged<br>";
910         return;
911       }
912       if (count($attrs)){
913         echo "DEBUG: Add tagging ($tag) to $dn.<br>";
914         $nattrs= array("gosaUnitTag" => $this->gosaUnitTag);
915         $nattrs['objectClass']= array();
916         for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
917           $oc= $attrs['objectClass'][$i];
918           if ($oc != "gosaAdministrativeUnitTag"){
919             $nattrs['objectClass'][]= $oc;
920           }
921         }
922         $nattrs['objectClass'][]= "gosaAdministrativeUnitTag";
923         $ldap->cd($dn);
924         $ldap->modify($nattrs);
925       } else {
926         echo "DEBUG: not tagging ($tag) $dn - seems to have moved away<br>";
927       }
928       
929     } else {
930       /* Remove objectclass and attribute */
931       $ldap= $this->config->get_ldap_link();
932       $ldap->cat($dn);
933       $attrs= $ldap->fetch();
934       if (!in_array_ics("gosaAdministrativeUnitTag", $attrs['objectClass'])){
935         echo "DEBUG: $dn is not tagged<br>";
936         return;
937       }
938       if (count($attrs)){
939         echo "DEBUG: Remove tagging from $dn.<br>";
940         $nattrs= array("gosaUnitTag" => array());
941         $nattrs['objectClass']= array();
942         for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
943           $oc= $attrs['objectClass'][$i];
944           if ($oc != "gosaAdministrativeUnitTag"){
945             $nattrs['objectClass'][]= $oc;
946           }
947         }
948         $ldap->cd($dn);
949         $ldap->modify($nattrs);
950         show_ldap_error($ldap->get_error());
951       } else {
952         echo "DEBUG: not removing tag ($tag) $dn - seems to have moved away<br>";
953       }
954     }
955     
956   }
959 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
960 ?>