Code

Updated FAI saving
[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();
299     /* check which objects must be saved */
300     $FAI_objects_to_save = session::get('FAI_objects_to_save');
301     if(!is_array($FAI_objects_to_save)) {
302       print_a(array(session::get('FAI_objects_to_save')));
303       trigger_error("Can't save FAI objects, no array given.");
304       return;
305     }
306   
307     foreach($FAI_objects_to_save as $Current_DN => $object){
308       if($object['diff']){
309         $sub_name = $Current_DN;
310         while(isset($FAI_objects_to_save[$sub_name])){
311           $to_save[strlen($sub_name)][$sub_name] = $FAI_objects_to_save[$sub_name]; 
312           unset($FAI_objects_to_save[$sub_name]);
313           $sub_name = preg_replace('/^[^,]+,/', '', $sub_name);
314         }
315       }
316     }
317     session::set('FAI_objects_to_save',$FAI_objects_to_save);
319     /* Sort list of objects that must be saved, and ensure that 
320        container   objects are safed, before their childs are saved */
321     ksort($to_save);
322     $tmp = array();
323     foreach($to_save as $SubObjects){
324       foreach($SubObjects as $object){
325         $tmp[] = $object;
326       }
327     }
328     $to_save = $tmp;
331     /* Save objects and manage the correct release behavior*/
332     foreach($to_save as $save){
334       $Current_DN = $save['Current_DN'];
335       $removed    = $save['removed'];
336       $objectAttrs= $save['objectAttrs'];
338       /* Get ldap object */ 
339       $ldap = $config->get_ldap_link();
340       $ldap->cd($config->current['BASE']);
342       /* Get some basic informations */
343       $base_release       = FAI::get_release_dn($Current_DN);
344       $sub_releases       = FAI::                       get_sub_releases_of_this_release($base_release,true);
345       $parent_obj         = FAI::get_parent_release_object($Current_DN);
346       $following_releases = FAI::                       get_sub_releases_of_this_release($base_release,true);
348       /* Check if given dn exists or if is a new entry */
349       $ldap->cat($Current_DN);
350       if(!$ldap->count()){
351         $is_new = true;
352       }else{
353         $is_new = false;
354       }
356       /* if parameter removed is true, we have to add FAIstate to the current attrs 
357          FAIstate should end with ...|removed after this operation */  
358       if($removed ){
359         $ldap->cat($Current_DN);
361         /* Get current object, because we must add the FAIstate ...|removed */
362         if((!$ldap->count()) && !empty($parent_obj)){
363           $ldap->cat($parent_obj);
364         }
366         /* Check if we have found a suiteable object */ 
367         if(!$ldap->count()){
368           echo "Error can't remove this object ".$Current_DN;
369           return;
370         }else{
372           /* Set FAIstate to current objectAttrs */
373           $objectAttrs = FAI::                           prepare_ldap_fetch_to_be_saved($ldap->fetch());
374           if(isset($objectAttrs['FAIstate'][0])){
375             if(!preg_match("/removed$/",$objectAttrs['FAIstate'][0])){
376               $objectAttrs['FAIstate'][0] .= "|removed";
377             }
378           }else{
379             $objectAttrs['FAIstate'][0] = "|removed";
380           }
381         }
382       }
384       /* Check if this a leaf release or not */ 
385       if(count($following_releases) == 0 ){
387         /* This is a leaf object. It isn't inherited by any other object */    
388         if(DEBUG_FAI_FUNC) { 
389           echo "<b>Saving directly, is a leaf object</b><br> ".$Current_DN;
390           print_a($objectAttrs);
391         }
392         FAI::save_FAI_object($Current_DN,$objectAttrs);
393       }else{
395         /* This object is inherited by some sub releases */  
397         /* Get all releases, that inherit this object */ 
398         $r = FAI::get_following_releases_that_inherit_this_object($Current_DN);
400         /* Get parent object */
401         $ldap->cat($parent_obj);
402         $parent_attrs = FAI::prepare_ldap_fetch_to_be_saved($ldap->fetch());
404         /* New objects require special handling */
405         if($is_new){
407           /* check if there is already an entry named like this,
408              in one of our parent releases */
409           if(!empty($parent_obj)){
410             if(DEBUG_FAI_FUNC) { 
411               echo "There is already an entry named like this.</b><br>";
413               echo "<b>Saving main object</b>".$Current_DN;
414               print_a($objectAttrs);
415             }    
416             FAI::save_FAI_object($Current_DN,$objectAttrs);
418             foreach($r as $key){
419               if(DEBUG_FAI_FUNC) { 
420                 echo "<b>Saving parent to following release</b> ".$key;
421                 print_a($parent_attrs);
422               }
423               FAI::save_FAI_object($key,$parent_attrs);
424             }
425           }else{
427             if(DEBUG_FAI_FUNC) { 
428               echo "<b>Saving main object</b>".$Current_DN;
429               print_a($objectAttrs);
430             }
431             FAI::save_FAI_object($Current_DN,$objectAttrs);
433             if(isset($objectAttrs['FAIstate'])){
434               $objectAttrs['FAIstate'] .= "|removed"; 
435             }else{
436               $objectAttrs['FAIstate'] = "|removed";
437             }
439             foreach($r as $key ){
440               if(DEBUG_FAI_FUNC) { 
441                 echo "<b>Create an empty placeholder in follwing release</b> ".$key; 
442                 print_a($objectAttrs);
443               }
444               FAI::save_FAI_object($key,$objectAttrs);
445             }
446           }
447         }else{
449           /* check if we must patch the follwing release */
450           if(!empty($r)){
451             foreach($r as $key ){
452               if(DEBUG_FAI_FUNC) { 
453                 echo "<b>Copy current objects original attributes to next release</b> ".$key;
454                 print_a($parent_attrs);
455               }
456               FAI::save_FAI_object($key,$parent_attrs);
457             }
458           }
460           if(DEBUG_FAI_FUNC) { 
461             echo "<b>Saving current object</b>".$parent_obj;
462             print_a($objectAttrs);
463           }
464           FAI::save_FAI_object($parent_obj,$objectAttrs);
466           if(($parent_obj != $Current_DN)){
467             msg_dialog::display(_("Error"), sprintf(_("Error, following objects should be equal '%s' and '%s'"),$parent_obj,$Current_DN), ERROR_DIALOG);
468           }
469         }
470       }
471     }
473     /* Reload GOsa si FAI DB/cache
474      */
475     if(count($to_save)){
476       if(class_available("DaemonEvent") && class_available("gosaSupportDaemon")){
477         $events = DaemonEvent::get_event_types(SYSTEM_EVENT | HIDDEN_EVENT);        
478         if(isset($events['TRIGGERED']['DaemonEvent_recreate_fai_release_db'])){
479           $evt = $events['TRIGGERED']['DaemonEvent_recreate_fai_release_db']; 
480           $tmp = new $evt['CLASS_NAME']($config);
481           $tmp->set_type(TRIGGERED_EVENT);
482           $tmp->add_targets(array("GOsa"));
483           $o_queue = new gosaSupportDaemon();
484           if(!$o_queue->append($tmp)){
485             msg_dialog::display(_("Service infrastructure"),msgPool::siError($o_queue->get_error()),ERROR_DIALOG);
486           }
487         }
488       }
489     }
491     session::set('FAI_objects_to_save',array());
492   }
495   /* this function will remove all unused (deleted) objects,
496      that have no parent object */
497   static function clean_up_releases($Current_DN)
498   {
499     global $config;
500     $ldap = $config->get_ldap_link();
501     $ldap->cd($config->current['BASE']);
503     /* Collect some basic informations and initialize some variables */ 
504     $base_release       = FAI::get_release_dn($Current_DN);
505     $previous_releases  = array_reverse(FAI::             get_previous_releases_of_this_release($base_release,true));
506     $Kill = array();
507     $Skip = array();
509     /* We must also include the given release dn */
510     $previous_releases[] = $base_release;
512     /* Walk through all releases */
513     foreach($previous_releases as $release){
515       /* Get fai departments */
516       $deps_to_search = FAI::get_FAI_departments($release); 
518       /* For every single department  (ou=hoos,ou ..) */
519       foreach($deps_to_search as $fai_base){
521         /* Ldap search for fai classes specified in this release */
522         $ldap->cd($fai_base);
523         $ldap->search("(objectClass=FAIclass)",array("dn","objectClass","FAIstate"));
525         /* check the returned objects, and add/replace them in our return variable */
526         while($attr = $ldap->fetch()){
528           $buffer = array();
529 #        $name = str_ireplace($release,"",$attr['dn']);
530           $name = preg_replace("/".normalizePreg($release)."/i","",$attr['dn']);
532           if(isset($attr['FAIstate'][0])&&(preg_match("/removed$/",$attr['FAIstate'][0]))){
534             /* Check if this object is required somehow */    
535             if(!isset($Skip[$name])){
536               $Kill[$attr['dn']] = $attr['dn'];
537             }
538           }else{
540             /* This object is required (not removed), so do not 
541                delete any following sub releases of this object */
542             $Skip[$name] = $attr['dn'];
543           }
544         }
545       }
546     }
547     return($Kill);
548   }
551   /* Remove numeric index and 'count' from ldap->fetch result */
552   static function prepare_ldap_fetch_to_be_saved($attrs)
553   {
554     foreach($attrs as $key => $value){
555       if(is_numeric($key) || ($key == "count") || ($key == "dn")){
556         unset($attrs[$key]);
557       }
558       if(is_array($value) && isset($value['count'])){
559         unset($attrs[$key]['count']);
560       }
561     }
562     return($attrs);
563   }
566   /* Save given attrs to specified dn*/
567   static function save_FAI_object($dn,$attrs)
568   {
569     global $config;
570     $ldap = $config->get_ldap_link();
571     $ldap->cd($config->current['BASE']);
572     $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dn));
573     $ldap->cd($dn);
575     $ldap->cat($dn,array("dn"));
576     if($ldap->count()){
578       /* Remove FAIstate*/
579       if(!isset($attrs['FAIstate'])){
580         $attrs['FAIstate'] = array();
581       }
583       $ldap->modify($attrs);
584     }else{
586       /* Unset description if empty  */
587       if(empty($attrs['description'])){
588         unset($attrs['description']);
589       }    
591       $ldap->add($attrs);
592     }
593     if (!$ldap->success()){
594       msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, 0, get_class()));
595     }
596   }
599   /* Return FAIstate freeze branch or "" for specified release department */
600   static function get_release_tag($dn)
601   {
602     global $config;
603     $ldap = $config->get_ldap_link();
604     $ldap->cd($dn);
605     $ldap->cat($dn,array("FAIstate"));
607     if($ldap->count()){
609       $attr = $ldap->fetch();
610       if(isset($attr['FAIstate'][0])){
611         if(preg_match("/freeze/",$attr['FAIstate'][0])){
612           return("freeze");
613         }elseif(preg_match("/branch/",$attr['FAIstate'][0])){
614           return("branch");
615         }
616       }
617     }
618     return("");
619   }
622   static function get_following_releases_that_inherit_this_object($dn)
623   {
624     global $config;
625     $ldap = $config->get_ldap_link();
626     $ldap->cd($config->current['BASE']);
628     $ret = array();
630     /* Get base release */
631     $base_release = FAI::get_release_dn($dn);
633     /* Get previous release dns */
634     $sub_releases = FAI::                       get_sub_releases_of_this_release($base_release);
636     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
637 #  $dn_suffix = str_ireplace($base_release,"",$dn);
638     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
640     /* Check if given object also exists whitin one of these releases */
641     foreach($sub_releases as $p_release => $name){
643       $check_dn = $dn_suffix.$p_release;
645       $ldap->cat($check_dn,array("dn","objectClass"));
647       if($ldap->count()){
648         //return($ret);
649       }else{
650         $ret[$check_dn]=$check_dn;
651       }
652     }
653     return($ret);
654   }
657   /* Get previous version of the object dn */
658   static function get_parent_release_object($dn,$include_myself=true)
659   {
660     global $config;
661     $ldap = $config->get_ldap_link();
662     $ldap->cd($config->current['BASE']);
663     $previous_releases= array();
665     /* Get base release */
666     $base_release = FAI::get_release_dn($dn);
667     if($include_myself){
668       $previous_releases[] = $base_release;  
669     }
671     /* Get previous release dns */
672     $tmp = FAI::             get_previous_releases_of_this_release($base_release,true);
673     foreach($tmp as $release){
674       $previous_releases[] = $release;
675     }
677     /* Get dn suffix. Example  "FAIvairableEntry=keksdose,FAIvariable=Keksregal," */
678 #  $dn_suffix = str_ireplace($base_release,"",$dn);
679     $dn_suffix = preg_replace("/".normalizePreg($base_release)."/i","",$dn);
681     /* Check if given object also exists whitin one of these releases */
682     foreach($previous_releases as $p_release){
683       $check_dn = $dn_suffix.$p_release;
684       $ldap->cat($check_dn,array("dn","objectClass"));
686       if($ldap->count()){
687         return($check_dn);
688       }
689     }
690     return("");
691   }
694   /* return release names of all parent releases */
695   static function get_previous_releases_of_this_release($dn,$flat)
696   {
697     global $config;
698     $ldap = $config->get_ldap_link();
699     $ldap->cd($config->current['BASE']);
700     $ret = array();
702     /* Explode dns into pieces, to be able to build parent dns */
703     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$dn));
705     if(!is_array($dns_to_check)){
706       return;  
707     }
709     /* Unset first entry which represents the given dn */
710     unset($dns_to_check['count']); 
711     unset($dns_to_check[key($dns_to_check)]);
713     /* Create dns addresses and check if this dn is a release dn */
714     $id = 0;
715     while(count($dns_to_check)){
717       /* build parent dn */
718       $new_dn = "";
719       foreach($dns_to_check as $part){
720         $new_dn .= $part.",";
721       }
722       $new_dn .= $config->current['BASE'];
724       /* check if this dn is a release */
725       if(FAI::is_release_department($new_dn)){
726         if($flat){
727           $ret[$id] = $new_dn; 
728         }else{
729           $ret = array($new_dn=>$ret); 
730         }
731         $id ++;
732       }else{
733         return($ret);
734       }
735       reset($dns_to_check);
736       unset($dns_to_check[key($dns_to_check)]);
737     }
738     return($ret);
739   } 
742   /* This function returns all sub release names, recursivly  */
743   static function get_sub_releases_of_this_release($dn,$flat = false)
744   {
745     global $config;
746     $res  = array();
747     $ldap = $config->get_ldap_link();
748     $ldap->cd($config->current['BASE']);
749     $ldap->ls("(objectClass=FAIbranch)",$dn,array("objectClass","dn","ou"));
750     while($attr = $ldap->fetch()){
752       /* Append department name */
753       if($flat){
754         $res[$attr['dn']] = $attr['ou'][0];
755       }else{
756         $res[$attr['dn']] = array();
757       }
759       /* Get sub release departments of this department */
760       if(in_array("FAIbranch",$attr['objectClass'])) {
761         if($flat){
762           $tmp = FAI::                       get_sub_releases_of_this_release($attr['dn'],$flat);
763           foreach($tmp as $dn => $value){
764             $res[$dn]=$value;
765           }
766         }else{
767           $res[$attr['dn']] = FAI::                       get_sub_releases_of_this_release($attr['dn']);
768         }
769       }
770     }
771     return($res);
772   }
775   /* Check if the given department is a release department */
776   static function is_release_department($dn)
777   {
778     global $config;
779     $ldap = $config->get_ldap_link();
780     $ldap->cd($config->current['BASE']);
781     $ldap->cat($dn,array("objectClass","ou"));
783     /* Check objectClasses and name to check if this is a release department */
784     if($ldap->count()){
785       $attrs = $ldap->fetch();
787       $ou = "";
788       if(isset($attrs['ou'][0])){
789         $ou = $attrs['ou'][0];  
790       }
792       if((in_array("FAIbranch",$attrs['objectClass'])) || ($ou == "fai")){
793         return($attrs['dn']);
794       }
795     }
796     return(false);
797   }
800   static function copy_FAI_group_releases($source_release , $destination_name, $type ="" )
801   {
802     global $config;
803     $start = microtime(TRUE);
804     $source_release = trim($source_release,"/");
806     echo "<h2>".sprintf(_("Creating group application release for %s"),$destination_name)."</h2>";
808     $sub_releases = array();
809     $source_dn = "";
810     
811     $tmp = split("\/",$source_release);
812     foreach($tmp as $part){
813       if(empty($part)){
814         continue;
815       }
816       $source_dn            = "ou=".$part.",".$source_dn;
817       $sub_releases[$part]  = $source_dn;
818     }
820     /* Get all groups */
821     $ldap =$config->get_ldap_link();
822     $ldap->cd($config->current['BASE']);
823     $ldap->search("(objectClass=posixGroup)",array("dn"));
824     $groups = array();
825     while($attrs = $ldap->fetch()){
826       $groups[$attrs['dn']] = $attrs;
827     }
829     /* Get all FAI releases, to be able to create missing group application releases 
830         with the correct type of release (FAIstate=freeze/branch).
831      */
832     $f_releases = array();
833     $ldap->cd ($config->current['BASE']);
834     $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
835     while($attrs = $ldap->fetch()){
836       foreach($sub_releases as $sub_rel){
837         if(preg_match("/^".normalizePreg($sub_rel.get_ou('faiou'))."/",$attrs['dn'])){
838           $f_releases[$sub_rel.get_ou('faiou')] = $attrs;
839         }
840       }
841     }
843     /* Get all group releases */
844     $g_releases = array();
845     foreach($groups as $dn => $data){
846       $ldap->cd($dn);
847       $ldap->search("(objectClass=FAIbranch)",array("ou","FAIstate"));
848       while($attrs = $ldap->fetch()){
849         $g_releases[$attrs['dn']] = $attrs;
850       }
851     }
853     /* Check if base releases exists.
854        If they do not exist, create them and adapt FAIstate attribute from FAI releases. 
855      */
856     foreach($sub_releases as $name => $sub_rel){
858       $FAIstate = "";
859       if(isset($f_releases[$sub_rel.get_ou('faiou')]) && isset($f_releases[$sub_rel.get_ou('faiou')]['FAIstate'])){
860         $FAIstate = $f_releases[$sub_rel.get_ou('faiou')]['FAIstate'][0];
861       }
863       foreach($groups as $dn => $data){
864         if(!isset($g_releases[$sub_rel.$dn])){
865           $ldap->cd($dn);
866           $r_data = array();
867           $r_data['ou'] = $name;
868           $r_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
869           if(!empty($FAIstate)) {
870             $r_data['FAIstate'] = $FAIstate;
871           }
872  
873           $ldap->cd($sub_rel.$dn) ;
874           $ldap->add($r_data);
875           echo "&nbsp;<b>"._("Object").":</b> ";
876           echo sprintf(_("Adding missing group application release container %s."),substr(LDAP::fix($sub_rel.$dn),0,96))."<br>";
877           flush();
878         }
879       }
880     } 
881  
882     /* Create new release container in each group.
883      */
884     $n_data = array();
885     $n_data = array();
886     $n_data['ou'] = $destination_name;
887     $n_data['objectClass'] = array("top","organizationalUnit","FAIbranch");
888     if(!empty($type)){
889       $n_data['FAIstate'] = $type."/cow";
890     }
892     foreach($groups as $dn => $att){
893       $n_dn = "ou=".$destination_name.",".$source_dn.$dn;
894       if(!isset($g_releases[$n_dn])){
895         $ldap->cd ($n_dn);
896         $ldap->add($n_data);
897         echo "&nbsp;<b>"._("Object").":</b> ";
898         echo sprintf(_("Adding group application release container %s."),substr(LDAP::fix($n_dn),0,96))."<br>";
899         flush();
900       }
901     }
903     /* If the source release is empty, then create a new release by copying 
904         all group application menus into a new ou=$destination_name release container.
905       
906        If the source release is not empty. 
907          We detect all releases which match the source release dn and copy the contents.
908      */
909     if(empty($source_release)){
910       $source_dns = $groups;
911     }else{
912       $source_dns = array();
913       foreach($g_releases as $dn => $data){
914         if(preg_match("/^".normalizePreg($source_dn)."/",$dn)){
915           $source_dns[$dn] = $data; 
916         }
917       }
918     }
920     /* Detect all menu object we have to copy 
921      */
922     $to_copy = array();
923     foreach($source_dns as $dn => $attrs){
924       $ldap->cd($dn);
925       $ldap->ls("(objectClass=gotoSubmenuEntry)(objectClass=gotoMenuEntry)",$dn,array("dn"));
926       while($attrs = $ldap->fetch()){
927         $destination = preg_replace("/".normalizePreg($dn)."$/","ou=".$destination_name.",".$dn,$attrs['dn']);
928         $to_copy[$attrs['dn']] = $destination;
929       }
930     }
931    
932     /* At least create the menu objects object */
933     $plug = new plugin($config);
934     foreach($to_copy as $source => $destination){
935       $ldap->cat($destination);
936       if($ldap->count()){
937         echo "&nbsp;<b>"._("Object").":</b> ";
938         echo sprintf(_("Could not create menu entry %s. (Already exists)."),substr(LDAP::fix($destination),0,96))."<br>";
939         flush();
940       }else{
941         $plug->copy($source,$destination);
942         echo "&nbsp;<b>"._("Object").":</b> ";
943         echo sprintf(_("Created group application menu entry for %s."),substr(LDAP::fix($destination),0,96))."<br>";
944         flush();
945       }
946     }
947   }
950   /*! \brief Create a new FAI branch.
951    *  @param $sourcedn          String  The source release dn
952    *  @param $destinationdn     String  The destination dn
953    *  @param $destinationName   String  The name of the new release
954    *  @param $type              String  The release type (freeze/branch)
955    *  @param $is_first          Boolean Use to identify the first func. call when recursivly called.
956    *  @param $depth             Integer Current depth of recursion.
957    */
958   function copy_FAI_resource_recursive($sourcedn,$destinationdn,$destinationName,$type="branch",$is_first = true,$depth=0)
959   {
960     global $config;
961     error_reporting(E_ALL | E_STRICT);
962     $ldap     = $config->get_ldap_link();
963     $basedn   = $config->current['BASE'];
964     $delarray = array();
966     /* The following code will output a status string
967      *  for each handled object, in a seperate iframe.
968      */
971     /* Display current action information.
972      */
973     if($is_first){
974       echo "<h2>".sprintf(_("Creating copy of %s"),"<i>".LDAP::fix($sourcedn)."</i>")."</h2>";
975     }else{
976       if(preg_match("/^ou=/",$sourcedn)){
977         echo "<h3>"._("Processing")." <i>".LDAP::fix($destinationdn)."</i></h3>";
978       }else{
979         $tmp = split(",",$sourcedn);
980         echo "&nbsp;<b>"._("Object").":</b> ";
981         $deststr = LDAP::fix($destinationdn);
982         if(strlen($deststr) > 96){
983           $deststr = substr($deststr,0,96)."...";
984         }
985         echo $deststr."<br>";
986       }
987     }
988     /* .. immediately display infos */
989     flush();
991     /* Check if destination entry already exists
992      */
993     $ldap->cat($destinationdn);
994     if($ldap->count()){
995       echo _("Could not create new release, the destination dn is already in use.");
996       return;
997     }else{
999       $ldap->clearResult();
1001       /* Get source entry
1002        *  if it does not exist, abort here.
1003        */
1004       $ldap->cd($basedn);
1005       $ldap->cat($sourcedn);
1006       $attr = $ldap->fetch();
1007       if((!$attr) || (count($attr)) ==0) {
1008         echo _("Error while fetching source dn - aborted!");
1009         return;
1010       }
1012       /* The current object we want to create is an department.
1013        * Create the department and add the FAIbranch tag.
1014        */
1015       if(in_array("organizationalUnit",$attr['objectClass'])){
1016         $attr['dn'] = LDAP::convert($destinationdn);
1017         $ldap->cd($basedn);
1018         $ldap->create_missing_trees($destinationdn);
1019         $ldap->cd($destinationdn);
1021         /* If is first entry, append FAIbranch to department entry */
1022         if($is_first){
1023           $ldap->cat($destinationdn);
1024           $attr= $ldap->fetch();
1025           /* Filter unneeded informations */
1026           foreach($attr as $key => $value){
1027             if(is_numeric($key)) unset($attr[$key]);
1028             if(isset($attr[$key]['count'])){
1029               if(is_array($attr[$key])){
1030                 unset($attr[$key]['count']);
1031               }
1032             }
1033           }
1035           unset($attr['count']);
1036           unset($attr['dn']);
1038           /* Add marking attribute */
1039           $attr['objectClass'][] = "FAIbranch";
1041           /* Add this entry */
1042           $ldap->modify($attr);
1043         }
1044       }else{
1046         /* Replicate all relevant FAI objects here.
1047          * FAI objects, Apps and Mimetypes.
1048          * Get all attributes as binary value, to ensure that Icon, File template aso
1049          *  are created correctly.
1050          */
1051         foreach($attr as $key => $value){
1053           if(in_array($key ,array("gotoLogonScript", "gosaApplicationIcon","gotoMimeIcon"))){
1054             $sr= ldap_read($ldap->cid, LDAP::fix($sourcedn), "$key=*", array($key));
1055             $ei= ldap_first_entry($ldap->cid, $sr);
1056             if ($tmp= @ldap_get_values_len($ldap->cid, $ei,$key)){
1057               $attr[$key] = $tmp;
1058             }
1059           }
1061           if(is_numeric($key)) unset($attr[$key]);
1062           if(isset($attr[$key]['count'])){
1063             if(is_array($attr[$key])){
1064               unset($attr[$key]['count']);
1065             }
1066           }
1067         }
1068         unset($attr['count']);
1069         unset($attr['dn']);
1071         /* Add entry
1072          */
1073         $ldap->cd($destinationdn);
1074         $ldap->cat($destinationdn);
1076         $a = $ldap->fetch();
1077         if(!count($a)){
1078           $ldap->add($attr);
1079         }
1081         if(!$ldap->success()){
1083           /* Some error occurred */
1084           print "---------------------------------------------";
1085           print $ldap->get_error()."<br>";
1086           print $sourcedn."<br>";
1087           print $destinationdn."<br>";
1088           print_a( $attr);
1089           exit();
1090         }
1091       }
1092     }
1094     echo "<script language=\"javascript\" type=\"text/javascript\">scrollDown2();</script>" ;
1096     /* Prepare for recursive copy.
1097      * Get all object within the source dn and
1098      *  call the recursive copy for each.
1099      */
1100     $ldap->ls ("(objectClass=*)",$sourcedn);
1101     while ($ldap->fetch()){
1102       $deldn= $ldap->getDN();
1103       $delarray[$deldn]= strlen($deldn);
1104     }
1105     asort ($delarray);
1106     reset ($delarray);
1107     $depth ++;
1108     foreach($delarray as $dn => $bla){
1109       if($dn != $destinationdn){
1110         $ldap->cd($basedn);
1111         $item = $ldap->fetch($ldap->cat($dn));
1112         if(!in_array("FAIbranch",$item['objectClass'])){
1113           FAI::copy_FAI_resource_recursive($dn,str_replace($sourcedn,$destinationdn,$dn),$destinationName,$type,false,$depth);
1114         }
1115       }
1116     }
1117     if($is_first){
1118       echo "<p class='seperator'>&nbsp;</p>";
1119     }
1120   }
1124   /* This function returns the dn of the object release */
1125   static function get_release_dn($Current_DN)
1126   {
1127     global $config;
1128     $ldap = $config->get_ldap_link();
1129     $ldap->cd($config->current['BASE']);
1131     /* Split dn into pices */ 
1132     $dns_to_check = gosa_ldap_explode_dn(preg_replace("/".normalizePreg(",".$config->current['BASE'])."/i","",$Current_DN));
1134     if(!is_array($dns_to_check)){
1135       return;  
1136     }
1138     /* Use dn pieces, to create sub dns like 
1139        ou=test,ou=1,ou=0...
1140        ou=1,ou=0...
1141        ou=0... 
1142        To check which dn is our release container.
1143      */
1144     unset($dns_to_check['count']); 
1145     while(count($dns_to_check)){
1147       /* Create dn */
1148       $new_dn = "";
1149       foreach($dns_to_check as $part){
1150         $new_dn .= $part.",";
1151       }
1152       $new_dn .= $config->current['BASE'];
1154       /* Check if this dn is a release dn */
1155       if(FAI::is_release_department($new_dn)){
1156         return($new_dn);
1157       }
1159       /* Remove first element of dn pieces */
1160       reset($dns_to_check);
1161       unset($dns_to_check[key($dns_to_check)]);
1162     }
1163     return("");
1164   }
1170 // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler:
1171 ?>