Code

- Removed obsoleted dir /usr/lib/gosa
[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   /* 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         }
283     
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 &nbsp; in between the ...option>&nbsp;</option.. because there is no value=".." specified in these option fields  
288          * This &nbsp; 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);
311     
312     $tmp= $ldap->fetch ();
313     
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])){
354           
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])){
363           
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])){
382           
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";
421         
422         /* ... objectClasses */
423         foreach ($this->objectclasses as $oc){
424           $ldif.= "objectClass: $oc\n";
425         }
426         
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]);
450           
451           $result= stream_get_contents($pipes[1]);
452           if ($result != ""){
453             $message[]= $result;
454           }
455           
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\">&nbsp;</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");
565         exec($command);
566       } else {
567         $message= sprintf(_("Command '%s', specified as POSTCREATE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
568         print_red ($message);
569       }
570     }
571   }
573   function postmodify($add_attrs= array())
574   {
575     /* Find postcreate entries for this class */
576     $command= search_config($this->config->data['MENU'], get_class($this), "POSTMODIFY");
577     if ($command == "" && isset($this->config->data['TABS'])){
578       $command= search_config($this->config->data['TABS'], get_class($this), "POSTMODIFY");
579     }
581     if ($command != ""){
583       /* Additional attributes */
584       foreach ($add_attrs as $name => $value){
585         $command= preg_replace("/%$name( |$)/", "$value ", $command);
586       }
588       /* Walk through attribute list */
589       foreach ($this->attributes as $attr){
590         if (!is_array($this->$attr)){
591           $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
592         }
593       }
594       $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
596       if (check_command($command)){
597         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
598             $command, "Execute");
600         exec($command);
601       } else {
602         $message= sprintf(_("Command '%s', specified as POSTMODIFY for plugin '%s' doesn't seem to exist."), $command, get_class($this));
603         print_red ($message);
604       }
605     }
606   }
608   function postremove($add_attrs= array())
609   {
610     /* Find postremove entries for this class */
611     $command= search_config($this->config->data['MENU'], get_class($this), "POSTREMOVE");
612     if ($command == "" && isset($this->config->data['TABS'])){
613       $command= search_config($this->config->data['TABS'], get_class($this), "POSTREMOVE");
614     }
616     if ($command != ""){
618       /* Additional attributes */
619       foreach ($add_attrs as $name => $value){
620         $command= preg_replace("/%$name( |$)/", "$value ", $command);
621       }
623       /* Walk through attribute list */
624       foreach ($this->attributes as $attr){
625         if (!is_array($this->$attr)){
626           $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
627         }
628       }
629       $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
631       if (check_command($command)){
632         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
633             $command, "Execute");
635         exec($command);
636       } else {
637         $message= sprintf(_("Command '%s', specified as POSTREMOVE for plugin '%s' doesn't seem to exist."), $command, get_class($this));
638         print_red ($message);
639       }
640     }
641   }
643   /* Create unique DN */
644   function create_unique_dn($attribute, $base)
645   {
646     $ldap= $this->config->get_ldap_link();
647     $base= preg_replace("/^,*/", "", $base);
649     /* Try to use plain entry first */
650     $dn= "$attribute=".$this->$attribute.",$base";
651     $ldap->cat ($dn, array('dn'));
652     if (!$ldap->fetch()){
653       return ($dn);
654     }
656     /* Look for additional attributes */
657     foreach ($this->attributes as $attr){
658       if ($attr == $attribute || $this->$attr == ""){
659         continue;
660       }
662       $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
663       $ldap->cat ($dn, array('dn'));
664       if (!$ldap->fetch()){
665         return ($dn);
666       }
667     }
669     /* None found */
670     return ("none");
671   }
673   function rebind($ldap, $referral)
674   {
675     $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
676     if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
677       $this->error = "Success";
678       $this->hascon=true;
679       $this->reconnect= true;
680       return (0);
681     } else {
682       $this->error = "Could not bind to " . $credentials['ADMIN'];
683       return NULL;
684     }
685   }
687   /* This is a workaround function. */
688   function copy($src_dn, $dst_dn)
689   {
690     /* Rename dn in possible object groups */
691     $ldap= $this->config->get_ldap_link();
692     $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.@LDAP::prepare4filter($src_dn).'))',
693         array('cn'));
694     while ($attrs= $ldap->fetch()){
695       $og= new ogroup($this->config, $ldap->getDN());
696       unset($og->member[$src_dn]);
697       $og->member[$dst_dn]= $dst_dn;
698       $og->save ();
699     }
701     $ldap->cat($dst_dn);
702     $attrs= $ldap->fetch();
703     if (count($attrs)){
704       trigger_error("Trying to overwrite ".@LDAP::fix($dst_dn).", which already exists.",
705           E_USER_WARNING);
706       return (FALSE);
707     }
709     $ldap->cat($src_dn);
710     $attrs= $ldap->fetch();
711     if (!count($attrs)){
712       trigger_error("Trying to move ".@LDAP::fix($src_dn).", which does not seem to exist.",
713           E_USER_WARNING);
714       return (FALSE);
715     }
717     /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
718     $ds= ldap_connect($this->config->current['SERVER']);
719     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
720     if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
721       ldap_set_rebind_proc($ds, array(&$this, "rebind"));
722     }
724     $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
725     error_reporting (0);
726     $sr=ldap_read($ds, @LDAP::fix($src_dn), "objectClass=*");
728     /* Fill data from LDAP */
729     $new= array();
730     if ($sr) {
731       $ei=ldap_first_entry($ds, $sr);
732       if ($ei) {
733         foreach($attrs as $attr => $val){
734           if ($info = ldap_get_values_len($ds, $ei, $attr)){
735             for ($i= 0; $i<$info['count']; $i++){
736               if ($info['count'] == 1){
737                 $new[$attr]= $info[$i];
738               } else {
739                 $new[$attr][]= $info[$i];
740               }
741             }
742           }
743         }
744       }
745     }
747     /* close conncetion */
748     error_reporting (E_ALL);
749     ldap_unbind($ds);
751     /* Adapt naming attribute */
752     $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
753     $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
754     $new[$dst_name]= @LDAP::fix($dst_val);
756     /* Check if this is a department.
757      * If it is a dep. && there is a , override in his ou 
758      *  change \2C to , again, else this entry can't be saved ...
759      */
760     if((isset($new['ou'])) &&( preg_match("/\\,/",$new['ou']))){
761       $new['ou'] = preg_replace("/\\\\,/",",",$new['ou']);
762     }
764     /* Save copy */
765     $ldap->connect();
766     $ldap->cd($this->config->current['BASE']);
767     
768     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
770     /* FAIvariable=.../..., cn=.. 
771         could not be saved, because the attribute FAIvariable was different to 
772         the dn FAIvariable=..., cn=... */
773     if(in_array_ics("FAIdebconfInfo",$new['objectClass'])){
774       $new['FAIvariable'] = $ldap->fix($new['FAIvariable']);
775     }
776     $ldap->cd($dst_dn);
777     $ldap->add($new);
779     if ($ldap->error != "Success"){
780       trigger_error("Trying to save $dst_dn failed.",
781           E_USER_WARNING);
782       return(FALSE);
783     }
785     return (TRUE);
786   }
789   function move($src_dn, $dst_dn)
790   {
792     /* Do not copy if only upper- lowercase has changed */
793     if(strtolower($src_dn) == strtolower($dst_dn)){
794       return(TRUE);
795     }
797     /* Copy source to destination */
798     if (!$this->copy($src_dn, $dst_dn)){
799       return (FALSE);
800     }
802     /* Delete source */
803     $ldap= $this->config->get_ldap_link();
804     $ldap->rmdir($src_dn);
805     if ($ldap->error != "Success"){
806       trigger_error("Trying to delete $src_dn failed.",
807           E_USER_WARNING);
808       return (FALSE);
809     }
811     return (TRUE);
812   }
815   /* Move/Rename complete trees */
816   function recursive_move($src_dn, $dst_dn)
817   {
818     /* Check if the destination entry exists */
819     $ldap= $this->config->get_ldap_link();
821     /* Check if destination exists - abort */
822     $ldap->cat($dst_dn, array('dn'));
823     if ($ldap->fetch()){
824       trigger_error("recursive_move $dst_dn already exists.",
825           E_USER_WARNING);
826       return (FALSE);
827     }
829     /* Perform a search for all objects to be moved */
830     $objects= array();
831     $ldap->cd($src_dn);
832     $ldap->search("(objectClass=*)", array("dn"));
833     while($attrs= $ldap->fetch()){
834       $dn= $attrs['dn'];
835       $objects[$dn]= strlen($dn);
836     }
838     /* Sort objects by indent level */
839     asort($objects);
840     reset($objects);
842     /* Copy objects from small to big indent levels by replacing src_dn by dst_dn */
843     foreach ($objects as $object => $len){
844       $src= $object;
845       $dst= preg_replace("/$src_dn$/", "$dst_dn", $object);
846       if (!$this->copy($src, $dst)){
847         return (FALSE);
848       }
849     }
851     /* Remove src_dn */
852     $ldap->cd($src_dn);
853     $ldap->recursive_remove();
854     return (TRUE);
855   }
858   function handle_post_events($mode, $add_attrs= array())
859   {
860     switch ($mode){
861       case "add":
862         $this->postcreate($add_attrs);
863       break;
865       case "modify":
866         $this->postmodify($add_attrs);
867       break;
869       case "remove":
870         $this->postremove($add_attrs);
871       break;
872     }
873   }
876   function saveCopyDialog(){
877   }
880   function getCopyDialog(){
881     return(array("string"=>"","status"=>""));
882   }
885   function PrepareForCopyPaste($source){
886     $todo = $this->attributes;
887     if(isset($this->CopyPasteVars)){
888       $todo = array_merge($todo,$this->CopyPasteVars);
889     }
890     $todo[] = "is_account";
891     foreach($todo as $var){
892       if (isset($source->$var)){
893         $this->$var= $source->$var;
894       }
895     }
896   }
899   function tag_attrs($at, $dn= "", $tag= "", $show= false)
900   {
901     /* Skip tagging? 
902        If this is called from departmentGeneric, we have to skip this
903         tagging procedure. 
904      */
905     if($this->skipTagging){
906       return;
907     }
909     /* No dn? Self-operation... */
910     if ($dn == ""){
911       $dn= $this->dn;
912     
913       /* No tag? Find it yourself... */
914       if ($tag == ""){
915         $len= strlen($dn);
917         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
918         $relevant= array();
919         foreach ($this->config->adepartments as $key => $ntag){
921           /* This one is bigger than our dn, its not relevant... */
922           if ($len <= strlen($key)){
923             continue;
924           }
926           /* This one matches with the latter part. Break and don't fix this entry */
927           if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
928             @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
929             $relevant[strlen($key)]= $ntag;
930             continue;
931           }
933         }
935         /* If we've some relevant tags to set, just get the longest one */
936         if (count($relevant)){
937           ksort($relevant);
938           $tmp= array_keys($relevant);
939           $idx= end($tmp);
940           $tag= $relevant[$idx];
941           $this->gosaUnitTag= $tag;
942         }
943       }
944     }
946     /* Remove tags that may already be here... */
947     remove_objectClass("gosaAdministrativeUnitTag", &$at);
948     if (isset($at['gosaUnitTag'])){
949         unset($at['gosaUnitTag']);
950     }
952     /* Set tag? */
953     if ($tag != ""){
954       add_objectClass("gosaAdministrativeUnitTag", &$at);
955       $at['gosaUnitTag']= $tag;
956     }
957   }
960   function handle_object_tagging($dn= "", $tag= "", $show= false)
961   {
962     //FIXME: How to optimize this? We have at least two
963     //       LDAP accesses per object. It would be a good
964     //       idea to have it integrated.
965   
966     /* No dn? Self-operation... */
967     if ($dn == ""){
968       $dn= $this->dn;
969     
970       /* No tag? Find it yourself... */
971       if ($tag == ""){
972         $len= strlen($dn);
974         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
975         $relevant= array();
976         foreach ($this->config->adepartments as $key => $ntag){
978           /* This one is bigger than our dn, its not relevant... */
979           if ($len <= strlen($key)){
980             continue;
981           }
983           /* This one matches with the latter part. Break and don't fix this entry */
984           if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
985             @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
986             $relevant[strlen($key)]= $ntag;
987             continue;
988           }
990         }
992         /* If we've some relevant tags to set, just get the longest one */
993         if (count($relevant)){
994           ksort($relevant);
995           $tmp= array_keys($relevant);
996           $idx= end($tmp);
997           $tag= $relevant[$idx];
998           $this->gosaUnitTag= $tag;
999         }
1000       }
1001     }
1002  
1004     /* Set tag? */
1005     if ($tag != ""){
1006       /* Set objectclass and attribute */
1007       $ldap= $this->config->get_ldap_link();
1008       $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
1009       $attrs= $ldap->fetch();
1010       if(isset($attrs['gosaUnitTag'][0]) && $attrs['gosaUnitTag'][0] == $tag){
1011         if ($show) {
1012           echo sprintf(_("Object '%s' is already tagged"), @LDAP::fix($dn))."<br>";
1013           flush();
1014         }
1015         return;
1016       }
1017       if (count($attrs)){
1018         if ($show){
1019           echo sprintf(_("Adding tag (%s) to object '%s'"), $tag, @LDAP::fix($dn))."<br>";
1020           flush();
1021         }
1022         $nattrs= array("gosaUnitTag" => $tag);
1023         $nattrs['objectClass']= array();
1024         for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
1025           $oc= $attrs['objectClass'][$i];
1026           if ($oc != "gosaAdministrativeUnitTag"){
1027             $nattrs['objectClass'][]= $oc;
1028           }
1029         }
1030         $nattrs['objectClass'][]= "gosaAdministrativeUnitTag";
1031         $ldap->cd($dn);
1032         $ldap->modify($nattrs);
1033         show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
1034       } else {
1035         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not tagging ($tag) $dn - seems to have moved away", "Tagging");
1036       }
1037       
1038     } else {
1039       /* Remove objectclass and attribute */
1040       $ldap= $this->config->get_ldap_link();
1041       $ldap->cat($dn, array('gosaUnitTag', 'objectClass'));
1042       $attrs= $ldap->fetch();
1043       if (isset($attrs['objectClass']) && !in_array_ics("gosaAdministrativeUnitTag", $attrs['objectClass'])){
1044         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "$dn is not tagged", "Tagging");
1045         return;
1046       }
1047       if (count($attrs)){
1048         if ($show){
1049           echo sprintf(_("Removing tag from object '%s'"), @LDAP::fix($dn))."<br>";
1050           flush();
1051         }
1052         $nattrs= array("gosaUnitTag" => array());
1053         $nattrs['objectClass']= array();
1054         for ($i= 0; $i<$attrs['objectClass']['count']; $i++){
1055           $oc= $attrs['objectClass'][$i];
1056           if ($oc != "gosaAdministrativeUnitTag"){
1057             $nattrs['objectClass'][]= $oc;
1058           }
1059         }
1060         $ldap->cd($dn);
1061         $ldap->modify($nattrs);
1062         show_ldap_error($ldap->get_error(), _("Handle object tagging failed"));
1063       } else {
1064         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "Not removing tag ($tag) $dn - seems to have moved away", "Tagging");
1065       }
1066     }
1067     
1068   }
1071   /* Add possibility to stop remove process */
1072   function allow_remove()
1073   {
1074     $reason= "";
1075     return $reason;
1076   }
1079 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1080 ?>