Code

Updated FAI group release 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   /* 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     }
162     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
163     $FAI_objects_to_save[$Current_DN] =  $addObj;
164     session::set('FAI_objects_to_save',$FAI_objects_to_save);
165   }
168   /* Detect differences in attribute arrays  */
169   static function array_diff_FAI($ar1,$ar2)
170   {
172     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
173       $ar1['description'] = "";
174     }
175     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
176       $ar2['description'] = "";
177     }
179     if(count($ar1) != count($ar2)) {
180       return (true);
181     }
183     foreach($ar1 as $key1 => $val1){
185       if((is_array($val1)) && (count($val1)==1)){
186         $ar1[$key1] = $val1[0];
187       }
189       if((is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
190         $val1 = $val1[0];
191         $ar2[$key1] = $ar2[$key1][0];
192       }
193     }
194     ksort($ar1);
195     ksort($ar2);
196     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
197       return(true);
198     }else{
199       return(false);
200     }
201   }
204   static function arr_diff($ar1,$ar2)
205   {
206     foreach($ar1 as $ak1 => $av1){
207       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
208         return(true);
209       }elseif(is_array($av1)){
210         return(FAI::arr_diff($av1,$ar2[$ak1]));
211       }
212     }
213     return(FALSE);
214   }
219   /* check which objects must be saved, and save them */
220   static function save_release_changes_now()
221   {
222     /* Variable init*/
223     $to_save = array();
225     /* check which objects must be saved */
226     $FAI_objects_to_save = session::get('FAI_objects_to_save');
227     foreach($FAI_objects_to_save as $Current_DN => $object){
228       if($object['diff']){
229         $sub_name = $Current_DN;
230         while(isset($FAI_objects_to_save[$sub_name])){
231           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
232           unset($FAI_objects_to_save[$sub_name]);
233           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
234         }
235       }
236     }
237     session::set('FAI_objects_to_save',$FAI_objects_to_save);
239     /* Sort list of objects that must be saved, and ensure that 
240        container   objects are safed, before their childs are saved */
241     ksort($to_save);
242     $tmp = array();
243     foreach($to_save as $SubObjects){
244       foreach($SubObjects as $object){
245         $tmp[] = $object;
246       }
247     }
248     $to_save = $tmp;
250     /* Save objects and manage the correct release behavior*/
251     foreach($to_save as $save){
253       $Current_DN = $save['Current_DN'];
254       $removed    = $save['removed'];
255       $objectAttrs= $save['objectAttrs'];
257       /* Get ldap object */ 
258       global $config;
259       $ldap = $config->get_ldap_link();
260       $ldap->cd($config->current['BASE']);
262       /* Get some basic informations */
263       $base_release       = FAI::get_release_dn($Current_DN);
264       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
265       $parent_obj         = FAI::get_parent_release_object($Current_DN);
266       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
268       /* Check if given dn exists or if is a new entry */
269       $ldap->cat($Current_DN);
270       if(!$ldap->count()){
271         $is_new = true;
272       }else{
273         $is_new = false;
274       }
276       /* if parameter removed is true, we have to add FAIstate to the current attrs 
277          FAIstate should end with ...|removed after this operation */  
278       if($removed ){
279         $ldap->cat($Current_DN);
281         /* Get current object, because we must add the FAIstate ...|removed */
282         if((!$ldap->count()) && !empty($parent_obj)){
283           $ldap->cat($parent_obj);
284         }
286         /* Check if we have found a suiteable object */ 
287         if(!$ldap->count()){
288           echo "Error can't remove this object ".$Current_DN;
289           return;
290         }else{
292           /* Set FAIstate to current objectAttrs */
293           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
294           if(isset($objectAttrs['FAIstate'][0])){
295             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
296               $objectAttrs['FAIstate'][0] .= "|removed";
297             }
298           }else{
299             $objectAttrs['FAIstate'][0] = "|removed";
300           }
301         }
302       }
304       /* Check if this a leaf release or not */ 
305       if(count($following_releases) == 0 ){
307         /* This is a leaf object. It isn't inherited by any other object */    
308         if(DEBUG_FAI_FUNC) { 
309           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
310           print_a($objectAttrs);
311         }
312         FAI::save_FAI_object($Current_DN,$objectAttrs);
313       }else{
315         /* This object is inherited by some sub releases */  
317         /* Get all releases, that inherit this object */ 
318         $r = get_following_releases_that_inherit_this_object($Current_DN);
320         /* Get parent object */
321         $ldap->cat($parent_obj);
322         $parent_attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
324         /* New objects require special handling */
325         if($is_new){
327           /* check if there is already an entry named like this,
328              in one of our parent releases */
329           if(!empty($parent_obj)){
330             if(DEBUG_FAI_FUNC) { 
331               echo "There is already an entry named like this.</b><br>";
333               echo "<b>Saving main object</b>".$Current_DN;
334               print_a($objectAttrs);
335             }    
336             FAI::save_FAI_object($Current_DN,$objectAttrs);
338             foreach($r as $key){
339               if(DEBUG_FAI_FUNC) { 
340                 echo "<b>Saving parent to following release</b> ".$key;
341                 print_a($parent_attrs);
342               }
343               FAI::save_FAI_object($key,$parent_attrs);
344             }
345           }else{
347             if(DEBUG_FAI_FUNC) { 
348               echo "<b>Saving main object</b>".$Current_DN;
349               print_a($objectAttrs);
350             }
351             FAI::save_FAI_object($Current_DN,$objectAttrs);
353             if(isset($objectAttrs['FAIstate'])){
354               $objectAttrs['FAIstate'] .= "|removed"; 
355             }else{
356               $objectAttrs['FAIstate'] = "|removed";
357             }
359             foreach($r as $key ){
360               if(DEBUG_FAI_FUNC) { 
361                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
362                 print_a($objectAttrs);
363               }
364               FAI::save_FAI_object($key,$objectAttrs);
365             }
366           }
367         }else{
369           /* check if we must patch the follwing release */
370           if(!empty($r)){
371             foreach($r as $key ){
372               if(DEBUG_FAI_FUNC) { 
373                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
374                 print_a($parent_attrs);
375               }
376               FAI::save_FAI_object($key,$parent_attrs);
377             }
378           }
380           if(DEBUG_FAI_FUNC) { 
381             echo "<b>Saving current object</b>".$parent_obj;
382             print_a($objectAttrs);
383           }
384           FAI::save_FAI_object($parent_obj,$objectAttrs);
386           if(($parent_obj != $Current_DN)){
387             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
388           }
389         }
390       }
391     } 
392     session::set('FAI_objects_to_save',array());
393   }
396   /* this function will remove all unused (deleted) objects,
397      that have no parent object */
398   static function clean_up_releases($Current_DN)
399   {
400     global $config;
401     $ldap = $config->get_ldap_link();
402     $ldap->cd($config->current['BASE']);
404     /* Collect some basic informations and initialize some variables */ 
405     $base_release       = FAI::get_release_dn($Current_DN);
406     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
407     $Kill = array();
408     $Skip = array();
410     /* We must also include the given release dn */
411     $previous_releases[] = $base_release;
413     /* Walk through all releases */
414     foreach($previous_releases as $release){
416       /* Get fai departments */
417       $deps_to_search = FAI::get_FAI_departments($release); 
419       /* For every single department  (ou=hoos,ou ..) */
420       foreach($deps_to_search as $fai_base){
422         /* Ldap search for fai classes specified in this release */
423         $ldap->cd($fai_base);
424         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
426         /* check the returned objects, and add/replace them in our return variable */
427         while($attr = $ldap->fetch()){
429           $buffer = array();
430 #        $name = str_ireplace($release,"",$attr['dn']);
431           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
433           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
435             /* Check if this object is required somehow */    
436             if(!isset($Skip[$name])){
437               $Kill[$attr['dn']] = $attr['dn'];
438             }
439           }else{
441             /* This object is required (not removed), so do not 
442                delete any following sub releases of this object */
443             $Skip[$name] = $attr['dn'];
444           }
445         }
446       }
447     }
448     return($Kill);
449   }
452   /* Remove numeric index and 'count' from ldap->fetch result */
453   static function prepare_ldap_fetch_to_be_saved($attrs)
454   {
455     foreach($attrs as $key => $value){
456       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
457         unset($attrs[$key]);
458       }
459       if(is_array($value) && isset($value['count'])){
460         unset($attrs[$key]['count']);
461       }
462     }
463     return($attrs);
464   }
467   /* Save given attrs to specified dn*/
468   static function save_FAI_object($dn,$attrs)
469   {
470     global $config;
471     $ldap = $config->get_ldap_link();
472     $ldap->cd($config->current['BASE']);
473     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
474     $ldap->cd($dn);
476     $ldap->cat($dn,array("dn"));
477     if($ldap->count()){
479       /* Remove FAIstate*/
480       if(!isset($attrs['FAIstate'])){
481         $attrs['FAIstate'] = array();
482       }
484       $ldap->modify($attrs);
485     }else{
487       /* Unset description if empty  */
488       if(empty($attrs['description'])){
489         unset($attrs['description']);
490       }    
492       $ldap->add($attrs);
493     }
494     show_ldap_error($ldap->get_error(),sprintf(_("Release management failed, can't save '%s'"),$dn));
495   }
498   /* Return FAIstate freeze branch or "" for specified release department */
499   static function get_release_tag($dn)
500   {
501     global $config;
502     $ldap = $config->get_ldap_link();
503     $ldap->cd($dn);
504     $ldap->cat($dn,array("FAIstate"));
506     if($ldap->count()){
508       $attr = $ldap->fetch();
509       if(isset($attr['FAIstate'][0])){
510         if(preg_match("/freeze/",$attr['FAIstate'][0])){
511           return("freeze");
512         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
513           return("branch");
514         }
515       }
516     }
517     return("");
518   }
521   static function get_following_releases_that_inherit_this_object($dn)
522   {
523     global $config;
524     $ldap = $config->get_ldap_link();
525     $ldap->cd($config->current['BASE']);
527     $ret = array();
529     /* Get base release */
530     $base_release = FAI::get_release_dn($dn);
532     /* Get previous release dns */
533     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
535     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
536 #  $dn_suffix = str_ireplace($base_release,"",$dn);
537     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
539     /* Check if given object also exists whitin one of these releases */
540     foreach($sub_releases as $p_release => $name){
542       $check_dn = $dn_suffix.$p_release;
544       $ldap->cat($check_dn,array("dn","objectClass"));
546       if($ldap->count()){
547         //return($ret);
548       }else{
549         $ret[$check_dn]=$check_dn;
550       }
551     }
552     return($ret);
553   }
556   /* Get previous version of the object dn */
557   static function get_parent_release_object($dn,$include_myself=true)
558   {
559     global $config;
560     $ldap = $config->get_ldap_link();
561     $ldap->cd($config->current['BASE']);
562     $previous_releases= array();
564     /* Get base release */
565     $base_release = FAI::get_release_dn($dn);
566     if($include_myself){
567       $previous_releases[] = $base_release;  
568     }
570     /* Get previous release dns */
571     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
572     foreach($tmp as $release){
573       $previous_releases[] = $release;
574     }
576     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
577 #  $dn_suffix = str_ireplace($base_release,"",$dn);
578     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
580     /* Check if given object also exists whitin one of these releases */
581     foreach($previous_releases as $p_release){
582       $check_dn = $dn_suffix.$p_release;
583       $ldap->cat($check_dn,array("dn","objectClass"));
585       if($ldap->count()){
586         return($check_dn);
587       }
588     }
589     return("");
590   }
593   /* return release names of all parent releases */
594   static function get_previous_releases_of_this_release($dn,$flat)
595   {
596     global $config;
597     $ldap = $config->get_ldap_link();
598     $ldap->cd($config->current['BASE']);
599     $ret = array();
601     /* Explode dns into pieces, to be able to build parent dns */
602     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
604     if(!is_array($dns_to_check)){
605       return;  
606     }
608     /* Unset first entry which represents the given dn */
609     unset($dns_to_check['count']); 
610     unset($dns_to_check[key($dns_to_check)]);
612     /* Create dns addresses and check if this dn is a release dn */
613     $id = 0;
614     while(count($dns_to_check)){
616       /* build parent dn */
617       $new_dn = "";
618       foreach($dns_to_check as $part){
619         $new_dn .= $part.",";
620       }
621       $new_dn .= $config->current['BASE'];
623       /* check if this dn is a release */
624       if(FAI::is_release_department($new_dn)){
625         if($flat){
626           $ret[$id] = $new_dn; 
627         }else{
628           $ret = array($new_dn=>$ret); 
629         }
630         $id ++;
631       }else{
632         return($ret);
633       }
634       reset($dns_to_check);
635       unset($dns_to_check[key($dns_to_check)]);
636     }
637     return($ret);
638   } 
641   /* This function returns all sub release names, recursivly  */
642   static function get_sub_releases_of_this_release($dn,$flat = false)
643   {
644     global $config;
645     $res  = array();
646     $ldap = $config->get_ldap_link();
647     $ldap->cd($config->current['BASE']);
648     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
649     while($attr = $ldap->fetch()){
651       /* Append department name */
652       if($flat){
653         $res[$attr['dn']] = $attr['ou'][0];
654       }else{
655         $res[$attr['dn']] = array();
656       }
658       /* Get sub release departments of this department */
659       if(in_array("FAIbranch",$attr['objectClass'])) {
660         if($flat){
661           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
662           foreach($tmp as $dn => $value){
663             $res[$dn]=$value;
664           }
665         }else{
666           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
667         }
668       }
669     }
670     return($res);
671   }
674   /* Check if the given department is a release department */
675   static function is_release_department($dn)
676   {
677     global $config;
678     $ldap = $config->get_ldap_link();
679     $ldap->cd($config->current['BASE']);
680     $ldap->cat($dn,array("objectClass","ou"));
682     /* Check objectClasses and name to check if this is a release department */
683     if($ldap->count()){
684       $attrs = $ldap->fetch();
686       $ou = "";
687       if(isset($attrs['ou'][0])){
688         $ou = $attrs['ou'][0];  
689       }
691       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
692         return($attrs['dn']);
693       }
694     }
695     return(false);
696   }
699   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
700   {
701     global $config;
702     $start = microtime(TRUE);
703     $source_release = trim($source_release,"/");
705     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
707     $sub_releases = array();
708     $source_dn = "";
709     
710     $tmp = split("\/",$source_release);
711     foreach($tmp as $part){
712       if(empty($part)){
713         continue;
714       }
715       $source_dn            = "ou=".$part.",".$source_dn;
716       $sub_releases[$part]  = $source_dn;
717     }
719     /* Get all groups */
720     $ldap =$config->get_ldap_link();
721     $ldap->cd($config->current['BASE']);
722     $ldap->search("(objectClass=posixGroup)",array("dn"));
723     $groups = array();
724     while($attrs = $ldap->fetch()){
725       $groups[$attrs['dn']] = $attrs;
726     }
728     /* Get all FAI releases, to be able to create missing group application releases 
729         with the correct type of release (FAIstate=freeze/branch).
730      */
731     $f_releases = array();
732     $ldap->cd ($config->current['BASE']);
733     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
734     while($attrs = $ldap->fetch()){
735       foreach($sub_releases as $sub_rel){
736         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
737           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
738         }
739       }
740     }
742     /* Get all group releases */
743     $g_releases = array();
744     foreach($groups as $dn => $data){
745       $ldap->cd($dn);
746       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
747       while($attrs = $ldap->fetch()){
748         $g_releases[$attrs['dn']] = $attrs;
749       }
750     }
752     /* Check if base releases exists.
753        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
754      */
755     foreach($sub_releases as $name => $sub_rel){
757       $FAIstate = "";
758       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
759         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
760       }
762       foreach($groups as $dn => $data){
763         if(!isset($g_releases[$sub_rel.$dn])){
764           $ldap->cd($dn);
765           $r_data = array();
766           $r_data['ou'] = $name;
767           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
768           if(!empty($FAIstate)) {
769             $r_data['FAIstate'] = $FAIstate;
770           }
771  
772           $ldap->cd($sub_rel.$dn) ;
773           $ldap->add($r_data);
774           echo "&nbsp;<b>"._("Object").":</b> ";
775           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
776           flush();
777         }
778       }
779     } 
780  
781     /* Create new release container in each group.
782      */
783     $n_data = array();
784     $n_data = array();
785     $n_data['ou'] = $destination_name;
786     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
787     if(!empty($type)){
788       $n_data['FAIstate'] = $type;
789     }
791     foreach($groups as $dn => $att){
792       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
793       if(!isset($g_releases[$n_dn])){
794         $ldap->cd ($n_dn);
795         $ldap->add($n_data);
796         echo "&nbsp;<b>"._("Object").":</b> ";
797         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
798         flush();
799       }
800     }
802     /* If the source release is empty, then create a new release by copying 
803         all group application menus into a new ou=$destination_name release container.
804       
805        If the source release is not empty. 
806          We detect all releases which match the source release dn and copy the contents.
807      */
808     if(empty($source_release)){
809       $source_dns = $groups;
810     }else{
811       $source_dns = array();
812       foreach($g_releases as $dn => $data){
813         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
814           $source_dns[$dn] = $data; 
815         }
816       }
817     }
819     /* Detect all menu object we have to copy 
820      */
821     $to_copy = array();
822     foreach($source_dns as $dn => $attrs){
823       $ldap->cd($dn);
824       $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
825       while($attrs = $ldap->fetch()){
826         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
827         $to_copy[$attrs['dn']] = $destination;
828       }
829     }
830    
831     /* At least create the menu objects object */
832     $plug = new plugin($config);
833     foreach($to_copy as $source => $destination){
834       $ldap->cat($destination);
835       if($ldap->count()){
836         echo "&nbsp;<b>"._("Object").":</b> ";
837         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
838         flush();
839       }else{
840         $plug->copy($source,$destination);
841         echo "&nbsp;<b>"._("Object").":</b> ";
842         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
843         flush();
844       }
845     }
846   }
849   /*! \brief Create a new FAI branch.
850    *  @param $sourcedn          String  The source release dn
851    *  @param $destinationdn     String  The destination dn
852    *  @param $destinationName   String  The name of the new release
853    *  @param $type              String  The release type (freeze/branch)
854    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
855    *  @param $depth             Integer Current depth of recursion.
856    */
857   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
858   {
859     global $config;
860     error_reporting(E_ALL | E_STRICT);
861     $ldap     = $config->get_ldap_link();
862     $basedn   = $config->current['BASE'];
863     $delarray = array();
865     /* The following code will output a status string
866      *  for each handled object, in a seperate iframe.
867      */
870     /* Display current action information.
871      */
872     if($is_first){
873       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
874     }else{
875       if(preg_match("/^ou=/",$sourcedn)){
876         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
877       }else{
878         $tmp = split(",",$sourcedn);
879         echo "&nbsp;<b>"._("Object").":</b> ";
880         $deststr = LDAP::fix($destinationdn);
881         if(strlen($deststr) > 96){
882           $deststr = substr($deststr,0,96)."...";
883         }
884         echo $deststr."<br>";
885       }
886     }
887     /* .. immediately display infos */
888     flush();
890     /* Check if destination entry already exists
891      */
892     $ldap->cat($destinationdn);
893     if($ldap->count()){
894       echo _("Could not create new release, the destination dn is already in use.");
895       return;
896     }else{
898       $ldap->clearResult();
900       /* Get source entry
901        *  if it does not exist, abort here.
902        */
903       $ldap->cd($basedn);
904       $ldap->cat($sourcedn);
905       $attr = $ldap->fetch();
906       if((!$attr) || (count($attr)) ==0) {
907         echo _("Error while fetching source dn - aborted!");
908         return;
909       }
911       /* The current object we want to create is an department.
912        * Create the department and add the FAIbranch tag.
913        */
914       if(in_array("organizationalUnit",$attr['objectClass'])){
915         $attr['dn'] = LDAP::convert($destinationdn);
916         $ldap->cd($basedn);
917         $ldap->create_missing_trees($destinationdn);
918         $ldap->cd($destinationdn);
920         /* If is first entry, append FAIbranch to department entry */
921         if($is_first){
922           $ldap->cat($destinationdn);
923           $attr= $ldap->fetch();
924           /* Filter unneeded informations */
925           foreach($attr as $key => $value){
926             if(is_numeric($key)) unset($attr[$key]);
927             if(isset($attr[$key]['count'])){
928               if(is_array($attr[$key])){
929                 unset($attr[$key]['count']);
930               }
931             }
932           }
934           unset($attr['count']);
935           unset($attr['dn']);
937           /* Add marking attribute */
938           $attr['objectClass'][] = "FAIbranch";
940           /* Add this entry */
941           $ldap->modify($attr);
942         }
943       }else{
945         /* Replicate all relevant FAI objects here.
946          * FAI objects, Apps and Mimetypes.
947          * Get all attributes as binary value, to ensure that Icon, File template aso
948          *  are created correctly.
949          */
950         foreach($attr as $key => $value){
952           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
953             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
954             $ei= ldap_first_entry($ldap->cid, $sr);
955             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
956               $attr[$key] = $tmp;
957             }
958           }
960           if(is_numeric($key)) unset($attr[$key]);
961           if(isset($attr[$key]['count'])){
962             if(is_array($attr[$key])){
963               unset($attr[$key]['count']);
964             }
965           }
966         }
967         unset($attr['count']);
968         unset($attr['dn']);
970         /* Add entry
971          */
972         $ldap->cd($destinationdn);
973         $ldap->cat($destinationdn);
975         $a = $ldap->fetch();
976         if(!count($a)){
977           $ldap->add($attr);
978         }
980         if($ldap->error != "Success"){
982           /* Some error occurred */
983           print "---------------------------------------------";
984           print $ldap->get_error()."<br>";
985           print $sourcedn."<br>";
986           print $destinationdn."<br>";
987           print_a( $attr);
988           exit();
989         }
990       }
991     }
993     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
995     /* Prepare for recursive copy.
996      * Get all object within the source dn and
997      *  call the recursive copy for each.
998      */
999     $ldap->ls ("(objectClass=*)",$sourcedn);
1000     while ($ldap->fetch()){
1001       $deldn= $ldap->getDN();
1002       $delarray[$deldn]= strlen($deldn);
1003     }
1004     asort ($delarray);
1005     reset ($delarray);
1006     $depth ++;
1007     foreach($delarray as $dn => $bla){
1008       if($dn != $destinationdn){
1009         $ldap->cd($basedn);
1010         $item = $ldap->fetch($ldap->cat($dn));
1011         if(!in_array("FAIbranch",$item['objectClass'])){
1012           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1013         }
1014       }
1015     }
1016     if($is_first){
1017       echo "<p class='seperator'>&nbsp;</p>";
1018     }
1019   }
1023   /* This function returns the dn of the object release */
1024   static function get_release_dn($Current_DN)
1025   {
1026     global $config;
1027     $ldap = $config->get_ldap_link();
1028     $ldap->cd($config->current['BASE']);
1030     /* Split dn into pices */ 
1031     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1033     if(!is_array($dns_to_check)){
1034       return;  
1035     }
1037     /* Use dn pieces, to create sub dns like 
1038        ou=test,ou=1,ou=0...
1039        ou=1,ou=0...
1040        ou=0... 
1041        To check which dn is our release container.
1042      */
1043     unset($dns_to_check['count']); 
1044     while(count($dns_to_check)){
1046       /* Create dn */
1047       $new_dn = "";
1048       foreach($dns_to_check as $part){
1049         $new_dn .= $part.",";
1050       }
1051       $new_dn .= $config->current['BASE'];
1053       /* Check if this dn is a release dn */
1054       if(FAI::is_release_department($new_dn)){
1055         return($new_dn);
1056       }
1058       /* Remove first element of dn pieces */
1059       reset($dns_to_check);
1060       unset($dns_to_check[key($dns_to_check)]);
1061     }
1062     return("");
1063   }
1069 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1070 ?>