Code

FAI package
[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     $ldap->cat($base_release);
32     $attrs = $ldap->fetch();
33     $FAIstate = "branch";
34     if(isset($attrs['FAIstate'][0])){
35       $FAIstate = $attrs['FAIstate'][0];
36     }
38     /* We must also include the given release dn */
39     $previous_releases[] = $base_release;
41     /* Walk through all releases */
42     foreach($previous_releases as $release){
44       /* Get fai departments */
45       $deps_to_search = FAI::get_FAI_departments($release); 
47       /* For every single department  (ou=hoos,ou ..) */
48       foreach($deps_to_search as $fai_base){
50         /* Ldap search for fai classes specified in this release */
51         $attributes  = array("dn","objectClass","FAIstate","cn");
52         $res_tmp = get_list($filter,"fai",$fai_base,$attributes,GL_SUBSEARCH | GL_SIZELIMIT);
54         /* check the returned objects, and add/replace them in our return variable */
55         foreach($res_tmp as $attr){
57           $buffer = array();
58           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
60           if(isset($attr['FAIstate'][0])){
61             if(preg_match("/removed$/",$attr['FAIstate'][0])){
62               if(isset($res[$name])){
63                 unset($res[$name]);
64               }
65               continue;
66             }
67           }
69           /* Seems to be an inherited class, apply current FAIstate to this classes 
70            */
71           if(!preg_match("/".normalizePreg($base_release)."$/i",$attr['dn'])){
72             $buffer['FAIstate'] = $FAIstate; 
73           }else{
75             /* Seems to be created within this release department.
76                This indicates - it can't be of state "freeze"
77              */              
78             $buffer['FAIstate'] = "branch";
79           }
81           /* In detailed mode are some additonal informations visible */
82           if($detailed){
84             /* Create list of parents */
85             if(isset($res[$name])){
86               $buffer = $res[$name];
87               $buffer['parents'][] = $res[$name]['dn'];
88             }else{
89               $buffer['parents'] = array();
90             }
92             /* Append objectClass to resulsts */
93             foreach($attributes as $val){
94               if(isset($attr[$val])){
95                 $buffer[$val] = $attr[$val];
96               }
97             }
98             unset($buffer['objectClass']['count']);
99           }
101           /* Add this object to our list */
102           $buffer['dn']           = $attr['dn'];
103           $res[$name] = $buffer;
104         }
105       }
106     }
107     return($res);
108   }
111   /* Return all relevant FAI departments */
112   static function get_FAI_departments($suffix = "")
113   {
114     $arr = array("hooks","scripts","disk","packages","profiles","templates","variables");
115     $tmp = array();
116     if(preg_match("/^,/",$suffix)){
117       $suffix = preg_replace("/^,/","",$suffix);
118     }
119     foreach($arr as $name){
120       if(empty($suffix)){
121         $tmp[$name] = "ou=".$name;
122       }else{
123         $tmp[$name] = "ou=".$name.",".$suffix;
124       }
125     }
126     return($tmp);
127   }
130   /* Return all releases within the given base */
131   static function get_all_releases_from_base($dn,$appendedName=false)
132   {
133     global $config;
135     if(!preg_match("/".normalizePreg(get_ou('faiou'))."/",$dn)){
136       $base = get_ou('faiou').$dn;
137     }else{
138       $base = $dn;
139     }
140     $res = array();  
142     $ldap = $config->get_ldap_link();
143     $ldap->cd($base);
144     $ldap->search("(objectClass=FAIbranch)",array("ou","dn"));
145     while($attrs = $ldap->fetch()){
146       if($appendedName){
147         $res[$attrs['dn']] = convert_department_dn(preg_replace("/,".normalizePreg(get_ou('faiou')).".*$/","",$attrs['dn']));
148       }else{
149         $res[$attrs['dn']] = $attrs['ou'][0];
150       }
151     }
152     return($res);
153   }
156   /* Add this object to list of objects, that must be checked for release saving */
157   static function prepare_to_save_FAI_object($Current_DN,$objectAttrs,$removed = false)
158   {
159     /* Get ldap object */  
160     global $config;
161     $addObj['Current_DN'] = $Current_DN;
162     $addObj['objectAttrs']= $objectAttrs;
163     $addObj['removed']    = $removed;
164     $addObj['diff']       = TRUE;
166     if(!$removed){
167       $ldap = $config->get_ldap_link();
168       $ldap->cd($config->current['BASE']);
170       /* Get some basic informations */
171       $parent_obj   = FAI::get_parent_release_object($Current_DN);
172       if(!empty($parent_obj)){
173         $ldap->cat($parent_obj,array("*"));
174         $attrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
176         if(!FAI::array_diff_FAI( $attrs,$objectAttrs)){
177           $addObj['diff'] = FALSE;
178         }
179       } 
180     }else{
182       /* If this is the last CLASS of a specific name (e.g. DEPOTSERVER)
183           we have to remove this name from all profiles in this release.
184       */
185       $ldap = $config->get_ldap_link();
186       $ldap->cd($config->current['BASE']);
187       $obj_dn = FAI::get_parent_release_object($Current_DN,TRUE);
189       /* Dont't try to modify non FAIclasses  
190        */
191       if(!preg_match("/[^,]+,".normalizePreg(get_ou("faiou"))."/",$obj_dn)){
192         trigger_error("PLEASE check fai class handling in ".__LINE__." -> ".__FILE__);        
193         echo "<br>-->".$Current_DN."<br>";
194         echo "<br>-->".$obj_dn."<br>";
195       }else{
197         /* Get source object and check if it is a base FAIclass
198          */
199         $ldap->cat($obj_dn);
200         $attrs = $ldap->fetch();
201         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
202         if(count(array_intersect($classes,$attrs['objectClass']))){
203           $cn    = $attrs['cn'][0];
205           /* Check if this is the last with this name in the current release.
206               In this case we have to remove the package name 
207               from all profiles in this release.
208            */
209           $classes = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
210               "(&(objectClass=FAIclass)(cn=".$cn."))"); 
212           /* Check if this is the last class with this name.
213            */
214           if(count($classes) == 1){
216             /* Get all FAI Profiles 
217              */
218             $profiles = FAI::get_all_objects_for_given_base(FAI::get_release_dn($Current_DN),
219                 "(&(objectClass=FAIprofile)(FAIclass=*))"); 
221             /* Walk though all profiles and remove the source class name
222              */
223             foreach($profiles as $dn){
224               $ldap->cat($dn['dn']);
225               $attrs = $ldap->fetch();
227               $attrs = array('FAIclass' => $attrs['FAIclass'][0]);
229               /* Check if this Profile uses the source class ($cn)
230                */
231               if(preg_match("/".normalizePreg($cn)."/",$attrs['FAIclass'])){
232                 $attrs['FAIclass'] = preg_replace("/[ ]*".normalizePreg($cn)."[ ]*/i"," ",$attrs['FAIclass']);
233                 if(empty($attrs['FAIclass'])){
234                   $attrs['FAIclass'] = array();
235                 }
236                 $ldap->cd($dn['dn']);
237                 $ldap->modify($attrs);
239                 if (!$ldap->success()){
240                   msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class()));
241                 }
242               }
243             }
244           }
245         }
246       }
247     }
251     $FAI_objects_to_save = session::get('FAI_objects_to_save') ;
252     $FAI_objects_to_save[$Current_DN] =  $addObj;
253     session::set('FAI_objects_to_save',$FAI_objects_to_save);
254   }
257   /* Detect differences in attribute arrays  */
258   static function array_diff_FAI($ar1,$ar2)
259   {
261     if((!isset($ar1['description'])) || (isset($ar1['description']) && (count($ar1['description']) == 0))){
262       $ar1['description'] = "";
263     }
264     if((!isset($ar2['description'])) || (isset($ar2['description']) && (count($ar2['description']) == 0))){
265       $ar2['description'] = "";
266     }
268     if(count($ar1) != count($ar2)) {
269       return (true);
270     }
272     foreach($ar1 as $key1 => $val1){
274       if((is_array($val1)) && (count($val1)==1)){
275         $ar1[$key1] = $val1[0];
276       }
278       if(isset($ar2[$key1])&&  (is_array($ar2[$key1])) && (count($ar2[$key1])==1)){
279         $val1 = $val1[0];
280         $ar2[$key1] = $ar2[$key1][0];
281       }
282     }
283     ksort($ar1);
284     ksort($ar2);
285     if(count( array_diff($ar1,$ar2)) || FAI::arr_diff($ar1,$ar2)){
286       return(true);
287     }else{
288       return(false);
289     }
290   }
293   static function arr_diff($ar1,$ar2)
294   {
295     foreach($ar1 as $ak1 => $av1){
296       if(!isset($ar2[$ak1]) || (!($av1 === $ar2[$ak1]))){
297         return(TRUE);    
298       }elseif(is_array($av1)){
299         $ret = (FAI::arr_diff($av1,$ar2[$ak1]));
300         if($ret) {
301           return(TRUE);
302         }
303       }
304     }
305     return(FALSE);
306   }
311   /* check which objects must be saved, and save them */
312   static function save_release_changes_now()
313   {
314     global $config;
315     /* Variable init*/
316     $to_save = array();
317     
318     $reload_fai_classes = FALSE;
320     /* check which objects must be saved */
321     if(!session::is_set('FAI_objects_to_save')){
322       return;
323     }
324     $FAI_objects_to_save = session::get('FAI_objects_to_save');
325     if(!is_array($FAI_objects_to_save)) {
326       print_a(array(session::get('FAI_objects_to_save')));
327       trigger_error("Can't save FAI objects, no array given.");
328       return;
329     }
330   
331     foreach($FAI_objects_to_save as $Current_DN => $object){
332       if($object['diff']){
333         $sub_name = $Current_DN;
334         while(isset($FAI_objects_to_save[$sub_name])){
335           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
336           unset($FAI_objects_to_save[$sub_name]);
337           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
338         }
339       }
340     }
341     session::set('FAI_objects_to_save',$FAI_objects_to_save);
343     /* Sort list of objects that must be saved, and ensure that 
344        container   objects are safed, before their childs are saved */
345     ksort($to_save);
346     $tmp = array();
347     foreach($to_save as $SubObjects){
348       foreach($SubObjects as $object){
349         $tmp[] = $object;
350       }
351     }
352     $to_save = $tmp;
355     /* Save objects and manage the correct release behavior*/
356     foreach($to_save as $save){
358       $Current_DN = $save['Current_DN'];
359       $removed    = $save['removed'];
360       $objectAttrs= $save['objectAttrs'];
362       /* Get ldap object */ 
363       $ldap = $config->get_ldap_link();
364       $ldap->cd($config->current['BASE']);
366       /* Get some basic informations */
367       $base_release       = FAI::get_release_dn($Current_DN);
368       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
369       $parent_obj         = FAI::get_parent_release_object($Current_DN);
370       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
372       /* Check if given dn exists or if is a new entry */
373       $ldap->cat($Current_DN);
374       if(!$ldap->count()){
375         $is_new = true;
376       }else{
377         $is_new = false;
378       }
380       /* if parameter removed is true, we have to add FAIstate to the current attrs 
381          FAIstate should end with ...|removed after this operation */  
382       if($removed ){
383         $ldap->cat($Current_DN);
385         /* Get current object, because we must add the FAIstate ...|removed */
386         if((!$ldap->count()) && !empty($parent_obj)){
387           $ldap->cat($parent_obj);
388         }
390         /* Check if we have found a suiteable object */ 
391         if(!$ldap->count()){
392           echo "Error can't remove this object ".$Current_DN;
393           return;
394         }else{
396           /* Set FAIstate to current objectAttrs */
397           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
398           if(isset($objectAttrs['FAIstate'][0])){
399             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
400               $objectAttrs['FAIstate'][0] .= "|removed";
401             }
402           }else{
403             $objectAttrs['FAIstate'][0] = "|removed";
404           }
406           /* Force reload of FAI classes */
407           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
408           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
409             $reload_fai_classes = TRUE;
410           }
411         }
412       }
414       /* Check if this a leaf release or not */ 
415       if(count($following_releases) == 0 ){
417         /* This is a leaf object. It isn't inherited by any other object */    
418         if(DEBUG_FAI_FUNC) { 
419           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
420           print_a($objectAttrs);
421         }
422         FAI::save_FAI_object($Current_DN,$objectAttrs);
424         /* Force reload of FAI classes */
425         $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
426         if(count(array_intersect($classes,$objectAttrs['objectClass']))){
427           $reload_fai_classes = TRUE;
428         }
430       }else{
432         /* This object is inherited by some sub releases */  
434         /* Get all releases, that inherit this object */ 
435         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
437         /* Get parent object */
438         $ldap->cat($parent_obj);
439         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
441         /* New objects require special handling */
442         if($is_new){
444           /* Force reload of FAI classes */
445           $classes = array("FAIprofile","FAIscript","FAIpackageList","FAIpartitionTable","FAIHook","FAIvariable","FAItemplate");
446           if(count(array_intersect($classes,$objectAttrs['objectClass']))){
447             $reload_fai_classes = TRUE;
448           }
450           /* check if there is already an entry named like this,
451              in one of our parent releases */
452           if(!empty($parent_obj)){
453             if(DEBUG_FAI_FUNC) { 
454               echo "There is already an entry named like this.</b><br>";
456               echo "<b>Saving main object</b>".$Current_DN;
457               print_a($objectAttrs);
458             }    
459             FAI::save_FAI_object($Current_DN,$objectAttrs);
461             foreach($r as $key){
462               if(DEBUG_FAI_FUNC) { 
463                 echo "<b>Saving parent to following release</b> ".$key;
464                 print_a($parent_attrs);
465               }
466               FAI::save_FAI_object($key,$parent_attrs);
467             }
468           }else{
470             if(DEBUG_FAI_FUNC) { 
471               echo "<b>Saving main object</b>".$Current_DN;
472               print_a($objectAttrs);
473             }
474             FAI::save_FAI_object($Current_DN,$objectAttrs);
476             if(isset($objectAttrs['FAIstate'])){
477               $objectAttrs['FAIstate'] .= "|removed"; 
478             }else{
479               $objectAttrs['FAIstate'] = "|removed";
480             }
482             foreach($r as $key ){
483               if(DEBUG_FAI_FUNC) { 
484                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
485                 print_a($objectAttrs);
486               }
487               FAI::save_FAI_object($key,$objectAttrs);
488             }
489           }
490         }else{
492           /* check if we must patch the follwing release */
493           if(!empty($r)){
494             foreach($r as $key ){
495               if(DEBUG_FAI_FUNC) { 
496                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
497                 print_a($parent_attrs);
498               }
499               FAI::save_FAI_object($key,$parent_attrs);
500             }
501           }
503           if(DEBUG_FAI_FUNC) { 
504             echo "<b>Saving current object</b>".$parent_obj;
505             print_a($objectAttrs);
506           }
507           FAI::save_FAI_object($parent_obj,$objectAttrs);
509           if(($parent_obj != $Current_DN)){
510             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
511           }
512         }
513       }
514     }
516     /* Reload GOsa si FAI DB/cache
517      */
518     if($reload_fai_classes){
519       if( class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
520         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
521         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
522           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
523           $tmp = new $evt['CLASS_NAME']($config);
524           $tmp->set_type(TRIGGERED_EVENT);
525           $tmp->add_targets(array("GOsa"));
526           $o_queue = new gosaSupportDaemon();
527           if(!$o_queue->append($tmp)){
528             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
529           }
530         }
531       }
532     }
534     session::set('FAI_objects_to_save',array());
535   }
538   /* this function will remove all unused (deleted) objects,
539      that have no parent object */
540   static function clean_up_releases($Current_DN)
541   {
542     global $config;
543     $ldap = $config->get_ldap_link();
544     $ldap->cd($config->current['BASE']);
546     /* Collect some basic informations and initialize some variables */ 
547     $base_release       = FAI::get_release_dn($Current_DN);
548     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
549     $Kill = array();
550     $Skip = array();
552     /* We must also include the given release dn */
553     $previous_releases[] = $base_release;
555     /* Walk through all releases */
556     foreach($previous_releases as $release){
558       /* Get fai departments */
559       $deps_to_search = FAI::get_FAI_departments($release); 
561       /* For every single department  (ou=hoos,ou ..) */
562       foreach($deps_to_search as $fai_base){
564         /* Ldap search for fai classes specified in this release */
565         $ldap->cd($fai_base);
566         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
568         /* check the returned objects, and add/replace them in our return variable */
569         while($attr = $ldap->fetch()){
571           $buffer = array();
572 #        $name = str_ireplace($release,"",$attr['dn']);
573           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
575           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
577             /* Check if this object is required somehow */    
578             if(!isset($Skip[$name])){
579               $Kill[$attr['dn']] = $attr['dn'];
580             }
581           }else{
583             /* This object is required (not removed), so do not 
584                delete any following sub releases of this object */
585             $Skip[$name] = $attr['dn'];
586           }
587         }
588       }
589     }
590     return($Kill);
591   }
594   /* Remove numeric index and 'count' from ldap->fetch result */
595   static function prepare_ldap_fetch_to_be_saved($attrs)
596   {
597     foreach($attrs as $key => $value){
598       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
599         unset($attrs[$key]);
600       }
601       if(is_array($value) && isset($value['count'])){
602         unset($attrs[$key]['count']);
603       }
604     }
605     return($attrs);
606   }
609   /* Save given attrs to specified dn*/
610   static function save_FAI_object($dn,$attrs)
611   {
612     global $config;
613     $ldap = $config->get_ldap_link();
614     $ldap->cd($config->current['BASE']);
615     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
616     $ldap->cd($dn);
618     $ldap->cat($dn,array("dn"));
619     if($ldap->count()){
621       /* Remove FAIstate*/
622       if(!isset($attrs['FAIstate'])){
623         $attrs['FAIstate'] = array();
624       }
626       $ldap->modify($attrs);
627     }else{
629       /* Unset description if empty  */
630       if(empty($attrs['description'])){
631         unset($attrs['description']);
632       }    
634       $ldap->add($attrs);
635     }
636     if (!$ldap->success()){
637       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
638     }
639   }
642   /* Return FAIstate freeze branch or "" for specified release department */
643   static function get_release_tag($dn)
644   {
645     global $config;
646     $ldap = $config->get_ldap_link();
647     $ldap->cd($dn);
648     $ldap->cat($dn,array("FAIstate"));
650     if($ldap->count()){
652       $attr = $ldap->fetch();
653       if(isset($attr['FAIstate'][0])){
654         if(preg_match("/freeze/",$attr['FAIstate'][0])){
655           return("freeze");
656         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
657           return("branch");
658         }
659       }
660     }
661     return("");
662   }
665   static function get_following_releases_that_inherit_this_object($dn)
666   {
667     global $config;
668     $ldap = $config->get_ldap_link();
669     $ldap->cd($config->current['BASE']);
671     $ret = array();
673     /* Get base release */
674     $base_release = FAI::get_release_dn($dn);
676     /* Get previous release dns */
677     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
679     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
680 #  $dn_suffix = str_ireplace($base_release,"",$dn);
681     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
683     /* Check if given object also exists whitin one of these releases */
684     foreach($sub_releases as $p_release => $name){
686       $check_dn = $dn_suffix.$p_release;
688       $ldap->cat($check_dn,array("dn","objectClass"));
690       if($ldap->count()){
691         //return($ret);
692       }else{
693         $ret[$check_dn]=$check_dn;
694       }
695     }
696     return($ret);
697   }
700   /* Get previous version of the object dn */
701   static function get_parent_release_object($dn,$include_myself=true)
702   {
703     global $config;
704     $ldap = $config->get_ldap_link();
705     $ldap->cd($config->current['BASE']);
706     $previous_releases= array();
708     /* Get base release */
709     $base_release = FAI::get_release_dn($dn);
710     if($include_myself){
711       $previous_releases[] = $base_release;  
712     }
714     /* Get previous release dns */
715     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
716     foreach($tmp as $release){
717       $previous_releases[] = $release;
718     }
720     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
721 #  $dn_suffix = str_ireplace($base_release,"",$dn);
722     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
724     /* Check if given object also exists whitin one of these releases */
725     foreach($previous_releases as $p_release){
726       $check_dn = $dn_suffix.$p_release;
727       $ldap->cat($check_dn,array("dn","objectClass"));
729       if($ldap->count()){
730         return($check_dn);
731       }
732     }
733     return("");
734   }
737   /* return release names of all parent releases */
738   static function get_previous_releases_of_this_release($dn,$flat)
739   {
740     global $config;
741     $ldap = $config->get_ldap_link();
742     $ldap->cd($config->current['BASE']);
743     $ret = array();
745     /* Explode dns into pieces, to be able to build parent dns */
746     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
748     if(!is_array($dns_to_check)){
749       return;  
750     }
752     /* Unset first entry which represents the given dn */
753     unset($dns_to_check['count']); 
754     unset($dns_to_check[key($dns_to_check)]);
756     /* Create dns addresses and check if this dn is a release dn */
757     $id = 0;
758     while(count($dns_to_check)){
760       /* build parent dn */
761       $new_dn = "";
762       foreach($dns_to_check as $part){
763         $new_dn .= $part.",";
764       }
765       $new_dn .= $config->current['BASE'];
767       /* check if this dn is a release */
768       if(FAI::is_release_department($new_dn)){
769         if($flat){
770           $ret[$id] = $new_dn; 
771         }else{
772           $ret = array($new_dn=>$ret); 
773         }
774         $id ++;
775       }else{
776         return($ret);
777       }
778       reset($dns_to_check);
779       unset($dns_to_check[key($dns_to_check)]);
780     }
781     return($ret);
782   } 
785   /* This function returns all sub release names, recursivly  */
786   static function get_sub_releases_of_this_release($dn,$flat = false)
787   {
788     global $config;
789     $res  = array();
790     $ldap = $config->get_ldap_link();
791     $ldap->cd($config->current['BASE']);
792     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
793     while($attr = $ldap->fetch()){
795       /* Append department name */
796       if($flat){
797         $res[$attr['dn']] = $attr['ou'][0];
798       }else{
799         $res[$attr['dn']] = array();
800       }
802       /* Get sub release departments of this department */
803       if(in_array("FAIbranch",$attr['objectClass'])) {
804         if($flat){
805           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
806           foreach($tmp as $dn => $value){
807             $res[$dn]=$value;
808           }
809         }else{
810           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
811         }
812       }
813     }
814     return($res);
815   }
818   /* Check if the given department is a release department */
819   static function is_release_department($dn)
820   {
821     global $config;
822     $ldap = $config->get_ldap_link();
823     $ldap->cd($config->current['BASE']);
824     $ldap->cat($dn,array("objectClass","ou"));
826     /* Check objectClasses and name to check if this is a release department */
827     if($ldap->count()){
828       $attrs = $ldap->fetch();
830       $ou = "";
831       if(isset($attrs['ou'][0])){
832         $ou = $attrs['ou'][0];  
833       }
835       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
836         return($attrs['dn']);
837       }
838     }
839     return(false);
840   }
843   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
844   {
845     global $config;
846     $start = microtime(TRUE);
847     $source_release = trim($source_release,"/");
849     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
851     $sub_releases = array();
852     $source_dn = "";
853     
854     $tmp = split("\/",$source_release);
855     foreach($tmp as $part){
856       if(empty($part)){
857         continue;
858       }
859       $source_dn            = "ou=".$part.",".$source_dn;
860       $sub_releases[$part]  = $source_dn;
861     }
863     /* Get all groups */
864     $ldap =$config->get_ldap_link();
865     $ldap->cd($config->current['BASE']);
866     $ldap->search("(objectClass=posixGroup)",array("dn"));
867     $groups = array();
868     while($attrs = $ldap->fetch()){
869       $groups[$attrs['dn']] = $attrs;
870     }
872     /* Get all FAI releases, to be able to create missing group application releases 
873         with the correct type of release (FAIstate=freeze/branch).
874      */
875     $f_releases = array();
876     $ldap->cd ($config->current['BASE']);
877     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
878     while($attrs = $ldap->fetch()){
879       foreach($sub_releases as $sub_rel){
880         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
881           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
882         }
883       }
884     }
886     /* Get all group releases */
887     $g_releases = array();
888     foreach($groups as $dn => $data){
889       $ldap->cd($dn);
890       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
891       while($attrs = $ldap->fetch()){
892         $g_releases[$attrs['dn']] = $attrs;
893       }
894     }
896     /* Check if base releases exists.
897        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
898      */
899     foreach($sub_releases as $name => $sub_rel){
901       $FAIstate = "";
902       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
903         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
904       }
906       foreach($groups as $dn => $data){
907         if(!isset($g_releases[$sub_rel.$dn])){
908           $ldap->cd($dn);
909           $r_data = array();
910           $r_data['ou'] = $name;
911           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
912           if(!empty($FAIstate)) {
913             $r_data['FAIstate'] = $FAIstate;
914           }
915  
916           $ldap->cd($sub_rel.$dn) ;
917           $ldap->add($r_data);
918           echo "&nbsp;<b>"._("Object").":</b> ";
919           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
920           flush();
921         }
922       }
923     } 
924  
925     /* Create new release container in each group.
926      */
927     $n_data = array();
928     $n_data = array();
929     $n_data['ou'] = $destination_name;
930     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
931     if(!empty($type)){
932       $n_data['FAIstate'] = $type."/cow";
933     }
935     foreach($groups as $dn => $att){
936       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
937       if(!isset($g_releases[$n_dn])){
938         $ldap->cd ($n_dn);
939         $ldap->add($n_data);
940         echo "&nbsp;<b>"._("Object").":</b> ";
941         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
942         flush();
943       }
944     }
946     /* If the source release is empty, then create a new release by copying 
947         all group application menus into a new ou=$destination_name release container.
948       
949        If the source release is not empty. 
950          We detect all releases which match the source release dn and copy the contents.
951      */
952     if(empty($source_release)){
953       $source_dns = $groups;
954     }else{
955       $source_dns = array();
956       foreach($g_releases as $dn => $data){
957         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
958           $source_dns[$dn] = $data; 
959         }
960       }
961     }
963     /* Detect all menu object we have to copy 
964      */
965     $to_copy = array();
966     foreach($source_dns as $dn => $attrs){
967       $ldap->cd($dn);
968       $ldap->ls("(|(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry))",$dn,array("dn"));
969       while($attrs = $ldap->fetch()){
970         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
971         $to_copy[$attrs['dn']] = $destination;
972       }
973     }
974    
975     /* At least create the menu objects object */
976     $plug = new plugin($config);
977     foreach($to_copy as $source => $destination){
978       $ldap->cat($destination);
979       if($ldap->count()){
980         echo "&nbsp;<b>"._("Object").":</b> ";
981         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
982         flush();
983       }else{
984         $plug->copy($source,$destination);
985         echo "&nbsp;<b>"._("Object").":</b> ";
986         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
987         flush();
988       }
989     }
990   }
993   /*! \brief Create a new FAI branch.
994    *  @param $sourcedn          String  The source release dn
995    *  @param $destinationdn     String  The destination dn
996    *  @param $destinationName   String  The name of the new release
997    *  @param $type              String  The release type (freeze/branch)
998    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
999    *  @param $depth             Integer Current depth of recursion.
1000    */
1001   static function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
1002   {
1003     global $config;
1004     error_reporting(E_ALL | E_STRICT);
1005     $ldap     = $config->get_ldap_link();
1006     $basedn   = $config->current['BASE'];
1007     $delarray = array();
1009     /* The following code will output a status string
1010      *  for each handled object, in a seperate iframe.
1011      */
1014     /* Display current action information.
1015      */
1016     if($is_first){
1017       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
1018     }else{
1019       if(preg_match("/^ou=/",$sourcedn)){
1020         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
1021       }else{
1022         $tmp = split(",",$sourcedn);
1023         echo "&nbsp;<b>"._("Object").":</b> ";
1024         $deststr = LDAP::fix($destinationdn);
1025         if(strlen($deststr) > 96){
1026           $deststr = substr($deststr,0,96)."...";
1027         }
1028         echo $deststr."<br>";
1029       }
1030     }
1031     /* .. immediately display infos */
1032     flush();
1034     /* Check if destination entry already exists
1035      */
1036     $ldap->cat($destinationdn);
1037     if($ldap->count()){
1038       echo _("Could not create new release, the destination dn is already in use.");
1039       return;
1040     }else{
1042       $ldap->clearResult();
1044       /* Get source entry
1045        *  if it does not exist, abort here.
1046        */
1047       $ldap->cd($basedn);
1048       $ldap->cat($sourcedn);
1049       $attr = $ldap->fetch();
1050       if((!$attr) || (count($attr)) ==0) {
1051         echo _("Error while fetching source dn - aborted!");
1052         return;
1053       }
1055       /* The current object we want to create is an department.
1056        * Create the department and add the FAIbranch tag.
1057        */
1058       if(in_array("organizationalUnit",$attr['objectClass'])){
1059         $attr['dn'] = LDAP::convert($destinationdn);
1060         $ldap->cd($basedn);
1061         $ldap->create_missing_trees($destinationdn);
1062         $ldap->cd($destinationdn);
1064         /* If is first entry, append FAIbranch to department entry */
1065         if($is_first){
1066           $ldap->cat($destinationdn);
1067           $attr= $ldap->fetch();
1068           /* Filter unneeded informations */
1069           foreach($attr as $key => $value){
1070             if(is_numeric($key)) unset($attr[$key]);
1071             if(isset($attr[$key]['count'])){
1072               if(is_array($attr[$key])){
1073                 unset($attr[$key]['count']);
1074               }
1075             }
1076           }
1078           unset($attr['count']);
1079           unset($attr['dn']);
1081           /* Add marking attribute */
1082           $attr['objectClass'][] = "FAIbranch";
1084           /* Add this entry */
1085           $ldap->modify($attr);
1086         }
1087       }else{
1089         /* Replicate all relevant FAI objects here.
1090          * FAI objects, Apps and Mimetypes.
1091          * Get all attributes as binary value, to ensure that Icon, File template aso
1092          *  are created correctly.
1093          */
1094         foreach($attr as $key => $value){
1096           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1097             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1098             $ei= ldap_first_entry($ldap->cid, $sr);
1099             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1100               $attr[$key] = $tmp;
1101             }
1102           }
1104           if(is_numeric($key)) unset($attr[$key]);
1105           if(isset($attr[$key]['count'])){
1106             if(is_array($attr[$key])){
1107               unset($attr[$key]['count']);
1108             }
1109           }
1110         }
1111         unset($attr['count']);
1112         unset($attr['dn']);
1114         /* Add entry
1115          */
1116         $ldap->cd($destinationdn);
1117         $ldap->cat($destinationdn);
1119         $a = $ldap->fetch();
1120         if(!count($a)){
1121           $ldap->add($attr);
1122         }
1124         if(!$ldap->success()){
1126           /* Some error occurred */
1127           print "---------------------------------------------";
1128           print $ldap->get_error()."<br>";
1129           print $sourcedn."<br>";
1130           print $destinationdn."<br>";
1131           print_a( $attr);
1132           exit();
1133         }
1134       }
1135     }
1137     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1139     /* Prepare for recursive copy.
1140      * Get all object within the source dn and
1141      *  call the recursive copy for each.
1142      */
1143     $ldap->ls ("(objectClass=*)",$sourcedn);
1144     while ($ldap->fetch()){
1145       $deldn= $ldap->getDN();
1146       $delarray[$deldn]= strlen($deldn);
1147     }
1148     asort ($delarray);
1149     reset ($delarray);
1150     $depth ++;
1151     foreach($delarray as $dn => $bla){
1152       if($dn != $destinationdn){
1153         $ldap->cd($basedn);
1154         $item = $ldap->fetch($ldap->cat($dn));
1155         if(!in_array("FAIbranch",$item['objectClass'])){
1156           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1157         }
1158       }
1159     }
1160     if($is_first){
1161       echo "<p class='seperator'>&nbsp;</p>";
1162     }
1163   }
1167   /* This function returns the dn of the object release */
1168   static function get_release_dn($Current_DN)
1169   {
1170     global $config;
1171     $ldap = $config->get_ldap_link();
1172     $ldap->cd($config->current['BASE']);
1174     /* Split dn into pices */ 
1175     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1177     if(!is_array($dns_to_check)){
1178       return;  
1179     }
1181     /* Use dn pieces, to create sub dns like 
1182        ou=test,ou=1,ou=0...
1183        ou=1,ou=0...
1184        ou=0... 
1185        To check which dn is our release container.
1186      */
1187     unset($dns_to_check['count']); 
1188     while(count($dns_to_check)){
1190       /* Create dn */
1191       $new_dn = "";
1192       foreach($dns_to_check as $part){
1193         $new_dn .= $part.",";
1194       }
1195       $new_dn .= $config->current['BASE'];
1197       /* Check if this dn is a release dn */
1198       if(FAI::is_release_department($new_dn)){
1199         return($new_dn);
1200       }
1202       /* Remove first element of dn pieces */
1203       reset($dns_to_check);
1204       unset($dns_to_check[key($dns_to_check)]);
1205     }
1206     return("");
1207   }
1213 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1214 ?>