Code

- Added a section how to report a bug
[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");
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']);
778     
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;
923     
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.
976   
977     /* No dn? Self-operation... */
978     if ($dn == ""){
979       $dn= $this->dn;
980     
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     }
1013  
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       }
1048       
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     }
1078     
1079   }
1082   /* Add possibility to stop remove process */
1083   function allow_remove()
1084   {
1085     $reason= "";
1086     return $reason;
1087   }
1090 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1091 ?>