Code

Updated FAI partition handling
[gosa.git] / 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","FAIdiskType","FAIlvmDevice","FAIdiskOption");
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           if(isset($attr['FAIdiskType'])){
101             $buffer['FAIdiskType'] = $attr['FAIdiskType'][0];
102           } else {
103             $buffer['FAIdiskType'] = "old";
104           }
106           if(isset($attr['FAIdiskOption'])){
107             $buffer['FAIdiskOption'] = $attr['FAIdiskOption'];
108           } else {
109             $buffer['FAIdiskOption'] = null;
110           }
111           if(isset($attr['FAIlvmDevice'])){
112             $buffer['FAIlvmDevice'] = $attr['FAIlvmDevice'];
113           }
115           /* In detailed mode are some additonal informations visible */
116           if($detailed){
118             /* Create list of parents */
119             if(isset($res[$name])){
120               $buffer = $res[$name];
121               $buffer['parents'][] = $res[$name]['dn'];
122             }else{
123               $buffer['parents'] = array();
124             }
126             /* Append objectClass to resulsts */
127             foreach($attributes as $val){
128               if(isset($attr[$val])){
129                 $buffer[$val] = $attr[$val];
130               }
131             }
132             unset($buffer['objectClass']['count']);
133           }
135           /* Add this object to our list */
136           $buffer['dn']           = $attr['dn'];
137           $res[$name] = $buffer;
138         }
139       }
140     }
141     return($res);
142   }
145   /* Return all relevant FAI departments */
146   static function get_FAI_departments($suffix = "")
147   {
148     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
149     $tmp = array();
150     if(preg_match("/^,/",$suffix)){
151       $suffix = preg_replace("/^,/","",$suffix);
152     }
153     foreach($arr as $name){
154       if(empty($suffix)){
155         $tmp[$name] = "ou=".$name;
156       }else{
157         $tmp[$name] = "ou=".$name.",".$suffix;
158       }
159     }
160     return($tmp);
161   }
164   /* Return all releases within the given base */
165   static function get_all_releases_from_base($dn,$appendedName=false)
166   {
167     global $config;
169     if(!preg_match("/".preg_quote(get_ou('faiBaseRDN'), '/')."/",$dn)){
170       $base = get_ou('faiBaseRDN').$dn;
171     }else{
172       $base = $dn;
173     }
174     $res = array();  
176     $ldap = $config->get_ldap_link();
177     $ldap->cd($base);
178     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
179     while($attrs = $ldap->fetch()){
180       if($appendedName){
181         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".preg_quote(get_ou('faiBaseRDN'), '/').".*$/","",$attrs['dn']));
182       }else{
183         $res[$attrs['dn']] = $attrs['ou'][0];
184       }
185     }
186     return($res);
187   }
190   /* Add this object to list of objects, that must be checked for release saving */
191   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
192   {
193     /* Get ldap object */  
194     global $config;
195     $addObj['Current_DN'] = $Current_DN;
196     $addObj['objectAttrs']= $objectAttrs;
197     $addObj['removed']    = $removed;
198     $addObj['diff']       = TRUE;
200     if(!$removed){
201       $ldap = $config->get_ldap_link();
202       $ldap->cd($config->current['BASE']);
204       /* Get some basic informations */
205       $parent_obj   = FAI::get_parent_release_object($Current_DN);
206       if(!empty($parent_obj)){
207         $ldap->cat($parent_obj,array("*"));
208         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
210         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
211           $addObj['diff'] = FALSE;
212         }
213       } 
214     }else{
216       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
217           we have to remove this name from all profiles in this release.
218       */
219       $ldap = $config->get_ldap_link();
220       $ldap->cd($config->current['BASE']);
221       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
223       /* Dont't try to modify non FAIclasses  
224        */
225       if(!preg_match("/[^,]+,".preg_quote(get_ou("faiBaseRDN"), '/')."/",$obj_dn)){
226         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
227         echo "<br>-->".$Current_DN."<br>";
228         echo "<br>-->".$obj_dn."<br>";
229       }else{
231         /* Get source object and check if it is a base FAIclass
232          */
233         $ldap->cat($obj_dn);
234         $attrs = $ldap->fetch();
235         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
236         if(count(array_intersect($classes,$attrs['objectClass']))){
237           $cn    = $attrs['cn'][0];
239           /* Check if this is the last with this name in the current release.
240               In this case we have to remove the package name 
241               from all profiles in this release.
242            */
243           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
244               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
246           /* Check if this is the last class with this name.
247            */
248           if(count($classes) == 1){
250             /* Get all FAI Profiles 
251              */
252             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
253                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
255             /* Walk though all profiles and remove the source class name
256              */
257             foreach($profiles as $dn){
258               $ldap->cat($dn['dn']);
259               $attrs = $ldap->fetch();
261               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
263               /* Check if this Profile uses the source class ($cn)
264                */
265               if(preg_match("/".preg_quote($cn, '/')."/",$attrs['FAIclass'])){
266                 $attrs['FAIclass'] = preg_replace("/[ ]*".preg_quote($cn, '/')."[ ]*/i"," ",$attrs['FAIclass']);
267                 if(empty($attrs['FAIclass'])){
268                   $attrs['FAIclass'] = array();
269                 }
270                 $ldap->cd($dn['dn']);
271                 $ldap->modify($attrs);
273                 if (!$ldap->success()){
274                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
275                 }
276               }
277             }
278           }
279         }
280       }
281     }
285     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
286     $FAI_objects_to_save[$Current_DN] =  $addObj;
287     session::set('FAI_objects_to_save',$FAI_objects_to_save);
288   }
291   /* Detect differences in attribute arrays  */
292   static function array_diff_FAI($ar1,$ar2)
293   {
295     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
296       $ar1['description'] = "";
297     }
298     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
299       $ar2['description'] = "";
300     }
302     if(count($ar1) != count($ar2)) {
303       return (true);
304     }
306     foreach($ar1 as $key1 => $val1){
308       if((is_array($val1)) && (count($val1)==1)){
309         $ar1[$key1] = $val1[0];
310       }
312       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
313         $val1 = $val1[0];
314         $ar2[$key1] = $ar2[$key1][0];
315       }
316     }
317     ksort($ar1);
318     ksort($ar2);
319     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
320       return(true);
321     }else{
322       return(false);
323     }
324   }
327   static function arr_diff($ar1,$ar2)
328   {
329     foreach($ar1 as $ak1 => $av1){
330       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
331         return(TRUE);    
332       }elseif(is_array($av1)){
333         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
334         if($ret) {
335           return(TRUE);
336         }
337       }
338     }
339     return(FALSE);
340   }
345   /* check which objects must be saved, and save them */
346   static function save_release_changes_now()
347   {
348     global $config;
349     /* Variable init*/
350     $to_save = array();
351     
352     $reload_fai_classes = FALSE;
354     /* check which objects must be saved */
355     if(!session::is_set('FAI_objects_to_save')){
356       return;
357     }
358     $FAI_objects_to_save = session::get('FAI_objects_to_save');
359     if(!is_array($FAI_objects_to_save)) {
360       print_a(array(session::get('FAI_objects_to_save')));
361       trigger_error("Can't save FAI objects, no array given.");
362       return;
363     }
364   
365     foreach($FAI_objects_to_save as $Current_DN => $object){
366       if($object['diff']){
367         $sub_name = $Current_DN;
368         while(isset($FAI_objects_to_save[$sub_name])){
369           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
370           unset($FAI_objects_to_save[$sub_name]);
371           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
372         }
373       }
374     }
375     session::set('FAI_objects_to_save',$FAI_objects_to_save);
377     /* Sort list of objects that must be saved, and ensure that 
378        container   objects are safed, before their childs are saved */
379     ksort($to_save);
380     $tmp = array();
381     foreach($to_save as $SubObjects){
382       foreach($SubObjects as $object){
383         $tmp[] = $object;
384       }
385     }
386     $to_save = $tmp;
389     /* Save objects and manage the correct release behavior*/
390     foreach($to_save as $save){
392       $Current_DN = $save['Current_DN'];
393       $removed    = $save['removed'];
394       $objectAttrs= $save['objectAttrs'];
396       /* Get ldap object */ 
397       $ldap = $config->get_ldap_link();
398       $ldap->cd($config->current['BASE']);
400       /* Get some basic informations */
401       $base_release       = FAI::get_release_dn($Current_DN);
402       $sub_releases       = FAI::get_sub_releases_of_this_release($base_release,true);
403       $parent_obj         = FAI::get_parent_release_object($Current_DN);
404       $following_releases = $sub_releases;
406       /* Check if given dn exists or if is a new entry */
407       $ldap->cat($Current_DN);
408       if(!$ldap->count()){
409         $is_new = true;
410       }else{
411         $is_new = false;
412       }
414       /* if parameter removed is true, we have to add FAIstate to the current attrs 
415          FAIstate should end with ...|removed after this operation */  
416       if($removed ){
417         $ldap->cat($Current_DN);
419         /* Get current object, because we must add the FAIstate ...|removed */
420         if((!$ldap->count()) && !empty($parent_obj)){
421           $ldap->cat($parent_obj);
422         }
424         /* Check if we have found a suiteable object */ 
425         if(!$ldap->count()){
426           echo "Error can't remove this object ".$Current_DN;
427           return;
428         }else{
430           /* Set FAIstate to current objectAttrs */
431           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
432           if(isset($objectAttrs['FAIstate'][0])){
433             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
434               $objectAttrs['FAIstate'][0] .= "|removed";
435             }
436           }else{
437             $objectAttrs['FAIstate'][0] = "|removed";
438           }
440           /* Force reload of FAI classes */
441           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
442           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
443             $reload_fai_classes = TRUE;
444           }
445         }
446       }
448       /* Check if this a leaf release or not */ 
449       if(count($following_releases) == 0 ){
451         /* This is a leaf object. It isn't inherited by any other object */    
452         if(DEBUG_FAI_FUNC) { 
453           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
454           print_a($objectAttrs);
455         }
456         FAI::save_FAI_object($Current_DN,$objectAttrs);
458         /* Force reload of FAI classes */
459         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
460         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
461           $reload_fai_classes = TRUE;
462         }
464       }else{
466         /* This object is inherited by some sub releases */  
468         /* Get all releases, that inherit this object */ 
469         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
471         /* Get parent object */
472         $ldap->cat($parent_obj);
473         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
475         /* New objects require special handling */
476         if($is_new){
478           /* Force reload of FAI classes */
479           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
480           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
481             $reload_fai_classes = TRUE;
482           }
484           /* check if there is already an entry named like this,
485              in one of our parent releases */
486           if(!empty($parent_obj)){
487             if(DEBUG_FAI_FUNC) { 
488               echo "There is already an entry named like this.</b><br>";
490               echo "<b>Saving main object</b>".$Current_DN;
491               print_a($objectAttrs);
492             }    
493             FAI::save_FAI_object($Current_DN,$objectAttrs);
495             foreach($r as $key){
496               if(DEBUG_FAI_FUNC) { 
497                 echo "<b>Saving parent to following release</b> ".$key;
498                 print_a($parent_attrs);
499               }
500               FAI::save_FAI_object($key,$parent_attrs);
501             }
502           }else{
504             if(DEBUG_FAI_FUNC) { 
505               echo "<b>Saving main object</b>".$Current_DN;
506               print_a($objectAttrs);
507             }
508             FAI::save_FAI_object($Current_DN,$objectAttrs);
510             if(isset($objectAttrs['FAIstate'])){
511               $objectAttrs['FAIstate'] .= "|removed"; 
512             }else{
513               $objectAttrs['FAIstate'] = "|removed";
514             }
516             foreach($r as $key ){
517               if(DEBUG_FAI_FUNC) { 
518                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
519                 print_a($objectAttrs);
520               }
521               FAI::save_FAI_object($key,$objectAttrs);
522             }
523           }
524         }else{
526           /* check if we must patch the follwing release */
527           if(!empty($r)){
529             foreach($r as $key ){
530               if(DEBUG_FAI_FUNC) { 
531                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
532                 print_a($parent_attrs);
533               }
534              
535               /* Append FAIstate tag to ensure that freezed objects stay freezed
536                */ 
537               $rTag = FAI::get_release_tag(FAI::get_release_dn($key));
538               $parent_attrs['FAIstate'] = $rTag;
540               /* FAItemplateFile can be binary, therefore it needs to be fetched with
541                * $ldap->get_attribute */
542               if (isset($parent_attrs['FAItemplateFile'])) {
543                 $parent_attrs['FAItemplateFile'] = $ldap->get_attribute($parent_obj, 'FAItemplateFile');
544               }
546               FAI::save_FAI_object($key,$parent_attrs);
547             }
548           }
550           if(DEBUG_FAI_FUNC) { 
551             echo "<b>Saving current object</b>".$parent_obj;
552             print_a($objectAttrs);
553           }
554           FAI::save_FAI_object($parent_obj,$objectAttrs);
556           if(($parent_obj != $Current_DN)){
557             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
558           }
559         }
560       }
561     }
563     /* Reload GOsa si FAI DB/cache
564      */
565     if($reload_fai_classes){
566       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
567         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
568         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
569           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
570           $tmp = new $evt['CLASS_NAME']($config);
571           $tmp->set_type(TRIGGERED_EVENT);
572           $tmp->add_targets(array("GOSA"));
573           $o_queue = new gosaSupportDaemon();
574           if(!$o_queue->append($tmp)){
575             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
576           }
577         }
578       }
579     }
581     session::set('FAI_objects_to_save',array());
582   }
585   /* this function will remove all unused (deleted) objects,
586      that have no parent object */
587   static function clean_up_releases($Current_DN)
588   {
589     global $config;
590     $ldap = $config->get_ldap_link();
591     $ldap->cd($config->current['BASE']);
593     /* Collect some basic informations and initialize some variables */ 
594     $base_release       = FAI::get_release_dn($Current_DN);
595     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
596     $Kill = array();
597     $Skip = array();
599     /* We must also include the given release dn */
600     $previous_releases[] = $base_release;
602     /* Walk through all releases */
603     foreach($previous_releases as $release){
605       /* Get fai departments */
606       $deps_to_search = FAI::get_FAI_departments($release); 
608       /* For every single department  (ou=hoos,ou ..) */
609       foreach($deps_to_search as $fai_base){
611         /* Ldap search for fai classes specified in this release */
612         $ldap->cd($fai_base);
613         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
615         /* check the returned objects, and add/replace them in our return variable */
616         while($attr = $ldap->fetch()){
618           $buffer = array();
619 #        $name = str_ireplace($release,"",$attr['dn']);
620           $name = preg_replace("/".preg_quote($release, '/')."/i","",$attr['dn']);
622           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
624             /* Check if this object is required somehow */    
625             if(!isset($Skip[$name])){
626               $Kill[$attr['dn']] = $attr['dn'];
627             }
628           }else{
630             /* This object is required (not removed), so do not 
631                delete any following sub releases of this object */
632             $Skip[$name] = $attr['dn'];
633           }
634         }
635       }
636     }
637     return($Kill);
638   }
641   /* Remove numeric index and 'count' from ldap->fetch result */
642   static function prepare_ldap_fetch_to_be_saved($attrs)
643   {
644     foreach($attrs as $key => $value){
645       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
646         unset($attrs[$key]);
647       }
648       if(is_array($value) && isset($value['count'])){
649         unset($attrs[$key]['count']);
650       }
651     }
652     return($attrs);
653   }
656   /* Save given attrs to specified dn*/
657   static function save_FAI_object($dn,$attrs)
658   {
659     global $config;
660     $ldap = $config->get_ldap_link();
661     $ldap->cd($config->current['BASE']);
662     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
663     $ldap->cd($dn);
665     $ldap->cat($dn,array("dn"));
666     if($ldap->count()){
668       /* Remove FAIstate*/
669       if(!isset($attrs['FAIstate'])){
670         $attrs['FAIstate'] = array();
671       }
673       $ldap->modify($attrs);
674     }else{
676       /* Unset description if empty  */
677       if(empty($attrs['description'])){
678         unset($attrs['description']);
679       }    
681       $ldap->add($attrs);
682     }
683     if (!$ldap->success()){
684       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
685     }
686   }
689   /* Return FAIstate freeze branch or "" for specified release department */
690   static function get_release_tag($dn)
691   {
692     global $config;
693     $ldap = $config->get_ldap_link();
694     $ldap->cd($dn);
695     $ldap->cat($dn,array("FAIstate"));
697     if($ldap->count()){
699       $attr = $ldap->fetch();
700       if(isset($attr['FAIstate'][0])){
701         if(preg_match("/freeze/",$attr['FAIstate'][0])){
702           return("freeze");
703         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
704           return("branch");
705         }
706       }
707     }
708     return("");
709   }
712   static function get_following_releases_that_inherit_this_object($dn)
713   {
714     global $config;
715     $ldap = $config->get_ldap_link();
716     $ldap->cd($config->current['BASE']);
718     $ret = array();
720     /* Get base release */
721     $base_release = FAI::get_release_dn($dn);
723     /* Get previous release dns */
724     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
726     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
727 #  $dn_suffix = str_ireplace($base_release,"",$dn);
728     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
730     /* Check if given object also exists whitin one of these releases */
731     foreach($sub_releases as $p_release => $name){
733       $check_dn = $dn_suffix.$p_release;
735       $ldap->cat($check_dn,array("dn","objectClass"));
737       if($ldap->count()){
738         //return($ret);
739       }else{
740         $ret[$check_dn]=$check_dn;
741       }
742     }
743     return($ret);
744   }
747   /* Get previous version of the object dn */
748   static function get_parent_release_object($dn,$include_myself=true)
749   {
750     global $config;
751     $ldap = $config->get_ldap_link();
752     $ldap->cd($config->current['BASE']);
753     $previous_releases= array();
755     /* Get base release */
756     $base_release = FAI::get_release_dn($dn);
757     if($include_myself){
758       $previous_releases[] = $base_release;  
759     }
761     /* Get previous release dns */
762     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
763     foreach($tmp as $release){
764       $previous_releases[] = $release;
765     }
767     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
768 #  $dn_suffix = str_ireplace($base_release,"",$dn);
769     $dn_suffix = preg_replace("/".preg_quote($base_release, '/')."/i","",$dn);
771     /* Check if given object also exists whitin one of these releases */
772     foreach($previous_releases as $p_release){
773       $check_dn = $dn_suffix.$p_release;
774       $ldap->cat($check_dn,array("dn","objectClass"));
776       if($ldap->count()){
777         return($check_dn);
778       }
779     }
780     return("");
781   }
784   /* return release names of all parent releases */
785   static function get_previous_releases_of_this_release($dn,$flat)
786   {
787     global $config;
788     $ldap = $config->get_ldap_link();
789     $ldap->cd($config->current['BASE']);
790     $ret = array();
792     /* Explode dns into pieces, to be able to build parent dns */
793     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$dn));
795     if(!is_array($dns_to_check)){
796       return;  
797     }
799     /* Unset first entry which represents the given dn */
800     unset($dns_to_check['count']); 
801     unset($dns_to_check[key($dns_to_check)]);
803     /* Create dns addresses and check if this dn is a release dn */
804     $id = 0;
805     while(count($dns_to_check)){
807       /* build parent dn */
808       $new_dn = "";
809       foreach($dns_to_check as $part){
810         $new_dn .= $part.",";
811       }
812       $new_dn .= $config->current['BASE'];
814       /* check if this dn is a release */
815       if(FAI::is_release_department($new_dn)){
816         if($flat){
817           $ret[$id] = $new_dn; 
818         }else{
819           $ret = array($new_dn=>$ret); 
820         }
821         $id ++;
822       }else{
823         return($ret);
824       }
825       reset($dns_to_check);
826       unset($dns_to_check[key($dns_to_check)]);
827     }
828     return($ret);
829   } 
832   /* This function returns all sub release names, recursivly  */
833   static function get_sub_releases_of_this_release($dn,$flat = false)
834   {
835     global $config;
836     $res  = array();
837     $ldap = $config->get_ldap_link();
838     $ldap->cd($config->current['BASE']);
839     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
840     while($attr = $ldap->fetch()){
842       /* Append department name */
843       if($flat){
844         $res[$attr['dn']] = $attr['ou'][0];
845       }else{
846         $res[$attr['dn']] = array();
847       }
849       /* Get sub release departments of this department */
850       if(in_array("FAIbranch",$attr['objectClass'])) {
851         if($flat){
852           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
853           foreach($tmp as $dn => $value){
854             $res[$dn]=$value;
855           }
856         }else{
857           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
858         }
859       }
860     }
861     return($res);
862   }
865   /* Check if the given department is a release department */
866   static function is_release_department($dn)
867   {
868     global $config;
869     $ldap = $config->get_ldap_link();
870     $ldap->cd($config->current['BASE']);
871     $ldap->cat($dn,array("objectClass","ou"));
873     /* Check objectClasses and name to check if this is a release department */
874     if($ldap->count()){
875       $attrs = $ldap->fetch();
877       $ou = "";
878       if(isset($attrs['ou'][0])){
879         $ou = $attrs['ou'][0];  
880       }
882       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
883         return($attrs['dn']);
884       }
885     }
886     return(false);
887   }
890   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
891   {
892     global $config;
893     $start = microtime(TRUE);
894     $source_release = trim($source_release,"/");
896     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
898     $sub_releases = array();
899     $source_dn = "";
900     
901     $tmp = split("\/",$source_release);
902     foreach($tmp as $part){
903       if(empty($part)){
904         continue;
905       }
906       $source_dn            = "ou=".$part.",".$source_dn;
907       $sub_releases[$part]  = $source_dn;
908     }
910     /* Get all groups */
911     $ldap =$config->get_ldap_link();
912     $ldap->cd($config->current['BASE']);
913     $ldap->search("(objectClass=posixGroup)",array("dn"));
914     $groups = array();
915     while($attrs = $ldap->fetch()){
916       $groups[$attrs['dn']] = $attrs;
917     }
919     /* Get all FAI releases, to be able to create missing group application releases 
920         with the correct type of release (FAIstate=freeze/branch).
921      */
922     $f_releases = array();
923     $ldap->cd ($config->current['BASE']);
924     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
925     while($attrs = $ldap->fetch()){
926       foreach($sub_releases as $sub_rel){
927         if(preg_match("/^".preg_quote($sub_rel.get_ou('faiBaseRDN'), '/')."/",$attrs['dn'])){
928           $f_releases[$sub_rel.get_ou('faiBaseRDN')] = $attrs;
929         }
930       }
931     }
933     /* Get all group releases */
934     $g_releases = array();
935     foreach($groups as $dn => $data){
936       $ldap->cd($dn);
937       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
938       while($attrs = $ldap->fetch()){
939         $g_releases[$attrs['dn']] = $attrs;
940       }
941     }
943     /* Check if base releases exists.
944        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
945      */
946     foreach($sub_releases as $name => $sub_rel){
948       $FAIstate = "";
949       if(isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]) && isset($f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'])){
950         $FAIstate = $f_releases[$sub_rel.get_ou('faiBaseRDN')]['FAIstate'][0];
951       }
953       foreach($groups as $dn => $data){
954         if(!isset($g_releases[$sub_rel.$dn])){
955           $ldap->cd($dn);
956           $r_data = array();
957           $r_data['ou'] = $name;
958           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
959           if(!empty($FAIstate)) {
960             $r_data['FAIstate'] = $FAIstate;
961           }
962  
963           $ldap->cd($sub_rel.$dn) ;
964           $ldap->add($r_data);
965           echo "&nbsp;<b>"._("Object").":</b> ";
966           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
967           flush();
968         }
969       }
970     } 
971  
972     /* Create new release container in each group.
973      */
974     $n_data = array();
975     $n_data = array();
976     $n_data['ou'] = $destination_name;
977     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
978     if(!empty($type)){
979       $n_data['FAIstate'] = $type."/cow";
980     }
982     foreach($groups as $dn => $att){
983       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
984       if(!isset($g_releases[$n_dn])){
985         $ldap->cd ($n_dn);
986         $ldap->add($n_data);
987         echo "&nbsp;<b>"._("Object").":</b> ";
988         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
989         flush();
990       }
991     }
993     /* If the source release is empty, then create a new release by copying 
994         all group application menus into a new ou=$destination_name release container.
995       
996        If the source release is not empty. 
997          We detect all releases which match the source release dn and copy the contents.
998      */
999     if(empty($source_release)){
1000       $source_dns = $groups;
1001     }else{
1002       $source_dns = array();
1003       foreach($g_releases as $dn => $data){
1004         if(preg_match("/^".preg_quote($source_dn, '/')."/",$dn)){
1005           $source_dns[$dn] = $data; 
1006         }
1007       }
1008     }
1010     /* Detect all menu object we have to copy 
1011      */
1012     $to_copy = array();
1013     foreach($source_dns as $dn => $attrs){
1014       $ldap->cd($dn);
1015       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
1016       while($attrs = $ldap->fetch()){
1017         $destination = preg_replace("/".preg_quote($dn, '/')."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
1018         $to_copy[$attrs['dn']] = $destination;
1019       }
1020     }
1021    
1022     /* At least create the menu objects object */
1023     $plug = new plugin($config);
1024     foreach($to_copy as $source => $destination){
1025       $ldap->cat($destination);
1026       if($ldap->count()){
1027         echo "&nbsp;<b>"._("Object").":</b> ";
1028         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
1029         flush();
1030       }else{
1031         $plug->copy($source,$destination);
1032         echo "&nbsp;<b>"._("Object").":</b> ";
1033         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
1034         flush();
1035       }
1036     }
1037   }
1040   /*! \brief Create a new FAI branch.
1041    *  @param $sourcedn          String  The source release dn
1042    *  @param $destinationdn     String  The destination dn
1043    *  @param $destinationName   String  The name of the new release
1044    *  @param $type              String  The release type (freeze/branch)
1045    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
1046    *  @param $depth             Integer Current depth of recursion.
1047    */
1048   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1049   {
1050     global $config;
1051     error_reporting(E_ALL | E_STRICT);
1052     $ldap     = $config->get_ldap_link();
1053     $basedn   = $config->current['BASE'];
1054     $delarray = array();
1056     /* The following code will output a status string
1057      *  for each handled object, in a seperate iframe.
1058      */
1061     /* Display current action information.
1062      */
1063     if($is_first){
1064       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1065     }else{
1066       if(preg_match("/^ou=/",$sourcedn)){
1067         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1068       }else{
1069         $tmp = split(",",$sourcedn);
1070         echo "&nbsp;<b>"._("Object").":</b> ";
1071         $deststr = LDAP::fix($destinationdn);
1072         if(strlen($deststr) > 96){
1073           $deststr = substr($deststr,0,96)."...";
1074         }
1075         echo $deststr."<br>";
1076       }
1077     }
1078     /* .. immediately display infos */
1079     flush();
1081     /* Check if destination entry already exists
1082      */
1083     $ldap->cat($destinationdn);
1084     if($ldap->count()){
1085       echo _("Could not create new release, the destination dn is already in use.");
1086       return;
1087     }else{
1089       $ldap->clearResult();
1091       /* Get source entry
1092        *  if it does not exist, abort here.
1093        */
1094       $ldap->cd($basedn);
1095       $ldap->cat($sourcedn);
1096       $attr = $ldap->fetch();
1097       if((!$attr) || (count($attr)) ==0) {
1098         echo _("Error while fetching source dn - aborted!");
1099         return;
1100       }
1102       /* The current object we want to create is an department.
1103        * Create the department and add the FAIbranch tag.
1104        */
1105       if(in_array("organizationalUnit",$attr['objectClass'])){
1106         $attr['dn'] = LDAP::convert($destinationdn);
1107         $ldap->cd($basedn);
1108         $ldap->create_missing_trees($destinationdn);
1109         $ldap->cd($destinationdn);
1111         /* If is first entry, append FAIbranch to department entry */
1112         if($is_first){
1113           $ldap->cat($destinationdn);
1114           $attr= $ldap->fetch();
1115           /* Filter unneeded informations */
1116           foreach($attr as $key => $value){
1117             if(is_numeric($key)) unset($attr[$key]);
1118             if(isset($attr[$key]['count'])){
1119               if(is_array($attr[$key])){
1120                 unset($attr[$key]['count']);
1121               }
1122             }
1123           }
1125           unset($attr['count']);
1126           unset($attr['dn']);
1128           /* Add marking attribute */
1129           $attr['objectClass'][] = "FAIbranch";
1130           $attr['FAIstate'] = $type;
1132           /* Add this entry */
1133           $ldap->modify($attr);
1134         }
1135       }else{
1137         /* Replicate all relevant FAI objects here.
1138          * FAI objects, Apps and Mimetypes.
1139          * Get all attributes as binary value, to ensure that Icon, File template aso
1140          *  are created correctly.
1141          */
1142         foreach($attr as $key => $value){
1144           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1145             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1146             $ei= ldap_first_entry($ldap->cid, $sr);
1147             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1148               $attr[$key] = $tmp;
1149             }
1150           }
1152           if(is_numeric($key)) unset($attr[$key]);
1153           if(isset($attr[$key]['count'])){
1154             if(is_array($attr[$key])){
1155               unset($attr[$key]['count']);
1156             }
1157           }
1158         }
1159         unset($attr['count']);
1160         unset($attr['dn']);
1161         if(!in_array("FAIobject",$attr['objectClass'])){
1162           $attr['objectClass'][] = "FAIobject";
1163         }
1164         $attr['FAIstate'] = $type;
1166         /* Add entry
1167          */
1168         $ldap->cd($destinationdn);
1169         $ldap->cat($destinationdn);
1171         $a = $ldap->fetch();
1172         if(!count($a)){
1173           $ldap->add($attr);
1174         }
1176         if(!$ldap->success()){
1178           /* Some error occurred */
1179           msg_dialog::display(_("Fatal error"),
1180               sprintf(_("Release creation failed due to ldap errors. Additional informations '%s'."),
1181                 $ldap->get_error()."<br>".$sourcedn."<br>".$destinationdn."<br>"),FATAL_ERROR_DIALOG);
1182           exit();
1183         }
1184       }
1185     }
1187     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1189     /* Prepare for recursive copy.
1190      * Get all object within the source dn and
1191      *  call the recursive copy for each.
1192      */
1193     $ldap->ls ("(objectClass=*)",$sourcedn);
1194     while ($ldap->fetch()){
1195       $deldn= $ldap->getDN();
1196       $delarray[$deldn]= strlen($deldn);
1197     }
1198     asort ($delarray);
1199     reset ($delarray);
1200     $depth ++;
1201     foreach($delarray as $dn => $bla){
1202       if($dn != $destinationdn){
1203         $ldap->cd($basedn);
1204         $item = $ldap->fetch($ldap->cat($dn));
1205         if(!in_array("FAIbranch",$item['objectClass'])){
1206           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1207         }
1208       }
1209     }
1210     if($is_first){
1211       echo "<p class='seperator'>&nbsp;</p>";
1212     }
1213   }
1217   /* This function returns the dn of the object release */
1218   static function get_release_dn($Current_DN)
1219   {
1220     global $config;
1221     $ldap = $config->get_ldap_link();
1222     $ldap->cd($config->current['BASE']);
1224     /* Split dn into pices */ 
1225     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".preg_quote(",".$config->current['BASE'], '/')."/i","",$Current_DN));
1227     if(!is_array($dns_to_check)){
1228       return;  
1229     }
1231     /* Use dn pieces, to create sub dns like 
1232        ou=test,ou=1,ou=0...
1233        ou=1,ou=0...
1234        ou=0... 
1235        To check which dn is our release container.
1236      */
1237     unset($dns_to_check['count']); 
1238     while(count($dns_to_check)){
1240       /* Create dn */
1241       $new_dn = "";
1242       foreach($dns_to_check as $part){
1243         $new_dn .= $part.",";
1244       }
1245       $new_dn .= $config->current['BASE'];
1247       /* Check if this dn is a release dn */
1248       if(FAI::is_release_department($new_dn)){
1249         return($new_dn);
1250       }
1252       /* Remove first element of dn pieces */
1253       reset($dns_to_check);
1254       unset($dns_to_check[key($dns_to_check)]);
1255     }
1256     return("");
1257   }
1263 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1264 ?>