Code

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