Code

Only reload FAI classes, if a class was added or removed
[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   /* Returns all object for the given release.
12      This function resolves the releases  
13      from base up to the given dn.
14    */
15   static function get_all_objects_for_given_base($Current_DN,$filter,$detailed = false)
16   {
17     global $config;
18     $ldap = $config->get_ldap_link();
19     $ldap->cd($config->current['BASE']);
20     $res = array();
21     $tmp = array();
23     if(!FAI::is_release_department($Current_DN)) {
24       return($res);
25     }
27     /* Collect some basic informations and initialize some variables */ 
28     $base_release       = FAI::get_release_dn($Current_DN);
29     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
31     /* We must also include the given release dn */
32     $previous_releases[] = $base_release;
34     /* Walk through all releases */
35     foreach($previous_releases as $release){
37       /* Get fai departments */
38       $deps_to_search = FAI::get_FAI_departments($release); 
40       /* For every single department  (ou=hoos,ou ..) */
41       foreach($deps_to_search as $fai_base){
43         /* Ldap search for fai classes specified in this release */
44         $attributes  = array("dn","objectClass","FAIstate","cn");
45         $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
47         /* check the returned objects, and add/replace them in our return variable */
48         foreach($res_tmp as $attr){
50           $buffer = array();
51           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
53           if(isset($attr['FAIstate'][0])){
54             if(preg_match("/removed$/",$attr['FAIstate'][0])){
55               if(isset($res[$name])){
56                 unset($res[$name]);
57               }
58               continue;
59             }
60           }
62           /* In detailed mode are some additonal informations visible */
63           if($detailed){
65             /* Create list of parents */
66             if(isset($res[$name])){
67               $buffer = $res[$name];
68               $buffer['parents'][] = $res[$name]['dn'];
69             }else{
70               $buffer['parents'] = array();
71             }
73             /* Append objectClass to resulsts */
74             foreach($attributes as $val){
75               if(isset($attr[$val])){
76                 $buffer[$val] = $attr[$val];
77               }
78             }
79             unset($buffer['objectClass']['count']);
80           }
82           /* Add this object to our list */
83           $buffer['dn']           = $attr['dn'];
84           $res[$name] = $buffer;
85         }
86       }
87     }
88     return($res);
89   }
92   /* Return all relevant FAI departments */
93   static function get_FAI_departments($suffix = "")
94   {
95     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
96     $tmp = array();
97     if(preg_match("/^,/",$suffix)){
98       $suffix = preg_replace("/^,/","",$suffix);
99     }
100     foreach($arr as $name){
101       if(empty($suffix)){
102         $tmp[$name] = "ou=".$name;
103       }else{
104         $tmp[$name] = "ou=".$name.",".$suffix;
105       }
106     }
107     return($tmp);
108   }
111   /* Return all releases within the given base */
112   static function get_all_releases_from_base($dn,$appendedName=false)
113   {
114     global $config;
116     if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
117       $base = get_ou('faiou').$dn;
118     }else{
119       $base = $dn;
120     }
121     $res = array();  
123     $ldap = $config->get_ldap_link();
124     $ldap->cd($base);
125     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
126     while($attrs = $ldap->fetch()){
127       if($appendedName){
128         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
129       }else{
130         $res[$attrs['dn']] = $attrs['ou'][0];
131       }
132     }
133     return($res);
134   }
137   /* Add this object to list of objects, that must be checked for release saving */
138   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
139   {
140     /* Get ldap object */  
141     global $config;
142     $addObj['Current_DN'] = $Current_DN;
143     $addObj['objectAttrs']= $objectAttrs;
144     $addObj['removed']    = $removed;
145     $addObj['diff']       = TRUE;
147     if(!$removed){
148       $ldap = $config->get_ldap_link();
149       $ldap->cd($config->current['BASE']);
151       /* Get some basic informations */
152       $parent_obj   = FAI::get_parent_release_object($Current_DN);
153       if(!empty($parent_obj)){
154         $ldap->cat($parent_obj,array("*"));
155         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
157         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
158           $addObj['diff'] = FALSE;
159         }
160       } 
161     }else{
163       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
164           we have to remove this name from all profiles in this release.
165       */
166       $ldap = $config->get_ldap_link();
167       $ldap->cd($config->current['BASE']);
168       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
170       /* Dont't try to modify non FAIclasses  
171        */
172       if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
173         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
174         echo "<br>-->".$Current_DN."<br>";
175         echo "<br>-->".$obj_dn."<br>";
176       }else{
178         /* Get source object and check if it is a base FAIclass
179          */
180         $ldap->cat($obj_dn);
181         $attrs = $ldap->fetch();
182         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
183         if(count(array_intersect($classes,$attrs['objectClass']))){
184           $cn    = $attrs['cn'][0];
186           /* Check if this is the last with this name in the current release.
187               In this case we have to remove the package name 
188               from all profiles in this release.
189            */
190           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
191               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
193           /* Check if this is the last class with this name.
194            */
195           if(count($classes) == 1){
197             /* Get all FAI Profiles 
198              */
199             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
200                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
202             /* Walk though all profiles and remove the source class name
203              */
204             foreach($profiles as $dn){
205               $ldap->cat($dn['dn']);
206               $attrs = $ldap->fetch();
208               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
210               /* Check if this Profile uses the source class ($cn)
211                */
212               if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
213                 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
214                 if(empty($attrs['FAIclass'])){
215                   $attrs['FAIclass'] = array();
216                 }
217                 $ldap->cd($dn['dn']);
218                 $ldap->modify($attrs);
220                 if (!$ldap->success()){
221                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
222                 }
223               }
224             }
225           }
226         }
227       }
228     }
232     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
233     $FAI_objects_to_save[$Current_DN] =  $addObj;
234     session::set('FAI_objects_to_save',$FAI_objects_to_save);
235   }
238   /* Detect differences in attribute arrays  */
239   static function array_diff_FAI($ar1,$ar2)
240   {
242     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
243       $ar1['description'] = "";
244     }
245     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
246       $ar2['description'] = "";
247     }
249     if(count($ar1) != count($ar2)) {
250       return (true);
251     }
253     foreach($ar1 as $key1 => $val1){
255       if((is_array($val1)) && (count($val1)==1)){
256         $ar1[$key1] = $val1[0];
257       }
259       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
260         $val1 = $val1[0];
261         $ar2[$key1] = $ar2[$key1][0];
262       }
263     }
264     ksort($ar1);
265     ksort($ar2);
266     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
267       return(true);
268     }else{
269       return(false);
270     }
271   }
274   static function arr_diff($ar1,$ar2)
275   {
276     foreach($ar1 as $ak1 => $av1){
277       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
278         return(TRUE);    
279       }elseif(is_array($av1)){
280         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
281         if($ret) {
282           return(TRUE);
283         }
284       }
285     }
286     return(FALSE);
287   }
292   /* check which objects must be saved, and save them */
293   static function save_release_changes_now()
294   {
295     global $config;
296     /* Variable init*/
297     $to_save = array();
298     
299     $reload_fai_classes = FALSE;
301     /* check which objects must be saved */
302     $FAI_objects_to_save = session::get('FAI_objects_to_save');
303     if(!is_array($FAI_objects_to_save)) {
304       print_a(array(session::get('FAI_objects_to_save')));
305       trigger_error("Can't save FAI objects, no array given.");
306       return;
307     }
308   
309     foreach($FAI_objects_to_save as $Current_DN => $object){
310       if($object['diff']){
311         $sub_name = $Current_DN;
312         while(isset($FAI_objects_to_save[$sub_name])){
313           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
314           unset($FAI_objects_to_save[$sub_name]);
315           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
316         }
317       }
318     }
319     session::set('FAI_objects_to_save',$FAI_objects_to_save);
321     /* Sort list of objects that must be saved, and ensure that 
322        container   objects are safed, before their childs are saved */
323     ksort($to_save);
324     $tmp = array();
325     foreach($to_save as $SubObjects){
326       foreach($SubObjects as $object){
327         $tmp[] = $object;
328       }
329     }
330     $to_save = $tmp;
333     /* Save objects and manage the correct release behavior*/
334     foreach($to_save as $save){
336       $Current_DN = $save['Current_DN'];
337       $removed    = $save['removed'];
338       $objectAttrs= $save['objectAttrs'];
340       /* Get ldap object */ 
341       $ldap = $config->get_ldap_link();
342       $ldap->cd($config->current['BASE']);
344       /* Get some basic informations */
345       $base_release       = FAI::get_release_dn($Current_DN);
346       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
347       $parent_obj         = FAI::get_parent_release_object($Current_DN);
348       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
350       /* Check if given dn exists or if is a new entry */
351       $ldap->cat($Current_DN);
352       if(!$ldap->count()){
353         $is_new = true;
354       }else{
355         $is_new = false;
356       }
358       /* if parameter removed is true, we have to add FAIstate to the current attrs 
359          FAIstate should end with ...|removed after this operation */  
360       if($removed ){
361         $ldap->cat($Current_DN);
363         /* Get current object, because we must add the FAIstate ...|removed */
364         if((!$ldap->count()) && !empty($parent_obj)){
365           $ldap->cat($parent_obj);
366         }
368         /* Check if we have found a suiteable object */ 
369         if(!$ldap->count()){
370           echo "Error can't remove this object ".$Current_DN;
371           return;
372         }else{
374           /* Set FAIstate to current objectAttrs */
375           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
376           if(isset($objectAttrs['FAIstate'][0])){
377             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
378               $objectAttrs['FAIstate'][0] .= "|removed";
379             }
380           }else{
381             $objectAttrs['FAIstate'][0] = "|removed";
382           }
384           /* Force reload of FAI classes */
385           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
386           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
387             $reload_fai_classes = TRUE;
388           }
389         }
390       }
392       /* Check if this a leaf release or not */ 
393       if(count($following_releases) == 0 ){
395         /* This is a leaf object. It isn't inherited by any other object */    
396         if(DEBUG_FAI_FUNC) { 
397           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
398           print_a($objectAttrs);
399         }
400         FAI::save_FAI_object($Current_DN,$objectAttrs);
402         /* Force reload of FAI classes */
403         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
404         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
405           $reload_fai_classes = TRUE;
406         }
408       }else{
410         /* This object is inherited by some sub releases */  
412         /* Get all releases, that inherit this object */ 
413         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
415         /* Get parent object */
416         $ldap->cat($parent_obj);
417         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
419         /* New objects require special handling */
420         if($is_new){
422           /* Force reload of FAI classes */
423           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
424           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
425             $reload_fai_classes = TRUE;
426           }
428           /* check if there is already an entry named like this,
429              in one of our parent releases */
430           if(!empty($parent_obj)){
431             if(DEBUG_FAI_FUNC) { 
432               echo "There is already an entry named like this.</b><br>";
434               echo "<b>Saving main object</b>".$Current_DN;
435               print_a($objectAttrs);
436             }    
437             FAI::save_FAI_object($Current_DN,$objectAttrs);
439             foreach($r as $key){
440               if(DEBUG_FAI_FUNC) { 
441                 echo "<b>Saving parent to following release</b> ".$key;
442                 print_a($parent_attrs);
443               }
444               FAI::save_FAI_object($key,$parent_attrs);
445             }
446           }else{
448             if(DEBUG_FAI_FUNC) { 
449               echo "<b>Saving main object</b>".$Current_DN;
450               print_a($objectAttrs);
451             }
452             FAI::save_FAI_object($Current_DN,$objectAttrs);
454             if(isset($objectAttrs['FAIstate'])){
455               $objectAttrs['FAIstate'] .= "|removed"; 
456             }else{
457               $objectAttrs['FAIstate'] = "|removed";
458             }
460             foreach($r as $key ){
461               if(DEBUG_FAI_FUNC) { 
462                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
463                 print_a($objectAttrs);
464               }
465               FAI::save_FAI_object($key,$objectAttrs);
466             }
467           }
468         }else{
470           /* check if we must patch the follwing release */
471           if(!empty($r)){
472             foreach($r as $key ){
473               if(DEBUG_FAI_FUNC) { 
474                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
475                 print_a($parent_attrs);
476               }
477               FAI::save_FAI_object($key,$parent_attrs);
478             }
479           }
481           if(DEBUG_FAI_FUNC) { 
482             echo "<b>Saving current object</b>".$parent_obj;
483             print_a($objectAttrs);
484           }
485           FAI::save_FAI_object($parent_obj,$objectAttrs);
487           if(($parent_obj != $Current_DN)){
488             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
489           }
490         }
491       }
492     }
494     /* Reload GOsa si FAI DB/cache
495      */
496     if($reload_fai_classes){
497       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
498         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
499         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
500           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
501           $tmp = new $evt['CLASS_NAME']($config);
502           $tmp->set_type(TRIGGERED_EVENT);
503           $tmp->add_targets(array("GOsa"));
504           $o_queue = new gosaSupportDaemon();
505           if(!$o_queue->append($tmp)){
506             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
507           }
508         }
509       }
510     }
512     session::set('FAI_objects_to_save',array());
513   }
516   /* this function will remove all unused (deleted) objects,
517      that have no parent object */
518   static function clean_up_releases($Current_DN)
519   {
520     global $config;
521     $ldap = $config->get_ldap_link();
522     $ldap->cd($config->current['BASE']);
524     /* Collect some basic informations and initialize some variables */ 
525     $base_release       = FAI::get_release_dn($Current_DN);
526     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
527     $Kill = array();
528     $Skip = array();
530     /* We must also include the given release dn */
531     $previous_releases[] = $base_release;
533     /* Walk through all releases */
534     foreach($previous_releases as $release){
536       /* Get fai departments */
537       $deps_to_search = FAI::get_FAI_departments($release); 
539       /* For every single department  (ou=hoos,ou ..) */
540       foreach($deps_to_search as $fai_base){
542         /* Ldap search for fai classes specified in this release */
543         $ldap->cd($fai_base);
544         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
546         /* check the returned objects, and add/replace them in our return variable */
547         while($attr = $ldap->fetch()){
549           $buffer = array();
550 #        $name = str_ireplace($release,"",$attr['dn']);
551           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
553           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
555             /* Check if this object is required somehow */    
556             if(!isset($Skip[$name])){
557               $Kill[$attr['dn']] = $attr['dn'];
558             }
559           }else{
561             /* This object is required (not removed), so do not 
562                delete any following sub releases of this object */
563             $Skip[$name] = $attr['dn'];
564           }
565         }
566       }
567     }
568     return($Kill);
569   }
572   /* Remove numeric index and 'count' from ldap->fetch result */
573   static function prepare_ldap_fetch_to_be_saved($attrs)
574   {
575     foreach($attrs as $key => $value){
576       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
577         unset($attrs[$key]);
578       }
579       if(is_array($value) && isset($value['count'])){
580         unset($attrs[$key]['count']);
581       }
582     }
583     return($attrs);
584   }
587   /* Save given attrs to specified dn*/
588   static function save_FAI_object($dn,$attrs)
589   {
590     global $config;
591     $ldap = $config->get_ldap_link();
592     $ldap->cd($config->current['BASE']);
593     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
594     $ldap->cd($dn);
596     $ldap->cat($dn,array("dn"));
597     if($ldap->count()){
599       /* Remove FAIstate*/
600       if(!isset($attrs['FAIstate'])){
601         $attrs['FAIstate'] = array();
602       }
604       $ldap->modify($attrs);
605     }else{
607       /* Unset description if empty  */
608       if(empty($attrs['description'])){
609         unset($attrs['description']);
610       }    
612       $ldap->add($attrs);
613     }
614     if (!$ldap->success()){
615       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
616     }
617   }
620   /* Return FAIstate freeze branch or "" for specified release department */
621   static function get_release_tag($dn)
622   {
623     global $config;
624     $ldap = $config->get_ldap_link();
625     $ldap->cd($dn);
626     $ldap->cat($dn,array("FAIstate"));
628     if($ldap->count()){
630       $attr = $ldap->fetch();
631       if(isset($attr['FAIstate'][0])){
632         if(preg_match("/freeze/",$attr['FAIstate'][0])){
633           return("freeze");
634         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
635           return("branch");
636         }
637       }
638     }
639     return("");
640   }
643   static function get_following_releases_that_inherit_this_object($dn)
644   {
645     global $config;
646     $ldap = $config->get_ldap_link();
647     $ldap->cd($config->current['BASE']);
649     $ret = array();
651     /* Get base release */
652     $base_release = FAI::get_release_dn($dn);
654     /* Get previous release dns */
655     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
657     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
658 #  $dn_suffix = str_ireplace($base_release,"",$dn);
659     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
661     /* Check if given object also exists whitin one of these releases */
662     foreach($sub_releases as $p_release => $name){
664       $check_dn = $dn_suffix.$p_release;
666       $ldap->cat($check_dn,array("dn","objectClass"));
668       if($ldap->count()){
669         //return($ret);
670       }else{
671         $ret[$check_dn]=$check_dn;
672       }
673     }
674     return($ret);
675   }
678   /* Get previous version of the object dn */
679   static function get_parent_release_object($dn,$include_myself=true)
680   {
681     global $config;
682     $ldap = $config->get_ldap_link();
683     $ldap->cd($config->current['BASE']);
684     $previous_releases= array();
686     /* Get base release */
687     $base_release = FAI::get_release_dn($dn);
688     if($include_myself){
689       $previous_releases[] = $base_release;  
690     }
692     /* Get previous release dns */
693     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
694     foreach($tmp as $release){
695       $previous_releases[] = $release;
696     }
698     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
699 #  $dn_suffix = str_ireplace($base_release,"",$dn);
700     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
702     /* Check if given object also exists whitin one of these releases */
703     foreach($previous_releases as $p_release){
704       $check_dn = $dn_suffix.$p_release;
705       $ldap->cat($check_dn,array("dn","objectClass"));
707       if($ldap->count()){
708         return($check_dn);
709       }
710     }
711     return("");
712   }
715   /* return release names of all parent releases */
716   static function get_previous_releases_of_this_release($dn,$flat)
717   {
718     global $config;
719     $ldap = $config->get_ldap_link();
720     $ldap->cd($config->current['BASE']);
721     $ret = array();
723     /* Explode dns into pieces, to be able to build parent dns */
724     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
726     if(!is_array($dns_to_check)){
727       return;  
728     }
730     /* Unset first entry which represents the given dn */
731     unset($dns_to_check['count']); 
732     unset($dns_to_check[key($dns_to_check)]);
734     /* Create dns addresses and check if this dn is a release dn */
735     $id = 0;
736     while(count($dns_to_check)){
738       /* build parent dn */
739       $new_dn = "";
740       foreach($dns_to_check as $part){
741         $new_dn .= $part.",";
742       }
743       $new_dn .= $config->current['BASE'];
745       /* check if this dn is a release */
746       if(FAI::is_release_department($new_dn)){
747         if($flat){
748           $ret[$id] = $new_dn; 
749         }else{
750           $ret = array($new_dn=>$ret); 
751         }
752         $id ++;
753       }else{
754         return($ret);
755       }
756       reset($dns_to_check);
757       unset($dns_to_check[key($dns_to_check)]);
758     }
759     return($ret);
760   } 
763   /* This function returns all sub release names, recursivly  */
764   static function get_sub_releases_of_this_release($dn,$flat = false)
765   {
766     global $config;
767     $res  = array();
768     $ldap = $config->get_ldap_link();
769     $ldap->cd($config->current['BASE']);
770     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
771     while($attr = $ldap->fetch()){
773       /* Append department name */
774       if($flat){
775         $res[$attr['dn']] = $attr['ou'][0];
776       }else{
777         $res[$attr['dn']] = array();
778       }
780       /* Get sub release departments of this department */
781       if(in_array("FAIbranch",$attr['objectClass'])) {
782         if($flat){
783           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
784           foreach($tmp as $dn => $value){
785             $res[$dn]=$value;
786           }
787         }else{
788           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
789         }
790       }
791     }
792     return($res);
793   }
796   /* Check if the given department is a release department */
797   static function is_release_department($dn)
798   {
799     global $config;
800     $ldap = $config->get_ldap_link();
801     $ldap->cd($config->current['BASE']);
802     $ldap->cat($dn,array("objectClass","ou"));
804     /* Check objectClasses and name to check if this is a release department */
805     if($ldap->count()){
806       $attrs = $ldap->fetch();
808       $ou = "";
809       if(isset($attrs['ou'][0])){
810         $ou = $attrs['ou'][0];  
811       }
813       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
814         return($attrs['dn']);
815       }
816     }
817     return(false);
818   }
821   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
822   {
823     global $config;
824     $start = microtime(TRUE);
825     $source_release = trim($source_release,"/");
827     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
829     $sub_releases = array();
830     $source_dn = "";
831     
832     $tmp = split("\/",$source_release);
833     foreach($tmp as $part){
834       if(empty($part)){
835         continue;
836       }
837       $source_dn            = "ou=".$part.",".$source_dn;
838       $sub_releases[$part]  = $source_dn;
839     }
841     /* Get all groups */
842     $ldap =$config->get_ldap_link();
843     $ldap->cd($config->current['BASE']);
844     $ldap->search("(objectClass=posixGroup)",array("dn"));
845     $groups = array();
846     while($attrs = $ldap->fetch()){
847       $groups[$attrs['dn']] = $attrs;
848     }
850     /* Get all FAI releases, to be able to create missing group application releases 
851         with the correct type of release (FAIstate=freeze/branch).
852      */
853     $f_releases = array();
854     $ldap->cd ($config->current['BASE']);
855     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
856     while($attrs = $ldap->fetch()){
857       foreach($sub_releases as $sub_rel){
858         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
859           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
860         }
861       }
862     }
864     /* Get all group releases */
865     $g_releases = array();
866     foreach($groups as $dn => $data){
867       $ldap->cd($dn);
868       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
869       while($attrs = $ldap->fetch()){
870         $g_releases[$attrs['dn']] = $attrs;
871       }
872     }
874     /* Check if base releases exists.
875        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
876      */
877     foreach($sub_releases as $name => $sub_rel){
879       $FAIstate = "";
880       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
881         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
882       }
884       foreach($groups as $dn => $data){
885         if(!isset($g_releases[$sub_rel.$dn])){
886           $ldap->cd($dn);
887           $r_data = array();
888           $r_data['ou'] = $name;
889           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
890           if(!empty($FAIstate)) {
891             $r_data['FAIstate'] = $FAIstate;
892           }
893  
894           $ldap->cd($sub_rel.$dn) ;
895           $ldap->add($r_data);
896           echo "&nbsp;<b>"._("Object").":</b> ";
897           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
898           flush();
899         }
900       }
901     } 
902  
903     /* Create new release container in each group.
904      */
905     $n_data = array();
906     $n_data = array();
907     $n_data['ou'] = $destination_name;
908     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
909     if(!empty($type)){
910       $n_data['FAIstate'] = $type."/cow";
911     }
913     foreach($groups as $dn => $att){
914       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
915       if(!isset($g_releases[$n_dn])){
916         $ldap->cd ($n_dn);
917         $ldap->add($n_data);
918         echo "&nbsp;<b>"._("Object").":</b> ";
919         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
920         flush();
921       }
922     }
924     /* If the source release is empty, then create a new release by copying 
925         all group application menus into a new ou=$destination_name release container.
926       
927        If the source release is not empty. 
928          We detect all releases which match the source release dn and copy the contents.
929      */
930     if(empty($source_release)){
931       $source_dns = $groups;
932     }else{
933       $source_dns = array();
934       foreach($g_releases as $dn => $data){
935         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
936           $source_dns[$dn] = $data; 
937         }
938       }
939     }
941     /* Detect all menu object we have to copy 
942      */
943     $to_copy = array();
944     foreach($source_dns as $dn => $attrs){
945       $ldap->cd($dn);
946       $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
947       while($attrs = $ldap->fetch()){
948         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
949         $to_copy[$attrs['dn']] = $destination;
950       }
951     }
952    
953     /* At least create the menu objects object */
954     $plug = new plugin($config);
955     foreach($to_copy as $source => $destination){
956       $ldap->cat($destination);
957       if($ldap->count()){
958         echo "&nbsp;<b>"._("Object").":</b> ";
959         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
960         flush();
961       }else{
962         $plug->copy($source,$destination);
963         echo "&nbsp;<b>"._("Object").":</b> ";
964         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
965         flush();
966       }
967     }
968   }
971   /*! \brief Create a new FAI branch.
972    *  @param $sourcedn          String  The source release dn
973    *  @param $destinationdn     String  The destination dn
974    *  @param $destinationName   String  The name of the new release
975    *  @param $type              String  The release type (freeze/branch)
976    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
977    *  @param $depth             Integer Current depth of recursion.
978    */
979   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
980   {
981     global $config;
982     error_reporting(E_ALL | E_STRICT);
983     $ldap     = $config->get_ldap_link();
984     $basedn   = $config->current['BASE'];
985     $delarray = array();
987     /* The following code will output a status string
988      *  for each handled object, in a seperate iframe.
989      */
992     /* Display current action information.
993      */
994     if($is_first){
995       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
996     }else{
997       if(preg_match("/^ou=/",$sourcedn)){
998         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
999       }else{
1000         $tmp = split(",",$sourcedn);
1001         echo "&nbsp;<b>"._("Object").":</b> ";
1002         $deststr = LDAP::fix($destinationdn);
1003         if(strlen($deststr) > 96){
1004           $deststr = substr($deststr,0,96)."...";
1005         }
1006         echo $deststr."<br>";
1007       }
1008     }
1009     /* .. immediately display infos */
1010     flush();
1012     /* Check if destination entry already exists
1013      */
1014     $ldap->cat($destinationdn);
1015     if($ldap->count()){
1016       echo _("Could not create new release, the destination dn is already in use.");
1017       return;
1018     }else{
1020       $ldap->clearResult();
1022       /* Get source entry
1023        *  if it does not exist, abort here.
1024        */
1025       $ldap->cd($basedn);
1026       $ldap->cat($sourcedn);
1027       $attr = $ldap->fetch();
1028       if((!$attr) || (count($attr)) ==0) {
1029         echo _("Error while fetching source dn - aborted!");
1030         return;
1031       }
1033       /* The current object we want to create is an department.
1034        * Create the department and add the FAIbranch tag.
1035        */
1036       if(in_array("organizationalUnit",$attr['objectClass'])){
1037         $attr['dn'] = LDAP::convert($destinationdn);
1038         $ldap->cd($basedn);
1039         $ldap->create_missing_trees($destinationdn);
1040         $ldap->cd($destinationdn);
1042         /* If is first entry, append FAIbranch to department entry */
1043         if($is_first){
1044           $ldap->cat($destinationdn);
1045           $attr= $ldap->fetch();
1046           /* Filter unneeded informations */
1047           foreach($attr as $key => $value){
1048             if(is_numeric($key)) unset($attr[$key]);
1049             if(isset($attr[$key]['count'])){
1050               if(is_array($attr[$key])){
1051                 unset($attr[$key]['count']);
1052               }
1053             }
1054           }
1056           unset($attr['count']);
1057           unset($attr['dn']);
1059           /* Add marking attribute */
1060           $attr['objectClass'][] = "FAIbranch";
1062           /* Add this entry */
1063           $ldap->modify($attr);
1064         }
1065       }else{
1067         /* Replicate all relevant FAI objects here.
1068          * FAI objects, Apps and Mimetypes.
1069          * Get all attributes as binary value, to ensure that Icon, File template aso
1070          *  are created correctly.
1071          */
1072         foreach($attr as $key => $value){
1074           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1075             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1076             $ei= ldap_first_entry($ldap->cid, $sr);
1077             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1078               $attr[$key] = $tmp;
1079             }
1080           }
1082           if(is_numeric($key)) unset($attr[$key]);
1083           if(isset($attr[$key]['count'])){
1084             if(is_array($attr[$key])){
1085               unset($attr[$key]['count']);
1086             }
1087           }
1088         }
1089         unset($attr['count']);
1090         unset($attr['dn']);
1092         /* Add entry
1093          */
1094         $ldap->cd($destinationdn);
1095         $ldap->cat($destinationdn);
1097         $a = $ldap->fetch();
1098         if(!count($a)){
1099           $ldap->add($attr);
1100         }
1102         if(!$ldap->success()){
1104           /* Some error occurred */
1105           print "---------------------------------------------";
1106           print $ldap->get_error()."<br>";
1107           print $sourcedn."<br>";
1108           print $destinationdn."<br>";
1109           print_a( $attr);
1110           exit();
1111         }
1112       }
1113     }
1115     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1117     /* Prepare for recursive copy.
1118      * Get all object within the source dn and
1119      *  call the recursive copy for each.
1120      */
1121     $ldap->ls ("(objectClass=*)",$sourcedn);
1122     while ($ldap->fetch()){
1123       $deldn= $ldap->getDN();
1124       $delarray[$deldn]= strlen($deldn);
1125     }
1126     asort ($delarray);
1127     reset ($delarray);
1128     $depth ++;
1129     foreach($delarray as $dn => $bla){
1130       if($dn != $destinationdn){
1131         $ldap->cd($basedn);
1132         $item = $ldap->fetch($ldap->cat($dn));
1133         if(!in_array("FAIbranch",$item['objectClass'])){
1134           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1135         }
1136       }
1137     }
1138     if($is_first){
1139       echo "<p class='seperator'>&nbsp;</p>";
1140     }
1141   }
1145   /* This function returns the dn of the object release */
1146   static function get_release_dn($Current_DN)
1147   {
1148     global $config;
1149     $ldap = $config->get_ldap_link();
1150     $ldap->cd($config->current['BASE']);
1152     /* Split dn into pices */ 
1153     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1155     if(!is_array($dns_to_check)){
1156       return;  
1157     }
1159     /* Use dn pieces, to create sub dns like 
1160        ou=test,ou=1,ou=0...
1161        ou=1,ou=0...
1162        ou=0... 
1163        To check which dn is our release container.
1164      */
1165     unset($dns_to_check['count']); 
1166     while(count($dns_to_check)){
1168       /* Create dn */
1169       $new_dn = "";
1170       foreach($dns_to_check as $part){
1171         $new_dn .= $part.",";
1172       }
1173       $new_dn .= $config->current['BASE'];
1175       /* Check if this dn is a release dn */
1176       if(FAI::is_release_department($new_dn)){
1177         return($new_dn);
1178       }
1180       /* Remove first element of dn pieces */
1181       reset($dns_to_check);
1182       unset($dns_to_check[key($dns_to_check)]);
1183     }
1184     return("");
1185   }
1191 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1192 ?>