Code

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