Code

de49eb40d2a4eb92e880bb78fd21b07d4165b98e
[gosa.git] / gosa-core / 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;
104   var $snapDialog = NULL;
106   /* attribute list for save action */
107   var $attributes= array();
108   var $objectclasses= array();
109   var $is_new= TRUE;
110   var $saved_attributes= array();
112   var $acl_base= "";
113   var $acl_category= "";
115   /* This can be set to render the tabulators in another stylesheet */
116   var $pl_notify= FALSE;
118   /* Object entry CSN */
119   var $entryCSN         = "";
120   var $CSN_check_active = FALSE;
122   /* This variable indicates that this class can handle multiple dns at once. */
123   var $multiple_support = FALSE;
124   var $multi_attrs      = array();
125   var $multi_attrs_all  = array(); 
127   /* This aviable indicates, that we are currently in multiple edit handle */
128   var $multiple_support_active = FALSE; 
129   var $selected_edit_values = array();
130   var $multi_boxes = array();
132   /*! \brief plugin constructor
134     If 'dn' is set, the node loads the given 'dn' from LDAP
136     \param dn Distinguished name to initialize plugin from
137     \sa plugin()
138    */
139   function plugin (&$config, $dn= NULL, $parent= NULL)
140   {
141     /* Configuration is fine, allways */
142     $this->config= &$config;    
143     $this->dn= $dn;
145     /* Handle new accounts, don't read information from LDAP */
146     if ($dn == "new"){
147       return;
148     }
150     /* Save current dn as acl_base */
151     $this->acl_base= $dn;
153     /* Get LDAP descriptor */
154     $ldap= $this->config->get_ldap_link();
155     if ($dn !== NULL){
157       /* Load data to 'attrs' and save 'dn' */
158       if ($parent !== NULL){
159         $this->attrs= $parent->attrs;
160       } else {
161         $ldap->cat ($dn);
162         $this->attrs= $ldap->fetch();
163       }
165       /* Copy needed attributes */
166       foreach ($this->attributes as $val){
167         $found= array_key_ics($val, $this->attrs);
168         if ($found != ""){
169           $this->$val= $this->attrs["$found"][0];
170         }
171       }
173       /* gosaUnitTag loading... */
174       if (isset($this->attrs['gosaUnitTag'][0])){
175         $this->gosaUnitTag= $this->attrs['gosaUnitTag'][0];
176       }
178       /* Set the template flag according to the existence of objectClass
179          gosaUserTemplate */
180       if (isset($this->attrs['objectClass'])){
181         if (in_array ("gosaUserTemplate", $this->attrs['objectClass'])){
182           $this->is_template= TRUE;
183           @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
184               "found", "Template check");
185         }
186       }
188       /* Is Account? */
189       $found= TRUE;
190       foreach ($this->objectclasses as $obj){
191         if (preg_match('/top/i', $obj)){
192           continue;
193         }
194         if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){
195           $found= FALSE;
196           break;
197         }
198       }
199       if ($found){
200         $this->is_account= TRUE;
201         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,
202             "found", "Object check");
203       }
205       /* Prepare saved attributes */
206       $this->saved_attributes= $this->attrs;
207       foreach ($this->saved_attributes as $index => $value){
208         if (preg_match('/^[0-9]+$/', $index)){
209           unset($this->saved_attributes[$index]);
210           continue;
211         }
212         if (!in_array($index, $this->attributes) && $index != "objectClass"){
213           unset($this->saved_attributes[$index]);
214           continue;
215         }
216         if (isset($this->saved_attributes[$index][0]) || $this->saved_attributes[$index]["count"] == 1){
217           $tmp= $this->saved_attributes[$index][0];
218           unset($this->saved_attributes[$index]);
219           $this->saved_attributes[$index]= $tmp;
220           continue;
221         }
223         unset($this->saved_attributes["$index"]["count"]);
224       }
225     }
227     /* Save initial account state */
228     $this->initially_was_account= $this->is_account;
229   }
232   /*! \brief execute plugin
234     Generates the html output for this node
235    */
236   function execute()
237   {
238     /* This one is empty currently. Fabian - please fill in the docu code */
239     session::set('current_class_for_help',get_class($this));
241     /* Reset Lock message POST/GET check array, to prevent perg_match errors*/
242     session::set('LOCK_VARS_TO_USE',array());
243     session::set('LOCK_VARS_USED',array());
244   }
246   /*! \brief execute plugin
247      Removes object from parent
248    */
249   function remove_from_parent()
250   {
251     /* include global link_info */
252     $ldap= $this->config->get_ldap_link();
254     /* Get current objectClasses in order to add the required ones */
255     $ldap->cat($this->dn);
256     $tmp= $ldap->fetch ();
257     $oc= array();
258     if (isset($tmp['objectClass'])){
259       $oc= $tmp['objectClass'];
260       unset($oc['count']);
261     }
263     /* Remove objectClasses from entry */
264     $ldap->cd($this->dn);
265     $this->attrs= array();
266     $this->attrs['objectClass']= array_remove_entries($this->objectclasses,$oc);
268     /* Unset attributes from entry */
269     foreach ($this->attributes as $val){
270       $this->attrs["$val"]= array();
271     }
273     /* Unset account info */
274     $this->is_account= FALSE;
276     /* Do not write in plugin base class, this must be done by
277        children, since there are normally additional attribs,
278        lists, etc. */
279     /*
280        $ldap->modify($this->attrs);
281      */
282   }
285   /*! \brief   Save HTML posted data to object 
286    */
287   function save_object()
288   {
289     /* Update entry CSN if it is empty. */
290     if(empty($this->entryCSN) && $this->CSN_check_active){
291       $this->entryCSN = getEntryCSN($this->dn);
292     }
294     /* Save values to object */
295     foreach ($this->attributes as $val){
296       if ($this->acl_is_writeable($val) && isset ($_POST["$val"])){
297         /* Check for modifications */
298         if (get_magic_quotes_gpc()) {
299           $data= stripcslashes($_POST["$val"]);
300         } else {
301           $data= $this->$val = $_POST["$val"];
302         }
303         if ($this->$val != $data){
304           $this->is_modified= TRUE;
305         }
306     
307         /* Okay, how can I explain this fix ... 
308          * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds. 
309          * So IE posts these 'unselectable' option, with value = chr(194) 
310          * chr(194) seems to be the &nbsp; in between the ...option>&nbsp;</option.. because there is no value=".." specified in these option fields  
311          * This &nbsp; was added for W3c compliance, but now causes these ... ldap errors ... 
312          * So we set these Fields to ""; a normal empty string, and we can check these values in plugin::check() again ...
313          */
314         if(isset($data[0]) && $data[0] == chr(194)) {
315           $data = "";  
316         }
317         $this->$val= $data;
318       }
319     }
320   }
323   /* Save data to LDAP, depending on is_account we save or delete */
324   function save()
325   {
326     /* include global link_info */
327     $ldap= $this->config->get_ldap_link();
329     /* Save all plugins */
330     $this->entryCSN = "";
332     /* Start with empty array */
333     $this->attrs= array();
335     /* Get current objectClasses in order to add the required ones */
336     $ldap->cat($this->dn);
337     
338     $tmp= $ldap->fetch ();
340     $oc= array();
341     if (isset($tmp['objectClass'])){
342       $oc= $tmp["objectClass"];
343       $this->is_new= FALSE;
344       unset($oc['count']);
345     } else {
346       $this->is_new= TRUE;
347     }
349     /* Load (minimum) attributes, add missing ones */
350     $this->attrs['objectClass']= gosa_array_merge($oc,$this->objectclasses);
352     /* Copy standard attributes */
353     foreach ($this->attributes as $val){
354       if ($this->$val != ""){
355         $this->attrs["$val"]= $this->$val;
356       } elseif (!$this->is_new) {
357         $this->attrs["$val"]= array();
358       }
359     }
361     /* Handle tagging */
362     $this->tag_attrs($this->attrs);
363   }
366   function cleanup()
367   {
368     foreach ($this->attrs as $index => $value){
370       /* Convert arrays with one element to non arrays, if the saved
371          attributes are no array, too */
372       if (is_array($this->attrs[$index]) && 
373           count ($this->attrs[$index]) == 1 &&
374           isset($this->saved_attributes[$index]) &&
375           !is_array($this->saved_attributes[$index])){
376           
377         $tmp= $this->attrs[$index][0];
378         $this->attrs[$index]= $tmp;
379       }
381       /* Remove emtpy arrays if they do not differ */
382       if (is_array($this->attrs[$index]) &&
383           count($this->attrs[$index]) == 0 &&
384           !isset($this->saved_attributes[$index])){
385           
386         unset ($this->attrs[$index]);
387         continue;
388       }
390       /* Remove single attributes that do not differ */
391       if (!is_array($this->attrs[$index]) &&
392           isset($this->saved_attributes[$index]) &&
393           !is_array($this->saved_attributes[$index]) &&
394           $this->attrs[$index] == $this->saved_attributes[$index]){
396         unset ($this->attrs[$index]);
397         continue;
398       }
400       /* Remove arrays that do not differ */
401       if (is_array($this->attrs[$index]) && 
402           isset($this->saved_attributes[$index]) &&
403           is_array($this->saved_attributes[$index])){
404           
405         if (!array_differs($this->attrs[$index],$this->saved_attributes[$index])){
406           unset ($this->attrs[$index]);
407           continue;
408         }
409       }
410     }
412     /* Update saved attributes and ensure that next cleanups will be successful too */
413     foreach($this->attrs as $name => $value){
414       $this->saved_attributes[$name] = $value;
415     }
416   }
418   /* Check formular input */
419   function check()
420   {
421     $message= array();
423     /* Skip if we've no config object */
424     if (!isset($this->config) || !is_object($this->config)){
425       return $message;
426     }
428     /* Find hooks entries for this class */
429     $command= $this->config->search(get_class($this), "CHECK", array('menu', 'tabs'));
431     if ($command != ""){
433       if (!check_command($command)){
434         $message[]= msgPool::cmdnotfound("CHECK", get_class($this));
435       } else {
437         /* Generate "ldif" for check hook */
438         $ldif= "dn: $this->dn\n";
439         
440         /* ... objectClasses */
441         foreach ($this->objectclasses as $oc){
442           $ldif.= "objectClass: $oc\n";
443         }
444         
445         /* ... attributes */
446         foreach ($this->attributes as $attr){
447           if ($this->$attr == ""){
448             continue;
449           }
450           if (is_array($this->$attr)){
451             foreach ($this->$attr as $val){
452               $ldif.= "$attr: $val\n";
453             }
454           } else {
455               $ldif.= "$attr: ".$this->$attr."\n";
456           }
457         }
459         /* Append empty line */
460         $ldif.= "\n";
462         /* Feed "ldif" into hook and retrieve result*/
463         $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"));
464         $fh= proc_open($command, $descriptorspec, $pipes);
465         if (is_resource($fh)) {
466           fwrite ($pipes[0], $ldif);
467           fclose($pipes[0]);
468           
469           $result= stream_get_contents($pipes[1]);
470           if ($result != ""){
471             $message[]= $result;
472           }
473           
474           fclose($pipes[1]);
475           fclose($pipes[2]);
476           proc_close($fh);
477         }
478       }
480     }
482     /* Check entryCSN */
483     if($this->CSN_check_active){
484       $current_csn = getEntryCSN($this->dn);
485       if($current_csn != $this->entryCSN && !empty($this->entryCSN) && !empty($current_csn)){
486         $this->entryCSN = $current_csn;
487         $message[] = _("The object has changed since opened in GOsa. All changes that may be done by others get lost if you save this entry!");
488       }
489     }
490     return ($message);
491   }
493   /* Adapt from template, using 'dn' */
494   function adapt_from_template($dn)
495   {
496     /* Include global link_info */
497     $ldap= $this->config->get_ldap_link();
499     /* Load requested 'dn' to 'attrs' */
500     $ldap->cat ($dn);
501     $this->attrs= $ldap->fetch();
503     /* Walk through attributes */
504     foreach ($this->attributes as $val){
506       if (isset($this->attrs["$val"][0])){
508         /* If attribute is set, replace dynamic parts: 
509            %sn, %givenName and %uid. Fill these in our local variables. */
510         $value= $this->attrs["$val"][0];
512         foreach (array("sn", "givenName", "uid") as $repl){
513           if (preg_match("/%$repl/i", $value)){
514             $value= preg_replace ("/%$repl/i", $this->parent->$repl, $value);
515           }
516         }
517         $this->$val= $value;
518       }
519     }
521     /* Is Account? */
522     $found= TRUE;
523     foreach ($this->objectclasses as $obj){
524       if (preg_match('/top/i', $obj)){
525         continue;
526       }
527       if (!in_array_ics ($obj, $this->attrs['objectClass'])){
528         $found= FALSE;
529         break;
530       }
531     }
532     if ($found){
533       $this->is_account= TRUE;
534     }
535   }
537   /* Indicate whether a password change is needed or not */
538   function password_change_needed()
539   {
540     return FALSE;
541   }
544   /* Show header message for tab dialogs */
545   function show_enable_header($button_text, $text, $disabled= FALSE)
546   {
547     if (($disabled == TRUE) || (!$this->acl_is_createable())){
548       $state= "disabled";
549     } else {
550       $state= "";
551     }
552     $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
553     $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".$state.
554       "><p class=\"seperator\">&nbsp;</p></td></tr></table>";
556     return($display);
557   }
560   /* Show header message for tab dialogs */
561   function show_disable_header($button_text, $text, $disabled= FALSE)
562   {
563     if (($disabled == TRUE) || !$this->acl_is_removeable()){
564       $state= "disabled";
565     } else {
566       $state= "";
567     }
568     $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
569     $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".$state.
570       "><p class=\"seperator\">&nbsp;</p></td></tr></table>";
572     return($display);
573   }
576   /* Show header message for tab dialogs */
577   function show_header($button_text, $text, $disabled= FALSE)
578   {
579     echo "FIXME: show_header should be replaced by show_disable_header and show_enable_header<br>";
580     if ($disabled == TRUE){
581       $state= "disabled";
582     } else {
583       $state= "";
584     }
585     $display= "<table summary=\"\" width=\"100%\"><tr>\n<td colspan=2><p><b>$text</b></p>\n";
586     $display.= "<input type=submit value=\"$button_text\" name=\"modify_state\" ".
587       ($this->acl_is_createable()?'':'disabled')." ".$state.
588       "><p class=\"seperator\">&nbsp;</p></td></tr></table>";
590     return($display);
591   }
594   function postcreate($add_attrs= array())
595   {
596     /* Find postcreate entries for this class */
597     $command= $this->config->search(get_class($this), "POSTCREATE",array('menu', 'tabs'));
599     if ($command != ""){
601       /* Additional attributes */
602       foreach ($add_attrs as $name => $value){
603         $command= preg_replace("/%$name( |$)/", "$value ", $command);
604       }
606       /* Walk through attribute list */
607       foreach ($this->attributes as $attr){
608         if (!is_array($this->$attr)){
609           $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
610         }
611       }
612       $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
614       if (check_command($command)){
615         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
616             $command, "Execute");
618         exec($command);
619       } else {
620         $message[]= msgPool::cmdnotfound("POSTCREATE", get_class($this));
621         msg_dialog::display(_("Error"), $message, ERROR_DIALOG);
622       }
623     }
624   }
626   function postmodify($add_attrs= array())
627   {
628     /* Find postcreate entries for this class */
629     $command= $this->config->search(get_class($this), "POSTMODIFY",array('menu','tabs'));
631     if ($command != ""){
633       /* Additional attributes */
634       foreach ($add_attrs as $name => $value){
635         $command= preg_replace("/%$name( |$)/", "$value ", $command);
636       }
638       /* Walk through attribute list */
639       foreach ($this->attributes as $attr){
640         if (!is_array($this->$attr)){
641           $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
642         }
643       }
644       $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
646       if (check_command($command)){
647         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
648             $command, "Execute");
650         exec($command);
651       } else {
652         $message[]= msgPool::cmdnotfound("POSTMODIFY", get_class($this));
653         msg_dialog::display(_("Error"), $message, ERROR_DIALOG);
654       }
655     }
656   }
658   function postremove($add_attrs= array())
659   {
660     /* Find postremove entries for this class */
661     $command= $this->config->search(get_class($this), "POSTREMOVE",array('menu','tabs'));
662     if ($command != ""){
664       /* Additional attributes */
665       foreach ($add_attrs as $name => $value){
666         $command= preg_replace("/%$name( |$)/", "$value ", $command);
667       }
669       /* Walk through attribute list */
670       foreach ($this->attributes as $attr){
671         if (!is_array($this->$attr)){
672           $command= preg_replace("/%$attr( |$)/", $this->$attr." ", $command);
673         }
674       }
675       $command= preg_replace("/%dn( |$)/", $this->dn." ", $command);
677       if (check_command($command)){
678         @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,
679             $command, "Execute");
681         exec($command);
682       } else {
683         $message[]= msgPool::cmdnotfound("POSTREMOVE", get_class($this));
684         msg_dialog::display(_("Error"), $message, ERROR_DIALOG);
685       }
686     }
687   }
689   /* Create unique DN */
690   function create_unique_dn($attribute, $base)
691   {
692     $ldap= $this->config->get_ldap_link();
693     $base= preg_replace("/^,*/", "", $base);
695     /* Try to use plain entry first */
696     $dn= "$attribute=".$this->$attribute.",$base";
697     $ldap->cat ($dn, array('dn'));
698     if (!$ldap->fetch()){
699       return ($dn);
700     }
702     /* Look for additional attributes */
703     foreach ($this->attributes as $attr){
704       if ($attr == $attribute || $this->$attr == ""){
705         continue;
706       }
708       $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base";
709       $ldap->cat ($dn, array('dn'));
710       if (!$ldap->fetch()){
711         return ($dn);
712       }
713     }
715     /* None found */
716     return ("none");
717   }
719   function rebind($ldap, $referral)
720   {
721     $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']);
722     if (ldap_bind($ldap, $credentials['ADMIN'], $credentials['PASSWORD'])) {
723       $this->error = "Success";
724       $this->hascon=true;
725       $this->reconnect= true;
726       return (0);
727     } else {
728       $this->error = "Could not bind to " . $credentials['ADMIN'];
729       return NULL;
730     }
731   }
734   /* Recursively copy ldap object */
735   function _copy($src_dn,$dst_dn)
736   {
737     $ldap=$this->config->get_ldap_link();
738     $ldap->cat($src_dn);
739     $attrs= $ldap->fetch();
741     /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */
742     $ds= ldap_connect($this->config->current['SERVER']);
743     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
744     if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) {
745       ldap_set_rebind_proc($ds, array(&$this, "rebind"));
746     }
748     $r=ldap_bind($ds,$this->config->current['ADMIN'], $this->config->current['PASSWORD']);
749     $sr=ldap_read($ds, @LDAP::fix($src_dn), "objectClass=*");
751     /* Fill data from LDAP */
752     $new= array();
753     if ($sr) {
754       $ei=ldap_first_entry($ds, $sr);
755       if ($ei) {
756         foreach($attrs as $attr => $val){
757           if ($info = @ldap_get_values_len($ds, $ei, $attr)){
758             for ($i= 0; $i<$info['count']; $i++){
759               if ($info['count'] == 1){
760                 $new[$attr]= $info[$i];
761               } else {
762                 $new[$attr][]= $info[$i];
763               }
764             }
765           }
766         }
767       }
768     }
770     /* close conncetion */
771     ldap_unbind($ds);
773     /* Adapt naming attribute */
774     $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn);
775     $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn);
776     $new[$dst_name]= @LDAP::fix($dst_val);
778     /* Check if this is a department.
779      * If it is a dep. && there is a , override in his ou 
780      *  change \2C to , again, else this entry can't be saved ...
781      */
782     if((isset($new['ou'])) &&( preg_match("/\\,/",$new['ou']))){
783       $new['ou'] = preg_replace("/\\\\,/",",",$new['ou']);
784     }
786     /* Save copy */
787     $ldap->connect();
788     $ldap->cd($this->config->current['BASE']);
789     
790     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn));
792     /* FAIvariable=.../..., cn=.. 
793         could not be saved, because the attribute FAIvariable was different to 
794         the dn FAIvariable=..., cn=... */
795     if(in_array_ics("FAIdebconfInfo",$new['objectClass'])){
796       $new['FAIvariable'] = $ldap->fix($new['FAIvariable']);
797     }
798     $ldap->cd($dst_dn);
799     $ldap->add($new);
801     if ($ldap->error != "Success"){
802       trigger_error("Trying to save $dst_dn failed.",
803           E_USER_WARNING);
804       return(FALSE);
805     }
806     return(TRUE);
807   }
810   /* This is a workaround function. */
811   function copy($src_dn, $dst_dn)
812   {
813     /* Rename dn in possible object groups */
814     $ldap= $this->config->get_ldap_link();
815     $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.@LDAP::prepare4filter($src_dn).'))',
816         array('cn'));
817     while ($attrs= $ldap->fetch()){
818       $og= new ogroup($this->config, $ldap->getDN());
819       unset($og->member[$src_dn]);
820       $og->member[$dst_dn]= $dst_dn;
821       $og->save ();
822     }
824     $ldap->cat($dst_dn);
825     $attrs= $ldap->fetch();
826     if (count($attrs)){
827       trigger_error("Trying to overwrite ".@LDAP::fix($dst_dn).", which already exists.",
828           E_USER_WARNING);
829       return (FALSE);
830     }
832     $ldap->cat($src_dn);
833     $attrs= $ldap->fetch();
834     if (!count($attrs)){
835       trigger_error("Trying to move ".@LDAP::fix($src_dn).", which does not seem to exist.",
836           E_USER_WARNING);
837       return (FALSE);
838     }
840     $ldap->cd($src_dn);
841     $ldap->search("objectClass=*",array("dn"));
842     while($attrs = $ldap->fetch()){
843       $src = $attrs['dn'];
844       $dst = preg_replace("/".normalizePreg($src_dn)."$/",$dst_dn,$attrs['dn']);
845       $this->_copy($src,$dst);
846     }
847     return (TRUE);
848   }
851   function move($src_dn, $dst_dn)
852   {
853     /* Do not copy if only upper- lowercase has changed */
854     if(strtolower($src_dn) == strtolower($dst_dn)){
855       return(TRUE);
856     }
858     /* Copy source to destination */
859     if (!$this->copy($src_dn, $dst_dn)){
860       return (FALSE);
861     }
863     /* Delete source */
864     $ldap= $this->config->get_ldap_link();
865     $ldap->rmdir_recursive($src_dn);
866     if ($ldap->error != "Success"){
867       trigger_error("Trying to delete $src_dn failed.",
868           E_USER_WARNING);
869       return (FALSE);
870     }
872     return (TRUE);
873   }
876   /* Move/Rename complete trees */
877   function recursive_move($src_dn, $dst_dn)
878   {
879     /* Check if the destination entry exists */
880     $ldap= $this->config->get_ldap_link();
882     /* Check if destination exists - abort */
883     $ldap->cat($dst_dn, array('dn'));
884     if ($ldap->fetch()){
885       trigger_error("recursive_move $dst_dn already exists.",
886           E_USER_WARNING);
887       return (FALSE);
888     }
890     $this->copy($src_dn, $dst_dn);
892     /* Remove src_dn */
893     $ldap->cd($src_dn);
894     $ldap->recursive_remove($src_dn);
895     return (TRUE);
896   }
899   function handle_post_events($mode, $add_attrs= array())
900   {
901     switch ($mode){
902       case "add":
903         $this->postcreate($add_attrs);
904       break;
906       case "modify":
907         $this->postmodify($add_attrs);
908       break;
910       case "remove":
911         $this->postremove($add_attrs);
912       break;
913     }
914   }
917   function saveCopyDialog(){
918   }
921   function getCopyDialog(){
922     return(array("string"=>"","status"=>""));
923   }
926   function PrepareForCopyPaste($source)
927   {
928     $todo = $this->attributes;
929     if(isset($this->CopyPasteVars)){
930       $todo = array_merge($todo,$this->CopyPasteVars);
931     }
933     if(count($this->objectclasses)){
934       $this->is_account = TRUE;
935       foreach($this->objectclasses as $class){
936         if(!in_array($class,$source['objectClass'])){
937           $this->is_account = FALSE;
938         }
939       }
940     }
942     foreach($todo as $var){
943       if (isset($source[$var])){
944         if(isset($source[$var]['count'])){
945           if($source[$var]['count'] > 1){
946             $this->$var = array();
947             $tmp = array();
948             for($i = 0 ; $i < $source[$var]['count']; $i++){
949               $tmp = $source[$var][$i];
950             }
951             $this->$var = $tmp;
952           }else{
953             $this->$var = $source[$var][0];
954           }
955         }else{
956           $this->$var= $source[$var];
957         }
958       }
959     }
960   }
962   function tag_attrs(&$at, $dn= "", $tag= "", $show= false)
963   {
964     /* Skip tagging? 
965        If this is called from departmentGeneric, we have to skip this
966         tagging procedure. 
967      */
968     if($this->skipTagging){
969       return;
970     }
972     /* No dn? Self-operation... */
973     if ($dn == ""){
974       $dn= $this->dn;
976       /* No tag? Find it yourself... */
977       if ($tag == ""){
978         $len= strlen($dn);
980         @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging");
981         $relevant= array();
982         foreach ($this->config->adepartments as $key => $ntag){
984           /* This one is bigger than our dn, its not relevant... */
985           if ($len <= strlen($key)){
986             continue;
987           }
989           /* This one matches with the latter part. Break and don't fix this entry */
990           if (preg_match('/(^|,)'.normalizePreg($key).'$/', $dn)){
991             @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging");
992             $relevant[strlen($key)]= $ntag;
993             continue;
994           }
996         }
998         /* If we've some relevant tags to set, just get the longest one */
999         if (count($relevant)){
1000           ksort($relevant);
1001           $tmp= array_keys($relevant);
1002           $idx= end($tmp);
1003           $tag= $relevant[$idx];
1004           $this->gosaUnitTag= $tag;
1005         }
1006       }
1007     }
1009     /* Remove tags that may already be here... */
1010     remove_objectClass("gosaAdministrativeUnitTag", $at);
1011     if (isset($at['gosaUnitTag'])){
1012         unset($at['gosaUnitTag']);
1013     }
1015     /* Set tag? */
1016     if ($tag != ""){
1017       add_objectClass("gosaAdministrativeUnitTag", $at);
1018       $at['gosaUnitTag']= $tag;
1019     }
1020   }
1023   /* Add possibility to stop remove process */
1024   function allow_remove()
1025   {
1026     $reason= "";
1027     return $reason;
1028   }
1031   /* Create a snapshot of the current object */
1032   function create_snapshot($type= "snapshot", $description= array())
1033   {
1035     /* Check if snapshot functionality is enabled */
1036     if(!$this->snapshotEnabled()){
1037       return;
1038     }
1040     /* Get configuration from gosa.conf */
1041     $tmp = $this->config->current;
1043     /* Create lokal ldap connection */
1044     $ldap= $this->config->get_ldap_link();
1045     $ldap->cd($this->config->current['BASE']);
1047     /* check if there are special server configurations for snapshots */
1048     if(!isset($tmp['SNAPSHOT_SERVER'])){
1050       /* Source and destination server are both the same, just copy source to dest obj */
1051       $ldap_to      = $ldap;
1052       $snapldapbase = $this->config->current['BASE'];
1054     }else{
1055       $server         = $tmp['SNAPSHOT_SERVER'];
1056       $user           = $tmp['SNAPSHOT_USER'];
1057       $password       = $tmp['SNAPSHOT_PASSWORD'];
1058       $snapldapbase   = $tmp['SNAPSHOT_BASE'];
1060       $ldap_to        = new LDAP($user,$password, $server);
1061       $ldap_to -> cd($snapldapbase);
1062       show_ldap_error($ldap->get_error(), sprintf(_("Saving object snapshot with dn '%s' failed."),$snapldapbase));
1063     }
1065     /* check if the dn exists */ 
1066     if ($ldap->dn_exists($this->dn)){
1068       /* Extract seconds & mysecs, they are used as entry index */
1069       list($usec, $sec)= explode(" ", microtime());
1071       /* Collect some infos */
1072       $base           = $this->config->current['BASE'];
1073       $snap_base      = $tmp['SNAPSHOT_BASE'];
1074       $base_of_object = preg_replace ('/^[^,]+,/i', '', $this->dn);
1075       $new_base       = preg_replace("/".normalizePreg($base)."$/","",$base_of_object).$snap_base;
1077       /* Create object */
1078 #$data             = preg_replace('/^dn:.*\n/', '', $ldap->gen_ldif($this->dn,"(!(objectClass=gosaDepartment))"));
1079       $data             = $ldap->gen_ldif($this->dn,"(&(!(objectClass=gosaDepartment))(!(objectClass=FAIclass)))");
1080       $newName          = preg_replace("/\./", "", $sec."-".$usec);
1081       $target= array();
1082       $target['objectClass']            = array("top", "gosaSnapshotObject");
1083       $target['gosaSnapshotData']       = gzcompress($data, 6);
1084       $target['gosaSnapshotType']       = $type;
1085       $target['gosaSnapshotDN']         = $this->dn;
1086       $target['description']            = $description;
1087       $target['gosaSnapshotTimestamp']  = $newName;
1089       /* Insert the new snapshot 
1090          But we have to check first, if the given gosaSnapshotTimestamp
1091          is already used, in this case we should increment this value till there is 
1092          an unused value. */ 
1093       $new_dn                           = "gosaSnapshotTimestamp=".$newName.",".$new_base;
1094       $ldap_to->cat($new_dn);
1095       while($ldap_to->count()){
1096         $ldap_to->cat($new_dn);
1097         $newName = preg_replace("/\./", "", $sec."-".($usec++));
1098         $new_dn                           = "gosaSnapshotTimestamp=".$newName.",".$new_base;
1099         $target['gosaSnapshotTimestamp']  = $newName;
1100       } 
1102       /* Inset this new snapshot */
1103       $ldap_to->cd($snapldapbase);
1104       $ldap_to->create_missing_trees($snapldapbase);
1105       $ldap_to->create_missing_trees($new_base);
1106       $ldap_to->cd($new_dn);
1107       $ldap_to->add($target);
1108     
1109       show_ldap_error($ldap->get_error(), sprintf(_("Saving object snapshot with dn '%s' failed."),$new_base));
1110       show_ldap_error($ldap_to->get_error(), sprintf(_("Saving object snapshot with dn '%s' failed."),$new_base));
1111     }
1112   }
1114   function remove_snapshot($dn)
1115   {
1116     $ui       = get_userinfo();
1117     $old_dn   = $this->dn; 
1118     $this->dn = $dn;
1119     $ldap = $this->config->get_ldap_link();
1120     $ldap->cd($this->config->current['BASE']);
1121     $ldap->rmdir_recursive($dn);
1122     $this->dn = $old_dn;
1123   }
1126   /* returns true if snapshots are enabled, and false if it is disalbed
1127      There will also be some errors psoted, if the configuration failed */
1128   function snapshotEnabled()
1129   {
1130     $tmp = $this->config->current;
1131     if(isset($tmp['ENABLE_SNAPSHOT'])){
1132       if (preg_match("/^true$/i", $tmp['ENABLE_SNAPSHOT']) || preg_match("/yes/i", $tmp['ENABLE_SNAPSHOT'])){
1134         /* Check if the snapshot_base is defined */
1135         if(!isset($tmp['SNAPSHOT_BASE'])){
1136           msg_dialog::display(_("Configuration error"), sprintf(_("The snapshot functionality is enabled, but the required variable '%s' is not set."),"SNAPSHOT_BASE"), ERROR_DIALOG);
1137           return(FALSE);
1138         }
1140         /* check if there are special server configurations for snapshots */
1141         if(isset($tmp['SNAPSHOT_SERVER'])){
1143           /* check if all required vars are available to create a new ldap connection */
1144           $missing = "";
1145           foreach(array("SNAPSHOT_SERVER","SNAPSHOT_USER","SNAPSHOT_PASSWORD","SNAPSHOT_BASE") as $var){
1146             if(!isset($tmp[$var])){
1147               $missing .= $var." ";
1148               msg_dialog::display(_("Configuration error"), sprintf(_("The snapshot functionality is enabled, but the required variable '%s' is not set."), $missing), ERROR_DIALOG);
1149               return(FALSE);
1150             }
1151           }
1152         }
1153         return(TRUE);
1154       }
1155     }
1156     return(FALSE);
1157   }
1160   /* Return available snapshots for the given base 
1161    */
1162   function Available_SnapsShots($dn,$raw = false)
1163   {
1164     if(!$this->snapshotEnabled()) return(array());
1166     /* Create an additional ldap object which
1167        points to our ldap snapshot server */
1168     $ldap= $this->config->get_ldap_link();
1169     $ldap->cd($this->config->current['BASE']);
1170     $cfg= &$this->config->current;
1172     /* check if there are special server configurations for snapshots */
1174     if(isset($cfg['SERVER']) && isset($cfg['SNAPSHOT_SERVER']) && $cfg['SERVER'] == $cfg['SNAPSHOT_SERVER']){
1175       $ldap_to    = $ldap;
1176     }elseif(isset($cfg['SNAPSHOT_SERVER'])){
1177       $server       = $cfg['SNAPSHOT_SERVER'];
1178       $user         = $cfg['SNAPSHOT_USER'];
1179       $password     = $cfg['SNAPSHOT_PASSWORD'];
1180       $snapldapbase = $cfg['SNAPSHOT_BASE'];
1182       $ldap_to      = new LDAP($user,$password, $server);
1183       $ldap_to -> cd ($snapldapbase);
1184       show_ldap_error($ldap->get_error(), sprintf(_("Method get available snapshots with dn '%s' failed."),$this->dn));
1185     }else{
1186       $ldap_to    = $ldap;
1187     }
1189     /* Prepare bases and some other infos */
1190     $base           = $this->config->current['BASE'];
1191     $snap_base      = $cfg['SNAPSHOT_BASE'];
1192     $base_of_object = preg_replace ('/^[^,]+,/i', '', $dn);
1193     $new_base       = preg_replace("/".normalizePreg($base)."$/","",$base_of_object).$snap_base;
1194     $tmp            = array(); 
1196     /* Fetch all objects with  gosaSnapshotDN=$dn */
1197     $ldap_to->cd($new_base);
1198     $ldap_to->ls("(&(objectClass=gosaSnapshotObject)(gosaSnapshotDN=".$dn."))",$new_base,
1199         array("gosaSnapshotType","gosaSnapshotTimestamp","gosaSnapshotDN","description")); 
1201     /* Put results into a list and add description if missing */
1202     while($entry = $ldap_to->fetch()){ 
1203       if(!isset($entry['description'][0])){
1204         $entry['description'][0]  = "";
1205       }
1206       $tmp[] = $entry; 
1207     }
1209     /* Return the raw array, or format the result */
1210     if($raw){
1211       return($tmp);
1212     }else{  
1213       $tmp2 = array();
1214       foreach($tmp as $entry){
1215         $tmp2[base64_encode($entry['dn'])] = $entry['description'][0]; 
1216       }
1217     }
1218     return($tmp2);
1219   }
1222   function getAllDeletedSnapshots($base_of_object,$raw = false)
1223   {
1224     if(!$this->snapshotEnabled()) return(array());
1226     /* Create an additional ldap object which
1227        points to our ldap snapshot server */
1228     $ldap= $this->config->get_ldap_link();
1229     $ldap->cd($this->config->current['BASE']);
1230     $cfg= &$this->config->current;
1232     /* check if there are special server configurations for snapshots */
1233     if(isset($cfg['SNAPSHOT_SERVER'])){
1234       $server       = $cfg['SNAPSHOT_SERVER'];
1235       $user         = $cfg['SNAPSHOT_USER'];
1236       $password     = $cfg['SNAPSHOT_PASSWORD'];
1237       $snapldapbase = $cfg['SNAPSHOT_BASE'];
1238       $ldap_to      = new LDAP($user,$password, $server);
1239       $ldap_to->cd ($snapldapbase);
1240       show_ldap_error($ldap_to->get_error(), sprintf(_("Method get deleted snapshots with dn '%s' failed."),$this->dn));
1241     }else{
1242       $ldap_to    = $ldap;
1243     }
1245     /* Prepare bases */ 
1246     $base           = $this->config->current['BASE'];
1247     $snap_base      = $cfg['SNAPSHOT_BASE'];
1248     $new_base       = preg_replace("/".normalizePreg($base)."$/","",$base_of_object).$snap_base;
1250     /* Fetch all objects and check if they do not exist anymore */
1251     $ui = get_userinfo();
1252     $tmp = array();
1253     $ldap_to->cd($new_base);
1254     $ldap_to->ls("(objectClass=gosaSnapshotObject)",$new_base,array("gosaSnapshotType","gosaSnapshotTimestamp","gosaSnapshotDN","description"));
1255     while($entry = $ldap_to->fetch()){
1257       $chk =  str_replace($new_base,"",$entry['dn']);
1258       if(preg_match("/,ou=/",$chk)) continue;
1260       if(!isset($entry['description'][0])){
1261         $entry['description'][0]  = "";
1262       }
1263       $tmp[] = $entry; 
1264     }
1266     /* Check if entry still exists */
1267     foreach($tmp as $key => $entry){
1268       $ldap->cat($entry['gosaSnapshotDN'][0]);
1269       if($ldap->count()){
1270         unset($tmp[$key]);
1271       }
1272     }
1274     /* Format result as requested */
1275     if($raw) {
1276       return($tmp);
1277     }else{
1278       $tmp2 = array();
1279       foreach($tmp as $key => $entry){
1280         $tmp2[base64_encode($entry['dn'])] = $entry['description'][0]; 
1281       }
1282     }
1283     return($tmp2);
1284   } 
1287   /* Restore selected snapshot */
1288   function restore_snapshot($dn)
1289   {
1290     if(!$this->snapshotEnabled()) return(array());
1292     $ldap= $this->config->get_ldap_link();
1293     $ldap->cd($this->config->current['BASE']);
1294     $cfg= &$this->config->current;
1296     /* check if there are special server configurations for snapshots */
1297     if(isset($cfg['SNAPSHOT_SERVER'])){
1298       $server       = $cfg['SNAPSHOT_SERVER'];
1299       $user         = $cfg['SNAPSHOT_USER'];
1300       $password     = $cfg['SNAPSHOT_PASSWORD'];
1301       $snapldapbase = $cfg['SNAPSHOT_BASE'];
1302       $ldap_to      = new LDAP($user,$password, $server);
1303       $ldap_to->cd ($snapldapbase);
1304       show_ldap_error($ldap->get_error(), sprintf(_("Restore snapshot with dn '%s' failed."),$snapldapbase));
1305     }else{
1306       $ldap_to    = $ldap;
1307     }
1309     /* Get the snapshot */ 
1310     $ldap_to->cat($dn);
1311     $restoreObject = $ldap_to->fetch();
1313     /* Prepare import string */
1314     $data  = gzuncompress($ldap_to->get_attribute($dn,'gosaSnapshotData'));
1316     /* Import the given data */
1317     $ldap->import_complete_ldif($data,$err,false,false);
1318     show_ldap_error($ldap->get_error(), sprintf(_("Restore snapshot with dn '%s' failed."),$dn));
1319   }
1322   function showSnapshotDialog($base,$baseSuffixe)
1323   {
1324     $once = true;
1325     foreach($_POST as $name => $value){
1327       /* Create a new snapshot, display a dialog */
1328       if(preg_match("/^CreateSnapShotDialog_/",$name) && $once){
1329         $once = false;
1330         $entry = preg_replace("/^CreateSnapShotDialog_/","",$name);
1331         $entry = base64_decode(preg_replace("/_[xy]$/","",$entry));
1332         $this->snapDialog = new SnapShotDialog($this->config,$entry,$this);
1333       }
1335       /* Restore a snapshot, display a dialog with all snapshots of the current object */
1336       if(preg_match("/^RestoreSnapShotDialog_/",$name) && $once){
1337         $once = false;
1338         $entry = preg_replace("/^RestoreSnapShotDialog_/","",$name);
1339         $entry = base64_decode(preg_replace("/_[xy]$/","",$entry));
1340         $this->snapDialog = new SnapShotDialog($this->config,$entry,$this);
1341         $this->snapDialog->display_restore_dialog = true;
1342       }
1344       /* Restore one of the already deleted objects */
1345       if(((isset($_POST['menu_action']) && $_POST['menu_action'] == "RestoreDeletedSnapShot") 
1346           || preg_match("/^RestoreDeletedSnapShot_/",$name)) && $once){
1347         $once = false;
1348         $this->snapDialog = new SnapShotDialog($this->config,"",$this);
1349         $this->snapDialog->set_snapshot_bases($baseSuffixe);
1350         $this->snapDialog->display_restore_dialog      = true;
1351         $this->snapDialog->display_all_removed_objects  = true;
1352       }
1354       /* Restore selected snapshot */
1355       if(preg_match("/^RestoreSnapShot_/",$name) && $once){
1356         $once = false;
1357         $entry = preg_replace("/^RestoreSnapShot_/","",$name);
1358         $entry = base64_decode(trim(preg_replace("/_[xy]$/","",$entry)));
1359         if(!empty($entry)){
1360           $this->restore_snapshot($entry);
1361           $this->snapDialog = NULL;
1362         }
1363       }
1364     }
1366     /* Create a new snapshot requested, check
1367        the given attributes and create the snapshot*/
1368     if(isset($_POST['CreateSnapshot']) && is_object($this->snapDialog)){
1369       $this->snapDialog->save_object();
1370       $msgs = $this->snapDialog->check();
1371       if(count($msgs)){
1372         foreach($msgs as $msg){
1373           msg_dialog::display(_("Error"), $msg, ERROR_DIALOG);
1374         }
1375       }else{
1376         $this->dn =  $this->snapDialog->dn;
1377         $this->create_snapshot("snapshot",$this->snapDialog->CurrentDescription);
1378         $this->snapDialog = NULL;
1379       }
1380     }
1382     /* Restore is requested, restore the object with the posted dn .*/
1383     if((isset($_POST['RestoreSnapshot'])) && (isset($_POST['SnapShot']))){
1384     }
1386     if(isset($_POST['CancelSnapshot'])){
1387       $this->snapDialog = NULL;
1388     }
1390     if(is_object($this->snapDialog )){
1391       $this->snapDialog->save_object();
1392       return($this->snapDialog->execute());
1393     }
1394   }
1397   static function plInfo()
1398   {
1399     return array();
1400   }
1403   function set_acl_base($base)
1404   {
1405     $this->acl_base= $base;
1406   }
1409   function set_acl_category($category)
1410   {
1411     $this->acl_category= "$category/";
1412   }
1415   function acl_is_writeable($attribute,$skip_write = FALSE)
1416   {
1417     $ui= get_userinfo();
1418     return preg_match('/w/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), $attribute, $skip_write));
1419   }
1422   function acl_is_readable($attribute)
1423   {
1424     $ui= get_userinfo();
1425     return preg_match('/r/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), $attribute));
1426   }
1429   function acl_is_createable()
1430   {
1431     $ui= get_userinfo();
1432     return preg_match('/c/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), '0'));
1433   }
1436   function acl_is_removeable()
1437   {
1438     $ui= get_userinfo();
1439     return preg_match('/d/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), '0'));
1440   }
1443   function acl_is_moveable()
1444   {
1445     $ui= get_userinfo();
1446     return preg_match('/m/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), '0'));
1447   }
1450   function acl_have_any_permissions()
1451   {
1452   }
1455   function getacl($attribute,$skip_write= FALSE)
1456   {
1457     $ui= get_userinfo();
1458     return  $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), $attribute,$skip_write);
1459   }
1461   /* Get all allowed bases to move an object to or to create a new object.
1462      Idepartments also contains all base departments which lead to the allowed bases */
1463   function get_allowed_bases($category = "")
1464   {
1465     $ui = get_userinfo();
1466     $deps = array();
1468     /* Set category */ 
1469     if(empty($category)){
1470       $category = $this->acl_category.get_class($this);
1471     }
1473     /* Is this a new object ? Or just an edited existing object */
1474     if(!$this->initially_was_account && $this->is_account){
1475       $new = true;
1476     }else{
1477       $new = false;
1478     }
1480     $cat_bases = $ui->get_module_departments(preg_replace("/\/.*$/","",$category));
1481     foreach($this->config->idepartments as $dn => $name){
1482       
1483       if(!in_array_ics($dn,$cat_bases)){
1484         continue;
1485       }
1486       
1487       $acl = $ui->get_permissions($dn,$category);
1488       if($new && preg_match("/c/",$acl)){
1489         $deps[$dn] = $name;
1490       }elseif(!$new && preg_match("/m/",$acl)){
1491         $deps[$dn] = $name;
1492       }
1493     }
1495     /* Add current base */      
1496     if(isset($this->base) && isset($this->config->idepartments[$this->base])){
1497       $deps[$this->base] = $this->config->idepartments[$this->base];
1498     }else{
1499       trigger_error("No default base found in class ".get_class($this).". ".$this->base);
1500     }
1501     return($deps);
1502   }
1505   /* This function modifies object acls too, if an object is moved.
1506    *  $old_dn   specifies the actually used dn
1507    *  $new_dn   specifies the destiantion dn
1508    */
1509   function update_acls($old_dn,$new_dn,$output_changes = FALSE)
1510   {
1511     /* Check if old_dn is empty. This should never happen */
1512     if(empty($old_dn) || empty($new_dn)){
1513       trigger_error("Failed to check acl dependencies, wrong dn given.");
1514       return;
1515     }
1517     /* Update userinfo if necessary */
1518     $ui = session::get('ui');
1519     if($ui->dn == $old_dn){
1520       $ui->dn = $new_dn;
1521       session::set('ui',$ui);
1522       new log("view","acl/".get_class($this),$this->dn,array(),"Updated current user dn from '".$old_dn."' to '".$new_dn."'");
1523     }
1525     /* Object was moved, ensure that all acls will be moved too */
1526     if($new_dn != $old_dn && $old_dn != "new"){
1528       /* get_ldap configuration */
1529       $update = array();
1530       $ldap = $this->config->get_ldap_link();
1531       $ldap->cd ($this->config->current['BASE']);
1532       $ldap->search("(&(objectClass=gosaAcl)(gosaAclEntry=*))",array("cn","gosaAclEntry"));
1533       while($attrs = $ldap->fetch()){
1535         $acls = array();
1537         /* Walk through acls */
1538         for($i = 0 ; $i <  $attrs['gosaAclEntry']['count'] ; $i ++ ){
1540           /* Reset vars */
1541           $found = false;
1543           /* Get Acl parts */
1544           $acl_parts = split(":",$attrs['gosaAclEntry'][$i]);
1546           /* Get every single member for this acl */  
1547           $members = array();  
1548           if(preg_match("/,/",$acl_parts[2])){
1549             $members = split(",",$acl_parts[2]);
1550           }else{
1551             $members = array($acl_parts[2]);
1552           } 
1553       
1554           /* Check if member match current dn */
1555           foreach($members as $key => $member){
1556             $member = base64_decode($member);
1557             if($member == $old_dn){
1558               $found = true;
1559               $members[$key] = base64_encode($new_dn);
1560             }
1561           } 
1562          
1563           /* Create new member string */ 
1564           $new_members = "";
1565           foreach($members as $member){
1566             $new_members .= $member.",";
1567           }
1568           $new_members = preg_replace("/,$/","",$new_members);
1569           $acl_parts[2] = $new_members;
1570         
1571           /* Reconstruckt acl entry */
1572           $acl_str  ="";
1573           foreach($acl_parts as $t){
1574            $acl_str .= $t.":";
1575           }
1576           $acl_str = preg_replace("/:$/","",$acl_str);
1577        }
1579        /* Acls for this object must be adjusted */
1580        if($found){
1582           $debug_info=  _("Changing ACL dn")."&nbsp;:&nbsp;<br>&nbsp;-"._("from")."&nbsp;<b>&nbsp;".
1583                   $old_dn."</b><br>&nbsp;-"._("to")."&nbsp;<b>".$new_dn."</b><br>";
1584           @DEBUG (DEBUG_ACL, __LINE__, __FUNCTION__, __FILE__,$debug_info,"ACL");
1586           $update[$attrs['dn']] =array();
1587           foreach($acls as $acl){
1588             $update[$attrs['dn']]['gosaAclEntry'][] = $acl;
1589           }
1590         }
1591       }
1593       /* Write updated acls */
1594       foreach($update as $dn => $attrs){
1595         $ldap->cd($dn);
1596         $ldap->modify($attrs);
1597       }
1598     }
1599   }
1601   
1603   /* This function enables the entry Serial ID check.
1604    * If an entry was edited while we have edited the entry too,
1605    *  an error message will be shown. 
1606    * To configure this check correctly read the FAQ.
1607    */    
1608   function enable_CSN_check()
1609   {
1610     $this->CSN_check_active =TRUE;
1611     $this->entryCSN = getEntryCSN($this->dn);
1612   }
1615   /*! \brief  Prepares the plugin to be used for multiple edit
1616    *          Update plugin attributes with given array of attribtues.
1617    *  @param  array   Array with attributes that must be updated.
1618    */
1619   function init_multiple_support($attrs,$all)
1620   {
1621     $ldap= $this->config->get_ldap_link();
1622     $this->multi_attrs    = $attrs;
1623     $this->multi_attrs_all= $all;
1625     /* Copy needed attributes */
1626     foreach ($this->attributes as $val){
1627       $found= array_key_ics($val, $this->multi_attrs);
1628       if ($found != ""){
1629         if(isset($this->multi_attrs["$found"][0])){
1630           $this->$val= $this->multi_attrs["$found"][0];
1631         }
1632       }
1633     }
1634   }
1636  
1637   /*! \brief  Enables multiple support for this plugin
1638    */
1639   function enable_multiple_support()
1640   {
1641     $this->ignore_account = TRUE;
1642     $this->multiple_support_active = TRUE;
1643   }
1646   /*! \brief  Returns all values that have been modfied in multiple edit mode.
1647       @return array Cotaining all mdofied values. 
1648    */
1649   function get_multi_edit_values()
1650   {
1651     $ret = array();
1652     foreach($this->attributes as $attr){
1653       if(in_array($attr,$this->multi_boxes)){
1654         $ret[$attr] = $this->$attr;
1655       }
1656     }
1657     return($ret);
1658   }
1660   
1661   /*! \brief  Update class variables with values collected by multiple edit.
1662    */
1663   function set_multi_edit_values($attrs)
1664   {
1665     foreach($attrs as $name => $value){
1666       $this->$name = $value;
1667     }
1668   }
1671   /*! \brief execute plugin
1673     Generates the html output for this node
1674    */
1675   function multiple_execute()
1676   {
1677     /* This one is empty currently. Fabian - please fill in the docu code */
1678     session::set('current_class_for_help',get_class($this));
1680     /* Reset Lock message POST/GET check array, to prevent perg_match errors*/
1681     session::set('LOCK_VARS_TO_USE',array());
1682     session::set('LOCK_VARS_USED',array());
1683     
1684     return("Multiple edit is currently not implemented for this plugin.");
1685   }
1688   /*! \brief   Save HTML posted data to object for multiple edit
1689    */
1690   function multiple_save_object()
1691   {
1692     if(empty($this->entryCSN) && $this->CSN_check_active){
1693       $this->entryCSN = getEntryCSN($this->dn);
1694     }
1696     /* Save values to object */
1697     $this->multi_boxes = array();
1698     foreach ($this->attributes as $val){
1699   
1700       /* Get selected checkboxes from multiple edit */
1701       if(isset($_POST["use_".$val])){
1702         $this->multi_boxes[] = $val;
1703       }
1705       if ($this->acl_is_writeable($val) && isset ($_POST["$val"])){
1707         /* Check for modifications */
1708         if (get_magic_quotes_gpc()) {
1709           $data= stripcslashes($_POST["$val"]);
1710         } else {
1711           $data= $this->$val = $_POST["$val"];
1712         }
1713         if ($this->$val != $data){
1714           $this->is_modified= TRUE;
1715         }
1716     
1717         /* IE post fix */
1718         if(isset($data[0]) && $data[0] == chr(194)) {
1719           $data = "";  
1720         }
1721         $this->$val= $data;
1722       }
1723     }
1724   }
1727   /*! \brief  Returns all attributes of this plugin, 
1728                to be able to detect multiple used attributes 
1729                in multi_plugg::detect_multiple_used_attributes().
1730       @return array Attributes required for intialization of multi_plug
1731    */
1732   public function get_multi_init_values()
1733   {
1734     $attrs = $this->attrs;
1735     return($attrs);
1736   }
1739   /*! \brief  Check given values in multiple edit
1740       @return array Error messages
1741    */
1742   function multiple_check()
1743   {
1744     $message = plugin::check();
1745     return($message);
1746   }
1749 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1750 ?>