Code

73848e7faf953ebd55959eb828532ea4cb0bdcc8
[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         echo "PLEASE check fai class handling in ".__LINE__." -> ".__FILE__;        
174       }else{
176         /* Get source object and check if it is a base FAIclass
177          */
178         $ldap->cat($obj_dn);
179         $attrs = $ldap->fetch();
180         $classes = array("FAIprofile","FAIscript","FAIpackage","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
181         if(count(array_intersect($classes,$attrs['objectClass']))){
182           $cn    = $attrs['cn'][0];
184           /* Check if this is the last with this name in the current release.
185               In this case we have to remove the package name 
186               from all profiles in this release.
187            */
188           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
189               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
191           /* Check if this is the last class with this name.
192            */
193           if(count($classes) == 1){
195             /* Get all FAI Profiles 
196              */
197             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
198                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
200             /* Walk though all profiles and remove the source class name
201              */
202             foreach($profiles as $dn){
203               $ldap->cat($dn['dn']);
204               $attrs = $ldap->fetch();
206               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
208               /* Check if this Profile uses the source class ($cn)
209                */
210               if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
211                 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
212                 if(empty($attrs['FAIclass'])){
213                   $attrs['FAIclass'] = array();
214                 }
215                 $ldap->cd($dn['dn']);
216                 $ldap->modify($attrs);
218                 if (!$ldap->success()){
219                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
220                 }
221               }
222             }
223           }
224         }
225       }
226     }
230     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
231     $FAI_objects_to_save[$Current_DN] =  $addObj;
232     session::set('FAI_objects_to_save',$FAI_objects_to_save);
233   }
236   /* Detect differences in attribute arrays  */
237   static function array_diff_FAI($ar1,$ar2)
238   {
240     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
241       $ar1['description'] = "";
242     }
243     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
244       $ar2['description'] = "";
245     }
247     if(count($ar1) != count($ar2)) {
248       return (true);
249     }
251     foreach($ar1 as $key1 => $val1){
253       if((is_array($val1)) && (count($val1)==1)){
254         $ar1[$key1] = $val1[0];
255       }
257       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
258         $val1 = $val1[0];
259         $ar2[$key1] = $ar2[$key1][0];
260       }
261     }
262     ksort($ar1);
263     ksort($ar2);
264     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
265       return(true);
266     }else{
267       return(false);
268     }
269   }
272   static function arr_diff($ar1,$ar2)
273   {
274     foreach($ar1 as $ak1 => $av1){
275       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
276         return(true);
277       }elseif(is_array($av1)){
278         return(FAI::arr_diff($av1,$ar2[$ak1]));
279       }
280     }
281     return(FALSE);
282   }
287   /* check which objects must be saved, and save them */
288   static function save_release_changes_now()
289   {
290     /* Variable init*/
291     $to_save = array();
293     /* check which objects must be saved */
294     $FAI_objects_to_save = session::get('FAI_objects_to_save');
295     foreach($FAI_objects_to_save as $Current_DN => $object){
296       if($object['diff']){
297         $sub_name = $Current_DN;
298         while(isset($FAI_objects_to_save[$sub_name])){
299           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
300           unset($FAI_objects_to_save[$sub_name]);
301           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
302         }
303       }
304     }
305     session::set('FAI_objects_to_save',$FAI_objects_to_save);
307     /* Sort list of objects that must be saved, and ensure that 
308        container   objects are safed, before their childs are saved */
309     ksort($to_save);
310     $tmp = array();
311     foreach($to_save as $SubObjects){
312       foreach($SubObjects as $object){
313         $tmp[] = $object;
314       }
315     }
316     $to_save = $tmp;
318     /* Save objects and manage the correct release behavior*/
319     foreach($to_save as $save){
321       $Current_DN = $save['Current_DN'];
322       $removed    = $save['removed'];
323       $objectAttrs= $save['objectAttrs'];
325       /* Get ldap object */ 
326       global $config;
327       $ldap = $config->get_ldap_link();
328       $ldap->cd($config->current['BASE']);
330       /* Get some basic informations */
331       $base_release       = FAI::get_release_dn($Current_DN);
332       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
333       $parent_obj         = FAI::get_parent_release_object($Current_DN);
334       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
336       /* Check if given dn exists or if is a new entry */
337       $ldap->cat($Current_DN);
338       if(!$ldap->count()){
339         $is_new = true;
340       }else{
341         $is_new = false;
342       }
344       /* if parameter removed is true, we have to add FAIstate to the current attrs 
345          FAIstate should end with ...|removed after this operation */  
346       if($removed ){
347         $ldap->cat($Current_DN);
349         /* Get current object, because we must add the FAIstate ...|removed */
350         if((!$ldap->count()) && !empty($parent_obj)){
351           $ldap->cat($parent_obj);
352         }
354         /* Check if we have found a suiteable object */ 
355         if(!$ldap->count()){
356           echo "Error can't remove this object ".$Current_DN;
357           return;
358         }else{
360           /* Set FAIstate to current objectAttrs */
361           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
362           if(isset($objectAttrs['FAIstate'][0])){
363             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
364               $objectAttrs['FAIstate'][0] .= "|removed";
365             }
366           }else{
367             $objectAttrs['FAIstate'][0] = "|removed";
368           }
369         }
370       }
372       /* Check if this a leaf release or not */ 
373       if(count($following_releases) == 0 ){
375         /* This is a leaf object. It isn't inherited by any other object */    
376         if(DEBUG_FAI_FUNC) { 
377           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
378           print_a($objectAttrs);
379         }
380         FAI::save_FAI_object($Current_DN,$objectAttrs);
381       }else{
383         /* This object is inherited by some sub releases */  
385         /* Get all releases, that inherit this object */ 
386         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
388         /* Get parent object */
389         $ldap->cat($parent_obj);
390         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
392         /* New objects require special handling */
393         if($is_new){
395           /* check if there is already an entry named like this,
396              in one of our parent releases */
397           if(!empty($parent_obj)){
398             if(DEBUG_FAI_FUNC) { 
399               echo "There is already an entry named like this.</b><br>";
401               echo "<b>Saving main object</b>".$Current_DN;
402               print_a($objectAttrs);
403             }    
404             FAI::save_FAI_object($Current_DN,$objectAttrs);
406             foreach($r as $key){
407               if(DEBUG_FAI_FUNC) { 
408                 echo "<b>Saving parent to following release</b> ".$key;
409                 print_a($parent_attrs);
410               }
411               FAI::save_FAI_object($key,$parent_attrs);
412             }
413           }else{
415             if(DEBUG_FAI_FUNC) { 
416               echo "<b>Saving main object</b>".$Current_DN;
417               print_a($objectAttrs);
418             }
419             FAI::save_FAI_object($Current_DN,$objectAttrs);
421             if(isset($objectAttrs['FAIstate'])){
422               $objectAttrs['FAIstate'] .= "|removed"; 
423             }else{
424               $objectAttrs['FAIstate'] = "|removed";
425             }
427             foreach($r as $key ){
428               if(DEBUG_FAI_FUNC) { 
429                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
430                 print_a($objectAttrs);
431               }
432               FAI::save_FAI_object($key,$objectAttrs);
433             }
434           }
435         }else{
437           /* check if we must patch the follwing release */
438           if(!empty($r)){
439             foreach($r as $key ){
440               if(DEBUG_FAI_FUNC) { 
441                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
442                 print_a($parent_attrs);
443               }
444               FAI::save_FAI_object($key,$parent_attrs);
445             }
446           }
448           if(DEBUG_FAI_FUNC) { 
449             echo "<b>Saving current object</b>".$parent_obj;
450             print_a($objectAttrs);
451           }
452           FAI::save_FAI_object($parent_obj,$objectAttrs);
454           if(($parent_obj != $Current_DN)){
455             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
456           }
457         }
458       }
459     } 
460     session::set('FAI_objects_to_save',array());
461   }
464   /* this function will remove all unused (deleted) objects,
465      that have no parent object */
466   static function clean_up_releases($Current_DN)
467   {
468     global $config;
469     $ldap = $config->get_ldap_link();
470     $ldap->cd($config->current['BASE']);
472     /* Collect some basic informations and initialize some variables */ 
473     $base_release       = FAI::get_release_dn($Current_DN);
474     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
475     $Kill = array();
476     $Skip = array();
478     /* We must also include the given release dn */
479     $previous_releases[] = $base_release;
481     /* Walk through all releases */
482     foreach($previous_releases as $release){
484       /* Get fai departments */
485       $deps_to_search = FAI::get_FAI_departments($release); 
487       /* For every single department  (ou=hoos,ou ..) */
488       foreach($deps_to_search as $fai_base){
490         /* Ldap search for fai classes specified in this release */
491         $ldap->cd($fai_base);
492         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
494         /* check the returned objects, and add/replace them in our return variable */
495         while($attr = $ldap->fetch()){
497           $buffer = array();
498 #        $name = str_ireplace($release,"",$attr['dn']);
499           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
501           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
503             /* Check if this object is required somehow */    
504             if(!isset($Skip[$name])){
505               $Kill[$attr['dn']] = $attr['dn'];
506             }
507           }else{
509             /* This object is required (not removed), so do not 
510                delete any following sub releases of this object */
511             $Skip[$name] = $attr['dn'];
512           }
513         }
514       }
515     }
516     return($Kill);
517   }
520   /* Remove numeric index and 'count' from ldap->fetch result */
521   static function prepare_ldap_fetch_to_be_saved($attrs)
522   {
523     foreach($attrs as $key => $value){
524       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
525         unset($attrs[$key]);
526       }
527       if(is_array($value) && isset($value['count'])){
528         unset($attrs[$key]['count']);
529       }
530     }
531     return($attrs);
532   }
535   /* Save given attrs to specified dn*/
536   static function save_FAI_object($dn,$attrs)
537   {
538     global $config;
539     $ldap = $config->get_ldap_link();
540     $ldap->cd($config->current['BASE']);
541     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
542     $ldap->cd($dn);
544     $ldap->cat($dn,array("dn"));
545     if($ldap->count()){
547       /* Remove FAIstate*/
548       if(!isset($attrs['FAIstate'])){
549         $attrs['FAIstate'] = array();
550       }
552       $ldap->modify($attrs);
553     }else{
555       /* Unset description if empty  */
556       if(empty($attrs['description'])){
557         unset($attrs['description']);
558       }    
560       $ldap->add($attrs);
561     }
562     if (!$ldap->success()){
563       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
564     }
565   }
568   /* Return FAIstate freeze branch or "" for specified release department */
569   static function get_release_tag($dn)
570   {
571     global $config;
572     $ldap = $config->get_ldap_link();
573     $ldap->cd($dn);
574     $ldap->cat($dn,array("FAIstate"));
576     if($ldap->count()){
578       $attr = $ldap->fetch();
579       if(isset($attr['FAIstate'][0])){
580         if(preg_match("/freeze/",$attr['FAIstate'][0])){
581           return("freeze");
582         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
583           return("branch");
584         }
585       }
586     }
587     return("");
588   }
591   static function get_following_releases_that_inherit_this_object($dn)
592   {
593     global $config;
594     $ldap = $config->get_ldap_link();
595     $ldap->cd($config->current['BASE']);
597     $ret = array();
599     /* Get base release */
600     $base_release = FAI::get_release_dn($dn);
602     /* Get previous release dns */
603     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
605     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
606 #  $dn_suffix = str_ireplace($base_release,"",$dn);
607     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
609     /* Check if given object also exists whitin one of these releases */
610     foreach($sub_releases as $p_release => $name){
612       $check_dn = $dn_suffix.$p_release;
614       $ldap->cat($check_dn,array("dn","objectClass"));
616       if($ldap->count()){
617         //return($ret);
618       }else{
619         $ret[$check_dn]=$check_dn;
620       }
621     }
622     return($ret);
623   }
626   /* Get previous version of the object dn */
627   static function get_parent_release_object($dn,$include_myself=true)
628   {
629     global $config;
630     $ldap = $config->get_ldap_link();
631     $ldap->cd($config->current['BASE']);
632     $previous_releases= array();
634     /* Get base release */
635     $base_release = FAI::get_release_dn($dn);
636     if($include_myself){
637       $previous_releases[] = $base_release;  
638     }
640     /* Get previous release dns */
641     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
642     foreach($tmp as $release){
643       $previous_releases[] = $release;
644     }
646     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
647 #  $dn_suffix = str_ireplace($base_release,"",$dn);
648     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
650     /* Check if given object also exists whitin one of these releases */
651     foreach($previous_releases as $p_release){
652       $check_dn = $dn_suffix.$p_release;
653       $ldap->cat($check_dn,array("dn","objectClass"));
655       if($ldap->count()){
656         return($check_dn);
657       }
658     }
659     return("");
660   }
663   /* return release names of all parent releases */
664   static function get_previous_releases_of_this_release($dn,$flat)
665   {
666     global $config;
667     $ldap = $config->get_ldap_link();
668     $ldap->cd($config->current['BASE']);
669     $ret = array();
671     /* Explode dns into pieces, to be able to build parent dns */
672     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
674     if(!is_array($dns_to_check)){
675       return;  
676     }
678     /* Unset first entry which represents the given dn */
679     unset($dns_to_check['count']); 
680     unset($dns_to_check[key($dns_to_check)]);
682     /* Create dns addresses and check if this dn is a release dn */
683     $id = 0;
684     while(count($dns_to_check)){
686       /* build parent dn */
687       $new_dn = "";
688       foreach($dns_to_check as $part){
689         $new_dn .= $part.",";
690       }
691       $new_dn .= $config->current['BASE'];
693       /* check if this dn is a release */
694       if(FAI::is_release_department($new_dn)){
695         if($flat){
696           $ret[$id] = $new_dn; 
697         }else{
698           $ret = array($new_dn=>$ret); 
699         }
700         $id ++;
701       }else{
702         return($ret);
703       }
704       reset($dns_to_check);
705       unset($dns_to_check[key($dns_to_check)]);
706     }
707     return($ret);
708   } 
711   /* This function returns all sub release names, recursivly  */
712   static function get_sub_releases_of_this_release($dn,$flat = false)
713   {
714     global $config;
715     $res  = array();
716     $ldap = $config->get_ldap_link();
717     $ldap->cd($config->current['BASE']);
718     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
719     while($attr = $ldap->fetch()){
721       /* Append department name */
722       if($flat){
723         $res[$attr['dn']] = $attr['ou'][0];
724       }else{
725         $res[$attr['dn']] = array();
726       }
728       /* Get sub release departments of this department */
729       if(in_array("FAIbranch",$attr['objectClass'])) {
730         if($flat){
731           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
732           foreach($tmp as $dn => $value){
733             $res[$dn]=$value;
734           }
735         }else{
736           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
737         }
738       }
739     }
740     return($res);
741   }
744   /* Check if the given department is a release department */
745   static function is_release_department($dn)
746   {
747     global $config;
748     $ldap = $config->get_ldap_link();
749     $ldap->cd($config->current['BASE']);
750     $ldap->cat($dn,array("objectClass","ou"));
752     /* Check objectClasses and name to check if this is a release department */
753     if($ldap->count()){
754       $attrs = $ldap->fetch();
756       $ou = "";
757       if(isset($attrs['ou'][0])){
758         $ou = $attrs['ou'][0];  
759       }
761       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
762         return($attrs['dn']);
763       }
764     }
765     return(false);
766   }
769   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
770   {
771     global $config;
772     $start = microtime(TRUE);
773     $source_release = trim($source_release,"/");
775     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
777     $sub_releases = array();
778     $source_dn = "";
779     
780     $tmp = split("\/",$source_release);
781     foreach($tmp as $part){
782       if(empty($part)){
783         continue;
784       }
785       $source_dn            = "ou=".$part.",".$source_dn;
786       $sub_releases[$part]  = $source_dn;
787     }
789     /* Get all groups */
790     $ldap =$config->get_ldap_link();
791     $ldap->cd($config->current['BASE']);
792     $ldap->search("(objectClass=posixGroup)",array("dn"));
793     $groups = array();
794     while($attrs = $ldap->fetch()){
795       $groups[$attrs['dn']] = $attrs;
796     }
798     /* Get all FAI releases, to be able to create missing group application releases 
799         with the correct type of release (FAIstate=freeze/branch).
800      */
801     $f_releases = array();
802     $ldap->cd ($config->current['BASE']);
803     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
804     while($attrs = $ldap->fetch()){
805       foreach($sub_releases as $sub_rel){
806         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
807           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
808         }
809       }
810     }
812     /* Get all group releases */
813     $g_releases = array();
814     foreach($groups as $dn => $data){
815       $ldap->cd($dn);
816       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
817       while($attrs = $ldap->fetch()){
818         $g_releases[$attrs['dn']] = $attrs;
819       }
820     }
822     /* Check if base releases exists.
823        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
824      */
825     foreach($sub_releases as $name => $sub_rel){
827       $FAIstate = "";
828       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
829         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
830       }
832       foreach($groups as $dn => $data){
833         if(!isset($g_releases[$sub_rel.$dn])){
834           $ldap->cd($dn);
835           $r_data = array();
836           $r_data['ou'] = $name;
837           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
838           if(!empty($FAIstate)) {
839             $r_data['FAIstate'] = $FAIstate;
840           }
841  
842           $ldap->cd($sub_rel.$dn) ;
843           $ldap->add($r_data);
844           echo "&nbsp;<b>"._("Object").":</b> ";
845           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
846           flush();
847         }
848       }
849     } 
850  
851     /* Create new release container in each group.
852      */
853     $n_data = array();
854     $n_data = array();
855     $n_data['ou'] = $destination_name;
856     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
857     if(!empty($type)){
858       $n_data['FAIstate'] = $type."/cow";
859     }
861     foreach($groups as $dn => $att){
862       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
863       if(!isset($g_releases[$n_dn])){
864         $ldap->cd ($n_dn);
865         $ldap->add($n_data);
866         echo "&nbsp;<b>"._("Object").":</b> ";
867         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
868         flush();
869       }
870     }
872     /* If the source release is empty, then create a new release by copying 
873         all group application menus into a new ou=$destination_name release container.
874       
875        If the source release is not empty. 
876          We detect all releases which match the source release dn and copy the contents.
877      */
878     if(empty($source_release)){
879       $source_dns = $groups;
880     }else{
881       $source_dns = array();
882       foreach($g_releases as $dn => $data){
883         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
884           $source_dns[$dn] = $data; 
885         }
886       }
887     }
889     /* Detect all menu object we have to copy 
890      */
891     $to_copy = array();
892     foreach($source_dns as $dn => $attrs){
893       $ldap->cd($dn);
894       $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
895       while($attrs = $ldap->fetch()){
896         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
897         $to_copy[$attrs['dn']] = $destination;
898       }
899     }
900    
901     /* At least create the menu objects object */
902     $plug = new plugin($config);
903     foreach($to_copy as $source => $destination){
904       $ldap->cat($destination);
905       if($ldap->count()){
906         echo "&nbsp;<b>"._("Object").":</b> ";
907         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
908         flush();
909       }else{
910         $plug->copy($source,$destination);
911         echo "&nbsp;<b>"._("Object").":</b> ";
912         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
913         flush();
914       }
915     }
916   }
919   /*! \brief Create a new FAI branch.
920    *  @param $sourcedn          String  The source release dn
921    *  @param $destinationdn     String  The destination dn
922    *  @param $destinationName   String  The name of the new release
923    *  @param $type              String  The release type (freeze/branch)
924    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
925    *  @param $depth             Integer Current depth of recursion.
926    */
927   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
928   {
929     global $config;
930     error_reporting(E_ALL | E_STRICT);
931     $ldap     = $config->get_ldap_link();
932     $basedn   = $config->current['BASE'];
933     $delarray = array();
935     /* The following code will output a status string
936      *  for each handled object, in a seperate iframe.
937      */
940     /* Display current action information.
941      */
942     if($is_first){
943       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
944     }else{
945       if(preg_match("/^ou=/",$sourcedn)){
946         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
947       }else{
948         $tmp = split(",",$sourcedn);
949         echo "&nbsp;<b>"._("Object").":</b> ";
950         $deststr = LDAP::fix($destinationdn);
951         if(strlen($deststr) > 96){
952           $deststr = substr($deststr,0,96)."...";
953         }
954         echo $deststr."<br>";
955       }
956     }
957     /* .. immediately display infos */
958     flush();
960     /* Check if destination entry already exists
961      */
962     $ldap->cat($destinationdn);
963     if($ldap->count()){
964       echo _("Could not create new release, the destination dn is already in use.");
965       return;
966     }else{
968       $ldap->clearResult();
970       /* Get source entry
971        *  if it does not exist, abort here.
972        */
973       $ldap->cd($basedn);
974       $ldap->cat($sourcedn);
975       $attr = $ldap->fetch();
976       if((!$attr) || (count($attr)) ==0) {
977         echo _("Error while fetching source dn - aborted!");
978         return;
979       }
981       /* The current object we want to create is an department.
982        * Create the department and add the FAIbranch tag.
983        */
984       if(in_array("organizationalUnit",$attr['objectClass'])){
985         $attr['dn'] = LDAP::convert($destinationdn);
986         $ldap->cd($basedn);
987         $ldap->create_missing_trees($destinationdn);
988         $ldap->cd($destinationdn);
990         /* If is first entry, append FAIbranch to department entry */
991         if($is_first){
992           $ldap->cat($destinationdn);
993           $attr= $ldap->fetch();
994           /* Filter unneeded informations */
995           foreach($attr as $key => $value){
996             if(is_numeric($key)) unset($attr[$key]);
997             if(isset($attr[$key]['count'])){
998               if(is_array($attr[$key])){
999                 unset($attr[$key]['count']);
1000               }
1001             }
1002           }
1004           unset($attr['count']);
1005           unset($attr['dn']);
1007           /* Add marking attribute */
1008           $attr['objectClass'][] = "FAIbranch";
1010           /* Add this entry */
1011           $ldap->modify($attr);
1012         }
1013       }else{
1015         /* Replicate all relevant FAI objects here.
1016          * FAI objects, Apps and Mimetypes.
1017          * Get all attributes as binary value, to ensure that Icon, File template aso
1018          *  are created correctly.
1019          */
1020         foreach($attr as $key => $value){
1022           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1023             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1024             $ei= ldap_first_entry($ldap->cid, $sr);
1025             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1026               $attr[$key] = $tmp;
1027             }
1028           }
1030           if(is_numeric($key)) unset($attr[$key]);
1031           if(isset($attr[$key]['count'])){
1032             if(is_array($attr[$key])){
1033               unset($attr[$key]['count']);
1034             }
1035           }
1036         }
1037         unset($attr['count']);
1038         unset($attr['dn']);
1040         /* Add entry
1041          */
1042         $ldap->cd($destinationdn);
1043         $ldap->cat($destinationdn);
1045         $a = $ldap->fetch();
1046         if(!count($a)){
1047           $ldap->add($attr);
1048         }
1050         if(!$ldap->success()){
1052           /* Some error occurred */
1053           print "---------------------------------------------";
1054           print $ldap->get_error()."<br>";
1055           print $sourcedn."<br>";
1056           print $destinationdn."<br>";
1057           print_a( $attr);
1058           exit();
1059         }
1060       }
1061     }
1063     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1065     /* Prepare for recursive copy.
1066      * Get all object within the source dn and
1067      *  call the recursive copy for each.
1068      */
1069     $ldap->ls ("(objectClass=*)",$sourcedn);
1070     while ($ldap->fetch()){
1071       $deldn= $ldap->getDN();
1072       $delarray[$deldn]= strlen($deldn);
1073     }
1074     asort ($delarray);
1075     reset ($delarray);
1076     $depth ++;
1077     foreach($delarray as $dn => $bla){
1078       if($dn != $destinationdn){
1079         $ldap->cd($basedn);
1080         $item = $ldap->fetch($ldap->cat($dn));
1081         if(!in_array("FAIbranch",$item['objectClass'])){
1082           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1083         }
1084       }
1085     }
1086     if($is_first){
1087       echo "<p class='seperator'>&nbsp;</p>";
1088     }
1089   }
1093   /* This function returns the dn of the object release */
1094   static function get_release_dn($Current_DN)
1095   {
1096     global $config;
1097     $ldap = $config->get_ldap_link();
1098     $ldap->cd($config->current['BASE']);
1100     /* Split dn into pices */ 
1101     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1103     if(!is_array($dns_to_check)){
1104       return;  
1105     }
1107     /* Use dn pieces, to create sub dns like 
1108        ou=test,ou=1,ou=0...
1109        ou=1,ou=0...
1110        ou=0... 
1111        To check which dn is our release container.
1112      */
1113     unset($dns_to_check['count']); 
1114     while(count($dns_to_check)){
1116       /* Create dn */
1117       $new_dn = "";
1118       foreach($dns_to_check as $part){
1119         $new_dn .= $part.",";
1120       }
1121       $new_dn .= $config->current['BASE'];
1123       /* Check if this dn is a release dn */
1124       if(FAI::is_release_department($new_dn)){
1125         return($new_dn);
1126       }
1128       /* Remove first element of dn pieces */
1129       reset($dns_to_check);
1130       unset($dns_to_check[key($dns_to_check)]);
1131     }
1132     return("");
1133   }
1139 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1140 ?>