Code

Revert 13752 because it might cause data loss
[gosa.git] / trunk / gosa-plugins / fai / admin / fai / class_FAI.inc
1 <?php
3 define("DEBUG_FAI_FUNC",FALSE);
6 class FAI
7 {
9   /* TEST PHASE .... */
11   static function get_all_objects_for_given_object($dn,$filter,$detailed = false)
12   {
13     $res  = FAI::get_all_objects_for_given_base($dn,$filter,$detailed);
14     $name = preg_replace("/,ou=.*$/","",$dn);
15     $entries = array();
16     foreach($res as $entry_dn => $data){
17       if(!preg_match("/,".$name.",/",$entry_dn)) continue;
18       $entries[$entry_dn] = $data; 
19     }
20     return($entries);
21   }
26   /* Returns all object for the given release.
27      This function resolves the releases  
28      from base up to the given dn.
29    */
30   static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
31   {
32     global $config;
33     $ldap = $config->get_ldap_link();
34     $ldap->cd($config->current['BASE']);
35     $res = array();
36     $tmp = array();
38     if(!FAI::is_release_department($Current_DN)) {
39 #      return($res);
40     }
42     /* Collect some basic informations and initialize some variables */ 
43     $base_release       = FAI::get_release_dn($Current_DN);
44     $previous_releases  = array_reverse(FAI::get_previous_releases_of_this_release($base_release,true));
46     $ldap->cat($base_release);
47     $attrs = $ldap->fetch();
48     $FAIstate = "branch";
49     if(isset($attrs['FAIstate'][0])){
50       $FAIstate = $attrs['FAIstate'][0];
51     }
53     /* We must also include the given release dn */
54     $previous_releases[] = $base_release;
56     /* Walk through all releases */
57     foreach($previous_releases as $release){
59       /* Get fai departments */
60       $deps_to_search = FAI::get_FAI_departments($release); 
62       /* For every single department  (ou=hoos,ou ..) */
63       foreach($deps_to_search as $fai_base){
65         /* Ldap search for fai classes specified in this release */
66         $attributes  = array("dn","objectClass","FAIstate","cn");
67         $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
69         /* check the returned objects, and add/replace them in our return variable */
70         foreach($res_tmp as $attr){
72           $buffer = array();
73           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
75           if(isset($attr['FAIstate'][0])){
76             if(preg_match("/removed$/",$attr['FAIstate'][0])){
77               if(isset($res[$name])){
78                 unset($res[$name]);
79               }
80               continue;
81             }
82           }
84           /* Seems to be an inherited class, apply current FAIstate to this classes 
85            */
86           if(!preg_match("/".preg_quote($base_release, '/')."$/i",$attr['dn'])){
87             $buffer['FAIstate'] = $FAIstate; 
88           }else{
90             /* Seems to be created within this release department.
91                This indicates - it can't be of state "freeze"
92              */             
93             if(isset($attr['FAIstate'])){
94               $buffer['FAIstate'] = $attr['FAIstate'][0];
95             }else{
96               $buffer['FAIstate'] = "branch"; 
97             }
98           }
100           /* In detailed mode are some additonal informations visible */
101           if($detailed){
103             /* Create list of parents */
104             if(isset($res[$name])){
105               $buffer = $res[$name];
106               $buffer['parents'][] = $res[$name]['dn'];
107             }else{
108               $buffer['parents'] = array();
109             }
111             /* Append objectClass to resulsts */
112             foreach($attributes as $val){
113               if(isset($attr[$val])){
114                 $buffer[$val] = $attr[$val];
115               }
116             }
117             unset($buffer['objectClass']['count']);
118           }
120           /* Add this object to our list */
121           $buffer['dn']           = $attr['dn'];
122           $res[$name] = $buffer;
123         }
124       }
125     }
126     return($res);
127   }
130   /* Return all relevant FAI departments */
131   static function get_FAI_departments($suffix = "")
132   {
133     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
134     $tmp = array();
135     if(preg_match("/^,/",$suffix)){
136       $suffix = preg_replace("/^,/","",$suffix);
137     }
138     foreach($arr as $name){
139       if(empty($suffix)){
140         $tmp[$name] = "ou=".$name;
141       }else{
142         $tmp[$name] = "ou=".$name.",".$suffix;
143       }
144     }
145     return($tmp);
146   }
149   /* Return all releases within the given base */
150   static function get_all_releases_from_base($dn,$appendedName=false)
151   {
152     global $config;
154     if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/",$dn)){
155       $base = get_ou('faiBaseRDN').$dn;
156     }else{
157       $base = $dn;
158     }
159     $res = array();  
161     $ldap = $config->get_ldap_link();
162     $ldap->cd($base);
163     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
164     while($attrs = $ldap->fetch()){
165       if($appendedName){
166         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/","",$attrs['dn']));
167       }else{
168         $res[$attrs['dn']] = $attrs['ou'][0];
169       }
170     }
171     return($res);
172   }
175   /* Add this object to list of objects, that must be checked for release saving */
176   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
177   {
178     /* Get ldap object */  
179     global $config;
180     $addObj['Current_DN'] = $Current_DN;
181     $addObj['objectAttrs']= $objectAttrs;
182     $addObj['removed']    = $removed;
183     $addObj['diff']       = TRUE;
185     if(!$removed){
186       $ldap = $config->get_ldap_link();
187       $ldap->cd($config->current['BASE']);
189       /* Get some basic informations */
190       $parent_obj   = FAI::get_parent_release_object($Current_DN);
191       if(!empty($parent_obj)){
192         $ldap->cat($parent_obj,array("*"));
193         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
195         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
196           $addObj['diff'] = FALSE;
197         }
198       } 
199     }else{
201       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
202           we have to remove this name from all profiles in this release.
203       */
204       $ldap = $config->get_ldap_link();
205       $ldap->cd($config->current['BASE']);
206       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
208       /* Dont't try to modify non FAIclasses  
209        */
210       if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/",$obj_dn)){
211         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
212         echo "<br>-->".$Current_DN."<br>";
213         echo "<br>-->".$obj_dn."<br>";
214       }else{
216         /* Get source object and check if it is a base FAIclass
217          */
218         $ldap->cat($obj_dn);
219         $attrs = $ldap->fetch();
220         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
221         if(count(array_intersect($classes,$attrs['objectClass']))){
222           $cn    = $attrs['cn'][0];
224           /* Check if this is the last with this name in the current release.
225               In this case we have to remove the package name 
226               from all profiles in this release.
227            */
228           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
229               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
231           /* Check if this is the last class with this name.
232            */
233           if(count($classes) == 1){
235             /* Get all FAI Profiles 
236              */
237             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
238                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
240             /* Walk though all profiles and remove the source class name
241              */
242             foreach($profiles as $dn){
243               $ldap->cat($dn['dn']);
244               $attrs = $ldap->fetch();
246               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
248               /* Check if this Profile uses the source class ($cn)
249                */
250               if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
251                 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
252                 if(empty($attrs['FAIclass'])){
253                   $attrs['FAIclass'] = array();
254                 }
255                 $ldap->cd($dn['dn']);
256                 $ldap->modify($attrs);
258                 if (!$ldap->success()){
259                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
260                 }
261               }
262             }
263           }
264         }
265       }
266     }
270     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
271     $FAI_objects_to_save[$Current_DN] =  $addObj;
272     session::set('FAI_objects_to_save',$FAI_objects_to_save);
273   }
276   /* Detect differences in attribute arrays  */
277   static function array_diff_FAI($ar1,$ar2)
278   {
280     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
281       $ar1['description'] = "";
282     }
283     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
284       $ar2['description'] = "";
285     }
287     if(count($ar1) != count($ar2)) {
288       return (true);
289     }
291     foreach($ar1 as $key1 => $val1){
293       if((is_array($val1)) && (count($val1)==1)){
294         $ar1[$key1] = $val1[0];
295       }
297       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
298         $val1 = $val1[0];
299         $ar2[$key1] = $ar2[$key1][0];
300       }
301     }
302     ksort($ar1);
303     ksort($ar2);
304     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
305       return(true);
306     }else{
307       return(false);
308     }
309   }
312   static function arr_diff($ar1,$ar2)
313   {
314     foreach($ar1 as $ak1 => $av1){
315       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
316         return(TRUE);    
317       }elseif(is_array($av1)){
318         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
319         if($ret) {
320           return(TRUE);
321         }
322       }
323     }
324     return(FALSE);
325   }
330   /* check which objects must be saved, and save them */
331   static function save_release_changes_now()
332   {
333     global $config;
334     /* Variable init*/
335     $to_save = array();
336     
337     $reload_fai_classes = FALSE;
339     /* check which objects must be saved */
340     if(!session::is_set('FAI_objects_to_save')){
341       return;
342     }
343     $FAI_objects_to_save = session::get('FAI_objects_to_save');
344     if(!is_array($FAI_objects_to_save)) {
345       print_a(array(session::get('FAI_objects_to_save')));
346       trigger_error("Can't save FAI objects, no array given.");
347       return;
348     }
349   
350     foreach($FAI_objects_to_save as $Current_DN => $object){
351       if($object['diff']){
352         $sub_name = $Current_DN;
353         while(isset($FAI_objects_to_save[$sub_name])){
354           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
355           unset($FAI_objects_to_save[$sub_name]);
356           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
357         }
358       }
359     }
360     session::set('FAI_objects_to_save',$FAI_objects_to_save);
362     /* Sort list of objects that must be saved, and ensure that 
363        container   objects are safed, before their childs are saved */
364     ksort($to_save);
365     $tmp = array();
366     foreach($to_save as $SubObjects){
367       foreach($SubObjects as $object){
368         $tmp[] = $object;
369       }
370     }
371     $to_save = $tmp;
374     /* Save objects and manage the correct release behavior*/
375     foreach($to_save as $save){
377       $Current_DN = $save['Current_DN'];
378       $removed    = $save['removed'];
379       $objectAttrs= $save['objectAttrs'];
381       /* Get ldap object */ 
382       $ldap = $config->get_ldap_link();
383       $ldap->cd($config->current['BASE']);
385       /* Get some basic informations */
386       $base_release       = FAI::get_release_dn($Current_DN);
387       $sub_releases       = FAI::get_sub_releases_of_this_release($base_release,true);
388       $parent_obj         = FAI::get_parent_release_object($Current_DN);
389       $following_releases = $sub_releases;
391       /* Check if given dn exists or if is a new entry */
392       $ldap->cat($Current_DN);
393       if(!$ldap->count()){
394         $is_new = true;
395       }else{
396         $is_new = false;
397       }
399       /* if parameter removed is true, we have to add FAIstate to the current attrs 
400          FAIstate should end with ...|removed after this operation */  
401       if($removed ){
402         $ldap->cat($Current_DN);
404         /* Get current object, because we must add the FAIstate ...|removed */
405         if((!$ldap->count()) && !empty($parent_obj)){
406           $ldap->cat($parent_obj);
407         }
409         /* Check if we have found a suiteable object */ 
410         if(!$ldap->count()){
411           echo "Error can't remove this object ".$Current_DN;
412           return;
413         }else{
415           /* Set FAIstate to current objectAttrs */
416           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
417           if(isset($objectAttrs['FAIstate'][0])){
418             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
419               $objectAttrs['FAIstate'][0] .= "|removed";
420             }
421           }else{
422             $objectAttrs['FAIstate'][0] = "|removed";
423           }
425           /* Force reload of FAI classes */
426           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
427           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
428             $reload_fai_classes = TRUE;
429           }
430         }
431       }
433       /* Check if this a leaf release or not */ 
434       if(count($following_releases) == 0 ){
436         /* This is a leaf object. It isn't inherited by any other object */    
437         if(DEBUG_FAI_FUNC) { 
438           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
439           print_a($objectAttrs);
440         }
441         FAI::save_FAI_object($Current_DN,$objectAttrs);
443         /* Force reload of FAI classes */
444         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
445         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
446           $reload_fai_classes = TRUE;
447         }
449       }else{
451         /* This object is inherited by some sub releases */  
453         /* Get all releases, that inherit this object */ 
454         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
456         /* Get parent object */
457         $ldap->cat($parent_obj);
458         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
460         /* New objects require special handling */
461         if($is_new){
463           /* Force reload of FAI classes */
464           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
465           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
466             $reload_fai_classes = TRUE;
467           }
469           /* check if there is already an entry named like this,
470              in one of our parent releases */
471           if(!empty($parent_obj)){
472             if(DEBUG_FAI_FUNC) { 
473               echo "There is already an entry named like this.</b><br>";
475               echo "<b>Saving main object</b>".$Current_DN;
476               print_a($objectAttrs);
477             }    
478             FAI::save_FAI_object($Current_DN,$objectAttrs);
480             foreach($r as $key){
481               if(DEBUG_FAI_FUNC) { 
482                 echo "<b>Saving parent to following release</b> ".$key;
483                 print_a($parent_attrs);
484               }
485               FAI::save_FAI_object($key,$parent_attrs);
486             }
487           }else{
489             if(DEBUG_FAI_FUNC) { 
490               echo "<b>Saving main object</b>".$Current_DN;
491               print_a($objectAttrs);
492             }
493             FAI::save_FAI_object($Current_DN,$objectAttrs);
495             if(isset($objectAttrs['FAIstate'])){
496               $objectAttrs['FAIstate'] .= "|removed"; 
497             }else{
498               $objectAttrs['FAIstate'] = "|removed";
499             }
501             foreach($r as $key ){
502               if(DEBUG_FAI_FUNC) { 
503                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
504                 print_a($objectAttrs);
505               }
506               FAI::save_FAI_object($key,$objectAttrs);
507             }
508           }
509         }else{
511           /* check if we must patch the follwing release */
512           if(!empty($r)){
514             foreach($r as $key ){
515               if(DEBUG_FAI_FUNC) { 
516                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
517                 print_a($parent_attrs);
518               }
519              
520               /* Append FAIstate tag to ensure that freezed objects stay freezed
521                */ 
522               $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
523               $parent_attrs['FAIstate'] = $rTag;
524               FAI::save_FAI_object($key,$parent_attrs);
525             }
526           }
528           if(DEBUG_FAI_FUNC) { 
529             echo "<b>Saving current object</b>".$parent_obj;
530             print_a($objectAttrs);
531           }
532           FAI::save_FAI_object($parent_obj,$objectAttrs);
534           if(($parent_obj != $Current_DN)){
535             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
536           }
537         }
538       }
539     }
541     /* Reload GOsa si FAI DB/cache
542      */
543     if($reload_fai_classes){
544       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
545         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
546         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
547           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
548           $tmp = new $evt['CLASS_NAME']($config);
549           $tmp->set_type(TRIGGERED_EVENT);
550           $tmp->add_targets(array("GOSA"));
551           $o_queue = new gosaSupportDaemon();
552           if(!$o_queue->append($tmp)){
553             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
554           }
555         }
556       }
557     }
559     session::set('FAI_objects_to_save',array());
560   }
563   /* this function will remove all unused (deleted) objects,
564      that have no parent object */
565   static function clean_up_releases($Current_DN)
566   {
567     global $config;
568     $ldap = $config->get_ldap_link();
569     $ldap->cd($config->current['BASE']);
571     /* Collect some basic informations and initialize some variables */ 
572     $base_release       = FAI::get_release_dn($Current_DN);
573     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
574     $sub_releases       = array_keys(FAI::get_sub_releases_of_this_release($base_release,false));
575     $Kill = array();
576     $Skip = array();
578     /* We must also include the given release dn */
579     $previous_releases[] = $base_release;
581     /* Merge parent, current and child releases into one big release to 
582        iterate over */
583     $all_releases = $previous_releases;
584     foreach($sub_releases as $sub_release){
585       $all_releases[] = $sub_release;
586     }
588     /* Walk through all releases */
589     foreach($all_releases as $release){
591       /* Get fai departments */
592       $deps_to_search = FAI::get_FAI_departments($release); 
594       /* For every single department  (ou=hoos,ou ..) */
595       foreach($deps_to_search as $fai_base){
597         /* Ldap search for fai classes specified in this release */
598         $ldap->cd($fai_base);
599         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
601         /* check the returned objects, and add/replace them in our return variable */
602         while($attr = $ldap->fetch()){
604           $buffer = array();
605 #        $name = str_ireplace($release,"",$attr['dn']);
606           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
608           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
610             /* Check if this object is required somehow */    
611             if(!isset($Skip[$name])){
612               $Kill[$attr['dn']] = $attr['dn'];
613             }
614           }else{
616             /* This object is required (not removed), so do not 
617                delete any following sub releases of this object */
618             $Skip[$name] = $attr['dn'];
619           }
620         }
621       }
622     }
623     return($Kill);
624   }
627   /* Remove numeric index and 'count' from ldap->fetch result */
628   static function prepare_ldap_fetch_to_be_saved($attrs)
629   {
630     foreach($attrs as $key => $value){
631       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
632         unset($attrs[$key]);
633       }
634       if(is_array($value) && isset($value['count'])){
635         unset($attrs[$key]['count']);
636       }
637     }
638     return($attrs);
639   }
642   /* Save given attrs to specified dn*/
643   static function save_FAI_object($dn,$attrs)
644   {
645     global $config;
646     $ldap = $config->get_ldap_link();
647     $ldap->cd($config->current['BASE']);
648     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
649     $ldap->cd($dn);
651     $ui= get_userinfo();
652     FAI::tag_attrs($attrs, $dn, $ui->gosaUnitTag);
654     $ldap->cat($dn,array("dn"));
655     if($ldap->count()){
657       /* Remove FAIstate*/
658       if(!isset($attrs['FAIstate'])){
659         $attrs['FAIstate'] = array();
660       }
662       $ldap->modify($attrs);
663     }else{
665       /* Unset description if empty  */
666       if(empty($attrs['description'])){
667         unset($attrs['description']);
668       }    
670       $ldap->add($attrs);
671     }
672     if (!$ldap->success()){
673       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
674     }
675   }
678   /* Return FAIstate freeze branch or "" for specified release department */
679   static function get_release_tag($dn)
680   {
681     global $config;
682     $ldap = $config->get_ldap_link();
683     $ldap->cd($dn);
684     $ldap->cat($dn,array("FAIstate"));
686     if($ldap->count()){
688       $attr = $ldap->fetch();
689       if(isset($attr['FAIstate'][0])){
690         if(preg_match("/freeze/",$attr['FAIstate'][0])){
691           return("freeze");
692         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
693           return("branch");
694         }
695       }
696     }
697     return("");
698   }
701   static function get_following_releases_that_inherit_this_object($dn)
702   {
703     global $config;
704     $ldap = $config->get_ldap_link();
705     $ldap->cd($config->current['BASE']);
707     $ret = array();
709     /* Get base release */
710     $base_release = FAI::get_release_dn($dn);
712     /* Get previous release dns */
713     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
715     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
716 #  $dn_suffix = str_ireplace($base_release,"",$dn);
717     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
719     /* Check if given object also exists whitin one of these releases */
720     foreach($sub_releases as $p_release => $name){
722       $check_dn = $dn_suffix.$p_release;
724       $ldap->cat($check_dn,array("dn","objectClass"));
726       if($ldap->count()){
727         //return($ret);
728       }else{
729         $ret[$check_dn]=$check_dn;
730       }
731     }
732     return($ret);
733   }
736   /* Get previous version of the object dn */
737   static function get_parent_release_object($dn,$include_myself=true)
738   {
739     global $config;
740     $ldap = $config->get_ldap_link();
741     $ldap->cd($config->current['BASE']);
742     $previous_releases= array();
744     /* Get base release */
745     $base_release = FAI::get_release_dn($dn);
746     if($include_myself){
747       $previous_releases[] = $base_release;  
748     }
750     /* Get previous release dns */
751     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
752     foreach($tmp as $release){
753       $previous_releases[] = $release;
754     }
756     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
757 #  $dn_suffix = str_ireplace($base_release,"",$dn);
758     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
760     /* Check if given object also exists whitin one of these releases */
761     foreach($previous_releases as $p_release){
762       $check_dn = $dn_suffix.$p_release;
763       $ldap->cat($check_dn,array("dn","objectClass"));
765       if($ldap->count()){
766         return($check_dn);
767       }
768     }
769     return("");
770   }
773   /* return release names of all parent releases */
774   static function get_previous_releases_of_this_release($dn,$flat)
775   {
776     global $config;
777     $ldap = $config->get_ldap_link();
778     $ldap->cd($config->current['BASE']);
779     $ret = array();
781     /* Explode dns into pieces, to be able to build parent dns */
782     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
784     if(!is_array($dns_to_check)){
785       return;  
786     }
788     /* Unset first entry which represents the given dn */
789     unset($dns_to_check['count']); 
790     unset($dns_to_check[key($dns_to_check)]);
792     /* Create dns addresses and check if this dn is a release dn */
793     $id = 0;
794     while(count($dns_to_check)){
796       /* build parent dn */
797       $new_dn = "";
798       foreach($dns_to_check as $part){
799         $new_dn .= $part.",";
800       }
801       $new_dn .= $config->current['BASE'];
803       /* check if this dn is a release */
804       if(FAI::is_release_department($new_dn)){
805         if($flat){
806           $ret[$id] = $new_dn; 
807         }else{
808           $ret = array($new_dn=>$ret); 
809         }
810         $id ++;
811       }else{
812         return($ret);
813       }
814       reset($dns_to_check);
815       unset($dns_to_check[key($dns_to_check)]);
816     }
817     return($ret);
818   } 
821   /* This function returns all sub release names, recursivly  */
822   static function get_sub_releases_of_this_release($dn,$flat = false)
823   {
824     global $config;
825     $res  = array();
826     $ldap = $config->get_ldap_link();
827     $ldap->cd($config->current['BASE']);
828     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
829     while($attr = $ldap->fetch()){
831       /* Append department name */
832       if($flat){
833         $res[$attr['dn']] = $attr['ou'][0];
834       }else{
835         $res[$attr['dn']] = array();
836       }
838       /* Get sub release departments of this department */
839       if(in_array("FAIbranch",$attr['objectClass'])) {
840         if($flat){
841           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
842           foreach($tmp as $dn => $value){
843             $res[$dn]=$value;
844           }
845         }else{
846           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
847         }
848       }
849     }
850     return($res);
851   }
854   /* Check if the given department is a release department */
855   static function is_release_department($dn)
856   {
857     global $config;
858     $ldap = $config->get_ldap_link();
859     $ldap->cd($config->current['BASE']);
860     $ldap->cat($dn,array("objectClass","ou"));
862     /* Check objectClasses and name to check if this is a release department */
863     if($ldap->count()){
864       $attrs = $ldap->fetch();
866       $ou = "";
867       if(isset($attrs['ou'][0])){
868         $ou = $attrs['ou'][0];  
869       }
871       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
872         return($attrs['dn']);
873       }
874     }
875     return(false);
876   }
879   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
880   {
881     global $config;
882     $start = microtime(TRUE);
883     $source_release = trim($source_release,"/");
885     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
887     $sub_releases = array();
888     $source_dn = "";
889     
890     $tmp = split("\/",$source_release);
891     foreach($tmp as $part){
892       if(empty($part)){
893         continue;
894       }
895       $source_dn            = "ou=".$part.",".$source_dn;
896       $sub_releases[$part]  = $source_dn;
897     }
899     /* Get all groups */
900     $ldap =$config->get_ldap_link();
901     $ldap->cd($config->current['BASE']);
902     $ldap->search("(objectClass=posixGroup)",array("dn"));
903     $groups = array();
904     while($attrs = $ldap->fetch()){
905       $groups[$attrs['dn']] = $attrs;
906     }
908     /* Get all FAI releases, to be able to create missing group application releases 
909         with the correct type of release (FAIstate=freeze/branch).
910      */
911     $f_releases = array();
912     $ldap->cd ($config->current['BASE']);
913     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
914     while($attrs = $ldap->fetch()){
915       foreach($sub_releases as $sub_rel){
916         if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
917           $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
918         }
919       }
920     }
922     /* Get all group releases */
923     $g_releases = array();
924     foreach($groups as $dn => $data){
925       $ldap->cd($dn);
926       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
927       while($attrs = $ldap->fetch()){
928         $g_releases[$attrs['dn']] = $attrs;
929       }
930     }
932     /* Check if base releases exists.
933        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
934      */
935     foreach($sub_releases as $name => $sub_rel){
937       $FAIstate = "";
938       if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
939         $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
940       }
942       foreach($groups as $dn => $data){
943         if(!isset($g_releases[$sub_rel.$dn])){
944           $ldap->cd($dn);
945           $r_data = array();
946           $r_data['ou'] = $name;
947           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
948           if(!empty($FAIstate)) {
949             $r_data['FAIstate'] = $FAIstate;
950           }
951  
952           $ldap->cd($sub_rel.$dn) ;
953           $ldap->add($r_data);
954           echo "&nbsp;<b>"._("Object").":</b> ";
955           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
956           flush();
957         }
958       }
959     } 
960  
961     /* Create new release container in each group.
962      */
963     $n_data = array();
964     $n_data = array();
965     $n_data['ou'] = $destination_name;
966     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
967     if(!empty($type)){
968       $n_data['FAIstate'] = $type."/cow";
969     }
971     foreach($groups as $dn => $att){
972       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
973       if(!isset($g_releases[$n_dn])){
974         $ldap->cd ($n_dn);
975         $ldap->add($n_data);
976         echo "&nbsp;<b>"._("Object").":</b> ";
977         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
978         flush();
979       }
980     }
982     /* If the source release is empty, then create a new release by copying 
983         all group application menus into a new ou=$destination_name release container.
984       
985        If the source release is not empty. 
986          We detect all releases which match the source release dn and copy the contents.
987      */
988     if(empty($source_release)){
989       $source_dns = $groups;
990     }else{
991       $source_dns = array();
992       foreach($g_releases as $dn => $data){
993         if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
994           $source_dns[$dn] = $data; 
995         }
996       }
997     }
999     /* Detect all menu object we have to copy 
1000      */
1001     $to_copy = array();
1002     foreach($source_dns as $dn => $attrs){
1003       $ldap->cd($dn);
1004       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1005       while($attrs = $ldap->fetch()){
1006         $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1007         $to_copy[$attrs['dn']] = $destination;
1008       }
1009     }
1010    
1011     /* At least create the menu objects object */
1012     $plug = new plugin($config);
1013     foreach($to_copy as $source => $destination){
1014       $ldap->cat($destination);
1015       if($ldap->count()){
1016         echo "&nbsp;<b>"._("Object").":</b> ";
1017         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1018         flush();
1019       }else{
1020         $plug->copy($source,$destination);
1021         echo "&nbsp;<b>"._("Object").":</b> ";
1022         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1023         flush();
1024       }
1025     }
1026   }
1029   /*! \brief Create a new FAI branch.
1030    *  @param $sourcedn          String  The source release dn
1031    *  @param $destinationdn     String  The destination dn
1032    *  @param $destinationName   String  The name of the new release
1033    *  @param $type              String  The release type (freeze/branch)
1034    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
1035    *  @param $depth             Integer Current depth of recursion.
1036    */
1037   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1038   {
1039     global $config;
1040     error_reporting(E_ALL | E_STRICT);
1041     $ldap     = $config->get_ldap_link();
1042     $basedn   = $config->current['BASE'];
1043     $delarray = array();
1045     /* The following code will output a status string
1046      *  for each handled object, in a seperate iframe.
1047      */
1050     /* Display current action information.
1051      */
1052     if($is_first){
1053       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1054     }else{
1055       if(preg_match("/^ou=/",$sourcedn)){
1056         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1057       }else{
1058         $tmp = split(",",$sourcedn);
1059         echo "&nbsp;<b>"._("Object").":</b> ";
1060         $deststr = LDAP::fix($destinationdn);
1061         if(strlen($deststr) > 96){
1062           $deststr = substr($deststr,0,96)."...";
1063         }
1064         echo $deststr."<br>";
1065       }
1066     }
1067     /* .. immediately display infos */
1068     flush();
1070     /* Check if destination entry already exists
1071      */
1072     $ldap->cat($destinationdn);
1073     if($ldap->count()){
1074       echo _("Could not create new release, the destination dn is already in use.");
1075       return;
1076     }else{
1078       $ldap->clearResult();
1080       /* Get source entry
1081        *  if it does not exist, abort here.
1082        */
1083       $ldap->cd($basedn);
1084       $ldap->cat($sourcedn);
1085       $attr = $ldap->fetch();
1086       if((!$attr) || (count($attr)) ==0) {
1087         echo _("Error while fetching source dn - aborted!");
1088         return;
1089       }
1091       /* The current object we want to create is an department.
1092        * Create the department and add the FAIbranch tag.
1093        */
1094       if(in_array("organizationalUnit",$attr['objectClass'])){
1095         $attr['dn'] = LDAP::convert($destinationdn);
1096         $ldap->cd($basedn);
1097         $ldap->create_missing_trees($destinationdn);
1098         $ldap->cd($destinationdn);
1100         /* If is first entry, append FAIbranch to department entry */
1101         if($is_first){
1102           $ldap->cat($destinationdn);
1103           $attr= $ldap->fetch();
1104           /* Filter unneeded informations */
1105           foreach($attr as $key => $value){
1106             if(is_numeric($key)) unset($attr[$key]);
1107             if(isset($attr[$key]['count'])){
1108               if(is_array($attr[$key])){
1109                 unset($attr[$key]['count']);
1110               }
1111             }
1112           }
1114           unset($attr['count']);
1115           unset($attr['dn']);
1117           /* Add marking attribute */
1118           $attr['objectClass'][] = "FAIbranch";
1119           $attr['FAIstate'] = $type;
1121           /* Add this entry */
1122           $ldap->modify($attr);
1123         }
1124       }else{
1126         /* Replicate all relevant FAI objects here.
1127          * FAI objects, Apps and Mimetypes.
1128          * Get all attributes as binary value, to ensure that Icon, File template aso
1129          *  are created correctly.
1130          */
1131         foreach($attr as $key => $value){
1133           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1134             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1135             $ei= ldap_first_entry($ldap->cid, $sr);
1136             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1137               $attr[$key] = $tmp;
1138             }
1139           }
1141           if(is_numeric($key)) unset($attr[$key]);
1142           if(isset($attr[$key]['count'])){
1143             if(is_array($attr[$key])){
1144               unset($attr[$key]['count']);
1145             }
1146           }
1147         }
1148         unset($attr['count']);
1149         unset($attr['dn']);
1150         if(!in_array("FAIobject",$attr['objectClass'])){
1151           $attr['objectClass'][] = "FAIobject";
1152         }
1153         $attr['FAIstate'] = $type;
1155         /* Add entry
1156          */
1157         $ldap->cd($destinationdn);
1158         $ldap->cat($destinationdn);
1160         $a = $ldap->fetch();
1161         if(!count($a)){
1162           $ldap->add($attr);
1163         }
1165         if(!$ldap->success()){
1167           /* Some error occurred */
1168           msg_dialog::display(_("Fatal error"),
1169               sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1170                 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1171           exit();
1172         }
1173       }
1174     }
1176     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1178     /* Prepare for recursive copy.
1179      * Get all object within the source dn and
1180      *  call the recursive copy for each.
1181      */
1182     $ldap->ls ("(objectClass=*)",$sourcedn);
1183     while ($ldap->fetch()){
1184       $deldn= $ldap->getDN();
1185       $delarray[$deldn]= strlen($deldn);
1186     }
1187     asort ($delarray);
1188     reset ($delarray);
1189     $depth ++;
1190     foreach($delarray as $dn => $bla){
1191       if($dn != $destinationdn){
1192         $ldap->cd($basedn);
1193         $item = $ldap->fetch($ldap->cat($dn));
1194         if(!in_array("FAIbranch",$item['objectClass'])){
1195           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1196         }
1197       }
1198     }
1199     if($is_first){
1200       echo "<p class='seperator'>&nbsp;</p>";
1201     }
1202   }
1206   /* This function returns the dn of the object release */
1207   static function get_release_dn($Current_DN)
1208   {
1209     global $config;
1210     $ldap = $config->get_ldap_link();
1211     $ldap->cd($config->current['BASE']);
1213     /* Split dn into pices */ 
1214     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1216     if(!is_array($dns_to_check)){
1217       return;  
1218     }
1220     /* Use dn pieces, to create sub dns like 
1221        ou=test,ou=1,ou=0...
1222        ou=1,ou=0...
1223        ou=0... 
1224        To check which dn is our release container.
1225      */
1226     unset($dns_to_check['count']); 
1227     while(count($dns_to_check)){
1229       /* Create dn */
1230       $new_dn = "";
1231       foreach($dns_to_check as $part){
1232         $new_dn .= $part.",";
1233       }
1234       $new_dn .= $config->current['BASE'];
1236       /* Check if this dn is a release dn */
1237       if(FAI::is_release_department($new_dn)){
1238         return($new_dn);
1239       }
1241       /* Remove first element of dn pieces */
1242       reset($dns_to_check);
1243       unset($dns_to_check[key($dns_to_check)]);
1244     }
1245     return("");
1246   }
1249   static function tag_attrs(&$at, $dn= "", $tag= "", $show= false)
1250   {                                                        
1251     /* Remove tags that may already be here... */                         
1252     remove_objectClass("gosaAdministrativeUnitTag", $at);                 
1253     if (isset($at['gosaUnitTag'])){                                       
1254         unset($at['gosaUnitTag']);                                        
1255     }                                                                     
1257     /* Set tag? */
1258     if ($tag != ""){
1259       add_objectClass("gosaAdministrativeUnitTag", $at);
1260       $at['gosaUnitTag']= $tag;                         
1261     }                                                   
1263     /* Initially this object was tagged. 
1264        - But now, it is no longer inside a tagged department. 
1265        So force the remove of the tag.                        
1266        (objectClass was already removed obove)                
1267      */                                                       
1268     if($tag == ""){                     
1269       $at['gosaUnitTag'] = array();                           
1270     }                                                         
1271   }                                                           
1279 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1280 ?>